1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest; 28 29 import java.io.*; 30 import java.net.URL; 31 import java.net.URLClassLoader; 32 import java.nio.charset.StandardCharsets; 33 import java.text.MessageFormat; 34 import java.util.Properties; 35 import java.util.ResourceBundle; 36 37 import com.sun.interview.Interview; 38 import com.sun.interview.Question; 39 import com.sun.interview.WizPrint; 40 import com.sun.javatest.util.BackupPolicy; 41 import com.sun.javatest.util.I18NResourceBundle; 42 43 /** 44 * This class provides a utility for command-line editing of configuration (.jti) files. 45 * It is intended to be invoked from the command line, as in: <pre> 46 * java com.sun.javatest.EditJIT options... 47 * </pre> 48 * For details of the options, use the <code>-help</code> option. 49 */ 50 public class EditJTI 51 { 52 /** 53 * This exception is used to indicate a problem with the command line arguments. 54 */ 55 public static class BadArgs extends Exception 56 { 57 /** 58 * Create a BadArgs exception. 59 * @param i18n A resource bundle in which to find the detail message. 60 * @param s The key for the detail message. 61 */ 62 BadArgs(ResourceBundle i18n, String s) { 63 super(i18n.getString(s)); 64 } 65 66 /** 67 * Create a BadArgs exception. 68 * @param i18n A resource bundle in which to find the detail message. 69 * @param s The key for the detail message. 70 * @param o An argument to be formatted with the detail message by 71 * {@link java.text.MessageFormat#format} 72 */ BadArgs(ResourceBundle i18n, String s, Object o) { 73 super(MessageFormat.format(i18n.getString(s), new Object[] {o})); 74 } 75 76 77 /** 78 * Create a BadArgs exception. 79 * @param i18n A resource bundle in which to find the detail message. 80 * @param s The key for the detail message. 81 * @param o An array of arguments to be formatted with the detail message by 82 * {@link java.text.MessageFormat#format} 83 */ 84 BadArgs(ResourceBundle i18n, String s, Object[] o) { 85 super(MessageFormat.format(i18n.getString(s), o)); 86 } 87 } 88 89 /** 90 * This exception is used to report problems that arise when using this API. 91 */ 92 public static class Fault extends Exception 93 { 94 Fault(I18NResourceBundle i18n, String s) { 95 super(i18n.getString(s)); 96 } 97 98 Fault(I18NResourceBundle i18n, String s, Object o) { 99 super(i18n.getString(s, o)); 100 } 101 102 Fault(I18NResourceBundle i18n, String s, Object[] o) { 103 super(i18n.getString(s, o)); 104 } 105 } 106 107 /** 108 * Command line entry point. Run with <code>-help</code> to get 109 * brief command line help. Warning: this method uses System.exit 110 * and so does not return if called directly. 111 * @param args Comamnd line arguments. 112 */ 113 public static void main(String[] args) { 114 try { 115 EditJTI e = new EditJTI(); 116 boolean ok = e.run(args); 117 System.exit(ok ? 0 : 1); 118 } 119 catch (BadArgs e) { 120 System.err.println(e.getMessage()); 121 usage(System.err); 122 System.exit(2); 123 } 124 catch (Fault e) { 125 System.err.println(e.getMessage()); 126 System.exit(3); 127 } 128 } 129 130 /** 131 * Print out brief command line help. 132 * @param out the stream to which to write the command line help. 133 */ 134 public static void usage(PrintStream out) { 135 String prog = System.getProperty("program", "java " + EditJTI.class.getName()); 136 out.println(i18n.getString("editJTI.usage.title")); 137 out.print(" "); 138 out.print(prog); 139 out.println(i18n.getString("editJTI.usage.summary")); 140 141 out.println(i18n.getString("editJTI.usage.options")); 142 out.println(i18n.getString("editJTI.usage.help1")); 143 out.println(i18n.getString("editJTI.usage.help2")); 144 out.println(i18n.getString("editJTI.usage.help3")); 145 out.println(i18n.getString("editJTI.usage.classpath1")); 146 out.println(i18n.getString("editJTI.usage.classpath2")); 147 out.println(i18n.getString("editJTI.usage.log1")); 148 out.println(i18n.getString("editJTI.usage.log2")); 149 out.println(i18n.getString("editJTI.usage.outfile1")); 150 out.println(i18n.getString("editJTI.usage.outfile2")); 151 out.println(i18n.getString("editJTI.usage.path1")); 152 out.println(i18n.getString("editJTI.usage.path2")); 153 out.println(i18n.getString("editJTI.usage.preview1")); 154 out.println(i18n.getString("editJTI.usage.preview2")); 155 out.println(i18n.getString("editJTI.usage.ts1")); 156 out.println(i18n.getString("editJTI.usage.ts2")); 157 out.println(i18n.getString("editJTI.usage.verbose1")); 158 out.println(i18n.getString("editJTI.usage.verbose2")); 159 out.println(""); 160 out.println(i18n.getString("editJTI.usage.edit")); 161 out.println(i18n.getString("editJTI.usage.set")); 162 out.println(i18n.getString("editJTI.usage.search")); 163 out.println(""); 164 } 165 166 /** 167 * Run the utility, without exiting. Any messages are written to 168 * the standard output stream. 169 * @param args command line args 170 * @return true if the resulting configuration is valid (complete), 171 * and false otherwise. 172 * @throws EditJTI.BadArgs if there is an error analysing the args 173 * @throws EditJTI.Fault if there is an error executing the args 174 */ 175 public boolean run(String[] args) throws BadArgs, Fault { 176 PrintWriter out = new PrintWriter(System.out); 177 try { 178 return run(args, out); 179 } 180 finally { 181 out.flush(); 182 } 183 } 184 185 186 /** 187 * Run the utility, without exiting, writing any messages to a specified stream. 188 * @param args command line args 189 * @param out the stream to which to write any messages 190 * @return true if the resulting configuration is valid (complete), 191 * and false otherwise. 192 * @throws EditJTI.BadArgs if there is an error analysing the args 193 * @throws EditJTI.Fault if there is an error executing the args 194 */ 195 public boolean run(String[] args, PrintWriter out) throws BadArgs, Fault { 196 File inFile = null; 197 File outFile = null; 198 File logFile = null; 199 File classPath = null; 200 File testSuitePath = null; 201 File workDirPath = null; 202 String[] editCmds = null; 203 boolean helpFlag = false; 204 boolean previewFlag = false; 205 boolean showPathFlag = false; 206 boolean verboseFlag = false; 207 208 for (int i = 0; i < args.length; i++) { 209 if ((args[i].equals("-o") || args[i].equals("-out")) 210 && i + 1 < args.length) { 211 checkUnset(outFile, args[i]); 212 outFile = new File(args[++i]); 213 } 214 else if ((args[i].equals("-i") || args[i].equals("-in")) 215 && i + 1 < args.length) { 216 checkUnset(inFile, args[i]); 217 inFile = new File(args[++i]); 218 } 219 else if ((args[i].equals("-l") || args[i].equals("-log")) 220 && i + 1 < args.length) { 221 checkUnset(logFile, args[i]); 222 logFile = new File(args[++i]); 223 } 224 else if (args[i].equals("-n") || args[i].equals("-preview")) 225 previewFlag = true; 226 else if (args[i].equals("-p") || args[i].equals("-path")) 227 showPathFlag = true; 228 else if (args[i].equals("-v") || args[i].equals("-verbose") ) 229 verboseFlag = true; 230 else if ((args[i].equals("-cp") || args[i].equals("-classpath")) && i + 1 < args.length) { 231 checkUnset(classPath, args[i]); 232 classPath = new File(args[++i]); 233 } 234 else if ((args[i].equals("-ts") || args[i].equals("-testsuite")) && i + 1 < args.length) { 235 checkUnset(testSuitePath, args[i]); 236 testSuitePath = new File(args[++i]); 237 } 238 else if ((args[i].equals("-wd") || args[i].equals("-workdir")) && i + 1 < args.length) { 239 checkUnset(testSuitePath, args[i]); 240 workDirPath = new File(args[++i]); 241 } 242 else if (args[i].equals("-help") || args[i].equals("-usage") || args[i].equals("/?") ) 243 helpFlag = true; 244 else if (args[i].startsWith("-")) 245 throw new BadArgs(i18n, "editJTI.badOption", args[i]); 246 else if (i <= args.length - 1) { 247 if (inFile == null) { 248 editCmds = new String[args.length - 1 - i]; 249 System.arraycopy(args, i, editCmds, 0, editCmds.length); 250 inFile = new File(args[args.length - 1]); 251 } 252 else { 253 editCmds = new String[args.length - i]; 254 System.arraycopy(args, i, editCmds, 0, editCmds.length); 255 } 256 i = args.length - 1; 257 } 258 else 259 throw new BadArgs(i18n, "editJTI.badOption", args[i]); 260 } 261 262 if (args.length == 0 || helpFlag) { 263 usage(System.out); 264 if (inFile == null) 265 return true; 266 } 267 268 if (classPath != null && testSuitePath != null) 269 throw new BadArgs(i18n, "editJTI.cantHaveClassPathAndTestSuite"); 270 271 if (inFile == null) 272 throw new BadArgs(i18n, "editJTI.noInterview"); 273 274 // if (editCmds.length == 0 && outFile == null && logFile == null && !showPathFlag) 275 // throw new BadArgs(...no.actions....); 276 277 verbose = verboseFlag; 278 this.out = out; 279 280 try { 281 /* the following looks nice and simple, but breaks compatibility 282 with 3.1.4, because InterviewParameters.open will try and open 283 the wd in the .jti file if not given explicitly -- and previously, 284 this was not required/done. So, only use the simple code if wd 285 is set, and use the old 3.1.4 code if wd is not set. 286 */ 287 /* See comment above 288 if (workDirPath != null || testSuitePath != null) { 289 interview = InterviewParameters.open(testSuitePath, workDirPath, inFile); 290 } 291 */ 292 if (workDirPath != null) 293 interview = InterviewParameters.open(testSuitePath, workDirPath, inFile); 294 else if (testSuitePath != null) { 295 // only open the test suite, not the work dir 296 TestSuite ts; 297 try { 298 ts = TestSuite.open(testSuitePath); 299 } 300 catch (FileNotFoundException e) { 301 throw new Fault(i18n, "editJTI.cantFindTestSuite", testSuitePath); 302 } 303 catch (TestSuite.NotTestSuiteFault e) { 304 throw new Fault(i18n, "editJTI.notATestSuite", testSuitePath); 305 } 306 catch (TestSuite.Fault e) { 307 throw new Fault(i18n, "editJTI.cantOpenTestSuite", 308 new Object[] { testSuitePath, e }); 309 } 310 load(inFile, ts); 311 } 312 // End of patches for 3.1.4 compatibility 313 else if (classPath != null) { 314 URLClassLoader loader = new URLClassLoader(new URL[] { classPath.toURL() }); 315 load(inFile, loader); 316 } 317 else 318 load(inFile); 319 320 } 321 catch (Interview.Fault e) { 322 throw new Fault(i18n, "editJTI.cantOpenFile", 323 new Object[] { inFile.getPath(), e.getMessage() }); 324 } 325 catch (FileNotFoundException e) { 326 throw new Fault(i18n, "editJTI.cantFindFile", inFile.getPath()); 327 } 328 catch (IOException e) { 329 throw new Fault(i18n, "editJTI.cantOpenFile", 330 new Object[] { inFile.getPath(), e }); 331 } 332 catch (IllegalStateException e) { 333 // only occurs if keywords are being used in the config, and the 334 // test suite is not available. user needs to specify -wd or -ts 335 if (verbose) 336 e.printStackTrace(); 337 338 throw new Fault(i18n, "editJTI.badState", e.getMessage()); 339 } 340 341 if (NUM_BACKUPS > 0) 342 interview.setBackupPolicy(BackupPolicy.simpleBackups(NUM_BACKUPS)); 343 344 if (editCmds != null) 345 edit(editCmds); 346 347 348 if (showPathFlag) 349 showPath(); 350 351 try { 352 if (logFile != null) { 353 if (previewFlag) { 354 String msg = i18n.getString("editJTI.wouldWriteLog", logFile); 355 out.println(msg); 356 } 357 else 358 writeLog(logFile); 359 } 360 } 361 catch (IOException e) { 362 throw new Fault(i18n, "editJTI.cantWriteLog", 363 new Object[] { logFile.getPath(), e }); 364 } 365 366 367 try { 368 if (previewFlag) { 369 String msg; 370 if (interview.isEdited()) 371 msg = i18n.getString("editJTI.wouldSaveEdited", 372 (outFile != null ? outFile : inFile)); 373 else if (outFile != null) 374 msg = i18n.getString("editJTI.wouldSaveNotEdited", outFile); 375 else 376 msg = i18n.getString("editJTI.wouldNotSave"); 377 out.println(msg); 378 } 379 else { 380 if (outFile != null) 381 save(outFile); 382 else if (interview.isEdited()) 383 save(inFile); 384 } 385 } 386 catch (Interview.Fault e) { 387 throw new Fault(i18n, "editJTI.cantOpenFile", 388 new Object[] { 389 (outFile == null || outFile.getPath() == null ? 390 "??": outFile.getPath()), e }); 391 } 392 catch (IOException e) { 393 File f = (outFile == null ? interview.getFile() : outFile); 394 throw new Fault(i18n, "editJTI.cantSaveFile", 395 new Object[] { f.getPath(), e }); 396 } 397 398 return (interview.isFinishable()); 399 } 400 401 /** 402 * Load a configuration file to be edited. 403 * @param inFile the file to be loaded 404 * @throws IOException if there is a problem reading the file 405 * @throws Interview.Fault if there is a problem loading the interview data from the file 406 */ 407 public void load(File inFile) throws IOException, Interview.Fault { 408 // this opens the interview via the work directory and test suite; 409 // the test suite implicitly knows its classpath via the .jtt file 410 interview = InterviewParameters.open(inFile); 411 interview.setEdited(false); 412 } 413 414 /** 415 * Load a configuration file to be edited. 416 * @param inFile the file to be loaded 417 * @param ts the test suite for which the interview is to be loaded 418 * @throws IOException if there is a problem reading the file 419 * @throws Interview.Fault if there is a problem loading the interview data from the file 420 * @throws EditJTI.Fault if there is a problem creating the interview for the testsuite 421 */ 422 public void load(File inFile, TestSuite ts) 423 throws IOException, Interview.Fault, Fault 424 { 425 // this opens the interview via the work directory and test suite; 426 // the test suite implicitly knows its classpath via the .jtt file 427 try { 428 interview = ts.createInterview(); 429 } 430 catch (TestSuite.Fault e) { 431 throw new Fault(i18n, "editJTI.cantCreateInterviewForTestSuite", 432 new Object[] { ts.getPath(), e.getMessage() }); 433 } 434 interview.load(inFile); 435 interview.setEdited(false); 436 } 437 438 /** 439 * Load a configuration file to be edited, using a specified class loader 440 * to load the interview class. 441 * @param inFile the file to be loaded 442 * @param loader the class loader to be used to load the interview class 443 * @throws IOException if there is a problem reading the file 444 * @throws Interview.Fault if there is a problem loading the interview data from the file 445 * @throws EditJTI.Fault if there is a problem creating the interview for the testsuite 446 */ 447 public void load(File inFile, URLClassLoader loader) 448 throws IOException, Interview.Fault, Fault 449 { 450 InputStream in = new BufferedInputStream(new FileInputStream(inFile)); 451 Properties p = new Properties(); 452 p.load(in); 453 in.close(); 454 455 String interviewClassName = (String) (p.get("INTERVIEW")); 456 try { 457 Class interviewClass = loader.loadClass(interviewClassName); 458 459 interview = (InterviewParameters)(interviewClass.newInstance()); 460 } 461 catch (ClassCastException e) { 462 throw new Fault(i18n, "editJTI.invalidInterview", inFile); 463 } 464 catch (ClassNotFoundException e) { 465 throw new Fault(i18n, "editJTI.cantFindClass", 466 new Object[] { interviewClassName, inFile }); 467 } 468 catch (InstantiationException e) { 469 throw new Fault(i18n, "editJTI.cantInstantiateClass", 470 new Object[] { interviewClassName, inFile }); 471 } 472 catch (IllegalAccessException e) { 473 throw new Fault(i18n, "editJTI.cantAccessClass", 474 new Object[] { interviewClassName, inFile }); 475 } 476 finally { 477 try { if (in != null) in.close(); } catch (IOException e) {} 478 } 479 480 interview.load(inFile); 481 interview.setEdited(false); 482 } 483 484 /** 485 * Save the edited configuration in a specified file. 486 * @param file The file in which to save the configuration 487 * @throws IOException if there is a problem while writing the file 488 * @throws Interview.Fault if there is a problem while saving the interview data 489 */ 490 public void save(File file) throws IOException, Interview.Fault { 491 interview.save(file); 492 } 493 494 /** 495 * Show the current question path for the configuration. 496 */ 497 public void showPath() { 498 Question[] path = interview.getPath(); 499 500 int indent = 0; 501 for (int i = 0; i < path.length; i++) 502 indent = Math.max(indent, path[i].getTag().length()); 503 indent = Math.min(indent, MAX_INDENT); 504 505 for (int i = 0; i < path.length; i++) { 506 Question q = path[i]; 507 String tag = q.getTag(); 508 String value = q.getStringValue(); 509 out.print(tag); 510 int l = tag.length(); 511 if (l > MAX_INDENT && value != null && value.length() > 0) { 512 out.println(); 513 l = 0; 514 } 515 for (int x = l; x < indent; x++) 516 out.print(' '); 517 out.print(' '); 518 out.println(value == null ? "" : value); 519 } 520 } 521 522 /** 523 * Write a log of the questions that determine the current configuration. 524 * @param logFile the file to which to write the log 525 * @throws IOException if there is a problem while writing the log file 526 */ 527 public void writeLog(File logFile) throws IOException { 528 WizPrint wp = new WizPrint(interview); 529 wp.setShowResponses(true); 530 wp.setShowResponseTypes(false); 531 wp.setShowTags(true); 532 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logFile), StandardCharsets.UTF_8)); 533 wp.write(out); 534 } 535 536 /** 537 * Apply a series of edits to the current configuration. 538 * @param cmds the editing commands to be applied 539 * @throws EditJTI.Fault if there is a problem while applying the edit commands. 540 * @see #edit(String) 541 */ 542 public void edit(String[] cmds) throws Fault { 543 for (int i = 0; i < cmds.length; i++) { 544 edit(cmds[i]); 545 } 546 } 547 548 /** 549 * Apply an edit to the current configuration. 550 * @param cmd the editing command to be applied 551 * Currently, two forms of command are supported: <dl> 552 * <dt><em>tag-name=value</em> 553 * <dd>Set the response to the question whose value is <em>tag-name</em> to <em>value</em> 554 * <dt><em>/search/replace/</em> 555 * <dd>For all questions on the current path, change instances of <em>search</em> to <em>replace</em> 556 * </dl> 557 * @throws EditJTI.Fault if there is a problem while applying the edit commands. 558 * @see #edit(String[]) 559 */ 560 public void edit(String cmd) throws Fault { 561 if (cmd == null || cmd.length() == 0) 562 return; 563 564 int eqIndex = cmd.indexOf('='); 565 if (Character.isJavaIdentifierStart(cmd.charAt(0)) && eqIndex > 0) 566 setValue(cmd.substring(0, eqIndex), cmd.substring(eqIndex + 1)); 567 else if (cmd.toLowerCase().startsWith("import:")) { 568 importFile(new File(cmd.substring("import:".length()))); 569 } 570 else { 571 int left = 0; 572 // could support a command letter in front? 573 char delim = cmd.charAt(left); 574 int center = cmd.indexOf(delim, left + 1); 575 if (center == -1) 576 throw new Fault(i18n, "editJTI.badCmd", cmd); 577 // could support trailing flags? 578 int right = cmd.length() - 1; 579 if (cmd.charAt(right) != delim) 580 throw new Fault(i18n, "editJTI.badCmd", cmd); 581 String searchText = cmd.substring(left + 1, center); 582 String replaceText = cmd.substring(center + 1, right); 583 if (searchText.length() == 0) 584 throw new Fault(i18n, "editJTI.badCmd", cmd); 585 setMatchingValues(searchText, replaceText); 586 } 587 } 588 589 private void importFile(File file) throws Fault { 590 591 InputStream in; 592 try { 593 in = new BufferedInputStream(new FileInputStream(file)); 594 } 595 catch (FileNotFoundException e) { 596 throw new Fault(i18n, "editJTI.cantFindImport", file); 597 } 598 catch (IOException e) { 599 throw new Fault(i18n, "editJTI.cantOpenImport", 600 new Object[] { file, e }); 601 } 602 603 Properties p; 604 try { 605 p = new Properties(); 606 p.load(in); 607 in.close(); 608 } 609 catch (IOException e) { 610 throw new Fault(i18n, "editJTI.cantReadImport", 611 new Object[] { file, e }); 612 } 613 finally { 614 try { if (in != null) in.close(); } catch (IOException e) {} 615 } 616 617 // for each question on the path, see if there is a corresponding 618 // imported value 619 Question[] path = interview.getPath(); 620 for (int i = 0; i < path.length; i++) { 621 Question q = path[i]; 622 String v = p.getProperty(q.getTag()); 623 if (v != null) { 624 setValue(q, v); 625 path = interview.getPath(); // update path in case tail has changed 626 } 627 } 628 } 629 630 private void setMatchingValues(String searchText, String replaceText) throws Fault { 631 boolean found = false; 632 633 Question[] path = interview.getPath(); 634 for (int i = 0; i < path.length; i++) { 635 Question q = path[i]; 636 String currValue = q.getStringValue(); 637 if (currValue == null) 638 continue; 639 // currently hardwired: considerCase: false; word match: false 640 int pos = match(searchText, currValue, false, false); 641 if (pos >= 0) { 642 String newValue = currValue.substring(0, pos) 643 + replaceText 644 + currValue.substring(pos + searchText.length()); 645 setValue(q, newValue); 646 found = true; 647 path = interview.getPath(); // update path in case tail has changed 648 } 649 } 650 if (!found) 651 throw new Fault(i18n, "editJTI.cantFindMatch", searchText); 652 } 653 654 private void setValue(String tag, String value) throws Fault { 655 Question[] path = interview.getPath(); 656 for (int i = 0; i < path.length; i++) { 657 Question q = path[i]; 658 if (q.getTag().equals(tag)) { 659 setValue(q, value); 660 return; 661 } 662 } 663 throw new Fault(i18n, "editJTI.cantFindQuestion", tag); 664 } 665 666 private void setValue(Question q, String value) throws Fault { 667 try { 668 String oldValue = q.getStringValue(); 669 q.setValue(value); 670 if (verbose) 671 out.println(i18n.getString("editJTI.update", 672 new Object[] { q.getTag(), oldValue, q.getStringValue() })); 673 } 674 catch (Interview.Fault e) { 675 throw new Fault(i18n, "editJTI.cantSetValue", new Object[] { q.getTag(), e.getMessage() } ); 676 } 677 } 678 679 private static int match(String s1, String s2, boolean considerCase, boolean word) { 680 int s1len = s1.length(); 681 int s2len = s2.length(); 682 for (int i = 0; i <= s2len - s1len; i++) { 683 if (s1.regionMatches(!considerCase, 0, s2, i, s1len)) { 684 if (!word || (word && 685 ( (i == 0 || isBoundaryCh(s2.charAt(i-1))) 686 && (i+s1len == s2.length() || isBoundaryCh(s2.charAt(i+s1len))) ))) 687 return i; 688 } 689 } 690 return -1; 691 } 692 693 private static boolean isBoundaryCh(char c) { 694 return !(Character.isUnicodeIdentifierStart(c) 695 || Character.isUnicodeIdentifierPart(c)); 696 } 697 698 private static void checkUnset(Object item, String option) 699 throws BadArgs 700 { 701 if (item != null) 702 throw new BadArgs(i18n, "editJTI.dupOption",option); 703 } 704 705 private InterviewParameters interview; 706 private boolean verbose; 707 private PrintWriter out; 708 709 private static int MAX_INDENT = Integer.getInteger("EditJTI.maxIndent", 32).intValue(); 710 private static int NUM_BACKUPS = Integer.getInteger("EditJTI.numBackups", 2).intValue(); 711 712 private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(EditJTI.class); 713 }