001package Torello.Java; 002 003import java.util.function.*; 004import java.util.regex.*; 005import java.io.*; 006 007import static Torello.Java.C.*; 008 009/** 010 * A functional-interface for specifying a regular-expression, and how to print the results, 011 * to the <CODE>GREP</CODE> Tool. 012 * 013 * <EMBED CLASS='external-html' DATA-FILE-ID=SEARCH_AND_PRNT> 014 */ 015@FunctionalInterface 016public interface SearchAndPrint extends java.io.Serializable 017{ 018 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUIDFI> */ 019 public static final long serialVersionUID = 1; 020 021 /** 022 * <EMBED CLASS='external-html' DATA-FILE-ID=FUNC_INTER_METH> 023 * 024 * @param fileName The name of any file, from the File-System. 025 * 026 * @param fileContents The contents of that file as a {@code String}. 027 * 028 * @return A {@code TRUE} value should mean that the {@code FileNode} has passed the match test. 029 * A return value of {@code FALSE} should indicate that the {@code FileNode} did not contain any 030 * matches for the {@code GREP} search routine. 031 * 032 * <BR /><BR /><B><SPAN STYLE="color: red;">IMPORTANT NOTE:</B></SPAN> This method is also 033 * expected to perform any printing and match-evaluating that needs to be performed when 034 * {@code GREP}'ING a directory, or directory-tree, of files. This is in addition to the 035 * simple job of returning a true/false boolean indicating whether a match occurred. 036 */ 037 public boolean test(String fileName, String fileContents) throws IOException; 038 039 040 // ******************************************************************************************** 041 // ******************************************************************************************** 042 // ALL, String-Token 043 // ******************************************************************************************** 044 // ******************************************************************************************** 045 046 047 /** 048 * This static-factory 'builder' method merely returns a C-Styled Function-Pointer, which in 049 * Java is referred to as a {@code FunctionalInterface} and may also be called a Lambda-Target. 050 * 051 * <BR /><BR />The function that is returned will simply look through the contents of a file 052 * which here is just called {@code 'fileContents'} (in the Method Body Code below) for a 053 * particular substring {@code 'token.'} 054 * 055 * <BR /><BR /><B CLASS=JDDescLabel>Matches Returned:</B> 056 * 057 * <BR />All Regular-Expression Matches found in {@code 'fileContents'} shall be sent to the 058 * User-Provided {@code Appendable} parameter {@code 'a'}. 059 * 060 * @param token The UNIX-GREP command scours a single-file, or all files in a directory or tree 061 * of directories for a particular {@code String}-token. This parameter {@code 'token'} is the 062 * {@code String} that the {@code GREP} Search-Logic will be using to search the files in the 063 * File-System. 064 * 065 * @param ignoreCase This parameter will inform the Search-Logic to ignore case sensitivity 066 * during the string comparisons of file-content. 067 * 068 * @param a Uses {@code java.lang.Appendable} to receive output-text information/messages. 069 * If this parameter is 'null', then output will not be printed, with the intention being, 070 * {@code GREP's} return value {@code Vector<FileNode>} is sufficient of a return-value. 071 * 072 * <EMBED CLASS='external-html' DATA-FILE-ID=APPENDABLE> 073 * 074 * @param useUNIXColorChars If both of the following are true, then UNIX Color-Code Characters 075 * will be appended to the output stream. 076 * 077 * @return An instance of {@code 'SearchAndPrint'} that obeys these search-criteria, and 078 * sends output to the specified destination. 079 */ 080 public static SearchAndPrint ALL 081 (String token, boolean ignoreCase, boolean useUNIXColorChars, Appendable a) 082 { 083 // FAIL-FAST: Before building a Lambda-Predicate, make sure the testing-supplies work. 084 if (token == null) throw new NullPointerException 085 ("String-Parameter 'token' was passed null to static-factory method 'ALL'."); 086 087 // Build & Generate an instance of 'SearchAndPrint', a @FunctionalInterface that is highly 088 // similar to java.util.function.BiPredicate (but throws IOException), and return it. 089 090 return (String fileName, String fileContents) -> 091 findAndPrint 092 (fileName, fileContents, token, -1, ignoreCase, true, useUNIXColorChars, a); 093 } 094 095 096 // ******************************************************************************************** 097 // ******************************************************************************************** 098 // All, Regular-Expression 099 // ******************************************************************************************** 100 // ******************************************************************************************** 101 102 103 /** 104 * This static-factory 'builder' method merely returns a C-Styled Function-Pointer, which in 105 * Java is referred to as a {@code FunctionalInterface} and may also be called a Lambda-Target. 106 * 107 * <BR /><BR />The function that is returned will simply look through the contents of a file 108 * which here is just called {@code 'fileContents'} (in the Method Body Code below) using a 109 * Regular-Expression Matcher, which here is {@code Pattern} parameter {@code 'regEx'}. 110 * 111 * <BR /><BR /><B CLASS=JDDescLabel>Matches Returned:</B> 112 * 113 * <BR />All Regular-Expression Matches found in {@code 'fileContents'} shall be sent to the 114 * User-Provided {@code Appendable} parameter {@code 'a'}. 115 * 116 * @param regEx The UNIX-GREP command scours a single-file, or all files in a directory or tree 117 * of directories for a match using a regular-expression matcher. This parameter 118 * {@code regEx}. 119 * 120 * @param a Uses {@code java.lang.Appendable} to receive output-text information/messages. 121 * If this parameter is 'null', then output will not be printed, with the intention being, 122 * {@code GREP's} return value {@code Vector<FileNode>} is sufficient of a return-value. 123 * 124 * <EMBED CLASS='external-html' DATA-FILE-ID=APPENDABLE> 125 * 126 * @param useUNIXColorChars If both of the following are true, then UNIX Color-Code Characters 127 * will be appended to the output stream. 128 * 129 * @return An instance of {@code 'SearchAndPrint'} that obeys these search-criteria, and sends 130 * output to the specified destination. 131 */ 132 public static SearchAndPrint ALL(Pattern regEx, boolean useUNIXColorChars, Appendable a) 133 { 134 // FAIL-FAST: Before building a Lambda-Predicate, make sure the testing-supplies work. 135 if (regEx == null) throw new NullPointerException( 136 "Regular-Expression Parameter 'regEx' was passed null to static-factory method " + 137 "'ALL'." 138 ); 139 140 // Build & Generate an instance of 'SearchAndPrint', a @FunctionalInterface that is highly 141 // similar to java.util.function.BiPredicate (but throws IOException), and return it. 142 143 return (String fileName, String fileContents) -> 144 findAndPrint(fileName, fileContents, regEx, -1, useUNIXColorChars, a); 145 } 146 147 148 // ******************************************************************************************** 149 // ******************************************************************************************** 150 // FIRSTN, String-Token 151 // ******************************************************************************************** 152 // ******************************************************************************************** 153 154 155 /** 156 * This static-factory 'builder' method merely returns a C-Styled Function-Pointer, which in 157 * Java is referred to as a {@code FunctionalInterface} and may also be called a Lambda-Target. 158 * 159 * <BR /><BR />The function that is returned will simply look through the contents of a file 160 * which here is just called {@code 'fileContents'} (in the Method Body Code below) for a 161 * particular substring {@code 'token'}. 162 * 163 * <BR /><BR /><B CLASS=JDDescLabel>Matches Returned:</B> 164 * 165 * <BR />The first {@code 'n'} number of matches shall be sent to the User-Provided 166 * {@code Appendable} parameter {@code 'a'}. 167 * 168 * @param token The UNIX-GREP command scours a single-file, or all files in a directory or tree 169 * of directories for a particular {@code String}-token. This parameter {@code 'token'} is the 170 * {@code String} that the {@code GREP} Search-Logic will be using to search the files in the 171 * File-System. 172 * 173 * @param n This will put a 'maximum-count' on the number of {@code String}-token-matches 174 * that the {@code GREP} Class / Command will return. Here, {@code 'n'} must be a 175 * positive-integer (greater-than 0), or an {@code 'NException'} will throw. 176 * 177 * @param ignoreCase This parameter will inform the Search-Logic to ignore case sensitivity 178 * during the {@code String} comparisons of file-content. 179 * 180 * @param a Uses {@code java.lang.Appendable} to receive output-text information/messages. 181 * If this parameter is 'null', then output will not be printed, with the intention being, 182 * {@code GREP's} return value {@code Vector<FileNode>} is sufficient of a return-value. 183 * 184 * <EMBED CLASS='external-html' DATA-FILE-ID=APPENDABLE> 185 * 186 * @param useUNIXColorChars If both of the following are true, then UNIX Color-Code 187 * Characters will be appended to the output stream. 188 * 189 * @return An instance of {@code 'SearchAndPrint'} that obeys these search-criteria, and 190 * sends output to the specified destination. 191 * 192 * @throws NException If {@code 'n'} is a negative integer, or zero. 193 */ 194 public static SearchAndPrint FIRSTN 195 (String token, int n, boolean ignoreCase, boolean useUNIXColorChars, Appendable a) 196 { 197 // FAIL-FAST: Before building a Lambda-Predicate, make sure the testing-supplies work. 198 if (token == null) throw new NullPointerException 199 ("String-Parameter 'token' was passed null to static-factory method 'FIRSTN'."); 200 201 // FAIL-FAST: Simple check on the value of 'n' - to make sure n is not negative, or zero. 202 NException.check(n); 203 204 // Build & Generate an instance of 'SearchAndPrint', a @FunctionalInterface that is highly 205 // similar to java.util.function.BiPredicate (but throws IOException), and return it. 206 207 return (String fileName, String fileContents) -> 208 findAndPrint(fileName, fileContents, token, n, ignoreCase, true, useUNIXColorChars, a); 209 } 210 211 212 // ******************************************************************************************** 213 // ******************************************************************************************** 214 // FIRSTN, Regular-Expression 215 // ******************************************************************************************** 216 // ******************************************************************************************** 217 218 219 /** 220 * This static-factory 'builder' method merely returns a C-Styled Function-Pointer, which in 221 * Java is referred to as a {@code FunctionalInterface} and may also be called a Lambda-Target. 222 * 223 * <BR /><BR />The function that is returned will simply look through the contents of a file 224 * which here is just called {@code 'fileContents'} (in the Method Body Code below) using a 225 * Regular-Expression Matcher, which here is {@code Pattern} parameter {@code 'regEx'}. 226 * 227 * <BR /><BR /><B CLASS=JDDescLabel>Matches Returned:</B> 228 * 229 * <BR />The first {@code 'n'} number of matches shall be sent to the User-Provided 230 * {@code Appendable} parameter {@code 'a'}. 231 * 232 * @param regEx The UNIX-GREP command scours a single-file, or all files in a directory or tree 233 * of directories for a match using a regular-expression matcher. This parameter 234 * {@code 'regEx'}. 235 * 236 * @param n This will put a 'maximum-count' on the number of regular-expression matches that 237 * the {@code GREP} Class / Command will return. Here, {@code 'n'} must be a positive-integer 238 * (greater-than 0), or an {@code 'NException'} will throw. 239 * 240 * @param a Uses {@code java.lang.Appendable} to receive output-text information/messages. 241 * If this parameter is 'null', then output will not be printed, with the intention being, 242 * {@code GREP's} return value {@code Vector<FileNode>} is sufficient of a return-value. 243 * 244 * <EMBED CLASS='external-html' DATA-FILE-ID=APPENDABLE> 245 * 246 * @param useUNIXColorChars If both of the following are true, then UNIX Color-Code Characters 247 * will be appended to the output stream. 248 * 249 * @return An instance of {@code 'SearchAndPrint'} that obeys these search-criteria, and sends 250 * output to the specified destination. 251 * 252 * @throws NException If {@code 'n'} is a negative integer, or zero. 253 */ 254 public static SearchAndPrint FIRSTN 255 (Pattern regEx, int n, boolean useUNIXColorChars, Appendable a) 256 { 257 // FAIL-FAST: Before building a Lambda-Predicate, make sure the testing-supplies work. 258 if (regEx == null) throw new NullPointerException( 259 "Regular-Expression Parameter 'regEx' was passed null to static-factory method " + 260 "'FIRSTN'." 261 ); 262 263 // FAIL-FAST: Simple check on the value of 'n' - to make sure n is not negative, or zero. 264 NException.check(n); 265 266 // Build & Generate an instance of 'SearchAndPrint', a @FunctionalInterface that is highly 267 // similar to java.util.function.BiPredicate (but throws IOException), and return it. 268 269 return (String fileName, String fileContents) -> 270 findAndPrint(fileName, fileContents, regEx, n, useUNIXColorChars, a); 271 } 272 273 274 // ******************************************************************************************** 275 // ******************************************************************************************** 276 // LASTN, String-Token 277 // ******************************************************************************************** 278 // ******************************************************************************************** 279 280 281 /** 282 * This static-factory 'builder' method merely returns a C-Styled Function-Pointer, which in 283 * Java is referred to as a {@code FunctionalInterface} and may also be called a Lambda-Target. 284 * 285 * <BR /><BR />The function that is returned will simply look through the contents of a file 286 * which here is just called {@code 'fileContents'} (in the Method Body Code below), for a 287 * particular substring {@code 'token'}. 288 * 289 * <BR /><BR /><B CLASS=JDDescLabel>Matches Returned:</B> 290 * 291 * <BR />The last {@code 'n'} number of matches shall be sent to the User-Provided 292 * {@code Appendable} parameter {@code 'a'}. 293 * 294 * @param token The UNIX-GREP command scours a single-file, or all files in a directory or tree 295 * of directories for a particular {@code String}-token. This parameter {@code 'token'} is the 296 * {@code String} that the {@code GREP} Search-Logic will be using to search the files in the 297 * File-System. 298 * 299 * @param n This will put a 'maximum-count' on the number of {@code String}-token-matches that 300 * the {@code GREP} Class / Command will return. Here, {@code 'n'} must be a positive-integer 301 * (greater-than 0), or an {@code 'NException'} will throw. 302 * 303 * @param ignoreCase This parameter will inform the Search-Logic to ignore case sensitivity 304 * during the {@code String} comparisons of file-content. 305 * 306 * @param a Uses {@code java.lang.Appendable} to receive output-text information/messages. If 307 * this parameter is 'null', then output will not be printed, with the intention being, 308 * {@code GREP's} return value {@code Vector<FileNode>} is sufficient of a return-value. 309 * 310 * <EMBED CLASS='external-html' DATA-FILE-ID=APPENDABLE> 311 * 312 * @param useUNIXColorChars If both of the following are true, then UNIX Color-Code Characters 313 * will be appended to the output stream. 314 * 315 * @return An instance of {@code 'SearchAndPrint'} that obeys these search-criteria, and sends 316 * output to the specified destination. 317 * 318 * @throws NException If {@code 'n'} is a negative integer, or zero. 319 */ 320 public static SearchAndPrint LASTN 321 (String token, int n, boolean ignoreCase, boolean useUNIXColorChars, Appendable a) 322 { 323 // FAIL-FAST: Before building a Lambda-Predicate, make sure the testing-supplies work. 324 if (token == null) throw new NullPointerException 325 ("String-Parameter 'token' was passed null to static-factory method 'FIRSTN'."); 326 327 // FAIL-FAST: Simple check on the value of 'n' - to make sure n is not negative, or zero. 328 NException.check(n); 329 330 // Build & Generate an instance of 'SearchAndPrint', a @FunctionalInterface that is highly 331 // similar to java.util.function.BiPredicate (but throws IOException), and return it. 332 333 return (String fileName, String fileContents) -> 334 findAndPrint 335 (fileName, fileContents, token, n, ignoreCase, false, useUNIXColorChars, a); 336 } 337 338 339 // ******************************************************************************************** 340 // ******************************************************************************************** 341 // PROTECTED TOP-LEVEL DISPATCH METHODS 342 // ******************************************************************************************** 343 // ******************************************************************************************** 344 345 346 /** 347 * This will search through a file using a regular-expression. 348 * 349 * @param numMatches This is the number of matches to print before exiting. Each match will 350 * decrement the counter by 1, and this method shall exit once this reaches zero, or once the 351 * number of matches has exceeded this count. 352 * 353 * <BR /><BR /><B>NOTE:</B> Setting this parameter to a negative number will disable the 354 * counter, and all matches will be returned. 355 * 356 * @return {@code TRUE} if there was match in the file, and {@code FALSE} otherwise. 357 */ 358 static boolean findAndPrint( 359 String fileName, String fileContents, Pattern regEx, int numMatches, 360 boolean useUNIXColorChars, Appendable a 361 ) 362 throws IOException 363 { 364 Matcher m = regEx.matcher(fileContents); 365 boolean ret = false; 366 367 while ((numMatches != 0) && m.find()) 368 { 369 ret = true; 370 371 if (a != null) a.append( 372 BRED + "File: " + RESET + BYELLOW + fileName + RESET + ", " + 373 BRED + "Line: " + RESET + StrPrint.lineOrLines 374 (fileContents, m.start(), m.end() - m.start(), BCYAN) + '\n' 375 ); 376 377 if (numMatches > 0) numMatches--; 378 } 379 380 return ret; 381 } 382 383 /** 384 * This will search through a file by looking for a particular {@code String} 'token.' 385 *= 386 * @param numMatches This is the number of matches to print before exiting. Each match will 387 * decrement the counter by 1, and this method shall exit once this reaches zero, or once the 388 * number of matches has exceeded this count. 389 * 390 * <BR /><BR /><B>NOTE:</B> Setting this parameter to a negative number will disable the 391 * counter, and all matches will be returned. 392 * 393 * @param forwardOrReverse When this parameter is {@code TRUE}, then the search shall begin at 394 * the start of the file-contents, and continue forward towards the End-Of-File. When this 395 * parameter is {@code FALSE}, the {@code String}-Token Matching shall start at the End-Of-File, 396 * and work towards the beginning. 397 * 398 * @return {@code TRUE} if there was match in the file, and {@code FALSE} otherwise. 399 */ 400 static boolean findAndPrint( 401 String fileName, String fileContents, String token, int numMatches, boolean ignoreCase, 402 boolean forwardOrReverse, boolean useUNIXColorChars, Appendable a 403 ) 404 throws IOException 405 { 406 int pos = forwardOrReverse ? 0 : (fileContents.length() - 1); 407 int len = token.length(); 408 boolean ret = false; 409 410 // IGNORE-CASE 411 if (ignoreCase) 412 { 413 // Search Forward, from beginning of fileContents 414 if (forwardOrReverse) 415 416 while ( (numMatches != 0) 417 && ((pos = StrIndexOf.first_CI(fileContents, pos, -1, token)) != -1) 418 ) 419 { 420 ret = true; 421 422 if (a != null) a.append( 423 BRED + "File: " + RESET + BYELLOW + fileName + RESET + ", " + 424 BRED + "Line: " + RESET + StrPrint.lineOrLines 425 (fileContents, pos, len, BCYAN) + '\n' 426 ); 427 428 pos += len; 429 if (numMatches > 0) numMatches--; 430 } 431 432 // Search Backwards, from ending of fileContents 433 else 434 435 while ( (numMatches != 0) 436 && ((pos = StrIndexOf.left(fileContents, pos, token)) != -1) 437 ) 438 { 439 ret = true; 440 441 if (a != null) a.append( 442 BRED + "File: " + RESET + BYELLOW + fileName + RESET + ", " + 443 BRED + "Line: " + RESET + StrPrint.lineOrLines 444 (fileContents, pos, len, BCYAN) + '\n' 445 ); 446 447 pos--; 448 if (numMatches > 0) numMatches--; 449 } 450 } 451 452 // else DO-NOT IGNORE-CASE 453 else 454 { 455 // Search Forward, from beginning of fileContents 456 if (forwardOrReverse) 457 458 while ( (numMatches != 0) 459 && ((pos = fileContents.indexOf(token, pos)) != -1) 460 ) 461 { 462 ret = true; 463 464 if (a != null) a.append( 465 BRED + "File: " + RESET + BYELLOW + fileName + RESET + ", " + 466 BRED + "Line: " + RESET + StrPrint.lineOrLines 467 (fileContents, pos, len, BCYAN) + '\n' 468 ); 469 470 pos += len; 471 if (numMatches > 0) numMatches--; 472 } 473 474 // Search Backwards, from ending of fileContents 475 else 476 while ( (numMatches != 0) 477 && ((pos = StrIndexOf.left(fileContents, pos, token)) != -1) 478 ) 479 { 480 ret = true; 481 482 if (a != null) a.append( 483 BRED + "File: " + RESET + BYELLOW + fileName + RESET + ", " + 484 BRED + "Line: " + RESET + StrPrint.lineOrLines 485 (fileContents, pos, len, BCYAN) + '\n' 486 ); 487 488 pos--; 489 if (numMatches > 0) numMatches--; 490 } 491 } 492 493 return ret; 494 } 495}