1 package org.sentrysoftware.jawk.util; 2 3 /*- 4 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲ 5 * Jawk 6 * ჻჻჻჻჻჻ 7 * Copyright (C) 2006 - 2023 Sentry Software 8 * ჻჻჻჻჻჻ 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU Lesser General Public License as 11 * published by the Free Software Foundation, either version 3 of the 12 * License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Lesser Public License for more details. 18 * 19 * You should have received a copy of the GNU General Lesser Public 20 * License along with this program. If not, see 21 * <http://www.gnu.org/licenses/lgpl-3.0.html>. 22 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱ 23 */ 24 25 import java.io.InputStream; 26 import java.io.PrintStream; 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.List; 30 import java.util.Locale; 31 import java.util.Map; 32 33 /** 34 * A simple container for the parameters of a single AWK invocation. 35 * These values have defaults. 36 * These defaults may be changed through command line arguments, 37 * or when invoking Jawk programmatically, from within Java code. 38 * 39 * @author Danny Daglas 40 */ 41 public class AwkSettings { 42 43 /** 44 * Where input is read from. 45 * By default, this is {@link System#in}. 46 */ 47 private InputStream input = System.in; 48 49 /** 50 * Contains variable assignments which are applied prior to 51 * executing the script (-v assignments). 52 * The values may be of type <code>Integer</code>, 53 * <code>Double</code> or <code>String</code>. 54 */ 55 private Map<String, Object> variables = new HashMap<String, Object>(); 56 57 /** 58 * Contains name=value or filename entries. 59 * Order is important, which is why name=value and filenames 60 * are listed in the same List container. 61 */ 62 private List<String> nameValueOrFileNames = new ArrayList<String>(); 63 64 /** 65 * Script sources meta info. 66 * This will usually be either one String container, 67 * made up of the script given on the command line directly, 68 * with the first non-"-" parameter, 69 * or one or multiple script file names (if provided with -f switches). 70 */ 71 private List<ScriptSource> scriptSources = new ArrayList<ScriptSource>(); 72 73 /** 74 * Initial Field Separator (FS) value. 75 * <code>null</code> means the default FS value. 76 */ 77 private String fieldSeparator = null; 78 79 /** 80 * Whether to dump the syntax tree; 81 * <code>false</code> by default. 82 */ 83 private boolean dumpSyntaxTree = false; 84 85 /** 86 * Whether to dump the intermediate code; 87 * <code>false</code> by default. 88 */ 89 private boolean dumpIntermediateCode = false; 90 91 /** 92 * Whether to enable additional functions (_sleep/_dump); 93 * <code>false</code> by default. 94 */ 95 private boolean additionalFunctions = false; 96 97 /** 98 * Whether to enable additional type functions (_INTEGER/_DOUBLE/_STRING); 99 * <code>false</code> by default. 100 */ 101 102 private boolean additionalTypeFunctions = false; 103 104 /** 105 * Whether to maintain array keys in sorted order; 106 * <code>false</code> by default. 107 */ 108 private boolean useSortedArrayKeys = false; 109 110 /** 111 * Whether to trap <code>IllegalFormatExceptions</code> 112 * for <code>[s]printf</code>; 113 * <code>true</code> by default. 114 */ 115 private boolean catchIllegalFormatExceptions = true; 116 117 /** 118 * Whether user extensions are enabled; 119 * <code>false</code> by default. 120 */ 121 private boolean userExtensions = false; 122 123 /** 124 * Write to intermediate file; 125 * <code>false</code> by default. 126 */ 127 private boolean writeIntermediateFile = false; 128 129 /** 130 * Output filename; 131 * <code>null</code> by default, 132 * which means the appropriate default file-name will get used. 133 */ 134 private String outputFilename = null; 135 136 /** 137 * Output stream; 138 * <code>System.out</code> by default, 139 * which means we will print to stdout by default 140 */ 141 private PrintStream outputStream = System.out; 142 143 /** 144 * Compiled destination directory (if provided); 145 * <code>"."</code> by default. 146 */ 147 private String destinationDirectory = "."; 148 149 /** 150 * Locale for the output of numbers 151 * <code>US-English</code> by default. 152 */ 153 private Locale locale = Locale.US; 154 155 /** 156 * Default value for RS, when not set specifically by the AWK script 157 */ 158 private String defaultRS = System.getProperty("line.separator", "\n"); 159 160 /** 161 * Default value for ORS, when not set specifically by the AWK script 162 */ 163 private String defaultORS = System.getProperty("line.separator", "\n"); 164 165 /** 166 * <p>toDescriptionString.</p> 167 * 168 * @return a human readable representation of the parameters values. 169 */ 170 public String toDescriptionString() { 171 172 StringBuilder desc = new StringBuilder(); 173 174 final char newLine = '\n'; 175 176 desc.append("variables = ") 177 .append(getVariables()).append(newLine); 178 desc.append("nameValueOrFileNames = ") 179 .append(getNameValueOrFileNames()).append(newLine); 180 desc.append("scriptSources = ") 181 .append(scriptSources).append(newLine); 182 desc.append("fieldSeparator = ") 183 .append(getFieldSeparator()).append(newLine); 184 desc.append("dumpSyntaxTree = ") 185 .append(isDumpSyntaxTree()).append(newLine); 186 desc.append("dumpIntermediateCode = ") 187 .append(isDumpIntermediateCode()).append(newLine); 188 desc.append("additionalFunctions = ") 189 .append(isAdditionalFunctions()).append(newLine); 190 desc.append("additionalTypeFunctions = ") 191 .append(isAdditionalTypeFunctions()).append(newLine); 192 desc.append("useSortedArrayKeys = ") 193 .append(isUseSortedArrayKeys()).append(newLine); 194 desc.append("catchIllegalFormatExceptions = ") 195 .append(isCatchIllegalFormatExceptions()).append(newLine); 196 desc.append("writeIntermediateFile = ") 197 .append(isWriteIntermediateFile()).append(newLine); 198 desc.append("outputFilename = ") 199 .append(getOutputFilename()).append(newLine); 200 desc.append("destinationDirectory = ") 201 .append(getDestinationDirectory()).append(newLine); 202 203 return desc.toString(); 204 } 205 206 /** 207 * Provides a description of extensions that are enabled/disabled. 208 * The default compiler implementation uses this method 209 * to describe extensions which are compiled into the script. 210 * The description is then provided to the user within the usage. 211 * 212 * @return A description of the extensions which are enabled/disabled. 213 */ 214 public String toExtensionDescription() { 215 216 StringBuilder extensions = new StringBuilder(); 217 218 if (isAdditionalFunctions()) { 219 extensions.append(", _sleep & _dump enabled"); 220 } 221 if (isAdditionalTypeFunctions()) { 222 extensions.append(", _INTEGER, _DOUBLE, _STRING enabled"); 223 } 224 if (isUseSortedArrayKeys()) { 225 extensions.append(", associative array keys are sorted"); 226 } 227 if (isCatchIllegalFormatExceptions()) { 228 extensions.append(", IllegalFormatExceptions NOT trapped"); 229 } 230 231 if (extensions.length() > 0) { 232 return "{extensions: " + extensions.substring(2) + "}"; 233 } else { 234 return "{no compiled extensions utilized}"; 235 } 236 } 237 238 239 @SuppressWarnings("unused") 240 private void addInitialVariable(String keyValue) { 241 int equalsIdx = keyValue.indexOf('='); 242 assert equalsIdx >= 0; 243 String name = keyValue.substring(0, equalsIdx); 244 String valueString = keyValue.substring(equalsIdx + 1); 245 Object value; 246 // deduce type 247 try { 248 value = Integer.parseInt(valueString); 249 } catch (NumberFormatException nfe) { 250 try { 251 value = Double.parseDouble(valueString); 252 } catch (NumberFormatException nfe2) { 253 value = valueString; 254 } 255 } 256 // note: can overwrite previously defined variables 257 getVariables().put(name, value); 258 } 259 260 /** 261 * <p>Getter for the field <code>outputFilename</code>.</p> 262 * 263 * @param defaultFileName The filename to return if -o argument 264 * is not used. 265 * @return the optarg for the -o parameter, or the defaultFileName 266 * parameter if -o is not utilized. 267 */ 268 public String getOutputFilename(String defaultFileName) { 269 if (getOutputFilename() == null) { 270 return defaultFileName; 271 } else { 272 return getOutputFilename(); 273 } 274 } 275 276 /** 277 * <p>Getter for the field <code>scriptSources</code>.</p> 278 * 279 * @return the script sources meta info. 280 * This will usually be either one String container, 281 * made up of the script given on the command line directly, 282 * with the first non-"-" parameter, 283 * or one or multiple script file names (if provided with -f switches). 284 */ 285 public List<ScriptSource> getScriptSources() { 286 return scriptSources; 287 } 288 289 /** 290 * Add the specified ScriptSource 291 * 292 * @param scriptSource ScriptSource instance to add 293 */ 294 public void addScriptSource(ScriptSource scriptSource) { 295 scriptSources.add(scriptSource); 296 } 297 298 /** 299 * Where input is read from. 300 * By default, this is {@link java.lang.System#in}. 301 * 302 * @return the input 303 */ 304 public InputStream getInput() { 305 return input; 306 } 307 308 /** 309 * Where input is read from. 310 * By default, this is {@link java.lang.System#in}. 311 * 312 * @param input the input to set 313 */ 314 public void setInput(InputStream input) { 315 this.input = input; 316 } 317 318 /** 319 * Contains variable assignments which are applied prior to 320 * executing the script (-v assignments). 321 * The values may be of type <code>Integer</code>, 322 * <code>Double</code> or <code>String</code>. 323 * 324 * @return the variables 325 */ 326 public Map<String, Object> getVariables() { 327 return variables; 328 } 329 330 /** 331 * Contains variable assignments which are applied prior to 332 * executing the script (-v assignments). 333 * The values may be of type <code>Integer</code>, 334 * <code>Double</code> or <code>String</code>. 335 * 336 * @param variables the variables to set 337 */ 338 public void setVariables(Map<String, Object> variables) { 339 this.variables = variables; 340 } 341 342 /** 343 * Contains name=value or filename entries. 344 * Order is important, which is why name=value and filenames 345 * are listed in the same List container. 346 * 347 * @return the nameValueOrFileNames 348 */ 349 public List<String> getNameValueOrFileNames() { 350 return nameValueOrFileNames; 351 } 352 353 /** 354 * Contains name=value or filename entries. 355 * Order is important, which is why name=value and filenames 356 * are listed in the same List container. 357 * 358 * @param nameValueOrFileNames the nameValueOrFileNames to set 359 */ 360 public void setNameValueOrFileNames(List<String> nameValueOrFileNames) { 361 this.nameValueOrFileNames = nameValueOrFileNames; 362 } 363 364 /** 365 * Script sources meta info. 366 * This will usually be either one String container, 367 * made up of the script given on the command line directly, 368 * with the first non-"-" parameter, 369 * or one or multiple script file names (if provided with -f switches). 370 * 371 * @param scriptSources the scriptSources to set 372 */ 373 public void setScriptSources(List<ScriptSource> scriptSources) { 374 this.scriptSources = scriptSources; 375 } 376 377 /** 378 * Initial Field Separator (FS) value. 379 * <code>null</code> means the default FS value. 380 * 381 * @return the fieldSeparator 382 */ 383 public String getFieldSeparator() { 384 return fieldSeparator; 385 } 386 387 /** 388 * Initial Field Separator (FS) value. 389 * <code>null</code> means the default FS value. 390 * 391 * @param fieldSeparator the fieldSeparator to set 392 */ 393 public void setFieldSeparator(String fieldSeparator) { 394 this.fieldSeparator = fieldSeparator; 395 } 396 397 /** 398 * Whether to dump the syntax tree; 399 * <code>false</code> by default. 400 * 401 * @return the dumpSyntaxTree 402 */ 403 public boolean isDumpSyntaxTree() { 404 return dumpSyntaxTree; 405 } 406 407 /** 408 * Whether to dump the syntax tree; 409 * <code>false</code> by default. 410 * 411 * @param dumpSyntaxTree the dumpSyntaxTree to set 412 */ 413 public void setDumpSyntaxTree(boolean dumpSyntaxTree) { 414 this.dumpSyntaxTree = dumpSyntaxTree; 415 } 416 417 /** 418 * Whether to dump the intermediate code; 419 * <code>false</code> by default. 420 * 421 * @return the dumpIntermediateCode 422 */ 423 public boolean isDumpIntermediateCode() { 424 return dumpIntermediateCode; 425 } 426 427 /** 428 * Whether to dump the intermediate code; 429 * <code>false</code> by default. 430 * 431 * @param dumpIntermediateCode the dumpIntermediateCode to set 432 */ 433 public void setDumpIntermediateCode(boolean dumpIntermediateCode) { 434 this.dumpIntermediateCode = dumpIntermediateCode; 435 } 436 437 /** 438 * Whether to enable additional functions (_sleep/_dump); 439 * <code>false</code> by default. 440 * 441 * @return the additionalFunctions 442 */ 443 public boolean isAdditionalFunctions() { 444 return additionalFunctions; 445 } 446 447 /** 448 * Whether to enable additional functions (_sleep/_dump); 449 * <code>false</code> by default. 450 * 451 * @param additionalFunctions the additionalFunctions to set 452 */ 453 public void setAdditionalFunctions(boolean additionalFunctions) { 454 this.additionalFunctions = additionalFunctions; 455 } 456 457 /** 458 * Whether to enable additional type functions (_INTEGER/_DOUBLE/_STRING); 459 * <code>false</code> by default. 460 * 461 * @return the additionalTypeFunctions 462 */ 463 public boolean isAdditionalTypeFunctions() { 464 return additionalTypeFunctions; 465 } 466 467 /** 468 * Whether to enable additional type functions (_INTEGER/_DOUBLE/_STRING); 469 * <code>false</code> by default. 470 * 471 * @param additionalTypeFunctions the additionalTypeFunctions to set 472 */ 473 public void setAdditionalTypeFunctions(boolean additionalTypeFunctions) { 474 this.additionalTypeFunctions = additionalTypeFunctions; 475 } 476 477 /** 478 * Whether to maintain array keys in sorted order; 479 * <code>false</code> by default. 480 * 481 * @return the useSortedArrayKeys 482 */ 483 public boolean isUseSortedArrayKeys() { 484 return useSortedArrayKeys; 485 } 486 487 /** 488 * Whether to maintain array keys in sorted order; 489 * <code>false</code> by default. 490 * 491 * @param useSortedArrayKeys the useSortedArrayKeys to set 492 */ 493 public void setUseSortedArrayKeys(boolean useSortedArrayKeys) { 494 this.useSortedArrayKeys = useSortedArrayKeys; 495 } 496 497 /** 498 * Whether user extensions are enabled; 499 * <code>false</code> by default. 500 * 501 * @return the userExtensions 502 */ 503 public boolean isUserExtensions() { 504 return userExtensions; 505 } 506 507 /** 508 * Whether user extensions are enabled; 509 * <code>false</code> by default. 510 * 511 * @param userExtensions the userExtensions to set 512 */ 513 public void setUserExtensions(boolean userExtensions) { 514 this.userExtensions = userExtensions; 515 } 516 517 /** 518 * Write to intermediate file; 519 * <code>false</code> by default. 520 * 521 * @return the writeIntermediateFile 522 */ 523 public boolean isWriteIntermediateFile() { 524 return writeIntermediateFile; 525 } 526 527 /** 528 * Write to intermediate file; 529 * <code>false</code> by default. 530 * 531 * @param writeIntermediateFile the writeIntermediateFile to set 532 */ 533 public void setWriteIntermediateFile(boolean writeIntermediateFile) { 534 this.writeIntermediateFile = writeIntermediateFile; 535 } 536 537 /** 538 * Output filename; 539 * <code>null</code> by default, 540 * which means the appropriate default file-name will get used. 541 * 542 * @return the outputFilename 543 */ 544 public String getOutputFilename() { 545 return outputFilename; 546 } 547 548 /** 549 * Output filename; 550 * <code>null</code> by default, 551 * which means the appropriate default file-name will get used. 552 * 553 * @param outputFilename the outputFilename to set 554 */ 555 public void setOutputFilename(String outputFilename) { 556 this.outputFilename = outputFilename; 557 } 558 559 /** 560 * Output stream; 561 * <code>System.out</code> by default, 562 * which means we will print to stdout by default 563 * 564 * @return the output stream 565 */ 566 public PrintStream getOutputStream() { 567 return outputStream; 568 } 569 570 /** 571 * Sets the OutputStream to print to (instead of System.out by default) 572 * 573 * @param pOutputStream OutputStream to use for print statements 574 */ 575 public void setOutputStream(PrintStream pOutputStream) { 576 outputStream = pOutputStream; 577 } 578 579 /** 580 * Compiled destination directory (if provided); 581 * <code>"."</code> by default. 582 * 583 * @return the destinationDirectory 584 */ 585 public String getDestinationDirectory() { 586 return destinationDirectory; 587 } 588 589 /** 590 * Compiled destination directory (if provided). 591 * 592 * @param destinationDirectory the destinationDirectory to set, 593 * <code>"."</code> by default. 594 */ 595 public void setDestinationDirectory(String destinationDirectory) { 596 597 if (destinationDirectory == null) { 598 throw new IllegalArgumentException("The destination directory might never be null (you might want to use \".\")"); 599 } 600 601 this.destinationDirectory = destinationDirectory; 602 } 603 604 /** 605 * Whether to trap <code>IllegalFormatExceptions</code> 606 * for <code>[s]printf</code>; 607 * <code>true</code> by default. 608 * 609 * @return the catchIllegalFormatExceptions 610 */ 611 public boolean isCatchIllegalFormatExceptions() { 612 return catchIllegalFormatExceptions; 613 } 614 615 /** 616 * Whether to trap <code>IllegalFormatExceptions</code> 617 * for <code>[s]printf</code>; 618 * <code>true</code> by default. 619 * 620 * @param catchIllegalFormatExceptions the catchIllegalFormatExceptions to set 621 */ 622 public void setCatchIllegalFormatExceptions(boolean catchIllegalFormatExceptions) { 623 this.catchIllegalFormatExceptions = catchIllegalFormatExceptions; 624 } 625 626 /** 627 * <p>Getter for the field <code>locale</code>.</p> 628 * 629 * @return the Locale that will be used for outputting numbers 630 */ 631 public Locale getLocale() { 632 return locale; 633 } 634 635 /** 636 * Sets the Locale for outputting numbers 637 * 638 * @param pLocale The locale to be used (e.g.: <code>Locale.US</code>) 639 */ 640 public void setLocale(Locale pLocale) { 641 locale = pLocale; 642 } 643 644 /** 645 * <p>Getter for the field <code>defaultRS</code>.</p> 646 * 647 * @return the default RS, when not set by the AWK script 648 */ 649 public String getDefaultRS() { 650 return defaultRS; 651 } 652 653 /** 654 * Sets the default RS, when not set by the AWK script 655 * 656 * @param rs The regular expression that separates records 657 */ 658 public void setDefaultRS(String rs) { 659 defaultRS = rs; 660 } 661 662 /** 663 * <p>Getter for the field <code>defaultORS</code>.</p> 664 * 665 * @return the default ORS, when not set by the AWK script 666 */ 667 public String getDefaultORS() { 668 return defaultORS; 669 } 670 671 /** 672 * Sets the default ORS, when not set by the AWK script 673 * 674 * @param ors The string that separates output records (with the print statement) 675 */ 676 public void setDefaultORS(String ors) { 677 defaultORS = ors; 678 } 679 }