1 /* 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /** 27 * jrunscript JavaScript built-in functions and objects. 28 */ 29 30 /** 31 * Creates an object that delegates all method calls on 32 * it to the 'invoke' method on the given delegate object.<br> 33 * 34 * Example: 35 * <pre> 36 * <code> 37 * var x = { invoke: function(name, args) { //code...} 38 * var y = new JSInvoker(x); 39 * y.func(3, 3); // calls x.invoke('func', args); where args is array of arguments 40 * </code> 41 * </pre> 42 * @param obj object to be wrapped by JSInvoker 43 * @constructor 44 */ 45 function JSInvoker(obj) { 46 return new JSAdapter({ 47 __get__ : function(name) { 48 return function() { 49 return obj.invoke(name, arguments); 50 } 51 } 52 }); 53 } 54 55 /** 56 * This variable represents OS environment. Environment 57 * variables can be accessed as fields of this object. For 58 * example, env.PATH will return PATH value configured. 59 */ 60 var env = new JSAdapter({ 61 __get__ : function (name) { 62 return java.lang.System.getenv(name); 63 }, 64 __has__ : function (name) { 65 return java.lang.System.getenv().containsKey(name); 66 }, 67 __getIds__ : function() { 68 return java.lang.System.getenv().keySet().toArray(); 69 }, 70 __delete__ : function(name) { 71 println("can't delete env item"); 72 }, 73 __put__ : function (name, value) { 74 println("can't change env item"); 75 }, 76 toString: function() { 77 return java.lang.System.getenv().toString(); 78 } 79 }); 80 81 /** 82 * Creates a convenient script object to deal with java.util.Map instances. 83 * The result script object's field names are keys of the Map. For example, 84 * scriptObj.keyName can be used to access value associated with given key.<br> 85 * Example: 86 * <pre> 87 * <code> 88 * var x = java.lang.SystemProperties(); 89 * var y = jmap(x); 90 * println(y['java.class.path']); // prints java.class.path System property 91 * delete y['java.class.path']; // remove java.class.path System property 92 * </code> 93 * </pre> 94 * 95 * @param map java.util.Map instance that will be wrapped 96 * @constructor 97 */ 98 function jmap(map) { 99 return new JSAdapter({ 100 __get__ : function(name) { 101 if (map.containsKey(name)) { 102 return map.get(name); 103 } else { 104 return undefined; 105 } 106 }, 107 __has__ : function(name) { 108 return map.containsKey(name); 109 }, 110 111 __delete__ : function (name) { 112 return map.remove(name); 113 }, 114 __put__ : function(name, value) { 115 map.put(name, value); 116 }, 117 __getIds__ : function() { 118 return map.keySet().toArray(); 119 }, 120 toString: function() { 121 return map.toString(); 122 } 123 }); 124 } 125 126 /** 127 * Creates a convenient script object to deal with java.util.List instances. 128 * The result script object behaves like an array. For example, 129 * scriptObj[index] syntax can be used to access values in the List instance. 130 * 'length' field gives size of the List. <br> 131 * 132 * Example: 133 * <pre> 134 * <code> 135 * var x = new java.util.ArrayList(4); 136 * x.add('Java'); 137 * x.add('JavaScript'); 138 * x.add('SQL'); 139 * x.add('XML'); 140 * 141 * var y = jlist(x); 142 * println(y[2]); // prints third element of list 143 * println(y.length); // prints size of the list 144 * 145 * @param map java.util.List instance that will be wrapped 146 * @constructor 147 */ 148 function jlist(list) { 149 function isValid(index) { 150 return typeof(index) == 'number' && 151 index > -1 && index < list.size(); 152 } 153 return new JSAdapter({ 154 __get__ : function(name) { 155 if (isValid(name)) { 156 return list.get(name); 157 } else if (name == 'length') { 158 return list.size(); 159 } else { 160 return undefined; 161 } 162 }, 163 __has__ : function (name) { 164 return isValid(name) || name == 'length'; 165 }, 166 __delete__ : function(name) { 167 if (isValid(name)) { 168 list.remove(name); 169 } 170 }, 171 __put__ : function(name, value) { 172 if (isValid(name)) { 173 list.set(name, value); 174 } 175 }, 176 __getIds__: function() { 177 var res = new Array(list.size()); 178 for (var i = 0; i < res.length; i++) { 179 res[i] = i; 180 } 181 return res; 182 }, 183 toString: function() { 184 return list.toString(); 185 } 186 }); 187 } 188 189 /** 190 * This is java.lang.System properties wrapped by JSAdapter. 191 * For eg. to access java.class.path property, you can use 192 * the syntax sysProps["java.class.path"] 193 */ 194 var sysProps = new JSAdapter({ 195 __get__ : function (name) { 196 return java.lang.System.getProperty(name); 197 }, 198 __has__ : function (name) { 199 return java.lang.System.getProperty(name) != null; 200 }, 201 __getIds__ : function() { 202 return java.lang.System.getProperties().keySet().toArray(); 203 }, 204 __delete__ : function(name) { 205 java.lang.System.clearProperty(name); 206 return true; 207 }, 208 __put__ : function (name, value) { 209 java.lang.System.setProperty(name, value); 210 }, 211 toString: function() { 212 return "<system properties>"; 213 } 214 }); 215 216 // stdout, stderr & stdin 217 var out = java.lang.System.out; 218 var err = java.lang.System.err; 219 // can't use 'in' because it is a JavaScript keyword :-( 220 var inp = java.lang.System["in"]; 221 222 var BufferedInputStream = java.io.BufferedInputStream; 223 var BufferedOutputStream = java.io.BufferedOutputStream; 224 var BufferedReader = java.io.BufferedReader; 225 var DataInputStream = java.io.DataInputStream; 226 var File = java.io.File; 227 var FileInputStream = java.io.FileInputStream; 228 var FileOutputStream = java.io.FileOutputStream; 229 var InputStream = java.io.InputStream; 230 var InputStreamReader = java.io.InputStreamReader; 231 var OutputStream = java.io.OutputStream; 232 var Reader = java.io.Reader; 233 var URL = java.net.URL; 234 235 /** 236 * Generic any object to input stream mapper 237 * @param str input file name, URL or InputStream 238 * @return InputStream object 239 * @private 240 */ 241 function inStream(str) { 242 if (typeof(str) == "string") { 243 // '-' means standard input 244 if (str == '-') { 245 return java.lang.System["in"]; 246 } 247 // try file first 248 var file = null; 249 try { 250 file = pathToFile(str); 251 } catch (e) { 252 } 253 if (file && file.exists()) { 254 return new FileInputStream(file); 255 } else { 256 try { 257 // treat the string as URL 258 return new URL(str).openStream(); 259 } catch (e) { 260 throw 'file or URL ' + str + ' not found'; 261 } 262 } 263 } else { 264 if (str instanceof InputStream) { 265 return str; 266 } else if (str instanceof URL) { 267 return str.openStream(); 268 } else if (str instanceof File) { 269 return new FileInputStream(str); 270 } 271 } 272 // everything failed, just give input stream 273 return java.lang.System["in"]; 274 } 275 276 /** 277 * Generic any object to output stream mapper 278 * 279 * @param out output file name or stream 280 * @return OutputStream object 281 * @private 282 */ 283 function outStream(out) { 284 if (typeof(out) == "string") { 285 if (out == '>') { 286 return java.lang.System.out; 287 } else { 288 // treat it as file 289 return new FileOutputStream(pathToFile(out)); 290 } 291 } else { 292 if (out instanceof OutputStream) { 293 return out; 294 } else if (out instanceof File) { 295 return new FileOutputStream(out); 296 } 297 } 298 299 // everything failed, just return System.out 300 return java.lang.System.out; 301 } 302 303 /** 304 * stream close takes care not to close stdin, out & err. 305 * @private 306 */ 307 function streamClose(stream) { 308 if (stream) { 309 if (stream != java.lang.System["in"] && 310 stream != java.lang.System.out && 311 stream != java.lang.System.err) { 312 try { 313 stream.close(); 314 } catch (e) { 315 println(e); 316 } 317 } 318 } 319 } 320 321 /** 322 * Loads and evaluates JavaScript code from a stream or file or URL<br> 323 * 324 * Examples: 325 * <pre> 326 * <code> 327 * load('test.js'); // load script file 'test.js' 328 * load('http://java.sun.com/foo.js'); // load from a URL 329 * </code> 330 * </pre> 331 * 332 * @param str input from which script is loaded and evaluated 333 */ 334 if (typeof(load) == 'undefined') { 335 this.load = function(str) { 336 var stream = inStream(str); 337 var bstream = new BufferedInputStream(stream); 338 var reader = new BufferedReader(new InputStreamReader(bstream)); 339 var oldFilename = engine.get(engine.FILENAME); 340 engine.put(engine.FILENAME, str); 341 try { 342 engine.eval(reader); 343 } finally { 344 engine.put(engine.FILENAME, oldFilename); 345 streamClose(stream); 346 } 347 } 348 } 349 350 // file system utilities 351 352 /** 353 * Creates a Java byte[] of given length 354 * @param len size of the array to create 355 * @private 356 */ 357 function javaByteArray(len) { 358 return java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, len); 359 } 360 361 var curDir = new File('.'); 362 363 /** 364 * Print present working directory 365 */ 366 function pwd() { 367 println(curDir.getAbsolutePath()); 368 } 369 370 /** 371 * Changes present working directory to given directory 372 * @param target directory to change to. optional, defaults to user's HOME 373 */ 374 function cd(target) { 375 if (target == undefined) { 376 target = sysProps["user.home"]; 377 } 378 if (!(target instanceof File)) { 379 target = pathToFile(target); 380 } 381 if (target.exists() && target.isDirectory()) { 382 curDir = target; 383 } else { 384 println(target + " is not a directory"); 385 } 386 } 387 388 /** 389 * Converts path to java.io.File taking care of shell present working dir 390 * 391 * @param pathname file path to be converted 392 * @private 393 */ 394 function pathToFile(pathname) { 395 var tmp = pathname; 396 if (!(tmp instanceof File)) { 397 tmp = new File(tmp); 398 } 399 if (!tmp.isAbsolute()) { 400 return new File(curDir, pathname); 401 } else { 402 return tmp; 403 } 404 } 405 406 /** 407 * Copies a file or URL or stream to another file or stream 408 * 409 * @param from input file or URL or stream 410 * @param to output stream or file 411 */ 412 function cp(from, to) { 413 if (from == to) { 414 println("file " + from + " cannot be copied onto itself!"); 415 return; 416 } 417 var inp = inStream(from); 418 var out = outStream(to); 419 var binp = new BufferedInputStream(inp); 420 var bout = new BufferedOutputStream(out); 421 var buff = javaByteArray(1024); 422 var len; 423 while ((len = binp.read(buff)) > 0 ) 424 bout.write(buff, 0, len); 425 426 bout.flush(); 427 streamClose(inp); 428 streamClose(out); 429 } 430 431 /** 432 * Shows the content of a file or URL or any InputStream<br> 433 * Examples: 434 * <pre> 435 * <code> 436 * cat('test.txt'); // show test.txt file contents 437 * cat('http://java.net'); // show the contents from the URL http://java.net 438 * </code> 439 * </pre> 440 * @param obj input to show 441 * @param pattern optional. show only the lines matching the pattern 442 */ 443 function cat(obj, pattern) { 444 if (obj instanceof File && obj.isDirectory()) { 445 ls(obj); 446 return; 447 } 448 449 var inp = null; 450 if (!(obj instanceof Reader)) { 451 inp = inStream(obj); 452 obj = new BufferedReader(new InputStreamReader(inp)); 453 } 454 var line; 455 if (pattern) { 456 var count = 1; 457 while ((line=obj.readLine()) != null) { 458 if (line.match(pattern)) { 459 println(count + "\t: " + line); 460 } 461 count++; 462 } 463 } else { 464 while ((line=obj.readLine()) != null) { 465 println(line); 466 } 467 } 468 } 469 470 /** 471 * Returns directory part of a filename 472 * 473 * @param pathname input path name 474 * @return directory part of the given file name 475 */ 476 function dirname(pathname) { 477 var dirName = "."; 478 // Normalize '/' to local file separator before work. 479 var i = pathname.replace('/', File.separatorChar ).lastIndexOf( 480 File.separator ); 481 if ( i != -1 ) 482 dirName = pathname.substring(0, i); 483 return dirName; 484 } 485 486 /** 487 * Creates a new dir of given name 488 * 489 * @param dir name of the new directory 490 */ 491 function mkdir(dir) { 492 dir = pathToFile(dir); 493 println(dir.mkdir()? "created" : "can not create dir"); 494 } 495 496 /** 497 * Creates the directory named by given pathname, including 498 * any necessary but nonexistent parent directories. 499 * 500 * @param dir input path name 501 */ 502 function mkdirs(dir) { 503 dir = pathToFile(dir); 504 println(dir.mkdirs()? "created" : "can not create dirs"); 505 } 506 507 /** 508 * Removes a given file 509 * 510 * @param pathname name of the file 511 */ 512 function rm(pathname) { 513 var file = pathToFile(pathname); 514 if (!file.exists()) { 515 println("file not found: " + pathname); 516 return false; 517 } 518 // note that delete is a keyword in JavaScript! 519 println(file["delete"]()? "deleted" : "can not delete"); 520 } 521 522 /** 523 * Removes a given directory 524 * 525 * @param pathname name of the directory 526 */ 527 function rmdir(pathname) { 528 rm(pathname); 529 } 530 531 /** 532 * Synonym for 'rm' 533 */ 534 function del(pathname) { 535 rm(pathname); 536 } 537 538 /** 539 * Moves a file to another 540 * 541 * @param from original name of the file 542 * @param to new name for the file 543 */ 544 function mv(from, to) { 545 println(pathToFile(from).renameTo(pathToFile(to))? 546 "moved" : "can not move"); 547 } 548 549 /** 550 * Synonym for 'mv'. 551 */ 552 function ren(from, to) { 553 mv(from, to); 554 } 555 556 var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", 557 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; 558 559 /** 560 * Helper function called by ls 561 * @private 562 */ 563 function printFile(f) { 564 var sb = new java.lang.StringBuffer(); 565 sb.append(f.isDirectory()? "d" : "-"); 566 sb.append(f.canRead() ? "r": "-" ); 567 sb.append(f.canWrite() ? "w": "-" ); 568 sb.append(" "); 569 570 var d = new java.util.Date(f.lastModified()); 571 var c = new java.util.GregorianCalendar(); 572 c.setTime(d); 573 var day = c.get(java.util.Calendar.DAY_OF_MONTH); 574 sb.append(months[c.get(java.util.Calendar.MONTH)] 575 + " " + day ); 576 if (day < 10) { 577 sb.append(" "); 578 } 579 580 // to get fixed length 'length' field 581 var fieldlen = 8; 582 var len = new java.lang.StringBuffer(); 583 for(var j=0; j<fieldlen; j++) 584 len.append(" "); 585 len.insert(0, java.lang.Long.toString(f.length())); 586 len.setLength(fieldlen); 587 // move the spaces to the front 588 var si = len.toString().indexOf(" "); 589 if ( si != -1 ) { 590 var pad = len.toString().substring(si); 591 len.setLength(si); 592 len.insert(0, pad); 593 } 594 sb.append(len.toString()); 595 sb.append(" "); 596 sb.append(f.getName()); 597 if (f.isDirectory()) { 598 sb.append('/'); 599 } 600 println(sb.toString()); 601 } 602 603 /** 604 * Lists the files in a directory 605 * 606 * @param dir directory from which to list the files. optional, default to pwd 607 * @param filter pattern to filter the files listed. optional, default is '.'. 608 */ 609 function ls(dir, filter) { 610 if (dir) { 611 dir = pathToFile(dir); 612 } else { 613 dir = curDir; 614 } 615 if (dir.isDirectory()) { 616 var files = dir.listFiles(); 617 for (var i in files) { 618 var f = files[i]; 619 if (filter) { 620 if(!f.getName().match(filter)) { 621 continue; 622 } 623 } 624 printFile(f); 625 } 626 } else { 627 printFile(dir); 628 } 629 } 630 631 /** 632 * Synonym for 'ls'. 633 */ 634 function dir(d, filter) { 635 ls(d, filter); 636 } 637 638 /** 639 * Unix-like grep, but accepts JavaScript regex patterns 640 * 641 * @param pattern to search in files 642 * @param files one or more files 643 */ 644 function grep(pattern, files /*, one or more files */) { 645 if (arguments.length < 2) return; 646 for (var i = 1; i < arguments.length; i++) { 647 println(arguments[i] + ":"); 648 cat(arguments[i], pattern); 649 } 650 } 651 652 /** 653 * Find in files. Calls arbitrary callback function 654 * for each matching file.<br> 655 * 656 * Examples: 657 * <pre> 658 * <code> 659 * find('.') 660 * find('.', '.*\.class', rm); // remove all .class files 661 * find('.', '.*\.java'); // print fullpath of each .java file 662 * find('.', '.*\.java', cat); // print all .java files 663 * </code> 664 * </pre> 665 * 666 * @param dir directory to search files 667 * @param pattern to search in the files 668 * @param callback function to call for matching files 669 */ 670 function find(dir, pattern, callback) { 671 dir = pathToFile(dir); 672 if (!callback) callback = print; 673 var files = dir.listFiles(); 674 for (var f in files) { 675 var file = files[f]; 676 if (file.isDirectory()) { 677 find(file, pattern, callback); 678 } else { 679 if (pattern) { 680 if (file.getName().match(pattern)) { 681 callback(file); 682 } 683 } else { 684 callback(file); 685 } 686 } 687 } 688 } 689 690 // process utilities 691 692 /** 693 * Exec's a child process, waits for completion & returns exit code 694 * 695 * @param cmd command to execute in child process 696 */ 697 function exec(cmd) { 698 var process = java.lang.Runtime.getRuntime().exec(cmd); 699 var inp = new DataInputStream(process.getInputStream()); 700 var line = null; 701 while ((line = inp.readLine()) != null) { 702 println(line); 703 } 704 process.waitFor(); 705 $exit = process.exitValue(); 706 } 707 708 if (typeof(exit) == 'undefined') { 709 /** 710 * Exit the shell program. 711 * 712 * @param exitCode integer code returned to OS shell. 713 * optional, defaults to 0 714 */ 715 this.exit = function (code) { 716 if (code) { 717 java.lang.System.exit(code + 0); 718 } else { 719 java.lang.System.exit(0); 720 } 721 } 722 } 723 724 if (typeof(quit) == 'undefined') { 725 /** 726 * synonym for exit 727 */ 728 this.quit = function (code) { 729 exit(code); 730 } 731 } 732 733 // XML utilities 734 735 /** 736 * Converts input to DOM Document object 737 * 738 * @param inp file or reader. optional, without this param, 739 * this function returns a new DOM Document. 740 * @return returns a DOM Document object 741 */ 742 function XMLDocument(inp) { 743 var factory = javax.xml.parsers.DocumentBuilderFactory.newInstance(); 744 var builder = factory.newDocumentBuilder(); 745 if (inp) { 746 if (typeof(inp) == "string") { 747 return builder.parse(pathToFile(inp)); 748 } else { 749 return builder.parse(inp); 750 } 751 } else { 752 return builder.newDocument(); 753 } 754 } 755 756 /** 757 * Converts arbitrary stream, file, URL to XMLSource 758 * 759 * @param inp input stream or file or URL 760 * @return XMLSource object 761 */ 762 function XMLSource(inp) { 763 if (inp instanceof javax.xml.transform.Source) { 764 return inp; 765 } else if (inp instanceof Packages.org.w3c.dom.Document) { 766 return new javax.xml.transform.dom.DOMSource(inp); 767 } else { 768 inp = new BufferedInputStream(inStream(inp)); 769 return new javax.xml.transform.stream.StreamSource(inp); 770 } 771 } 772 773 /** 774 * Converts arbitrary stream, file to XMLResult 775 * 776 * @param inp output stream or file 777 * @return XMLResult object 778 */ 779 function XMLResult(out) { 780 if (out instanceof javax.xml.transform.Result) { 781 return out; 782 } else if (out instanceof Packages.org.w3c.dom.Document) { 783 return new javax.xml.transform.dom.DOMResult(out); 784 } else { 785 out = new BufferedOutputStream(outStream(out)); 786 return new javax.xml.transform.stream.StreamResult(out); 787 } 788 } 789 790 /** 791 * Perform XSLT transform 792 * 793 * @param inp Input XML to transform (URL, File or InputStream) 794 * @param style XSL Stylesheet to be used (URL, File or InputStream). optional. 795 * @param out Output XML (File or OutputStream 796 */ 797 function XSLTransform(inp, style, out) { 798 switch (arguments.length) { 799 case 2: 800 inp = arguments[0]; 801 out = arguments[1]; 802 break; 803 case 3: 804 inp = arguments[0]; 805 style = arguments[1]; 806 out = arguments[2]; 807 break; 808 default: 809 println("XSL transform requires 2 or 3 arguments"); 810 return; 811 } 812 813 var factory = javax.xml.transform.TransformerFactory.newInstance(); 814 var transformer; 815 if (style) { 816 transformer = factory.newTransformer(XMLSource(style)); 817 } else { 818 transformer = factory.newTransformer(); 819 } 820 var source = XMLSource(inp); 821 var result = XMLResult(out); 822 transformer.transform(source, result); 823 if (source.getInputStream) { 824 streamClose(source.getInputStream()); 825 } 826 if (result.getOutputStream) { 827 streamClose(result.getOutputStream()); 828 } 829 } 830 831 // miscellaneous utilities 832 833 /** 834 * Prints which command is selected from PATH 835 * 836 * @param cmd name of the command searched from PATH 837 */ 838 function which(cmd) { 839 var st = new java.util.StringTokenizer(env.PATH, File.pathSeparator); 840 while (st.hasMoreTokens()) { 841 var file = new File(st.nextToken(), cmd); 842 if (file.exists()) { 843 println(file.getAbsolutePath()); 844 return; 845 } 846 } 847 } 848 849 /** 850 * Prints IP addresses of given domain name 851 * 852 * @param name domain name 853 */ 854 function ip(name) { 855 var addrs = InetAddress.getAllByName(name); 856 for (var i in addrs) { 857 println(addrs[i]); 858 } 859 } 860 861 /** 862 * Prints current date in current locale 863 */ 864 function date() { 865 println(new Date().toLocaleString()); 866 } 867 868 /** 869 * Echoes the given string arguments 870 */ 871 function echo(x) { 872 for (var i = 0; i < arguments.length; i++) { 873 println(arguments[i]); 874 } 875 } 876 877 if (typeof(printf) == 'undefined') { 878 /** 879 * This is C-like printf 880 * 881 * @param format string to format the rest of the print items 882 * @param args variadic argument list 883 */ 884 this.printf = function (format, args/*, more args*/) { 885 var array = java.lang.reflect.Array.newInstance(java.lang.Object, 886 arguments.length - 1); 887 for (var i = 0; i < array.length; i++) { 888 array[i] = arguments[i+1]; 889 } 890 java.lang.System.out.printf(format, array); 891 } 892 } 893 894 /** 895 * Reads one or more lines from stdin after printing prompt 896 * 897 * @param prompt optional, default is '>' 898 * @param multiline to tell whether to read single line or multiple lines 899 */ 900 function read(prompt, multiline) { 901 if (!prompt) { 902 prompt = '>'; 903 } 904 var inp = java.lang.System["in"]; 905 var reader = new BufferedReader(new InputStreamReader(inp)); 906 if (multiline) { 907 var line = ''; 908 while (true) { 909 java.lang.System.err.print(prompt); 910 java.lang.System.err.flush(); 911 var tmp = reader.readLine(); 912 if (tmp == '' || tmp == null) break; 913 line += tmp + '\n'; 914 } 915 return line; 916 } else { 917 java.lang.System.err.print(prompt); 918 java.lang.System.err.flush(); 919 return reader.readLine(); 920 } 921 } 922 923 if (typeof(println) == 'undefined') { 924 // just synonym to print 925 this.println = print; 926 } 927