In this method, we make the following translations: *
* & becomes & * " becomes " * < becomes < * > becomes > * newline becomes * carriage return becomes $amp;#13; ** @see #unescapeForXML(String) * * @param string The string to escape. * @return A new string with special characters replaced. */ public static String escapeForXML(String string) { // This method gets called quite a bit when parsing large // files, so rather than calling substitute() many times, // we combine all the loops in one pass. // A different solution might be to scan the string for // escaped xml characters and if any are found, then create a // StringBuffer and do the conversion. Using a profiler would // help here. if (string == null) { return null; } StringBuffer buffer = new StringBuffer(string); int i = 0; int length = string.length(); while (i < length) { switch (buffer.charAt(i)) { case '\n': buffer.deleteCharAt(i); buffer.insert(i, " "); length += 4; break; case '\r': buffer.deleteCharAt(i); buffer.insert(i, " "); length += 4; break; case '"': buffer.deleteCharAt(i); buffer.insert(i, """); length += 5; break; case '&': buffer.deleteCharAt(i); buffer.insert(i, "&"); length += 4; break; case '<': buffer.deleteCharAt(i); buffer.insert(i, "<"); length += 3; break; case '>': buffer.deleteCharAt(i); buffer.insert(i, ">"); length += 3; break; } i++; } return buffer.toString(); } /** Given a string, return a string that when fed to the * Ptolemy expression parser, will turn into the argument * string. That is, replace all the instances of backslashes * with double backslashes, all quotation marks with \", * etc. * For example *
* x"y becomes x\"y; * x\"y becomes x\\\"y; * x\y"z becomes x\\y\"z; * x\\y\"z becomes x\\\\y\\\" ** Similarly, this method replaces the following characters * exactly as defined in Java strings: \n, \t, \b, \r, and \f. * @param string The string to escape. * @return A new string with that can be put between quotation marks. */ public static String escapeString(String string) { // Since the first string is a regular expression, it needs extra escaping. // I have no idea why the extra escaping is needed on the second argument. string = string.replaceAll("\\\\", "\\\\\\\\"); string = string.replaceAll("\"", "\\\\\""); string = string.replaceAll("\n", "\\\\n"); string = string.replaceAll("\t", "\\\\t"); string = string.replaceAll("\b", "\\\\b"); string = string.replaceAll("\r", "\\\\r"); // Not needed. // string = string.replaceAll("\'", "\\\\'"); return string; } /** If the ptolemy.ptII.exitAfterWrapup or the * ptolemy.ptII.doNotExit properties are not set, then call * System.exit(). * Ptolemy code should call this method instead of directly calling * System.exit() so that we can test code that would usually exit. * @param returnValue The return value of this process, where * non-zero values indicate an error. */ public static void exit(int returnValue) { try { if (StringUtilities.getProperty("ptolemy.ptII.doNotExit").length() > 0) { return; } } catch (SecurityException ex) { System.out.println("Warning: failed to get property \"" + "ptolemy.ptII.doNotExit\". " + "(-sandbox always causes this)"); } try { if (StringUtilities.getProperty("ptolemy.ptII.exitAfterWrapup") .length() > 0) { throw new RuntimeException("Normally, we would " + "exit here because Manager.exitAfterWrapup() " + "was called. However, because the " + "ptolemy.ptII.exitAfterWrapup property " + "is set, we throw this exception instead."); } } catch (SecurityException ex) { System.out.println("Warning: failed to get property \"" + "ptolemy.ptII.exitAfterWrapup\". " + "(-sandbox always causes this)"); } if (!inApplet()) { // Only call System.exit if we are not in an applet. // Non-zero indicates a problem. System.exit(returnValue); } } /** Return a number of spaces that is proportional to the argument. * If the argument is negative or zero, return an empty string. * @param level The level of indenting represented by the spaces. * @return A string with zero or more spaces. */ public static String getIndentPrefix(int level) { if (level <= 0) { return ""; } StringBuffer result = new StringBuffer(level * 4); for (int i = 0; i < level; i++) { result.append(" "); } return result.toString(); } /** Get the specified property from the environment. An empty * string is returned if the property named by the "propertyName" * argument environment variable does not exist, though if * certain properties are not defined, then we make various * attempts to determine them and then set them. See the javadoc * page for java.util.System.getProperties() for a list of system * properties. *
The following properties are handled specially *
c:/foo
whereas most of the other
* methods that operate on path names return
* C:/foo
.
* * "An identifier is an unlimited-length sequence of Java letters * and Java digits, the first of which must be a Java letter. An * identifier cannot have the same spelling (Unicode character * sequence) as a keyword (3.9), boolean literal (3.10.3), or * the null literal (3.10.7)." ** Java characters are A-Z, a-z, $ and _. *
Characters that are not permitted in a Java identifier are changed * to underscores. * This method does not check that the returned string is a * keyword or literal. * Note that two different strings can sanitize to the same * string. * This method is commonly used during code generation to map the * name of a ptolemy object to a valid identifier name. * @param name A string with spaces and other characters that * cannot be in a Java name. * @return A String that follows the Java identifier rules. */ public static String sanitizeName(String name) { char[] nameArray = name.toCharArray(); for (int i = 0; i < nameArray.length; i++) { if (!Character.isJavaIdentifierPart(nameArray[i])) { nameArray[i] = '_'; } } if (nameArray.length == 0) { return ""; } else { if (!Character.isJavaIdentifierStart(nameArray[0])) { return "_" + new String(nameArray); } else { return new String(nameArray); } } } /** Test whether a string is a valid Java identifier. * Section 3.8 of the Java language spec says: *
* "An identifier is an unlimited-length sequence of Java letters * and Java digits, the first of which must be a Java letter. An * identifier cannot have the same spelling (Unicode character * sequence) as a keyword (3.9), boolean literal (3.10.3), or * the null literal (3.10.7)." ** Java characters are A-Z, a-z, $ and _. *
Characters that are not permitted in a Java identifier are changed
* to underscores.
* This method does not check whether the string is a keyword or literal.
* @param name The name to be checked.
* @return True if the given name is a valid Java identifier, or false otherwise.
*/
public static boolean isValidIdentifier(String name) {
char[] nameArray = name.toCharArray();
for (int i = 0; i < nameArray.length; i++) {
if (!Character.isJavaIdentifierPart(nameArray[i])) {
return false;
}
}
return true;
}
/** If the string is longer than 79 characters, split it up by
* adding newlines in all newline delimited substrings
* that are longer than 79 characters.
* If the longName argument is null, then the string
* ">Unnamed<" is returned.
* @see #abbreviate(String)
* @see #split(String, int)
* @param longName The string to optionally split up
* @return Either the original string, or the string with newlines
* inserted.
*/
public static String split(String longName) {
return split(longName, 79);
}
/** If the string is longer than length characters,
* split the string up by adding newlines in all
* newline delimited substrings that are longer than length
* characters.
* If the longName argument is null, then the string
* ">Unnamed<" is returned.
* @see #abbreviate(String)
* @see #split(String)
* @param longName The string to optionally split.
* @param length The maximum length of the sequence of characters
* before a newline is inserted.
* @return Either the original string, or the string with newlines
* inserted.
*/
public static String split(String longName, int length) {
if (longName == null) {
return " If prefix is not a simple prefix of string, then
* we use the file system to find the canonical names of the files.
* For this to work, prefix and string should name
* files that exist, see java.io.File.getCanonicalFile() for details.
*
* If prefix is not a prefix of string, then
* we return string
*
* @param prefix The prefix string, for example, "c:/ptII".
* @param string The string to be substituted, for example,
* "c:/ptII/ptolemy".
* @param replacement The replacement to be substituted in, for example,
* "$PTII"
* @return The possibly substituted string.
*/
public static String substituteFilePrefix(String prefix, String string,
String replacement) {
// This method is currently used by $PTII/util/testsuite/auto.tcl
if (string.startsWith(prefix)) {
// Hmm, what about file separators?
return replacement + string.substring(prefix.length());
} else {
try {
String prefixCanonicalPath = new File(prefix)
.getCanonicalPath();
String stringCanonicalPath = new File(string)
.getCanonicalPath();
if (stringCanonicalPath.startsWith(prefixCanonicalPath)) {
return replacement
+ stringCanonicalPath.substring(prefixCanonicalPath
.length());
}
} catch (Throwable throwable) {
// ignore.
}
}
return string;
}
/** Tokenize a String to an array of Strings for use with
* Runtime.exec(String []).
*
* Lines that begin with an octothorpe '#' are ignored.
* Substrings that start and end with a double quote are considered
* to be a single token and are returned as a single array element.
*
* @param inputString The String to tokenize
* @return An array of substrings.
* @exception IOException If StreamTokenizer.nextToken() throws it.
*/
public static String[] tokenizeForExec(String inputString)
throws IOException {
// The java.lang.Runtime.exec(String command) call uses
// java.util.StringTokenizer() to parse the command string.
// Unfortunately, this means that double quotes are not handled
// in the same way that the shell handles them in that 'ls "foo
// 'bar"' will interpreted as three tokens 'ls', '"foo' and
// 'bar"'. In the shell, the string would be two tokens 'ls' and
// '"foo bar"'. What is worse is that the exec() behaviour is
// slightly different under Windows and Unix. To solve this
// problem, we preprocess the command argument using
// java.io.StreamTokenizer, which converts quoted substrings into
// single tokens. We then call java.lang.Runtime.exec(String []
// commands);
// Parse the command into tokens
List In this method, we make the following translations:
*
* & becomes &
* " becomes "
* < becomes <
* > becomes >
* becomes newline
* becomes carriage return
*
* @see #escapeForXML(String)
*
* @param string The string to escape.
* @return A new string with special characters replaced.
*/
public static String unescapeForXML(String string) {
if (string.indexOf("&") != -1) {
string = substitute(string, "&", "&");
string = substitute(string, """, "\"");
string = substitute(string, "<", "<");
string = substitute(string, ">", ">");
string = substitute(string, "
", "\n");
string = substitute(string, "
", "\r");
}
return string;
}
/** Return a string that contains a description of how to use a
* class that calls this method. For example, this method is
* called by "$PTII/bin/vergil -help".
* @param commandTemplate A string naming the command and the
* format of the arguments, for example
* "moml [options] [file . . .]"
* @param commandOptions A 2xN array of Strings that list command-line
* options that take arguments where the first
* element is a String naming the command line option, and the
* second element is the argument, for example
* {"-class", "
* @param commandFlags An array of Strings that list command-line
* options that are either present or not.
* @return A string that describes the command.
*/
public static String usageString(String commandTemplate,
String[][] commandOptions, String[] commandFlags) {
String[][] commandFlagsWithDescriptions = new String[commandFlags.length][2];
for (int i = 0; i < commandFlags.length; i++) {
commandFlagsWithDescriptions[i][0] = commandFlags[i];
commandFlagsWithDescriptions[i][1] = "";
}
return usageString(commandTemplate, commandOptions,
commandFlagsWithDescriptions);
}
/** Return a string that contains a description of how to use a
* class that calls this method. For example, this method is
* called by "$PTII/bin/vergil -help".
* @param commandTemplate A string naming the command and the
* format of the arguments, for example
* "moml [options] [file . . .]"
* @param commandOptions A 2xN array of Strings that list command-line
* options that take arguments where the first
* element is a String naming the command line option, and the
* second element is the argument, for example
* {"-class", "
* @param commandFlagsWithDescriptions A 2xM array of Strings that list
* command-line options that are either present or not and a description
* of what the command line option does.
* @return A string that describes the command.
*/
public static String usageString(String commandTemplate,
String[][] commandOptions, String[][] commandFlagsWithDescriptions) {
// This method is static so that we can reuse it in places
// like copernicus/kernel/Copernicus and actor/gui/MoMLApplication
StringBuffer result = new StringBuffer("Usage: " + commandTemplate
+ "\n\n" + "Options that take values:\n");
int i;
for (i = 0; i < commandOptions.length; i++) {
result.append(" " + commandOptions[i][0]);
if (commandOptions[i][1].length() > 0) {
result.append(" " + commandOptions[i][1]);
}
result.append("\n");
}
result.append("\nBoolean flags:\n");
for (i = 0; i < commandFlagsWithDescriptions.length; i++) {
result.append(" " + commandFlagsWithDescriptions[i][0]);
if (commandFlagsWithDescriptions[i][1].length() > 0) {
result.append("\t" + commandFlagsWithDescriptions[i][1]);
}
result.append("\n");
}
return result.toString();
}
///////////////////////////////////////////////////////////////////
//// public variables ////
// If you change these, be sure to try running vergil on
// a HSIF moml file
// vergil ../hsif/demo/SwimmingPool/SwimmingPool.xml
/** Maximum length in characters of a long string before
* {@link #ellipsis(String, int)} truncates and add a
* trailing ". . .". This variable is used by callers
* of ellipsis(String, int).
*/
public static final int ELLIPSIS_LENGTH_LONG = 2000;
/** Maximum length in characters of a short string before
* {@link #ellipsis(String, int)} truncates and add a
* trailing ". . .". This variable is used by callers
* of ellipsis(String, int).
*/
public static final int ELLIPSIS_LENGTH_SHORT = 400;
/** The line separator string. Under Windows, this would
* be "\r\n"; under Unix, "\n"; Under Macintosh, "\r".
*/
public static final String LINE_SEPARATOR = System
.getProperty("line.separator");
/** Location of Application preferences such as the user library.
* This field is not final in case other applications want to
* set it to a different directory.
* @see #preferencesDirectory()
*/
public static final String PREFERENCES_DIRECTORY = ".ptolemyII";
///////////////////////////////////////////////////////////////////
//// private variables ////
/** Set to true if we print the cygwin warning in getProperty(). */
private static boolean _printedCygwinWarning = false;
/** Cached value of ptolemy.ptII.dir property. */
private static String _ptolemyPtIIDir = null;
}