Clover coverage report - DrJava Test Coverage (drjava-20120304-r5456)
Coverage timestamp: Sun Mar 4 2012 03:13:23 CST
file stats: LOC: 1,515   Methods: 97
NCLOC: 1,341   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DrJavaPropertySetup.java 40.2% 60.8% 63.9% 57.2%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK
 2    *
 3    * Copyright (c) 2001-2010, JavaPLT group at Rice University (drjava@rice.edu)
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    * * Redistributions of source code must retain the above copyright
 9    * notice, this list of conditions and the following disclaimer.
 10    * * Redistributions in binary form must reproduce the above copyright
 11    * notice, this list of conditions and the following disclaimer in the
 12    * documentation and/or other materials provided with the distribution.
 13    * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
 14    * names of its contributors may be used to endorse or promote products
 15    * derived from this software without specific prior written permission.
 16    *
 17    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18    * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 19    * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 20    * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 21    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 22    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 23    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 24    * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 25    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 26    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28    *
 29    * This software is Open Source Initiative approved Open Source Software.
 30    * Open Source Initative Approved is a trademark of the Open Source Initiative.
 31    *
 32    * This file is part of DrJava. Download the current version of this project
 33    * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
 34    *
 35    * END_COPYRIGHT_BLOCK*/
 36   
 37    package edu.rice.cs.drjava.config;
 38   
 39    import edu.rice.cs.util.StringOps;
 40    import edu.rice.cs.util.XMLConfig;
 41    import edu.rice.cs.drjava.DrJava;
 42    import edu.rice.cs.plt.concurrent.JVMBuilder;
 43    import edu.rice.cs.plt.lambda.Thunk;
 44    import edu.rice.cs.plt.lambda.Lambda;
 45    import edu.rice.cs.plt.lambda.Lambda2;
 46    import edu.rice.cs.plt.lambda.Lambda3;
 47    import edu.rice.cs.plt.lambda.Lambda4;
 48    import edu.rice.cs.plt.reflect.JavaVersion;
 49    import edu.rice.cs.plt.text.TextUtil;
 50   
 51    import java.io.*;
 52    import java.util.Map;
 53    import java.util.HashMap;
 54    import java.util.List;
 55   
 56    import static edu.rice.cs.util.XMLConfig.XMLConfigException;
 57   
 58    /** Class setting up the variables for external processes.
 59    * @version $Id: DrJavaPropertySetup.java 5436 2011-08-02 06:58:19Z mgricken $
 60    */
 61    public class DrJavaPropertySetup implements OptionConstants {
 62  46 public static void setup() {
 63  46 final String DEF_DIR = "${drjava.working.dir}";
 64   
 65    // fake "Config" properties
 66  46 String msg1 =
 67    "This property contains all the JVM arguments passed to DrJava's master JVM, i.e. the JVM the user is editing " +
 68    "programs in. The arguments from the \"JVM Args for Main JVM\" and the special -X arguments from " +
 69    "\"Maximum Heap Size for Main JVM\" are combined.";
 70   
 71  46 EagerProperty prop1 = new EagerProperty("config.master.jvm.args.combined", msg1) {
 72  6 public void update(PropertyMaps pm) {
 73  6 StringBuilder sb = new StringBuilder();
 74  6 if (!DrJava.getConfig().getSetting(MASTER_JVM_XMX).equals("default") &&
 75    !DrJava.getConfig().getSetting(MASTER_JVM_XMX).equals("")) {
 76  3 sb.append("-Xmx");
 77  3 sb.append(DrJava.getConfig().getSetting(MASTER_JVM_XMX));
 78  3 sb.append("M ");
 79    }
 80  6 sb.append(DrJava.getConfig().getSetting(MASTER_JVM_ARGS));
 81  6 _value = sb.toString().trim();
 82    }
 83  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 84  46 public void resetAttributes() {
 85  46 _attributes.clear();
 86    }
 87    };
 88   
 89  46 PropertyMaps.TEMPLATE.setProperty("Config", prop1).
 90    listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("Config", "config.master.jvm.args")).
 91    listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("Config", "config.master.jvm.xmx"));
 92   
 93  46 String msg2 =
 94    "This property contains all the JVM arguments passed to DrJava's master JVM, i.e. the JVM the user is editing " +
 95    "programs in. The arguments from the \"JVM Args for Slave JVM\" and the special -X arguments from " +
 96    "\"Maximum Heap Size for Main JVM\" are combined.";
 97   
 98  46 EagerProperty prop2 = new EagerProperty("config.slave.jvm.args.combined", msg2) {
 99  6 public void update(PropertyMaps pm) {
 100  6 StringBuilder sb = new StringBuilder();
 101  6 if (!DrJava.getConfig().getSetting(SLAVE_JVM_XMX).equals("default") &&
 102    !DrJava.getConfig().getSetting(SLAVE_JVM_XMX).equals("")) {
 103  3 sb.append("-Xmx");
 104  3 sb.append(DrJava.getConfig().getSetting(SLAVE_JVM_XMX));
 105  3 sb.append("M ");
 106    }
 107  6 sb.append(DrJava.getConfig().getSetting(SLAVE_JVM_ARGS));
 108  6 _value = sb.toString().trim();
 109    }
 110  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 111  46 public void resetAttributes() {
 112  46 _attributes.clear();
 113    }
 114    };
 115   
 116  46 PropertyMaps.TEMPLATE.setProperty("Config", prop2).
 117    listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("Config", "config.slave.jvm.args")).
 118    listenToInvalidatesOf(PropertyMaps.TEMPLATE.getProperty("Config", "config.slave.jvm.xmx"));
 119   
 120  46 String msg3 =
 121    "Creates a temporary file and returns the name of it.\n" +
 122    "Optional attributes:\n" +
 123    "\tname=\"<name for temp file>\"\n" +
 124    "\tdir=\"<dir for temp file>\"\n" +
 125    "\tkeep=\"<true if the file should not be erased>\"\n" +
 126    "\tcontent=\"<text to go into the file>\"";
 127   
 128  46 DrJavaProperty prop3 = new DrJavaProperty("tmpfile", msg3) {
 129    java.util.Random _r = new java.util.Random();
 130  6 public void update(PropertyMaps pm) {
 131  6 try {
 132  6 String name = _attributes.get("name");
 133  6 String dir = _attributes.get("dir");
 134  6 if (name.equals(""))
 135  4 name = "DrJava-Execute-" + System.currentTimeMillis() + "-" + (_r.nextInt() & 0xffff) + ".tmp";
 136  3 if (dir.equals("")) dir = System.getProperty("java.io.tmpdir");
 137    else {
 138  3 dir = StringOps.unescapeFileName(dir);
 139    }
 140   
 141  6 File f = new File(dir, name);
 142  6 f.deleteOnExit();
 143  6 _value = StringOps.escapeFileName(f.toString());
 144    }
 145  0 catch(SecurityException e) { _value = "Error."; }
 146    }
 147  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 148  6 public String getCurrent(PropertyMaps pm) {
 149  6 invalidate();
 150  6 final String s = super.getCurrent(pm);
 151  6 File f = new File(StringOps.unescapeFileName(_value));
 152  6 final String keep = _attributes.get("keep");
 153  6 if (!(keep.equals("true") || keep.equals("yes") || keep.equals("1"))) {
 154  6 f.deleteOnExit();
 155    }
 156  6 String text = StringOps.unescapeFileName(_attributes.get("content"));
 157  6 try {
 158  6 FileWriter fw = new FileWriter(f);
 159  6 fw.write(text, 0, text.length());
 160  6 fw.close();
 161    }
 162    catch(IOException ioe) { /*ignore*/ }
 163  6 return s;
 164    }
 165  47 public void resetAttributes() {
 166  47 _attributes.clear();
 167  47 _attributes.put("dir", "");
 168  47 _attributes.put("name", "");
 169  47 _attributes.put("keep", "");
 170  47 _attributes.put("content", "");
 171    }
 172    };
 173   
 174    // Misc
 175  46 PropertyMaps.TEMPLATE.setProperty("Misc", prop3);
 176   
 177  46 String msg4 =
 178    "Return a list of files found in the starting dir.\n" +
 179    "Optional attributes:\n" +
 180    "\tsep=\"<separator between files>\"\n" +
 181    "\tdir=\"<dir where to start>\"\n" +
 182    "\trel=\"<dir to which the files are relative>\"\n" +
 183    "\tfilter=\"<filter, like *.txt, for files to list>\"\n" +
 184    "\tdirfilter=\"<filter for which dirs to recurse>\"\n" +
 185    "\tsquote=\"<true to enclose file in single quotes>\"\n" +
 186    "\tdquote=\"<true to enclose file in double quotes>\"";
 187   
 188  46 DrJavaProperty prop4 = new RecursiveFileListProperty("file.find", File.pathSeparator, DEF_DIR, DEF_DIR, msg4);
 189   
 190  46 PropertyMaps.TEMPLATE.setProperty("File", prop4);
 191   
 192  46 String msg5 =
 193    "Return true if the specified file is a directory, false " +
 194    "otherwise.\n" +
 195    "Required attributes:\n" +
 196    "\tfile=\"<file to test>\"\n" +
 197    "Multiple files can be specified, separated by ${path.separator}, " +
 198    "which is " + File.pathSeparator + " on this machine. If multiple " +
 199    "files are specified, then a list of values, each " +
 200    "separated by ${path.separator}, is returned.";
 201   
 202  46 DrJavaProperty prop5 = new DrJavaProperty("file.isdir", msg5) {
 203  5 public void update(PropertyMaps pm) {
 204  5 String s = _attributes.get("file");
 205  5 if (s == null) {
 206  1 _value = "(file.isdir Error...)";
 207  1 return;
 208    }
 209  4 StringBuilder sb = new StringBuilder();
 210  4 for(String fs: s.split(TextUtil.regexEscape(File.pathSeparator),-1)) {
 211  6 File f = new File(StringOps.unescapeFileName(fs));
 212  6 sb.append(File.pathSeparator);
 213  6 sb.append((f.exists() && f.isDirectory())?"true":"false");
 214    }
 215  4 s = sb.toString();
 216  4 if (s.startsWith(File.pathSeparator)) {
 217  4 _value = s.substring(File.pathSeparator.length());
 218    }
 219    else {
 220  0 _value = s;
 221    }
 222    }
 223  5 public boolean isCurrent() { return false; }
 224  46 public void resetAttributes() {
 225  46 _attributes.clear();
 226  46 _attributes.put("file", null);
 227    }
 228    };
 229   
 230  46 PropertyMaps.TEMPLATE.setProperty("File", prop5);
 231   
 232  46 String msg6 =
 233    "Return true if the specified file is a file, not a " +
 234    "directory.\n" +
 235    "Required attributes:\n" +
 236    "\tfile=\"<file to test>\"\n" +
 237    "Multiple files can be specified, separated by ${path.separator}, " +
 238    "which is " +File.pathSeparator + " on this machine. If multiple " +
 239    "files are specified, then a list of values, each " +
 240    "separated by ${path.separator}, is returned.";
 241   
 242  46 DrJavaProperty prop6 = new DrJavaProperty("file.isfile", msg6) {
 243  5 public void update(PropertyMaps pm) {
 244  5 String s = _attributes.get("file");
 245  5 if (s == null) {
 246  1 _value = "(file.isfile Error...)";
 247  1 return;
 248    }
 249  4 StringBuilder sb = new StringBuilder();
 250  4 for(String fs: s.split(TextUtil.regexEscape(File.pathSeparator),-1)) {
 251  6 fs = StringOps.unescapeFileName(fs);
 252  6 File f = new File(fs);
 253  6 sb.append(File.pathSeparator);
 254  6 sb.append((f.exists() && f.isFile())?"true":"false");
 255    }
 256  4 s = sb.toString();
 257  4 if (s.startsWith(File.pathSeparator)) {
 258  4 _value = s.substring(File.pathSeparator.length());
 259    }
 260    else {
 261  0 _value = s;
 262    }
 263    }
 264  5 public boolean isCurrent() { return false; }
 265  46 public void resetAttributes() {
 266  46 _attributes.clear();
 267  46 _attributes.put("file", null);
 268    }
 269    };
 270   
 271  46 PropertyMaps.TEMPLATE.setProperty("File", prop6);
 272   
 273  46 String msg7 =
 274    "Return true if the specified file exists.\n" +
 275    "Required attributes:\n" +
 276    "\tfile=\"<file to test>\"\n" +
 277    "Multiple files can be specified, separated by ${path.separator}, " +
 278    "which is " +File.pathSeparator + " on this machine. If multiple " +
 279    "files are specified, then a list of values, each " +
 280    "separated by ${path.separator}, is returned.";
 281   
 282  46 DrJavaProperty prop7 = new DrJavaProperty("file.exists", msg7) {
 283  5 public void update(PropertyMaps pm) {
 284  5 String s = _attributes.get("file");
 285  5 if (s == null) {
 286  1 _value = "(file.exists Error... )";
 287  1 return;
 288    }
 289  4 StringBuilder sb = new StringBuilder();
 290  4 for(String fs: s.split(TextUtil.regexEscape(File.pathSeparator),-1)) {
 291  6 fs = StringOps.unescapeFileName(fs);
 292  6 File f = new File(fs);
 293  6 sb.append(File.pathSeparator);
 294  6 sb.append(f.exists()?"true":"false");
 295    }
 296  4 s = sb.toString();
 297  4 if (s.startsWith(File.pathSeparator)) {
 298  4 _value = s.substring(File.pathSeparator.length());
 299    }
 300    else {
 301  0 _value = s;
 302    }
 303    }
 304  5 public boolean isCurrent() { return false; }
 305  46 public void resetAttributes() {
 306  46 _attributes.clear();
 307  46 _attributes.put("file", null);
 308    }
 309    };
 310   
 311  46 PropertyMaps.TEMPLATE.setProperty("File", prop7);
 312   
 313  46 String msg8 =
 314    "Return the path of the parent, or and empty string \"\" if no parent exists.\n" +
 315    "Required attributes:\n" +
 316    "\tfile=\"<file for which to return the parent>\"\n" +
 317    "Multiple files can be specified, separated by ${path.separator}, which is " + File.pathSeparator +
 318    " on this machine. If multiple files are specified, then a list of values, each " +
 319    "separated by ${path.separator}, is returned.";
 320   
 321  46 DrJavaProperty prop8 = new DrJavaProperty("file.parent", msg8) {
 322  5 public void update(PropertyMaps pm) {
 323  5 String s = _attributes.get("file");
 324  5 if (s == null) {
 325  1 _value = "(file.parent Error...)";
 326  1 return;
 327    }
 328  4 StringBuilder sb = new StringBuilder();
 329  4 for(String fs: s.split(edu.rice.cs.plt.text.TextUtil.regexEscape(File.pathSeparator),-1)) {
 330  6 fs = StringOps.unescapeFileName(fs);
 331  6 File f = new File(fs);
 332  6 String p = StringOps.escapeFileName(f.getParent());
 333  6 sb.append(File.pathSeparator);
 334  6 sb.append((p != null)?p:"");
 335    }
 336  4 s = sb.toString();
 337  4 if (s.startsWith(File.pathSeparator)) {
 338  4 _value = s.substring(File.pathSeparator.length());
 339    }
 340    else {
 341  0 _value = s;
 342    }
 343    }
 344  5 public boolean isCurrent() { return false; }
 345  46 public void resetAttributes() {
 346  46 _attributes.clear();
 347  46 _attributes.put("file", null);
 348    }
 349    };
 350   
 351  46 PropertyMaps.TEMPLATE.setProperty("File", prop8);
 352   
 353  46 String msg9 =
 354    "Return the absolute path of the file which has been " +
 355    "relative to another file.\n" +
 356    "Required attributes:\n" +
 357    "\tfile=\"<file for which to return the absolute path>\"\n" +
 358    "\tbase=\"<other file which serves as base path>\"\n" +
 359    "Multiple files can be specified for the file attribute, each " +
 360    "separated by ${path.separator}, which is " + File.pathSeparator +
 361    " on this machine. If multiple files are specified, then a list " +
 362    "of values, each separated by ${path.separator}, is returned.";
 363   
 364  46 PropertyMaps.TEMPLATE.setProperty("File", new DrJavaProperty("file.abs", msg9) {
 365  7 public void update(PropertyMaps pm) {
 366  7 String s = _attributes.get("base");
 367  7 if (s == null) {
 368  2 _value = "(file.abs Error: base missing...)";
 369  2 return;
 370    }
 371  5 s = StringOps.unescapeFileName(s);
 372  5 File base = new File(s);
 373  5 s = _attributes.get("file");
 374  5 if (s == null) {
 375  1 _value = "(file.abs Error: file missing...)";
 376  1 return;
 377    }
 378  4 StringBuilder sb = new StringBuilder();
 379  4 for(String fs: s.split(TextUtil.regexEscape(File.pathSeparator),-1)) {
 380  6 fs = StringOps.unescapeFileName(fs);
 381  6 File f = new File(base,fs);
 382  6 sb.append(File.pathSeparator);
 383  6 sb.append(StringOps.escapeFileName(f.getAbsolutePath()));
 384    }
 385  4 s = sb.toString();
 386  4 if (s.startsWith(File.pathSeparator)) {
 387  4 _value = s.substring(File.pathSeparator.length());
 388    }
 389    else {
 390  0 _value = s;
 391    }
 392    }
 393  7 public boolean isCurrent() { return false; }
 394  47 public void resetAttributes() {
 395  47 _attributes.clear();
 396  47 _attributes.put("file", null);
 397  47 _attributes.put("base", null);
 398    }
 399    });
 400   
 401  46 String msg10 =
 402    "Return the path of the file, relative to another file.\n" +
 403    "Required attributes:\n" +
 404    "\tfile=\"<file for which to return the relative path>\"\n" +
 405    "\tbase=\"<other file which serves as base path>\"\n" +
 406    "Multiple files can be specified for the file attribute, each " +
 407    "separated by ${path.separator}, which is " +File.pathSeparator+
 408    " on this machine. If multiple files are specified, then a list " +
 409    "of values, each separated by ${path.separator}, is returned.";
 410   
 411  46 PropertyMaps.TEMPLATE.setProperty("File", new DrJavaProperty("file.rel", msg10) {
 412  6 public void update(PropertyMaps pm) {
 413  6 String s = _attributes.get("base");
 414  6 if (s == null) {
 415  2 _value = "(file.rel Error: base missing...)";
 416  2 return;
 417    }
 418  4 s = StringOps.unescapeFileName(s);
 419  4 File b = new File(s);
 420  4 s = _attributes.get("file");
 421  4 if (s == null) {
 422  1 _value = "(file.rel Error: file missing...)";
 423  1 return;
 424    }
 425  3 StringBuilder sb = new StringBuilder();
 426  3 for(String fs: s.split(TextUtil.regexEscape(File.pathSeparator),-1)) {
 427  3 fs = StringOps.unescapeFileName(fs);
 428  3 File f = new File(fs);
 429  3 try {
 430  3 s = edu.rice.cs.util.FileOps.stringMakeRelativeTo(f,b);
 431  3 if (s.endsWith(File.separator)) {
 432    // path ends with "/", check if we can remove the "/"
 433  1 File[] roots = File.listRoots();
 434  1 if (roots != null) {
 435  1 boolean equalsRoot = false;
 436  1 for(File r: roots) {
 437  1 if (s.equals(r.toString())) {
 438  0 equalsRoot = true;
 439  0 break;
 440    }
 441    }
 442  1 if (!equalsRoot) {
 443    // path ends with "/" and does not equal a file system root
 444    // we can remove the trailing "/"
 445  1 s = s.substring(0, s.length()-1);
 446    }
 447    }
 448    }
 449  1 if (s.length() == 0) { s = "."; }
 450  3 sb.append(File.pathSeparator);
 451  3 sb.append(StringOps.escapeFileName(s));
 452    }
 453    catch(IOException e) {
 454  0 _value = "(file.rel I/O Error...)";
 455  0 return;
 456    }
 457    }
 458  3 s = sb.toString();
 459  3 if (s.startsWith(File.pathSeparator)) {
 460  3 _value = s.substring(File.pathSeparator.length());
 461    }
 462    else {
 463  0 _value = s;
 464    }
 465    }
 466  6 public boolean isCurrent() { return false; }
 467  47 public void resetAttributes() {
 468  47 _attributes.clear();
 469  47 _attributes.put("file", null);
 470  47 _attributes.put("base", null);
 471    }
 472    });
 473   
 474  46 String msg11 =
 475    "Make the directory with the provided file name. Evaluates to the empty string \"\" if successful.\n" +
 476    "Required attributes:\n" +
 477    "\tfile=\"<directory to create>\"\n" +
 478    "Multiple files can be specified for the file attribute, each separated by ${path.separator}, which is " +
 479    File.pathSeparator + " on this machine. If multiple files are specified, then DrJava " +
 480    "will attempt to make all those directories.";
 481   
 482  46 PropertyMaps.TEMPLATE.setProperty("File", new DrJavaProperty("file.mkdir", msg11) {
 483  1 public void update(PropertyMaps pm) {
 484  1 String s = _attributes.get("file");
 485  1 if (s == null) {
 486  1 _value = "(file.mkdir Error: file missing...)";
 487  1 return;
 488    }
 489  0 for(String fs: s.split(TextUtil.regexEscape(File.pathSeparator),-1)) {
 490  0 fs = StringOps.unescapeFileName(fs);
 491  0 File n = new File(fs);
 492  0 if (!n.mkdir()) {
 493  0 _value = "(file.mkdir I/O Error...)";
 494  0 return;
 495    }
 496    }
 497  0 _value = "";
 498    }
 499  1 public boolean isCurrent() { return false; }
 500  46 public void resetAttributes() {
 501  46 _attributes.clear();
 502  46 _attributes.put("file", null);
 503    }
 504    });
 505   
 506  46 String msg12 =
 507    "Remove the specified file or directory, recursively if desired. Evaluates to the empty string \"\" " +
 508    "if successful.\n" + "Required attributes:\n" +
 509    "\tfile=\"<file or directory to remove>\"\n" +
 510    "Optional attributes:\n" +
 511    "\trec=\"<true for recursive removal>\"\n" +
 512    "(if not specified, false is used and removal is not recursive)\n" +
 513    "Multiple files can be specified for the file attribute, each separated by ${path.separator}, which is " +
 514    File.pathSeparator + " on this machine. If multiple files are specified, then DrJava " +
 515    "will attempt to remove all those files.";
 516   
 517  46 PropertyMaps.TEMPLATE.setProperty("File", new DrJavaProperty("file.rm", msg12) {
 518  1 public void update(PropertyMaps pm) {
 519  1 String s = _attributes.get("rec");
 520  1 boolean rec = new Boolean(s).booleanValue();
 521  1 s = _attributes.get("file");
 522  1 if (s == null) {
 523  1 _value = "(file.rm Error...)";
 524  1 return;
 525    }
 526  0 s = StringOps.unescapeFileName(s);
 527  0 boolean res = false;
 528  0 for(String fs: s.split(TextUtil.regexEscape(File.pathSeparator),-1)) {
 529  0 fs = StringOps.unescapeFileName(fs);
 530  0 File f = new File(fs);
 531  0 if (rec) {
 532    // recursive removal
 533  0 try {
 534  0 res = edu.rice.cs.plt.io.IOUtil.deleteRecursively(f);
 535    }
 536  0 catch(Exception e) { res = false; }
 537    }
 538    else {
 539    // non-recursive removal
 540  0 try {
 541  0 res = f.delete();
 542    }
 543  0 catch(SecurityException e) { res = false; }
 544    }
 545    }
 546  0 _value = res?"":"(file.rm I/O Error...)";
 547    }
 548  1 public boolean isCurrent() { return false; }
 549  46 public void resetAttributes() {
 550  46 _attributes.clear();
 551  46 _attributes.put("file", null);
 552  46 _attributes.put("rec", "false");
 553    }
 554    });
 555   
 556  46 String msg13 =
 557    "Move the specified file or directory to a new location. Evaluates to the empty string \"\" if successful.\n" +
 558    "Required attributes:\n" +
 559    "\tfile=\"<file or directory to move>\"\tnew=\"<new location>\"";
 560   
 561  46 PropertyMaps.TEMPLATE.setProperty("File", new DrJavaProperty("file.mv", msg13) {
 562  1 public void update(PropertyMaps pm) {
 563  1 String s = _attributes.get("file");
 564  1 if (s == null) {
 565  1 _value = "(file.mv Error: file missing...)";
 566  1 return;
 567    }
 568  0 File f = new File(s);
 569  0 s = _attributes.get("new");
 570  0 if (s == null) {
 571  0 _value = "(file.mv Error: new missing...)";
 572  0 return;
 573    }
 574  0 File n = new File(s);
 575  0 boolean res = false;
 576  0 if ((f.getParent() != null) && (f.getParent().equals(n.getParent()))) {
 577    // just renaming a file or directory
 578  0 res = edu.rice.cs.plt.io.IOUtil.attemptRenameTo(f,n);
 579    }
 580    else {
 581  0 if (f.isFile()) {
 582    // just moving a file
 583  0 try {
 584  0 res = edu.rice.cs.plt.io.IOUtil.attemptMove(f,n);
 585    }
 586  0 catch(Exception e) { res = false; }
 587    }
 588    else {
 589    // moving a whole directory
 590  0 try {
 591  0 res = edu.rice.cs.util.FileOps.moveRecursively(f,n);
 592    }
 593  0 catch(Exception e) { res = false; }
 594    }
 595    }
 596  0 _value = res?"":"(file.mv I/O Error...)";
 597    }
 598  1 public boolean isCurrent() { return false; }
 599  46 public void resetAttributes() {
 600  46 _attributes.clear();
 601  46 _attributes.put("file", null);
 602  46 _attributes.put("new", null);
 603    }
 604    });
 605   
 606  46 String msg14 =
 607    "Returns the current time in milliseconds since 01/01/1970, " +
 608    "unless other format is specified by the fmt attribute.\n" + "Optional attributes:\n" +
 609    "\tfmt=\"full\" or \"long\" or \"medium\" or \"short\"";
 610   
 611  46 PropertyMaps.TEMPLATE.setProperty("DrJava", new DrJavaProperty("drjava.current.time.millis", msg14) {
 612  0 public void update(PropertyMaps pm) {
 613  0 long millis = System.currentTimeMillis();
 614  0 String f = _attributes.get("fmt").toLowerCase();
 615  0 if (f.equals("full")) {
 616  0 _value = java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL).format(new java.util.Date(millis));
 617    }
 618  0 else if (f.equals("long")) {
 619  0 _value = java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG).format(new java.util.Date(millis));
 620    }
 621  0 else if (f.equals("medium")) {
 622  0 _value = java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM).format(new java.util.Date(millis));
 623    }
 624  0 else if (f.equals("short")) {
 625  0 _value = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT).format(new java.util.Date(millis));
 626    }
 627    else {
 628  0 _value = String.valueOf(millis);
 629    }
 630    }
 631  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 632  46 public void resetAttributes() {
 633  46 _attributes.clear();
 634  46 _attributes.put("fmt", "millis");
 635    }
 636    });
 637   
 638  46 String msg15 =
 639    "Evaluates the string specified in the command attribute, but ignore the result of the evaluation. Only side " +
 640    "effects of the evaluation are apparent. This property always evaluates to the empty string \"\" (unless the " +
 641    "command attribute is missing).\n" +
 642    "Required attributes:\n" +
 643    "\tcmd=\"<command to evaluate>\"";
 644   
 645  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("ignore", msg15) {
 646  0 public void update(PropertyMaps pm) {
 647  0 String s = _attributes.get("cmd");
 648  0 if (s == null) {
 649  0 _value = "(ignore Error...)";
 650  0 return;
 651    }
 652  0 _value = "";
 653    }
 654  46 public void resetAttributes() {
 655  46 _attributes.clear();
 656  46 _attributes.put("cmd", null);
 657    }
 658    });
 659   
 660  46 String msg16 =
 661    "If the cond attribute evaluates to true, returns the evaluation of the then attribute, otherwise " +
 662    "the evaluation of the else attribute.\n" +
 663    "Required attribute:\n" +
 664    "\tcond=\"<string evaluating to true of false>\"\n" +
 665    "Optional attributes:\n" +
 666    "\tthen=\"<evaluated if true>\"\n" +
 667    "\telse=\"<evaluated if false>\"";
 668   
 669  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("if", msg16) {
 670  0 public void update(PropertyMaps pm) {
 671  0 if (_attributes.get("cond") == null) {
 672  0 _value = "(if Error...)";
 673  0 return;
 674    }
 675  0 if (_attributes.get("cond").toLowerCase().equals("true")) {
 676  0 _value = _attributes.get("then");
 677    }
 678  0 else if (_attributes.get("cond").toLowerCase().equals("false")) {
 679  0 _value = _attributes.get("else");
 680    }
 681    else {
 682  0 _value = "(if Error...)";
 683  0 return;
 684    }
 685    }
 686  0 public String getCurrent(PropertyMaps pm) {
 687  0 invalidate();
 688  0 return super.getCurrent(pm);
 689    }
 690  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 691  46 public void resetAttributes() {
 692  46 _attributes.clear();
 693  46 _attributes.put("cond", null);
 694  46 _attributes.put("then", "");
 695  46 _attributes.put("else", "");
 696    }
 697    });
 698   
 699  46 String msg17 =
 700    "If the op1 is greater than op2, returns true," +
 701    "false otherwise.\n" +
 702    "Required attributes:\n" +
 703    "\top1=\"<string evaluating to a number>\"\n" +
 704    "\top2=\"<string evaluating to a number>\"";
 705   
 706  46 Lambda2<Double,Double,Boolean> lam17 = new Lambda2<Double,Double,Boolean>() {
 707  3 public Boolean value(Double op1, Double op2) { return (op1>op2); }
 708    };
 709   
 710  46 BinaryOpProperty<Double,Double,Boolean> prop17 =
 711    new BinaryOpProperty<Double,Double,Boolean>("gt",
 712    msg17,
 713    lam17,
 714    UnaryOpProperty.PARSE_DOUBLE,
 715    UnaryOpProperty.PARSE_DOUBLE,
 716    UnaryOpProperty.FORMAT_BOOL);
 717   
 718  46 PropertyMaps.TEMPLATE.setProperty("Misc", prop17);
 719   
 720  46 String msg18 =
 721    "If the op1 is less than op2, returns true,false otherwise.\n" +
 722    "Required attributes:\n" +
 723    "\top1=\"<string evaluating to a number>\"\n" +
 724    "\top2=\"<string evaluating to a number>\"";
 725   
 726  46 Lambda2<Double,Double,Boolean> lam18 = new Lambda2<Double,Double,Boolean>() {
 727  3 public Boolean value(Double op1, Double op2) { return (op1<op2); }
 728    };
 729   
 730  46 BinaryOpProperty<Double,Double,Boolean> prop18 =
 731    new BinaryOpProperty<Double,Double,Boolean>("lt",
 732    msg18,
 733    lam18,
 734    UnaryOpProperty.PARSE_DOUBLE,
 735    UnaryOpProperty.PARSE_DOUBLE,
 736    UnaryOpProperty.FORMAT_BOOL);
 737   
 738  46 PropertyMaps.TEMPLATE.setProperty("Misc",prop18);
 739   
 740  46 String msg19 =
 741    "If the op1 is greater than or equal to op2, returns true,false otherwise.\n" +
 742    "Required attributes:\n" +
 743    "\top1=\"<string evaluating to a number>\"\n" +
 744    "\top2=\"<string evaluating to a number>\"";
 745   
 746  46 Lambda2<Double,Double,Boolean> lam19 = new Lambda2<Double,Double,Boolean>() {
 747  3 public Boolean value(Double op1, Double op2) { return (op1>=op2); }
 748    };
 749   
 750  46 BinaryOpProperty<Double,Double,Boolean> prop19 =
 751    new BinaryOpProperty<Double,Double,Boolean>("gte",
 752    msg19,
 753    lam19,
 754    UnaryOpProperty.PARSE_DOUBLE,
 755    UnaryOpProperty.PARSE_DOUBLE,
 756    UnaryOpProperty.FORMAT_BOOL);
 757   
 758  46 PropertyMaps.TEMPLATE.setProperty("Misc", prop19);
 759   
 760  46 String msg20 =
 761    "If the op1 is less than or equal to op2, returns true,false otherwise.\n" +
 762    "Required attributes:\n" +
 763    "\top1=\"<string evaluating to a number>\"\n" +
 764    "\top2=\"<string evaluating to a number>\"";
 765   
 766  46 Lambda2<Double,Double,Boolean> lam20 = new Lambda2<Double,Double,Boolean>() {
 767  3 public Boolean value(Double op1, Double op2) { return (op1<=op2); }
 768    };
 769   
 770  46 BinaryOpProperty<Double,Double,Boolean> prop20 =
 771    new BinaryOpProperty<Double,Double,Boolean>("lte",
 772    msg20,
 773    lam20,
 774    UnaryOpProperty.PARSE_DOUBLE,
 775    UnaryOpProperty.PARSE_DOUBLE,
 776    UnaryOpProperty.FORMAT_BOOL);
 777   
 778  46 PropertyMaps.TEMPLATE.setProperty("Misc", prop20);
 779   
 780  46 String msg21 = "If the op1 is equal to op2, returns true,false otherwise.\n" +
 781    "Required attributes:\n" +
 782    "\top1=\"<string>\"\n" +
 783    "\top2=\"<string>\"";
 784   
 785  46 Lambda2<String,String,Boolean> lam21 = new Lambda2<String,String,Boolean>() {
 786  5 public Boolean value(String op1, String op2) { return op1.equals(op2); }
 787    };
 788   
 789  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 790    <String,String,Boolean>("eq",
 791    msg21,
 792    lam21,
 793    UnaryOpProperty.PARSE_STRING,
 794    UnaryOpProperty.PARSE_STRING,
 795    UnaryOpProperty.FORMAT_BOOL));
 796  46 String msg22 =
 797    "If the op1 is not equal to op2, returns true,false otherwise.\n" +
 798    "Required attributes:\n" +
 799    "\top1=\"<string>\"\n" +
 800    "\top2=\"<string>\"";
 801   
 802  46 Lambda2<String,String,Boolean> lam22 = new Lambda2<String,String,Boolean>() {
 803  5 public Boolean value(String op1, String op2) { return !op1.equals(op2); }
 804    };
 805   
 806  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 807    <String,String,Boolean>("neq",
 808    msg22,
 809    lam22,
 810    UnaryOpProperty.PARSE_STRING,
 811    UnaryOpProperty.PARSE_STRING,
 812    UnaryOpProperty.FORMAT_BOOL));
 813  46 String msg23 =
 814    "If op1 and op2 are true, returns true,false otherwise.\n" +
 815    "Required attributes:\n" +
 816    "\top1=\"<boolean>\"\n" +
 817    "\top2=\"<boolean>\"";
 818   
 819  46 Lambda2<Boolean,Boolean,Boolean> lam23 = new Lambda2<Boolean,Boolean,Boolean>() {
 820  8 public Boolean value(Boolean op1, Boolean op2) { return op1 && op2; }
 821    };
 822   
 823  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 824    <Boolean,Boolean,Boolean>("and",
 825    msg23,
 826    lam23,
 827    UnaryOpProperty.PARSE_BOOL,
 828    UnaryOpProperty.PARSE_BOOL,
 829    UnaryOpProperty.FORMAT_BOOL));
 830   
 831  46 String msg24 =
 832    "If at least one of op1, op2 is true, returns true,false otherwise.\n" +
 833    "Required attributes:\n" +
 834    "\top1=\"<boolean>\"\n" +
 835    "\top2=\"<boolean>\"";
 836   
 837  46 Lambda2<Boolean,Boolean,Boolean> lam24 = new Lambda2<Boolean,Boolean,Boolean>() {
 838  8 public Boolean value(Boolean op1, Boolean op2) { return op1 || op2; }
 839    };
 840   
 841  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 842    <Boolean,Boolean,Boolean>("or",
 843    msg24,
 844    lam24,
 845    UnaryOpProperty.PARSE_BOOL,
 846    UnaryOpProperty.PARSE_BOOL,
 847    UnaryOpProperty.FORMAT_BOOL));
 848   
 849  46 Lambda<Boolean,Boolean> lam25 = new Lambda<Boolean,Boolean>() {
 850  4 public Boolean value(Boolean op) { return !op; }
 851    };
 852   
 853  46 PropertyMaps.TEMPLATE.setProperty("Misc", new UnaryOpProperty
 854    <Boolean,Boolean>("not",
 855    "If op is true, returns false," +
 856    "true otherwise.\n" +
 857    "Required attributes:\n" +
 858    "\top=\"<boolean>\"",
 859    lam25,
 860    UnaryOpProperty.PARSE_BOOL,
 861    UnaryOpProperty.FORMAT_BOOL));
 862   
 863  46 Lambda2<Double,Double,Double> lam26 = new Lambda2<Double,Double,Double>() {
 864  3 public Double value(Double op1, Double op2) { return op1 + op2; }
 865    };
 866   
 867  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 868    <Double,Double,Double>("add",
 869    "Returns the sum of the two operands (op1+op2).\n" +
 870    "Required attributes:\n" +
 871    "\top1=\"<string evaluating to a number>\"\n" +
 872    "\top2=\"<string evaluating to a number>\"",
 873    lam26,
 874    UnaryOpProperty.PARSE_DOUBLE,
 875    UnaryOpProperty.PARSE_DOUBLE,
 876    UnaryOpProperty.FORMAT_DOUBLE));
 877   
 878  46 Lambda2<Double,Double,Double> lam27 = new Lambda2<Double,Double,Double>() {
 879  3 public Double value(Double op1, Double op2) { return op1 - op2; }
 880    };
 881   
 882  46 PropertyMaps.TEMPLATE.
 883    setProperty("Misc", new BinaryOpProperty
 884    <Double,Double,Double>("sub",
 885    "Returns the difference between the two operands (op1-op2).\n" +
 886    "Required attributes:\n" +
 887    "\top1=\"<string evaluating to a number>\"\n" +
 888    "\top2=\"<string evaluating to a number>\"",
 889    lam27,
 890    UnaryOpProperty.PARSE_DOUBLE,
 891    UnaryOpProperty.PARSE_DOUBLE,
 892    UnaryOpProperty.FORMAT_DOUBLE));
 893   
 894  46 Lambda2<Double,Double,Double> lam28 = new Lambda2<Double,Double,Double>() {
 895  3 public Double value(Double op1, Double op2) { return op1 * op2; }
 896    };
 897   
 898  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 899    <Double,Double,Double>("mul",
 900    "Returns the product of the two operands (op1*op2).\n" +
 901    "Required attributes:\n" +
 902    "\top1=\"<string evaluating to a number>\"\n" +
 903    "\top2=\"<string evaluating to a number>\"",
 904    lam28,
 905    UnaryOpProperty.PARSE_DOUBLE,
 906    UnaryOpProperty.PARSE_DOUBLE,
 907    UnaryOpProperty.FORMAT_DOUBLE));
 908  46 Lambda2<Double,Double,Double> lam29 = new Lambda2<Double,Double,Double>() {
 909  3 public Double value(Double op1, Double op2) { return op1 / op2; }
 910    };
 911   
 912  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 913    <Double,Double,Double>("div",
 914    "Returns the quotient of the two operands (op1/op2).\n" +
 915    "Required attributes:\n" +
 916    "\top1=\"<string evaluating to a number>\"\n" +
 917    "\top2=\"<string evaluating to a number>\"",
 918    lam29,
 919    UnaryOpProperty.PARSE_DOUBLE,
 920    UnaryOpProperty.PARSE_DOUBLE,
 921    UnaryOpProperty.FORMAT_DOUBLE));
 922   
 923  46 Lambda<String,Double> lam30 = new Lambda<String,Double>() {
 924  3 public Double value(String s) { return ((double)s.length()); }
 925    };
 926   
 927  46 PropertyMaps.TEMPLATE.setProperty("Misc", new UnaryOpProperty
 928    <String,Double>("strlen",
 929    "Returns the length of the operand in characters.\n" +
 930    "Required attributes:\n" +
 931    "\top=\"<string>\"",
 932    lam30,
 933    UnaryOpProperty.PARSE_STRING,
 934    UnaryOpProperty.FORMAT_DOUBLE));
 935   
 936  46 Lambda2<String,String,Double> lam31 = new Lambda2<String,String,Double>() {
 937  24 public Double value(String s, String sep) {
 938  3 if (s.length() == 0) return 0.0;
 939  21 return ((double)s.split(TextUtil.regexEscape(sep),-1).length);
 940    }
 941    };
 942   
 943  46 PropertyMaps.TEMPLATE.setProperty("Misc", new BinaryOpProperty
 944    <String,String,Double>("count",
 945    "Counts the number of elements in the list.\n" +
 946    "Required attributes:\n" +
 947    "\tlist=\"<list string>\"\n" +
 948    "Optional attributes:\n" +
 949    "\tsep=\"<separator string>\"\n" +
 950    "(if none specified, ${path.separator} will be used)",
 951    lam31,
 952    "list",
 953    null,
 954    UnaryOpProperty.PARSE_STRING,
 955    "sep",
 956    System.getProperty("path.separator"),
 957    UnaryOpProperty.PARSE_STRING,
 958    UnaryOpProperty.FORMAT_DOUBLE));
 959   
 960  46 String msg32 =
 961    "Extracts a sublist of elements from a list, beginning at a specified index, and including a specified number " +
 962    "of elements.\n" +
 963    "Required attributes:\n" +
 964    "\tlist=\"<list string>\"\n" +
 965    "\tindex=\"<index in list, starting with 0>\"\n" +
 966    "Optional attributes:\n" +
 967    "\tcount=\"<number of items>\"\n" +
 968    "(if not specified, 1 will be used)\n" +
 969    "\tsep=\"<separator string>\"\n" +
 970    "(if none specified, ${path.separator} will be used)";
 971   
 972  46 Lambda4<String,Double,Double,String,String> lam32 = new Lambda4<String,Double,Double,String,String>() {
 973  48 public String value(String s, Double index, Double count, String sep) {
 974  8 if (s.length() == 0) return "";
 975  40 int i = index.intValue();
 976  40 int c = count.intValue();
 977  40 StringBuilder sb = new StringBuilder();
 978  40 String[] els = s.split(TextUtil.regexEscape(sep),-1);
 979  40 for(int j=0; j<c; ++j) {
 980  12 if (i+j>=els.length) { break; }
 981  46 sb.append(sep);
 982  46 sb.append(els[i+j]);
 983    }
 984  40 s = sb.toString();
 985  40 if (s.length() >= sep.length()) {
 986  36 return s.substring(sep.length());
 987    }
 988    else {
 989  4 return "";
 990    }
 991    }
 992    };
 993   
 994  46 PropertyMaps.TEMPLATE.setProperty("Misc", new QuaternaryOpProperty
 995    <String,Double,Double,String,String>("sublist",
 996    msg32,
 997    lam32,
 998    "list",
 999    null,
 1000    UnaryOpProperty.PARSE_STRING,
 1001    "index",
 1002    null,
 1003    UnaryOpProperty.PARSE_DOUBLE,
 1004    "count",
 1005    "1",
 1006    UnaryOpProperty.PARSE_DOUBLE,
 1007    "sep",
 1008    System.getProperty("path.separator"),
 1009    UnaryOpProperty.PARSE_STRING,
 1010    UnaryOpProperty.FORMAT_STRING));
 1011   
 1012  46 Lambda3<String,String,String,String> lam33 = new Lambda3<String,String,String,String>() {
 1013  24 public String value(String s, String oldSep, String newSep) {
 1014  3 if (s.length() == 0) return "";
 1015  21 StringBuilder sb = new StringBuilder();
 1016  21 for(String el: s.split(TextUtil.regexEscape(oldSep),-1)) {
 1017  84 sb.append(newSep);
 1018  84 sb.append(el);
 1019    }
 1020  21 s = sb.toString();
 1021  21 if (s.startsWith(newSep)) {
 1022  21 s = s.substring(newSep.length());
 1023    }
 1024  21 return s;
 1025    }
 1026    };
 1027   
 1028  46 PropertyMaps.TEMPLATE.setProperty("Misc", new TernaryOpProperty
 1029    <String,String,String,String>("change.sep",
 1030    "Changes the separator used in a list of values." +
 1031    "Required attributes:\n" +
 1032    "\tlist=\"<list string>\"\n" +
 1033    "\told=\"<old separator>\"\n" +
 1034    "\tnew=\"<new separator>\"",
 1035    lam33,
 1036    "list",
 1037    null,
 1038    UnaryOpProperty.PARSE_STRING,
 1039    "old",
 1040    null,
 1041    UnaryOpProperty.PARSE_STRING,
 1042    "new",
 1043    null,
 1044    UnaryOpProperty.PARSE_STRING,
 1045    UnaryOpProperty.FORMAT_STRING));
 1046   
 1047  46 Lambda3<String,String,String,String> lam34 = new Lambda3<String,String,String,String>() {
 1048  5 public String value(String s, String oldStr, String newStr) {
 1049  1 if (s.length() == 0) return "";
 1050  4 return s.replaceAll(TextUtil.regexEscape(oldStr), newStr);
 1051    }
 1052    };
 1053   
 1054  46 PropertyMaps.TEMPLATE.setProperty("Misc", new TernaryOpProperty
 1055    <String,String,String,String>("replace.string",
 1056    "Replaces each occurrence in a string." +
 1057    "Required attributes:\n" +
 1058    "\ttext=\"<text in which to replace>\"\n" +
 1059    "\told=\"<old string>\"\n" +
 1060    "\tnew=\"<new string>\"",
 1061    lam34,
 1062    "text",
 1063    null,
 1064    UnaryOpProperty.PARSE_STRING,
 1065    "old",
 1066    null,
 1067    UnaryOpProperty.PARSE_STRING,
 1068    "new",
 1069    null,
 1070    UnaryOpProperty.PARSE_STRING,
 1071    UnaryOpProperty.FORMAT_STRING));
 1072   
 1073    // XML properties, correspond to XMLConfig
 1074  46 String msg35 =
 1075    "Read data from an XML file.\n" +
 1076    "Required attributes:\n" +
 1077    "\tfile=\"<file with the XML>\"\n" +
 1078    "\tpath=\"<path into the XML tree>\"\n" +
 1079    "\tdefault=\"<default value if not found>\"\n" +
 1080    "\tmulti=\"<true if multiple values are allowed>\"\n" +
 1081    "\tsep=\"<separator between results>\"";
 1082   
 1083  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("xml.in", "(XML Input...)",msg35) {
 1084  0 public String toString() {
 1085  0 return "(XML Input...)";
 1086    }
 1087  0 public void update(PropertyMaps pm) {
 1088  0 String xmlfile = _attributes.get("file");
 1089  0 String xmlpath = _attributes.get("path");
 1090  0 String defval = _attributes.get("default");
 1091  0 String multi = _attributes.get("multi");
 1092  0 String sep = _attributes.get("sep");
 1093  0 if ((xmlfile == null) ||
 1094    (xmlpath == null) ||
 1095    (defval == null)) {
 1096  0 _value = "(XML Input Error...)";
 1097  0 return;
 1098    }
 1099  0 try {
 1100  0 File f = new File(xmlfile);
 1101  0 if (!f.exists()) {
 1102  0 _value = defval;
 1103  0 return;
 1104    }
 1105  0 XMLConfig xc = new XMLConfig(f);
 1106  0 List<String> values = xc.getMultiple(xmlpath);
 1107  0 if (!"true".equals(multi.toLowerCase())) {
 1108  0 if (values.size() != 1) {
 1109  0 _value = defval;
 1110  0 return;
 1111    }
 1112  0 _value = values.get(0);
 1113  0 return;
 1114    }
 1115  0 StringBuilder sb = new StringBuilder();
 1116  0 for (String v: values) {
 1117  0 sb.append(sep);
 1118  0 sb.append(v);
 1119    }
 1120  0 _value = sb.toString().substring(1);
 1121    }
 1122    catch(XMLConfigException xce) {
 1123  0 _value = defval;
 1124    }
 1125    }
 1126  0 public String getCurrent(PropertyMaps pm) {
 1127  0 invalidate();
 1128  0 return super.getCurrent(pm);
 1129    }
 1130  46 public void resetAttributes() {
 1131  46 _attributes.clear();
 1132  46 _attributes.put("file", null);
 1133  46 _attributes.put("path", null);
 1134  46 _attributes.put("default", null);
 1135  46 _attributes.put("multi", "true");
 1136  46 _attributes.put("sep", File.pathSeparator);
 1137    }
 1138    });
 1139   
 1140  46 String msg36 =
 1141    "Write data to an XML file. Since this is an action, it will not produce any output, but it will " +
 1142    "write to the XML file.\n" +
 1143    "Required attributes:\n" +
 1144    "\tfile=\"<file with the XML>\"\n" +
 1145    "\tpath=\"<path into the XML tree>\"\n" +
 1146    "\tcontent=\"<value to write into the XML>\"\n" +
 1147    "\tappend=\"<true to append, false to overwrite existing>\"";
 1148   
 1149  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("xml.out.action", "(XML Output...)", msg36) {
 1150  0 public String toString() {
 1151  0 return "(XML Output...)";
 1152    }
 1153  0 public void update(PropertyMaps pm) {
 1154  0 String xmlfile = _attributes.get("file");
 1155  0 String xmlpath = _attributes.get("path");
 1156  0 String content = _attributes.get("content");
 1157  0 String append = _attributes.get("append");
 1158  0 if ((xmlfile == null) ||
 1159    (xmlpath == null)) {
 1160  0 _value = "(XML Output Error...)";
 1161    }
 1162  0 try {
 1163  0 File f = new File(xmlfile);
 1164  0 XMLConfig xc;
 1165  0 if (f.exists()) { xc = new XMLConfig(f); }
 1166  0 else { xc = new XMLConfig(); }
 1167  0 xc.set(xmlpath, content, append.toLowerCase().equals("false"));
 1168  0 xc.save(xmlfile);
 1169  0 _value = "";
 1170    }
 1171    catch(XMLConfigException xce) {
 1172  0 _value = "(XML Output Error...)";
 1173    }
 1174    }
 1175  0 public String getCurrent(PropertyMaps pm) {
 1176  0 invalidate();
 1177  0 return super.getCurrent(pm);
 1178    }
 1179  46 public void resetAttributes() {
 1180  46 _attributes.clear();
 1181  46 _attributes.put("file", null);
 1182  46 _attributes.put("path", null);
 1183  46 _attributes.put("content", "");
 1184  46 _attributes.put("append", "false");
 1185    }
 1186    });
 1187   
 1188    // Variables
 1189  46 String msg37 =
 1190    "Create a new scope and define a variable with the " +
 1191    "specified name and value; then evaluate the command " +
 1192    "with the new variable in the environment.\n" +
 1193    "Required attributes:\n" +
 1194    "\tname=\"<name of the variable>\"\n" +
 1195    "\tval=\"<value of the variable>\"\n" +
 1196    "\tcmd=\"<command to evaluate>\"";
 1197   
 1198  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("var", msg37) {
 1199  0 public void update(PropertyMaps pm) {
 1200  0 String name = _attributes.get("name");
 1201  0 String val = _attributes.get("val");
 1202  0 String cmd = _attributes.get("cmd");
 1203  0 if (name == null) {
 1204  0 _value = "(var Error: name missing...)";
 1205  0 return;
 1206    }
 1207  0 if (val == null) {
 1208  0 _value = "(var Error: val missing...)";
 1209  0 return;
 1210    }
 1211  0 if (cmd == null) {
 1212  0 _value = "(var Error: cmd missing...)";
 1213  0 return;
 1214    }
 1215  0 try {
 1216  0 PropertyMaps.TEMPLATE.addVariable(name,val);
 1217  0 _value = StringOps.replaceVariables(cmd, pm, PropertyMaps.GET_CURRENT);
 1218  0 PropertyMaps.TEMPLATE.removeVariable(name);
 1219    }
 1220    catch(IllegalArgumentException e) {
 1221  0 _value = "(var Error: " +e.getMessage() + "...)";
 1222    }
 1223    }
 1224  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 1225  0 public boolean isCurrent() { return false; }
 1226  46 public void resetAttributes() {
 1227  46 _attributes.clear();
 1228  46 _attributes.put("name", null);
 1229  46 _attributes.put("val", null);
 1230  46 _attributes.put("cmd", null);
 1231    }
 1232  0 public String toString() { return "--uninitialized--"; }
 1233  0 public void setAttributes(HashMap<String,String> attrs, Lambda<String,String> replaceLambda) {
 1234  0 for(Map.Entry<String,String> e: attrs.entrySet()) {
 1235  0 if (e.getKey().equals("cmd")) {
 1236    // do not evaluate the cmd attribute yet
 1237  0 setAttribute(e.getKey(), e.getValue());
 1238    }
 1239    else {
 1240  0 setAttribute(e.getKey(), replaceLambda.value(e.getValue()));
 1241    }
 1242    }
 1243    }
 1244    });
 1245   
 1246  46 String msg38 =
 1247    "Mutate the value of the variable with the specified name and value.\n" +
 1248    "Required attributes:\n" +
 1249    "\tname=\"<name of the variable>\"\n" +
 1250    "\tval=\"<value of the variable>\"";
 1251   
 1252  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("var.set", msg38) {
 1253  0 public void update(PropertyMaps pm) {
 1254  0 String name = _attributes.get("name");
 1255  0 String val = _attributes.get("val");
 1256  0 if (name == null) {
 1257  0 _value = "(var.set Error: name missing...)";
 1258  0 return;
 1259    }
 1260  0 if (val == null) {
 1261  0 _value = "(var.set Error: val missing...)";
 1262  0 return;
 1263    }
 1264  0 try {
 1265  0 pm.setVariable(name,val);
 1266    }
 1267    catch(IllegalArgumentException e) {
 1268  0 _value = "(var.set Error: " +e.getMessage() + "...)";
 1269  0 return;
 1270    }
 1271  0 _value = "";
 1272    }
 1273  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 1274  0 public boolean isCurrent() { return false; }
 1275  46 public void resetAttributes() {
 1276  46 _attributes.clear();
 1277  46 _attributes.put("name", null);
 1278  46 _attributes.put("val", null);
 1279    }
 1280  0 public String toString() { return ""; }
 1281    });
 1282   
 1283  46 String msg39 =
 1284    "Create a new scope and define a variable with the specified name. Then process the given list in smaller " +
 1285    "pieces, assigning them to the variable.\n" +
 1286    "Required attributes:\n" +
 1287    "\tlist=\"<list string>\"\n" +
 1288    "\tvar=\"<name of the variable>\"\n" +
 1289    "\tcmd=\"<command to evaluate for each piece>\"\n" +
 1290    "Optional attributes:\n" +
 1291    "\tsep=\"<separator between elements>\"\n" +
 1292    "(if not defined, ${path.separator}, which is " + File.pathSeparator + " on this machine)\n" +
 1293    "\toutsep=\"<separator between elements in the output>\"\n" +
 1294    "(if not defined, ${process.separator}, which is " + edu.rice.cs.util.ProcessChain.PROCESS_SEPARATOR +
 1295    " on this machine, will be used)\n" +
 1296    "\teach=\"<number of elements to process as one piece>\"\n" +
 1297    "(if not defined, 1 is used)";
 1298   
 1299  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("for", msg39) {
 1300  0 public void update(PropertyMaps pm) {
 1301  0 String list = _attributes.get("list");
 1302  0 String var = _attributes.get("var");
 1303  0 String cmd = _attributes.get("cmd");
 1304  0 if (list == null) {
 1305  0 _value = "(for Error: list missing...)";
 1306  0 return;
 1307    }
 1308  0 if (var == null) {
 1309  0 _value = "(for Error: var missing...)";
 1310  0 return;
 1311    }
 1312  0 if (cmd == null) {
 1313  0 _value = "(for Error: cmd missing...)";
 1314  0 return;
 1315    }
 1316  0 String sep = _attributes.get("sep");
 1317  0 String outSep = _attributes.get("outsep");
 1318  0 int each = 1;
 1319  0 try {
 1320  0 each = new Integer(_attributes.get("each"));
 1321  0 if (each<1) { throw new NumberFormatException(); }
 1322    }
 1323    catch(NumberFormatException e) {
 1324  0 _value = "(for Error: each not a positive number...)";
 1325  0 return;
 1326    }
 1327  0 StringBuilder sb = new StringBuilder();
 1328  0 StringBuilder sbVar = new StringBuilder();
 1329  0 pm.addVariable(var,"");
 1330  0 String val;
 1331  0 try {
 1332  0 String[] els = list.split(TextUtil.regexEscape(sep),-1);
 1333  0 int start = 0;
 1334  0 while(start<els.length) {
 1335  0 sbVar.setLength(0);
 1336  0 for(int i=start; i < start+each; ++i) {
 1337  0 if (i>=els.length) break;
 1338  0 sbVar.append(sep);
 1339  0 sbVar.append(els[i]);
 1340    }
 1341  0 val = sbVar.toString();
 1342  0 if (val.startsWith(sep)) {
 1343  0 val = val.substring(sep.length());
 1344    }
 1345  0 pm.setVariable(var,val);
 1346  0 sb.append(outSep);
 1347  0 sb.append(StringOps.replaceVariables(cmd, pm, PropertyMaps.GET_CURRENT));
 1348  0 start += each;
 1349    }
 1350    }
 1351    catch(IllegalArgumentException e) {
 1352  0 _value = "(for Error: " +e.getMessage() + "...)";
 1353    }
 1354  0 pm.removeVariable(var);
 1355  0 val = sb.toString();
 1356  0 if (val.startsWith(outSep)) {
 1357  0 val = val.substring(outSep.length());
 1358    }
 1359  0 _value = val;
 1360    }
 1361  0 public boolean isCurrent() { return false; }
 1362  46 public void resetAttributes() {
 1363  46 _attributes.clear();
 1364  46 _attributes.put("list", null);
 1365  46 _attributes.put("var", null);
 1366  46 _attributes.put("cmd", null);
 1367  46 _attributes.put("sep", File.pathSeparator);
 1368  46 _attributes.put("outsep", edu.rice.cs.util.ProcessChain.PROCESS_SEPARATOR);
 1369  46 _attributes.put("each", "1");
 1370    }
 1371  0 public String toString() { return "--uninitialized--"; }
 1372  0 public void setAttributes(HashMap<String,String> attrs, Lambda<String,String> replaceLambda) {
 1373  0 for(Map.Entry<String,String> e: attrs.entrySet()) {
 1374  0 if (e.getKey().equals("cmd")) {
 1375    // do not evaluate the cmd attribute yet
 1376  0 setAttribute(e.getKey(), e.getValue());
 1377    }
 1378    else {
 1379  0 setAttribute(e.getKey(), replaceLambda.value(e.getValue()));
 1380    }
 1381    }
 1382    }
 1383    });
 1384   
 1385  46 ConstantProperty prop40 = new ConstantProperty("process.separator",
 1386    edu.rice.cs.util.ProcessChain.PROCESS_SEPARATOR,
 1387    "This property contains the separator used between processes.");
 1388  46 PropertyMaps.TEMPLATE.setProperty("Config", prop40);
 1389   
 1390  46 String msg41 =
 1391    "If the command line was enclosed in a .djapp file that was a JAR file, then this property contains the file. " +
 1392    "Otherwise, it is empty.\n" +
 1393    "Optional attributes:\n" +
 1394    "\trel=\"<dir to which the files are relative>\"\n" +
 1395    "\tsquote=\"<true to enclose file in single quotes>\"\n" +
 1396    "\tdquote=\"<true to enclose file in double quotes>\"";
 1397   
 1398  46 PropertyMaps.TEMPLATE.setProperty("Misc", new MutableFileProperty("enclosing.djapp.file", null, msg41));
 1399   
 1400  46 String[] cps = System.getProperty("java.class.path").split(TextUtil.regexEscape(File.pathSeparator),-1);
 1401  46 File found = null;
 1402  46 for(String cp: cps) {
 1403  322 try {
 1404  322 File f = new File(cp);
 1405  0 if (!f.exists()) { continue; }
 1406  322 if (f.isDirectory()) {
 1407    // this is a directory, maybe DrJava is contained here as individual files
 1408  92 File cf = new File(f, edu.rice.cs.drjava.DrJava.class.getName().replace('.', File.separatorChar) + ".class");
 1409  92 if (cf.exists() && cf.isFile()) {
 1410  46 found = f;
 1411  46 break;
 1412    }
 1413    }
 1414  230 else if (f.isFile()) {
 1415    // this is a file, it should be a jar file
 1416  230 java.util.jar.JarFile jf = new java.util.jar.JarFile(f);
 1417    // if it's not a jar file, an exception will already have been thrown
 1418    // so we know it is a jar file
 1419    // now let's check if it contains DrJava
 1420  230 if (jf.getJarEntry(edu.rice.cs.drjava.DrJava.class.getName().replace('.', '/') + ".class") != null) {
 1421  0 found = f;
 1422  0 break;
 1423    }
 1424    }
 1425    }
 1426    catch(IOException e) { /* ignore, we'll continue with the next classpath item */ }
 1427    }
 1428   
 1429  46 final File drjavaFile = found;
 1430   
 1431  46 String msg42 =
 1432    "Returns the executable file of DrJava that is currently running.\n" +
 1433    "Optional attributes:\n" +
 1434    "\trel=\"<dir to which the output should be relative\"\n" +
 1435    "\tsquote=\"<true to enclose file in single quotes>\"\n" +
 1436    "\tdquote=\"<true to enclose file in double quotes>\"";
 1437   
 1438  46 Thunk<File> thunk42 = new Thunk<File>() {
 1439  0 public File value() { return drjavaFile; }
 1440    };
 1441   
 1442  46 FileProperty prop42 = new FileProperty("drjava.file", thunk42, msg42) {
 1443  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 1444    };
 1445   
 1446  46 PropertyMaps.TEMPLATE.setProperty("Misc", prop42);
 1447   
 1448  46 String msg43 =
 1449    "Returns the Java interpreter executable file.\n" +
 1450    "Optional attributes:\n" +
 1451    "\trel=\"<dir to which the output should be relative\"\n" +
 1452    "\tsquote=\"<true to enclose file in single quotes>\"\n" +
 1453    "\tdquote=\"<true to enclose file in double quotes>\"";
 1454   
 1455  46 FileProperty prop43 = new FileProperty("java.file",
 1456    new Thunk<File>() {
 1457  0 public File value() {
 1458  0 return new File(JVMBuilder.DEFAULT.javaCommand());
 1459    }
 1460    }, msg43) {
 1461  0 public String getLazy(PropertyMaps pm) { return getCurrent(pm); }
 1462    };
 1463   
 1464  46 PropertyMaps.TEMPLATE.setProperty("Misc", prop43);
 1465   
 1466  46 PropertyMaps.TEMPLATE.setProperty("Misc", new DrJavaProperty("echo",
 1467    "Echo text to the console.\n" +
 1468    "Required attributes:\n" +
 1469    "\ttext=\"<text to echo>\"") {
 1470  0 public void update(PropertyMaps pm) {
 1471  0 String text = _attributes.get("text");
 1472  0 if (text == null) {
 1473  0 _value = "(echo Error: text missing...)";
 1474  0 return;
 1475    }
 1476  0 StringBuilder sb = new StringBuilder();
 1477  0 final String osName = System.getProperty("os.name");
 1478  0 if ((osName.indexOf("Windows") >= 0)) {
 1479  0 String exe = "cmd";
 1480  0 if ((osName.indexOf("95") >= 0) || (osName.indexOf("98") >= 0)) { exe = "command"; }
 1481  0 if (JavaVersion.CURRENT.supports(JavaVersion.JAVA_5)) {
 1482    // System.getenv is deprecated under 1.3 and 1.4, and may throw a java.lang.Error (!),
 1483    // which we'd rather not have to catch
 1484  0 String var = System.getenv("ComSpec");
 1485  0 if (var != null) { sb.append(var); }
 1486    else {
 1487  0 var = System.getenv("WinDir");
 1488  0 if (var != null) {
 1489  0 sb.append(var);
 1490  0 sb.append("\\System32\\");
 1491    }
 1492  0 sb.append(exe);
 1493    }
 1494    }
 1495    else {
 1496  0 sb.append(exe);
 1497    }
 1498  0 sb.append(" /c echo ");
 1499  0 sb.append(text);
 1500    }
 1501    else {
 1502  0 sb.append("echo ");
 1503  0 sb.append(text);
 1504    }
 1505  0 _value = sb.toString();
 1506    }
 1507  0 public boolean isCurrent() { return false; }
 1508  46 public void resetAttributes() {
 1509  46 _attributes.clear();
 1510  46 _attributes.put("text", null);
 1511    }
 1512  0 public String toString() { return "--uninitialized--"; }
 1513    });
 1514    }
 1515    }