jdk/src/jdk.dev/share/classes/com/sun/tools/script/shell/init.js
changeset 27565 729f9700483a
parent 27564 eaaa79b68cd5
child 27566 fc4c57a0a8e2
equal deleted inserted replaced
27564:eaaa79b68cd5 27565:729f9700483a
     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 &amp; 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