Back to index

wims  3.65+svn20090927
StringUtilities.java
Go to the documentation of this file.
00001 /* Utilities used to manipulate strings.
00002 
00003  Copyright (c) 2002-2008 The Regents of the University of California.
00004  All rights reserved.
00005  Permission is hereby granted, without written agreement and without
00006  license or royalty fees, to use, copy, modify, and distribute this
00007  software and its documentation for any purpose, provided that the above
00008  copyright notice and the following two paragraphs appear in all copies
00009  of this software.
00010 
00011  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
00012  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
00013  ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
00014  THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
00015  SUCH DAMAGE.
00016 
00017  THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
00018  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
00020  PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
00021  CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
00022  ENHANCEMENTS, OR MODIFICATIONS.
00023 
00024  PT_COPYRIGHT_VERSION_2
00025  COPYRIGHTENDKEY
00026 
00027  */
00028 package ptolemy.util;
00029 
00030 // Note that classes in ptolemy.util do not depend on any
00031 // other ptolemy packages.
00032 import java.io.BufferedReader;
00033 import java.io.File;
00034 import java.io.IOException;
00035 import java.io.StreamTokenizer;
00036 import java.io.StringReader;
00037 import java.net.MalformedURLException;
00038 import java.net.URI;
00039 import java.net.URL;
00040 import java.util.LinkedList;
00041 import java.util.List;
00042 import java.util.Properties;
00043 import java.util.StringTokenizer;
00044 
00047 
00058 public class StringUtilities {
00061     private StringUtilities() {
00062     }
00063 
00066 
00077     public static String abbreviate(String longName) {
00078         // This method is used to abbreviate window titles so that long
00079         // file names may appear in the window title bar.  It is not
00080         // parameterized so that we can force a unified look and feel.
00081         // FIXME: it would be nice to split on a nearby space.
00082         if (longName == null) {
00083             return "<Unnamed>";
00084         }
00085 
00086         if (longName.length() <= 80) {
00087             return longName;
00088         }
00089 
00090         return longName.substring(0, 37) + ". . ."
00091                 + longName.substring(longName.length() - 38);
00092     }
00093 
00106     public static String ellipsis(String string, int length) {
00107         // If necessary, insert newlines into long strings.
00108         // If we don't do split long lines and we throw an exception
00109         // with a very long line, then the window close button and
00110         // possible the dismiss button will be off the right side of
00111         // the screen.
00112         // The number 160 was generated by trying different sizes and
00113         // seeing what fits on a 1024 wide screen.
00114         string = StringUtilities.split(string, 160);
00115 
00116         // Third argument being true means return the delimiters as tokens.
00117         StringTokenizer tokenizer = new StringTokenizer(string, LINE_SEPARATOR,
00118                 true);
00119 
00120         // If there are more than 42 lines and 42 newlines, return
00121         // truncate after the first 42 lines and newlines.
00122         // This is necessary so that we can deal with very long lines
00123         // of text without spaces.
00124         if (tokenizer.countTokens() > 42) {
00125             StringBuffer results = new StringBuffer();
00126 
00127             for (int i = 0; (i < 42) && tokenizer.hasMoreTokens(); i++) {
00128                 results.append(tokenizer.nextToken());
00129             }
00130 
00131             results.append("...");
00132             string = results.toString();
00133         }
00134 
00135         if (string.length() > length) {
00136             return string.substring(0, length - 3) + "...";
00137         }
00138 
00139         return string;
00140     }
00141 
00160     public static String escapeForXML(String string) {
00161         string = substitute(string, "&", "&amp;");
00162         string = substitute(string, "\"", "&quot;");
00163         string = substitute(string, "<", "&lt;");
00164         string = substitute(string, ">", "&gt;");
00165         string = substitute(string, "\n", "&#10;");
00166         string = substitute(string, "\r", "&#13;"); // Carriage return
00167         return string;
00168     }
00169 
00187     public static String escapeString(String string) {
00188         // Since the first string is a regular expression, it needs extra escaping.
00189         // I have no idea why the extra escaping is needed on the second argument.
00190         string = string.replaceAll("\\\\", "\\\\\\\\");
00191         string = string.replaceAll("\"", "\\\\\"");
00192         string = string.replaceAll("\n", "\\\\n");
00193         string = string.replaceAll("\t", "\\\\t");
00194         string = string.replaceAll("\b", "\\\\b");
00195         string = string.replaceAll("\r", "\\\\r");
00196         // Not needed.
00197         // string = string.replaceAll("\'", "\\\\'");
00198         return string;
00199     }
00200 
00208     public static void exit(int returnValue) {
00209         if (StringUtilities.getProperty("ptolemy.ptII.exitAfterWrapup")
00210                 .length() > 0) {
00211             throw new RuntimeException("Normally, we would "
00212                     + "exit here because Manager.exitAfterWrapup() "
00213                     + "was called.  However, because the "
00214                     + "ptolemy.ptII.exitAfterWrapup property "
00215                     + "is set, we throw this exception instead.");
00216         } else {
00217             // Non-zero indicates a problem.
00218             System.exit(returnValue);
00219         }
00220     }
00221 
00227     public static String getIndentPrefix(int level) {
00228         if (level <= 0) {
00229             return "";
00230         }
00231 
00232         StringBuffer result = new StringBuffer(level * 4);
00233 
00234         for (int i = 0; i < level; i++) {
00235             result.append("    ");
00236         }
00237 
00238         return result.toString();
00239     }
00240 
00272     public static String getProperty(String propertyName) {
00273         // NOTE: getProperty() will probably fail in applets, which
00274         // is why this is in a try block.
00275         String property = null;
00276 
00277         try {
00278             property = System.getProperty(propertyName);
00279         } catch (SecurityException ex) {
00280             if (!propertyName.equals("ptolemy.ptII.dir")) {
00281                 // Constants.java depends on this when running with
00282                 // -sandbox.
00283                 SecurityException security = new SecurityException(
00284                         "Could not find '" + propertyName + "' System property");
00285                 security.initCause(ex);
00286                 throw security;
00287             }
00288         }
00289 
00290         if (propertyName.equals("user.dir")) {
00291             try {
00292                 File userDirFile = new File(property);
00293                 return userDirFile.getCanonicalPath();
00294             } catch (IOException ex) {
00295                 return property;
00296             }
00297         }
00298 
00299         // Check for cases where the ptII property starts with
00300         // the string "/cygdrive".  This can happen if the property
00301         // was set by doing "PTII=`pwd`" under Cygwin bash.
00302         if (property != null) {
00303             if (propertyName.equals("ptolemy.ptII.dir")
00304                     && property.startsWith("/cygdrive")
00305                     && !_printedCygwinWarning) {
00306                 // This error only occurs when users build their own,
00307                 // so it is safe to print to stderr
00308                 _printedCygwinWarning = true;
00309                 System.err.println("ptolemy.ptII.dir property = \"" + property
00310                         + "\", which contains \"cygdrive\". "
00311                         + "This is almost always an error under Cygwin that "
00312                         + "is occurs when one does PTII=`pwd`.  Instead, do "
00313                         + "PTII=c:/foo/ptII");
00314             }
00315 
00316             return property;
00317         }
00318 
00319         if (propertyName.equals("ptolemy.ptII.dirAsURL")) {
00320             // Return $PTII as a URL.  For example, if $PTII was c:\ptII,
00321             // then return file:/c:/ptII/
00322             File ptIIAsFile = new File(getProperty("ptolemy.ptII.dir"));
00323 
00324             try {
00325                 // Convert first to a URI, then to a URL so that we
00326                 // properly handle cases where $PTII has spaces in it.
00327                 URI ptIIAsURI = ptIIAsFile.toURI();
00328                 URL ptIIAsURL = ptIIAsURI.toURL();
00329                 return ptIIAsURL.toString();
00330             } catch (java.net.MalformedURLException malformed) {
00331                 throw new RuntimeException("While trying to find '"
00332                         + propertyName + "', could not convert '" + ptIIAsFile
00333                         + "' to a URL", malformed);
00334             }
00335         }
00336 
00337         if (propertyName.equals("ptolemy.ptII.dir")) {
00338             if (_ptolemyPtIIDir != null) {
00339                 // Return the previously calculated value
00340                 return _ptolemyPtIIDir;
00341             } else {
00342                 String stringUtilitiesPath = "ptolemy/util/StringUtilities.class";
00343 
00344                 // PTII variable was not set
00345                 URL namedObjURL = Thread.currentThread()
00346                         .getContextClassLoader().getResource(
00347                                 stringUtilitiesPath);
00348 
00349                 if (namedObjURL != null) {
00350                     // Get the file portion of URL
00351                     String namedObjFileName = namedObjURL.getFile();
00352 
00353                     // FIXME: How do we get from a URL to a pathname?
00354                     if (namedObjFileName.startsWith("file:")) {
00355                         if (namedObjFileName.startsWith("file:/")
00356                                 || namedObjFileName.startsWith("file:\\")) {
00357                             // We get rid of either file:/ or file:\
00358                             namedObjFileName = namedObjFileName.substring(6);
00359                         } else {
00360                             // Get rid of file:
00361                             namedObjFileName = namedObjFileName.substring(5);
00362                         }
00363                     }
00364 
00365                     String abnormalHome = namedObjFileName.substring(0,
00366                             namedObjFileName.length()
00367                                     - stringUtilitiesPath.length());
00368 
00369                     // abnormalHome will have values like: "/C:/ptII/"
00370                     // which cause no end of trouble, so we construct a File
00371                     // and call toString().
00372                     _ptolemyPtIIDir = (new File(abnormalHome)).toString();
00373 
00374                     // If we are running under Web Start, then strip off
00375                     // the trailing "!"
00376                     if (_ptolemyPtIIDir.endsWith("/!")
00377                             || _ptolemyPtIIDir.endsWith("\\!")) {
00378                         _ptolemyPtIIDir = _ptolemyPtIIDir.substring(0,
00379                                 _ptolemyPtIIDir.length() - 1);
00380                     }
00381 
00382                     // Web Start, we might have
00383                     // RMptsupport.jar or
00384                     // XMptsupport.jar1088483703686
00385                     String ptsupportJarName = File.separator + "DMptolemy"
00386                             + File.separator + "RMptsupport.jar";
00387 
00388                     if (_ptolemyPtIIDir.endsWith(ptsupportJarName)) {
00389                         _ptolemyPtIIDir = _ptolemyPtIIDir.substring(0,
00390                                 _ptolemyPtIIDir.length()
00391                                         - ptsupportJarName.length());
00392                     } else {
00393                         ptsupportJarName = "/DMptolemy/XMptsupport.jar";
00394 
00395                         if (_ptolemyPtIIDir.lastIndexOf(ptsupportJarName) != -1) {
00396                             _ptolemyPtIIDir = _ptolemyPtIIDir.substring(0,
00397                                     _ptolemyPtIIDir
00398                                             .lastIndexOf(ptsupportJarName));
00399                         } else {
00400                             // Ptolemy II 6.0.1 under Windows: remove
00401                             // "\ptolemy\ptsupport.jar!"
00402                             // If we don't do this, then ptolemy.ptII.dir
00403                             // is set incorrectly and then links to the javadoc
00404                             // files will not be found if the javadoc only
00405                             // exists in codeDoc.jar and lib/ptII.properties
00406                             // is not present.
00407                             ptsupportJarName = File.separator + "ptolemy"
00408                                     + File.separator + "ptsupport.jar";
00409 
00410                             if (_ptolemyPtIIDir.lastIndexOf(ptsupportJarName) != -1) {
00411                                 _ptolemyPtIIDir = _ptolemyPtIIDir.substring(0,
00412                                         _ptolemyPtIIDir
00413                                                 .lastIndexOf(ptsupportJarName));
00414                             }
00415                         }
00416                     }
00417                 }
00418 
00419                 // Convert %20 to spaces because if a URL has %20 in it,
00420                 // then we know we have a space, but file names do not
00421                 // recognize %20 as being a single space, instead file names
00422                 // see %20 as three characters: '%', '2', '0'.
00423                 if (_ptolemyPtIIDir != null) {
00424                     _ptolemyPtIIDir = StringUtilities.substitute(
00425                             _ptolemyPtIIDir, "%20", " ");
00426                 }
00427 
00428                 if (_ptolemyPtIIDir == null) {
00429                     throw new RuntimeException("Could not find "
00430                             + "'ptolemy.ptII.dir'" + " property.  "
00431                             + "Also tried loading '" + stringUtilitiesPath
00432                             + "' as a resource and working from that. "
00433                             + "Vergil should be "
00434                             + "invoked with -Dptolemy.ptII.dir" + "=\"$PTII\"");
00435                 }
00436 
00437                 try {
00438                     // Here, we set the property so that future updates
00439                     // will get the correct value.
00440                     System.setProperty("ptolemy.ptII.dir", _ptolemyPtIIDir);
00441                 } catch (SecurityException security) {
00442                     // Ignore, we are probably running as an applet or -sandbox
00443                 }
00444 
00445                 return _ptolemyPtIIDir;
00446             }
00447         }
00448 
00449         // If the property is not set then we return the empty string.
00450         if (property == null) {
00451             return "";
00452         }
00453 
00454         return property;
00455     }
00456 
00465     public static void mergePropertiesFile() throws IOException {
00466         Properties systemProperties = System.getProperties();
00467         Properties newProperties = new Properties();
00468         String propertyFileName = "$CLASSPATH/lib/ptII.properties";
00469 
00470         // FIXME: xxxxxxCLASSPATHxxxxxx is an ugly hack
00471         URL propertyFileURL = FileUtilities.nameToURL(
00472                 "xxxxxxCLASSPATHxxxxxx/lib/ptII.properties", null, null);
00473 
00474         if (propertyFileURL == null) {
00475             throw new IOException("Could not find " + propertyFileName);
00476         }
00477 
00478         newProperties.load(propertyFileURL.openStream());
00479 
00480         // systemProperties is a HashSet, so we merge in the new properties.
00481         newProperties.putAll(systemProperties);
00482         System.setProperties(newProperties);
00483         // FIXME: This should be logged, not printed.
00484         //System.out.println("Loaded " + propertyFileURL);
00485     }
00486 
00494     public static String objectToSourceFileName(Object object) {
00495         String sourceFileNameBase = object.getClass().getName().replace('.',
00496                 '/');
00497 
00498         // Inner classes: Get rid of everything past the first $
00499         if (sourceFileNameBase.indexOf("$") != -1) {
00500             sourceFileNameBase = sourceFileNameBase.substring(0,
00501                     sourceFileNameBase.indexOf("$"));
00502         }
00503 
00504         return sourceFileNameBase + ".java";
00505     }
00506 
00514     public static String preferencesDirectory() throws IOException {
00515         String preferencesDirectoryName = StringUtilities
00516                 .getProperty("user.home")
00517                 + File.separator
00518                 + StringUtilities.PREFERENCES_DIRECTORY
00519                 + File.separator;
00520         File preferencesDirectory = new File(preferencesDirectoryName);
00521 
00522         if (!preferencesDirectory.isDirectory()) {
00523             if (preferencesDirectory.mkdirs() == false) {
00524                 throw new IOException("Could not create user preferences "
00525                         + "directory '" + preferencesDirectoryName + "'");
00526             }
00527         }
00528 
00529         return preferencesDirectoryName;
00530     }
00531 
00544     public static String propertiesFileName() throws IOException {
00545         return preferencesDirectory() + "ptII.properties";
00546     }
00547 
00553     public static LinkedList readLines(String lines) throws IOException {
00554         BufferedReader bufferedReader = null;
00555         LinkedList returnList = new LinkedList();
00556         String line;
00557         bufferedReader = new BufferedReader(new StringReader(lines));
00558         try {
00559             // Read line by line, skipping comments.
00560             while ((line = bufferedReader.readLine()) != null) {
00561                 line = line.trim();
00562                 if (!(line.length() == 0 || line.startsWith("/*") || line
00563                         .startsWith("//"))) {
00564                     returnList.add(line);
00565                 }
00566             }
00567         } finally {
00568             if (bufferedReader != null) {
00569                 try {
00570                     bufferedReader.close();
00571                 } catch (IOException ex) {
00572                     // Ignore
00573                     ex.printStackTrace();
00574                 }
00575             }
00576         }
00577         return returnList;
00578     }
00579 
00602     public static String sanitizeName(String name) {
00603         char[] nameArray = name.toCharArray();
00604 
00605         for (int i = 0; i < nameArray.length; i++) {
00606             if (!Character.isJavaIdentifierPart(nameArray[i])) {
00607                 nameArray[i] = '_';
00608             }
00609         }
00610 
00611         if (nameArray.length == 0) {
00612             return "";
00613         } else {
00614             if (!Character.isJavaIdentifierStart(nameArray[0])) {
00615                 return "_" + new String(nameArray);
00616             } else {
00617                 return new String(nameArray);
00618             }
00619         }
00620     }
00621 
00633     public static String split(String longName) {
00634         return split(longName, 79);
00635     }
00636 
00651     public static String split(String longName, int length) {
00652         if (longName == null) {
00653             return "<Unnamed>";
00654         }
00655 
00656         if (longName.length() <= length) {
00657             return longName;
00658         }
00659 
00660         StringBuffer results = new StringBuffer();
00661 
00662         // The third argument is true, which means return the delimiters
00663         // as part of the tokens.
00664         StringTokenizer tokenizer = new StringTokenizer(longName,
00665                 LINE_SEPARATOR, true);
00666 
00667         while (tokenizer.hasMoreTokens()) {
00668             String token = tokenizer.nextToken();
00669             int mark = 0;
00670 
00671             while (mark < (token.length() - length)) {
00672                 // We look for the space from the end of the first length
00673                 // characters.  If we find one, then we use that
00674                 // as the place to insert a newline.
00675                 int lastSpaceIndex = token.substring(mark, mark + length)
00676                         .lastIndexOf(" ");
00677 
00678                 if (lastSpaceIndex < 0) {
00679                     // No space found, just insert a new line after length
00680                     results.append(token.substring(mark, mark + length)
00681                             + LINE_SEPARATOR);
00682                     mark += length;
00683                 } else {
00684                     results.append(token.substring(mark, mark + lastSpaceIndex)
00685                             + LINE_SEPARATOR);
00686                     mark += (lastSpaceIndex + 1);
00687                 }
00688             }
00689 
00690             results.append(token.substring(mark));
00691         }
00692 
00693         return results.toString();
00694     }
00695 
00716     public static URL stringToURL(String name, URI baseDirectory,
00717             ClassLoader classLoader) throws IOException {
00718         return FileUtilities.nameToURL(name, baseDirectory, classLoader);
00719     }
00720 
00731     public static String substitute(String string, String pattern,
00732             String replacement) {
00733         int start = string.indexOf(pattern);
00734 
00735         while (start != -1) {
00736             StringBuffer buffer = new StringBuffer(string);
00737             buffer.delete(start, start + pattern.length());
00738             buffer.insert(start, replacement);
00739             string = new String(buffer);
00740             start = string.indexOf(pattern, start + replacement.length());
00741         }
00742 
00743         return string;
00744     }
00745 
00769     public static String substituteFilePrefix(String prefix, String string,
00770             String replacement) {
00771         // This method is currently used by $PTII/util/testsuite/auto.tcl
00772         if (string.startsWith(prefix)) {
00773             // Hmm, what about file separators?
00774             return replacement + string.substring(prefix.length());
00775         } else {
00776             try {
00777                 String prefixCanonicalPath = (new File(prefix))
00778                         .getCanonicalPath();
00779 
00780                 String stringCanonicalPath = (new File(string))
00781                         .getCanonicalPath();
00782 
00783                 if (stringCanonicalPath.startsWith(prefixCanonicalPath)) {
00784                     return replacement
00785                             + stringCanonicalPath.substring(prefixCanonicalPath
00786                                     .length());
00787                 }
00788             } catch (Throwable throwable) {
00789                 // ignore.
00790             }
00791         }
00792 
00793         return string;
00794     }
00795 
00807     public static String[] tokenizeForExec(String inputString)
00808             throws IOException {
00809         // The java.lang.Runtime.exec(String command) call uses
00810         // java.util.StringTokenizer() to parse the command string.
00811         // Unfortunately, this means that double quotes are not handled
00812         // in the same way that the shell handles them in that 'ls "foo
00813         // 'bar"' will interpreted as three tokens 'ls', '"foo' and
00814         // 'bar"'.  In the shell, the string would be two tokens 'ls' and
00815         // '"foo bar"'.  What is worse is that the exec() behaviour is
00816         // slightly different under Windows and Unix.  To solve this
00817         // problem, we preprocess the command argument using
00818         // java.io.StreamTokenizer, which converts quoted substrings into
00819         // single tokens.  We then call java.lang.Runtime.exec(String []
00820         // commands);
00821         // Parse the command into tokens
00822         List commandList = new LinkedList();
00823 
00824         StreamTokenizer streamTokenizer = new StreamTokenizer(new StringReader(
00825                 inputString));
00826 
00827         // We reset the syntax so that we don't convert to numbers,
00828         // otherwise, if PTII is "d:\\tmp\\ptII\ 2.0", then
00829         // we have no end of problems.
00830         streamTokenizer.resetSyntax();
00831         streamTokenizer.whitespaceChars(0, 32);
00832         streamTokenizer.wordChars(33, 127);
00833 
00834         // We can't use quoteChar here because it does backslash
00835         // substitution, so "c:\ptII" ends up as "c:ptII"
00836         // Substituting forward slashes for backward slashes seems like
00837         // overkill.
00838         // streamTokenizer.quoteChar('"');
00839         streamTokenizer.ordinaryChar('"');
00840 
00841         streamTokenizer.eolIsSignificant(true);
00842 
00843         streamTokenizer.commentChar('#');
00844 
00845         // Current token
00846         String token = "";
00847 
00848         // Single character token, usually a -
00849         String singleToken = "";
00850 
00851         // Set to true if we are inside a double quoted String.
00852         boolean inDoubleQuotedString = false;
00853 
00854         while (streamTokenizer.nextToken() != StreamTokenizer.TT_EOF) {
00855             switch (streamTokenizer.ttype) {
00856             case StreamTokenizer.TT_WORD:
00857 
00858                 if (inDoubleQuotedString) {
00859                     if (token.length() > 0) {
00860                         // FIXME: multiple spaces will get compacted here
00861                         token += " ";
00862                     }
00863 
00864                     token += (singleToken + streamTokenizer.sval);
00865                 } else {
00866                     token = singleToken + streamTokenizer.sval;
00867                     commandList.add(token);
00868                 }
00869 
00870                 singleToken = "";
00871                 break;
00872 
00873             case StreamTokenizer.TT_NUMBER:
00874                 throw new RuntimeException("Internal error: Found TT_NUMBER: '"
00875                         + streamTokenizer.nval + "'.  We should not be "
00876                         + "tokenizing numbers");
00877 
00878                 //break;
00879             case StreamTokenizer.TT_EOL:
00880             case StreamTokenizer.TT_EOF:
00881                 break;
00882 
00883             default:
00884                 singleToken = Character.toString((char) streamTokenizer.ttype);
00885 
00886                 if (singleToken.equals("\"")) {
00887                     if (inDoubleQuotedString) {
00888                         commandList.add(token);
00889                     }
00890 
00891                     inDoubleQuotedString = !inDoubleQuotedString;
00892                     singleToken = "";
00893                     token = "";
00894                 }
00895 
00896                 break;
00897             }
00898         }
00899 
00900         return (String[]) commandList.toArray(new String[commandList.size()]);
00901     }
00902 
00914     public static String truncateString(String string, int lineLength,
00915             int numberOfLines) {
00916 
00917         // Third argument being true means the delimiters (LINE_SEPARATOR) are
00918         // included in as tokens in the parsed results.
00919         StringTokenizer tokenizer = new StringTokenizer(string, LINE_SEPARATOR,
00920                 true);
00921 
00922         StringBuffer results = new StringBuffer();
00923         // Count the lines + newlines.
00924         int lineCount = 0;
00925         while (tokenizer.hasMoreTokens()) {
00926             if (lineCount >= numberOfLines * 2) {
00927                 // Presumably, the last line is a line separator.
00928                 // We append an additional line to indicate that there
00929                 // are more lines.
00930                 results.append("...");
00931                 break;
00932             }
00933             lineCount++;
00934             String line = tokenizer.nextToken();
00935             if (line.length() > lineLength) {
00936                 line = line.substring(0, lineLength - 3) + "...";
00937             }
00938             results.append(line);
00939         }
00940         return results.toString();
00941     }
00942 
00961     public static String unescapeForXML(String string) {
00962         string = substitute(string, "&amp;", "&");
00963         string = substitute(string, "&quot;", "\"");
00964         string = substitute(string, "&lt;", "<");
00965         string = substitute(string, "&gt;", ">");
00966         string = substitute(string, "&#10;", "\n");
00967         string = substitute(string, "&#13;", "\r");
00968         return string;
00969     }
00970 
00986     public static String usageString(String commandTemplate,
00987             String[][] commandOptions, String[] commandFlags) {
00988         // This method is static so that we can reuse it in places
00989         // like copernicus/kernel/Copernicus and actor/gui/MoMLApplication
00990         StringBuffer result = new StringBuffer("Usage: " + commandTemplate
00991                 + "\n\n" + "Options that take values:\n");
00992 
00993         int i;
00994 
00995         for (i = 0; i < commandOptions.length; i++) {
00996             result.append(" " + commandOptions[i][0] + " "
00997                     + commandOptions[i][1] + "\n");
00998         }
00999 
01000         result.append("\nBoolean flags:\n");
01001 
01002         for (i = 0; i < commandFlags.length; i++) {
01003             result.append(" " + commandFlags[i]);
01004         }
01005 
01006         return result.toString();
01007     }
01008 
01011     // If you change these, be sure to try running vergil on
01012     // a HSIF moml file
01013     // vergil ../hsif/demo/SwimmingPool/SwimmingPool.xml
01014 
01020     public static final int ELLIPSIS_LENGTH_LONG = 2000;
01021 
01027     public static final int ELLIPSIS_LENGTH_SHORT = 400;
01028 
01032     public static final String LINE_SEPARATOR = System
01033             .getProperty("line.separator");
01034 
01040     public static String PREFERENCES_DIRECTORY = ".ptolemyII";
01041 
01044 
01046     private static boolean _printedCygwinWarning = false;
01047 
01049     private static String _ptolemyPtIIDir = null;
01050 }