0001: /*
0002: * MiscUtilities.java - Various miscallaneous utility functions
0003: * :tabSize=8:indentSize=8:noTabs=false:
0004: * :folding=explicit:collapseFolds=1:
0005: *
0006: * Copyright (C) 1999, 2005 Slava Pestov
0007: * Portions copyright (C) 2000 Richard S. Hall
0008: * Portions copyright (C) 2001 Dirk Moebius
0009: *
0010: * This program is free software; you can redistribute it and/or
0011: * modify it under the terms of the GNU General Public License
0012: * as published by the Free Software Foundation; either version 2
0013: * of the License, or any later version.
0014: *
0015: * This program is distributed in the hope that it will be useful,
0016: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0018: * GNU General Public License for more details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with this program; if not, write to the Free Software
0022: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0023: */
0024:
0025: package org.gjt.sp.jedit;
0026:
0027: //{{{ Imports
0028: import javax.swing.text.Segment;
0029: import javax.swing.JMenuItem;
0030: import java.io.*;
0031: import java.net.MalformedURLException;
0032: import java.net.URL;
0033: import java.text.DecimalFormat;
0034: import java.util.*;
0035: import java.util.regex.Matcher;
0036: import java.util.regex.Pattern;
0037:
0038: import org.xml.sax.InputSource;
0039: import org.xml.sax.helpers.DefaultHandler;
0040:
0041: import org.gjt.sp.jedit.io.*;
0042: import org.gjt.sp.util.Log;
0043: import org.gjt.sp.util.ProgressObserver;
0044: import org.gjt.sp.util.StandardUtilities;
0045: import org.gjt.sp.util.IOUtilities;
0046: import org.gjt.sp.util.XMLUtilities;
0047: import org.gjt.sp.jedit.menu.EnhancedMenuItem;
0048:
0049: //}}}
0050:
0051: /**
0052: * Path name manipulation, string manipulation, and more.<p>
0053: *
0054: * The most frequently used members of this class are:<p>
0055: *
0056: * <b>Some path name methods:</b><p>
0057: * <ul>
0058: * <li>{@link #getFileName(String)}</li>
0059: * <li>{@link #getParentOfPath(String)}</li>
0060: * <li>{@link #constructPath(String,String)}</li>
0061: * </ul>
0062: * <b>String comparison:</b><p>
0063:
0064: * A {@link #compareStrings(String,String,boolean)} method that unlike
0065: * <function>String.compareTo()</function>, correctly recognizes and handles
0066: * embedded numbers.<p>
0067: *
0068: * This class also defines several inner classes for use with the
0069: * sorting features of the Java collections API:
0070: *
0071: * <ul>
0072: * <li>{@link MiscUtilities.StringCompare}</li>
0073: * <li>{@link MiscUtilities.StringICaseCompare}</li>
0074: * <li>{@link MiscUtilities.MenuItemCompare}</li>
0075: * </ul>
0076: *
0077: * For example, you might call:<p>
0078: *
0079: * <code>Arrays.sort(myListOfStrings,
0080: * new MiscUtilities.StringICaseCompare());</code>
0081: *
0082: * @author Slava Pestov
0083: * @author John Gellene (API documentation)
0084: * @version $Id: MiscUtilities.java 9835 2007-06-22 10:51:33Z Vampire0 $
0085: */
0086: public class MiscUtilities {
0087: /**
0088: * This encoding is not supported by Java, yet it is useful.
0089: * A UTF-8 file that begins with 0xEFBBBF.
0090: * @deprecated
0091: * Extended encodings are now supported as services.
0092: * This value is no longer used.
0093: */
0094: @Deprecated
0095: public static final String UTF_8_Y = "UTF-8Y";
0096:
0097: //{{{ Path name methods
0098:
0099: //{{{ canonPath() method
0100: /**
0101: * @return the canonical form of the specified path name. Currently
0102: * only expands a leading <code>~</code>. <b>For local path names
0103: * only.</b>
0104: * @param path The path name
0105: * @since jEdit 4.0pre2
0106: */
0107: public static String canonPath(String path) {
0108: if (path.length() == 0)
0109: return path;
0110:
0111: if (path.startsWith("file://"))
0112: path = path.substring("file://".length());
0113: else if (path.startsWith("file:"))
0114: path = path.substring("file:".length());
0115: else if (isURL(path))
0116: return path;
0117:
0118: if (File.separatorChar == '\\') {
0119: // get rid of mixed paths on Windows
0120: path = path.replace('/', '\\');
0121: // also get rid of trailing spaces on Windows
0122: int trim = path.length();
0123: while (path.charAt(trim - 1) == ' ')
0124: trim--;
0125:
0126: if (path.charAt(trim - 1) == '\\')
0127: while (trim > 1 && path.charAt(trim - 2) == '\\') {
0128: trim--;
0129: }
0130: path = path.substring(0, trim);
0131: } else if (OperatingSystem.isMacOS()) {
0132: // do the same on OS X
0133: path = path.replace(':', '/');
0134: }
0135:
0136: if (path.startsWith('~' + File.separator)) {
0137: path = path.substring(2);
0138: String home = System.getProperty("user.home");
0139:
0140: if (home.endsWith(File.separator))
0141: return home + path;
0142: else
0143: return home + File.separator + path;
0144: } else if (path.equals("~"))
0145: return System.getProperty("user.home");
0146: else
0147: return path;
0148: } //}}}
0149:
0150: //{{{ expandVariables() method
0151: static final String varPatternString = "(\\$([a-zA-Z0-9_]+))";
0152: static final String varPatternString2 = "(\\$\\{([^}]+)\\})";
0153: static final Pattern varPattern = Pattern.compile(varPatternString);
0154: static final Pattern varPattern2 = Pattern
0155: .compile(varPatternString2);
0156:
0157: /** Accepts a string from the user which may contain variables of various syntaxes.
0158: * The goal is to support the following:
0159: * $varname
0160: * ${varname}
0161: * And expand each of these by looking at the system environment variables for possible
0162: * expansions.
0163: * @return a string which is either the unchanged input string, or one with expanded variables.
0164: * @since 4.3pre7
0165: * @author ezust
0166: */
0167: public static String expandVariables(String arg) {
0168: Pattern p = varPattern;
0169: Matcher m = p.matcher(arg);
0170: if (!m.find()) {
0171: p = varPattern2;
0172: m = p.matcher(arg);
0173: if (!m.find()) // no variables to substitute
0174: return arg;
0175: }
0176: String varName = m.group(2);
0177: String expansion = System.getenv(varName);
0178: if (expansion == null) { // try everything uppercase?
0179: varName = varName.toUpperCase();
0180: String uparg = arg.toUpperCase();
0181: m = p.matcher(uparg);
0182: expansion = System.getenv(varName);
0183: }
0184: if (expansion != null) {
0185: expansion = expansion.replace("\\", "\\\\");
0186: return m.replaceFirst(expansion);
0187: }
0188: return arg;
0189: } //}}}
0190:
0191: //{{{ resolveSymlinks() method
0192: /**
0193: * Resolves any symbolic links in the path name specified
0194: * using <code>File.getCanonicalPath()</code>. <b>For local path
0195: * names only.</b>
0196: * @since jEdit 4.2pre1
0197: */
0198: public static String resolveSymlinks(String path) {
0199: if (isURL(path))
0200: return path;
0201:
0202: // 2 aug 2003: OS/2 Java has a broken getCanonicalPath()
0203: if (OperatingSystem.isOS2())
0204: return path;
0205: // 18 nov 2003: calling this on a drive letter on Windows causes
0206: // drive access
0207: if (OperatingSystem.isDOSDerived()) {
0208: if (path.length() == 2 || path.length() == 3) {
0209: if (path.charAt(1) == ':')
0210: return path;
0211: }
0212: }
0213: try {
0214: return new File(path).getCanonicalPath();
0215: } catch (IOException io) {
0216: return path;
0217: }
0218: } //}}}
0219:
0220: //{{{ isAbsolutePath() method
0221: /**
0222: * Returns if the specified path name is an absolute path or URL.
0223: * @since jEdit 4.1pre11
0224: */
0225: public static boolean isAbsolutePath(String path) {
0226: if (isURL(path))
0227: return true;
0228: else if (path.startsWith("~/")
0229: || path.startsWith("~" + File.separator)
0230: || path.equals("~"))
0231: return true;
0232: else if (OperatingSystem.isDOSDerived()) {
0233: if (path.length() == 2 && path.charAt(1) == ':')
0234: return true;
0235: if (path.length() > 2
0236: && path.charAt(1) == ':'
0237: && (path.charAt(2) == '\\' || path.charAt(2) == '/'))
0238: return true;
0239: if (path.startsWith("\\\\") || path.startsWith("//"))
0240: return true;
0241: }
0242: // not sure if this is correct for OpenVMS.
0243: else if (OperatingSystem.isUnix() || OperatingSystem.isVMS()) {
0244: // nice and simple
0245: if (path.length() > 0 && path.charAt(0) == '/')
0246: return true;
0247: }
0248:
0249: return false;
0250: } //}}}
0251:
0252: //{{{ constructPath() method
0253: /**
0254: * Constructs an absolute path name from a directory and another
0255: * path name. This method is VFS-aware.
0256: * @param parent The directory
0257: * @param path The path name
0258: */
0259: public static String constructPath(String parent, String path) {
0260: if (isAbsolutePath(path))
0261: return canonPath(path);
0262:
0263: if (parent == null)
0264: parent = System.getProperty("user.dir");
0265:
0266: if (path == null || path.length() == 0)
0267: return parent;
0268:
0269: // have to handle this case specially on windows.
0270: // insert \ between, eg A: and myfile.txt.
0271: if (OperatingSystem.isDOSDerived()) {
0272: if (path.length() == 2 && path.charAt(1) == ':')
0273: return path;
0274: else if (path.length() > 2 && path.charAt(1) == ':'
0275: && path.charAt(2) != '\\') {
0276: path = path.substring(0, 2) + '\\' + path.substring(2);
0277: return canonPath(path);
0278: }
0279: }
0280:
0281: String dd = ".." + File.separator;
0282: String d = '.' + File.separator;
0283:
0284: for (;;) {
0285: if (path.equals("."))
0286: return parent;
0287: else if (path.equals(".."))
0288: return getParentOfPath(parent);
0289: else if (path.startsWith(dd) || path.startsWith("../")) {
0290: parent = getParentOfPath(parent);
0291: path = path.substring(3);
0292: } else if (path.startsWith(d) || path.startsWith("./"))
0293: path = path.substring(2);
0294: else
0295: break;
0296: }
0297:
0298: if (OperatingSystem.isDOSDerived() && !isURL(parent)
0299: && path.charAt(0) == '\\')
0300: parent = parent.substring(0, 2);
0301:
0302: VFS vfs = VFSManager.getVFSForPath(parent);
0303:
0304: return canonPath(vfs.constructPath(parent, path));
0305: } //}}}
0306:
0307: //{{{ constructPath() method
0308: /**
0309: * Constructs an absolute path name from three path components.
0310: * This method is VFS-aware.
0311: * @param parent The parent directory
0312: * @param path1 The first path
0313: * @param path2 The second path
0314: */
0315: public static String constructPath(String parent, String path1,
0316: String path2) {
0317: return constructPath(constructPath(parent, path1), path2);
0318: } //}}}
0319:
0320: //{{{ concatPath() method
0321: /**
0322: * Like {@link #constructPath}, except <code>path</code> will be
0323: * appended to <code>parent</code> even if it is absolute.
0324: * <b>For local path names only.</b>.
0325: *
0326: * @param path
0327: * @param parent
0328: */
0329: public static String concatPath(String parent, String path) {
0330: parent = canonPath(parent);
0331: path = canonPath(path);
0332:
0333: // Make all child paths relative.
0334: if (path.startsWith(File.separator))
0335: path = path.substring(1);
0336: else if ((path.length() >= 3) && (path.charAt(1) == ':'))
0337: path = path.replace(':', File.separatorChar);
0338:
0339: if (parent == null)
0340: parent = System.getProperty("user.dir");
0341:
0342: if (parent.endsWith(File.separator))
0343: return parent + path;
0344: else
0345: return parent + File.separator + path;
0346: } //}}}
0347:
0348: //{{{ getFirstSeparatorIndex() method
0349: /**
0350: * Return the first index of either / or the OS-specific file
0351: * separator.
0352: * @param path The path
0353: * @since jEdit 4.3pre3
0354: */
0355: public static int getFirstSeparatorIndex(String path) {
0356: int start = getPathStart(path);
0357: int index = path.indexOf('/', start);
0358: if (index == -1)
0359: index = path.indexOf(File.separatorChar, start);
0360: return index;
0361: } //}}}
0362:
0363: //{{{ getLastSeparatorIndex() method
0364: /**
0365: * Return the last index of either / or the OS-specific file
0366: * separator.
0367: * @param path The path
0368: * @since jEdit 4.3pre3
0369: */
0370: public static int getLastSeparatorIndex(String path) {
0371: int start = getPathStart(path);
0372: if (start != 0)
0373: path = path.substring(start);
0374: int index = Math.max(path.lastIndexOf('/'), path
0375: .lastIndexOf(File.separatorChar));
0376: if (index == -1)
0377: return index;
0378: else
0379: return index + start;
0380: } //}}}
0381:
0382: //{{{ getFileExtension() method
0383: /**
0384: * Returns the extension of the specified filename, or an empty
0385: * string if there is none.
0386: * @param path The path
0387: */
0388: public static String getFileExtension(String path) {
0389: int fsIndex = getLastSeparatorIndex(path);
0390: int index = path.lastIndexOf('.');
0391: // there could be a dot in the path and no file extension
0392: if (index == -1 || index < fsIndex)
0393: return "";
0394: else
0395: return path.substring(index);
0396: } //}}}
0397:
0398: //{{{ getFileName() method
0399: /**
0400: * Returns the last component of the specified path.
0401: * This method is VFS-aware.
0402: * @param path The path name
0403: */
0404: public static String getFileName(String path) {
0405: return VFSManager.getVFSForPath(path).getFileName(path);
0406: } //}}}
0407:
0408: //{{{ getFileNameNoExtension() method
0409: /**
0410: * Returns the last component of the specified path name without the
0411: * trailing extension (if there is one).
0412: * @param path The path name
0413: * @since jEdit 4.0pre8
0414: */
0415: public static String getFileNameNoExtension(String path) {
0416: String name = getFileName(path);
0417: int index = name.indexOf('.');
0418: if (index == -1)
0419: return name;
0420: else
0421: return name.substring(0, index);
0422: } //}}}
0423:
0424: //{{{ getFileParent() method
0425: /**
0426: * @deprecated Call getParentOfPath() instead
0427: */
0428: @Deprecated
0429: public static String getFileParent(String path) {
0430: return getParentOfPath(path);
0431: } //}}}
0432:
0433: //{{{ getParentOfPath() method
0434: /**
0435: * Returns the parent of the specified path. This method is VFS-aware.
0436: * @param path The path name
0437: * @since jEdit 2.6pre5
0438: */
0439: public static String getParentOfPath(String path) {
0440: return VFSManager.getVFSForPath(path).getParentOfPath(path);
0441: } //}}}
0442:
0443: //{{{ getFileProtocol() method
0444: /**
0445: * @deprecated Call getProtocolOfURL() instead
0446: */
0447: @Deprecated
0448: public static String getFileProtocol(String url) {
0449: return getProtocolOfURL(url);
0450: } //}}}
0451:
0452: //{{{ getProtocolOfURL() method
0453: /**
0454: * Returns the protocol specified by a URL.
0455: * @param url The URL
0456: * @since jEdit 2.6pre5
0457: */
0458: public static String getProtocolOfURL(String url) {
0459: return url.substring(0, url.indexOf(':'));
0460: } //}}}
0461:
0462: //{{{ isURL() method
0463: /**
0464: * Checks if the specified string is a URL.
0465: * @param str The string to check
0466: * @return True if the string is a URL, false otherwise
0467: */
0468: public static boolean isURL(String str) {
0469: int fsIndex = getLastSeparatorIndex(str);
0470: if (fsIndex == 0) // /etc/passwd
0471: return false;
0472: else if (fsIndex == 2) // C:\AUTOEXEC.BAT
0473: return false;
0474:
0475: int cIndex = str.indexOf(':');
0476: if (cIndex <= 1) // D:\WINDOWS, or doesn't contain : at all
0477: return false;
0478:
0479: String protocol = str.substring(0, cIndex);
0480: VFS vfs = VFSManager.getVFSForProtocol(protocol);
0481: if (vfs != null && !(vfs instanceof UrlVFS))
0482: return true;
0483:
0484: try {
0485: new URL(str);
0486: return true;
0487: } catch (MalformedURLException mf) {
0488: return false;
0489: }
0490: } //}}}
0491:
0492: //{{{ saveBackup() method
0493: /**
0494: * Saves a backup (optionally numbered) of a file.
0495: * @param file A local file
0496: * @param backups The number of backups. Must be >= 1. If > 1, backup
0497: * files will be numbered.
0498: * @param backupPrefix The backup file name prefix
0499: * @param backupSuffix The backup file name suffix
0500: * @param backupDirectory The directory where to save backups; if null,
0501: * they will be saved in the same directory as the file itself.
0502: * @since jEdit 4.0pre1
0503: */
0504: public static void saveBackup(File file, int backups,
0505: String backupPrefix, String backupSuffix,
0506: String backupDirectory) {
0507: saveBackup(file, backups, backupPrefix, backupSuffix,
0508: backupDirectory, 0);
0509: } //}}}
0510:
0511: //{{{ saveBackup() method
0512: /**
0513: * Saves a backup (optionally numbered) of a file.
0514: * @param file A local file
0515: * @param backups The number of backups. Must be >= 1. If > 1, backup
0516: * files will be numbered.
0517: * @param backupPrefix The backup file name prefix
0518: * @param backupSuffix The backup file name suffix
0519: * @param backupDirectory The directory where to save backups; if null,
0520: * they will be saved in the same directory as the file itself.
0521: * @param backupTimeDistance The minimum time in minutes when a backup
0522: * version 1 shall be moved into version 2; if 0, backups are always
0523: * moved.
0524: * @since jEdit 4.2pre5
0525: */
0526: public static void saveBackup(File file, int backups,
0527: String backupPrefix, String backupSuffix,
0528: String backupDirectory, int backupTimeDistance) {
0529: if (backupPrefix == null)
0530: backupPrefix = "";
0531: if (backupSuffix == null)
0532: backupSuffix = "";
0533:
0534: String name = file.getName();
0535:
0536: // If backups is 1, create ~ file
0537: if (backups == 1) {
0538: File backupFile = new File(backupDirectory, backupPrefix
0539: + name + backupSuffix);
0540: long modTime = backupFile.lastModified();
0541: /* if backup file was created less than
0542: * 'backupTimeDistance' ago, we do not
0543: * create the backup */
0544: if (System.currentTimeMillis() - modTime >= backupTimeDistance) {
0545: Log.log(Log.DEBUG, MiscUtilities.class,
0546: "Saving backup of file \""
0547: + file.getAbsolutePath() + "\" to \""
0548: + backupFile.getAbsolutePath() + '"');
0549: backupFile.delete();
0550: if (!file.renameTo(backupFile))
0551: IOUtilities.moveFile(file, backupFile);
0552: }
0553: }
0554: // If backups > 1, move old ~n~ files, create ~1~ file
0555: else {
0556: /* delete a backup created using above method */
0557: new File(backupDirectory, backupPrefix + name
0558: + backupSuffix + backups + backupSuffix).delete();
0559:
0560: File firstBackup = new File(backupDirectory, backupPrefix
0561: + name + backupSuffix + "1" + backupSuffix);
0562: long modTime = firstBackup.lastModified();
0563: /* if backup file was created less than
0564: * 'backupTimeDistance' ago, we do not
0565: * create the backup */
0566: if (System.currentTimeMillis() - modTime >= backupTimeDistance) {
0567: for (int i = backups - 1; i > 0; i--) {
0568: File backup = new File(backupDirectory,
0569: backupPrefix + name + backupSuffix + i
0570: + backupSuffix);
0571:
0572: backup.renameTo(new File(backupDirectory,
0573: backupPrefix + name + backupSuffix
0574: + (i + 1) + backupSuffix));
0575: }
0576:
0577: File backupFile = new File(backupDirectory,
0578: backupPrefix + name + backupSuffix + "1"
0579: + backupSuffix);
0580: Log.log(Log.DEBUG, MiscUtilities.class,
0581: "Saving backup of file \""
0582: + file.getAbsolutePath() + "\" to \""
0583: + backupFile.getAbsolutePath() + '"');
0584: if (!file.renameTo(backupFile))
0585: IOUtilities.moveFile(file, backupFile);
0586: }
0587: }
0588: } //}}}
0589:
0590: //{{{ moveFile() method
0591: /**
0592: * Moves the source file to the destination.
0593: *
0594: * If the destination cannot be created or is a read-only file, the
0595: * method returns <code>false</code>. Otherwise, the contents of the
0596: * source are copied to the destination, the source is deleted,
0597: * and <code>true</code> is returned.
0598: *
0599: * @param source The source file to move.
0600: * @param dest The destination where to move the file.
0601: * @return true on success, false otherwise.
0602: *
0603: * @since jEdit 4.3pre1
0604: * @deprecated use {@link org.gjt.sp.util.IOUtilities#moveFile(java.io.File, java.io.File)}
0605: */
0606: @Deprecated
0607: public static boolean moveFile(File source, File dest) {
0608: return IOUtilities.moveFile(source, dest);
0609: } //}}}
0610:
0611: //{{{ copyStream() method
0612: /**
0613: * Copy an input stream to an output stream.
0614: *
0615: * @param bufferSize the size of the buffer
0616: * @param progress the progress observer it could be null
0617: * @param in the input stream
0618: * @param out the output stream
0619: * @param canStop if true, the copy can be stopped by interrupting the thread
0620: * @return <code>true</code> if the copy was done, <code>false</code> if it was interrupted
0621: * @throws IOException IOException If an I/O error occurs
0622: * @since jEdit 4.3pre3
0623: * @deprecated use {@link IOUtilities#copyStream(int, org.gjt.sp.util.ProgressObserver, java.io.InputStream, java.io.OutputStream, boolean)}
0624: */
0625: @Deprecated
0626: public static boolean copyStream(int bufferSize,
0627: ProgressObserver progress, InputStream in,
0628: OutputStream out, boolean canStop) throws IOException {
0629: return IOUtilities.copyStream(bufferSize, progress, in, out,
0630: canStop);
0631: } //}}}
0632:
0633: //{{{ copyStream() method
0634: /**
0635: * Copy an input stream to an output stream with a buffer of 4096 bytes.
0636: *
0637: * @param progress the progress observer it could be null
0638: * @param in the input stream
0639: * @param out the output stream
0640: * @param canStop if true, the copy can be stopped by interrupting the thread
0641: * @return <code>true</code> if the copy was done, <code>false</code> if it was interrupted
0642: * @throws IOException IOException If an I/O error occurs
0643: * @since jEdit 4.3pre3
0644: * @deprecated use {@link IOUtilities#copyStream(org.gjt.sp.util.ProgressObserver, java.io.InputStream, java.io.OutputStream, boolean)}
0645: */
0646: @Deprecated
0647: public static boolean copyStream(ProgressObserver progress,
0648: InputStream in, OutputStream out, boolean canStop)
0649: throws IOException {
0650: return IOUtilities.copyStream(4096, progress, in, out, canStop);
0651: } //}}}
0652:
0653: //{{{ isBinary() method
0654: /**
0655: * Check if a Reader is binary.
0656: * @deprecated
0657: * Use isBinary(InputStream) instead.
0658: */
0659: @Deprecated
0660: public static boolean isBinary(Reader reader) throws IOException {
0661: return containsNullCharacter(reader);
0662: } //}}}
0663:
0664: //{{{ isBinary() method
0665: /**
0666: * Check if an InputStream is binary.
0667: * First this tries encoding auto detection. If an encoding is
0668: * detected, the stream should be a text stream. Otherwise, this
0669: * will check the first characters 100
0670: * (jEdit property vfs.binaryCheck.length) in the system default
0671: * encoding. If more than 1 (jEdit property vfs.binaryCheck.count)
0672: * NUL(\u0000) was found, the stream is declared binary.
0673: *
0674: * This is not 100% because sometimes the autodetection could fail.
0675: *
0676: * This method will not close the stream. You have to do it yourself
0677: *
0678: * @param in the stream
0679: * @return <code>true</code> if the stream was detected as binary
0680: * @throws IOException IOException If an I/O error occurs
0681: * @since jEdit 4.3pre10
0682: */
0683: public static boolean isBinary(InputStream in) throws IOException {
0684: AutoDetection.Result detection = new AutoDetection.Result(in);
0685: // If an encoding is detected, this is a text stream
0686: if (detection.getDetectedEncoding() != null) {
0687: return false;
0688: }
0689: // Read the stream in system default encoding. The encoding
0690: // might be wrong. But enough for binary detection.
0691: return containsNullCharacter(new InputStreamReader(detection
0692: .getRewindedStream()));
0693: } //}}}
0694:
0695: //{{{ isBackup() method
0696: /**
0697: * Check if the filename is a backup file.
0698: * @param filename the filename to check
0699: * @return true if this is a backup file.
0700: * @since jEdit 4.3pre5
0701: */
0702: public static boolean isBackup(String filename) {
0703: if (filename.startsWith("#"))
0704: return true;
0705: if (filename.endsWith("~"))
0706: return true;
0707: if (filename.endsWith(".bak"))
0708: return true;
0709: return false;
0710: } //}}}
0711:
0712: //{{{ autodetect() method
0713: /**
0714: * Tries to detect if the stream is gzipped, and if it has an encoding
0715: * specified with an XML PI.
0716: *
0717: * @param in the input stream reader that must be autodetected
0718: * @param buffer a buffer. It can be null if you only want to autodetect the encoding of a file
0719: * @return a Reader using the detected encoding
0720: * @throws IOException io exception during read
0721: * @since jEdit 4.3pre5
0722: */
0723: public static Reader autodetect(InputStream in, Buffer buffer)
0724: throws IOException {
0725: String encoding;
0726: if (buffer == null)
0727: encoding = System.getProperty("file.encoding");
0728: else
0729: encoding = buffer.getStringProperty(Buffer.ENCODING);
0730: boolean gzipped = false;
0731:
0732: if (buffer == null
0733: || buffer
0734: .getBooleanProperty(Buffer.ENCODING_AUTODETECT)) {
0735: AutoDetection.Result detection = new AutoDetection.Result(
0736: in);
0737: gzipped = detection.streamIsGzipped();
0738: if (gzipped) {
0739: Log.log(Log.DEBUG, MiscUtilities.class,
0740: "Stream is Gzipped");
0741: }
0742: String detected = detection.getDetectedEncoding();
0743: if (detected != null) {
0744: encoding = detected;
0745: Log.log(Log.DEBUG, MiscUtilities.class,
0746: "Stream encoding detected is " + detected);
0747: }
0748: in = detection.getRewindedStream();
0749: } else {
0750: // Make the stream buffered in the same way.
0751: in = AutoDetection.getMarkedStream(in);
0752: }
0753:
0754: Reader result = EncodingServer.getTextReader(in, encoding);
0755: if (buffer != null) {
0756: // Store the successful properties.
0757: if (gzipped) {
0758: buffer.setBooleanProperty(Buffer.GZIPPED, true);
0759: }
0760: buffer.setProperty(Buffer.ENCODING, encoding);
0761: }
0762: return result;
0763: } //}}}
0764:
0765: //{{{ closeQuietly() method
0766: /**
0767: * Method that will close an {@link InputStream} ignoring it if it is null and ignoring exceptions.
0768: *
0769: * @param in the InputStream to close.
0770: * @since jEdit 4.3pre3
0771: * @deprecated use {@link IOUtilities#closeQuietly(java.io.InputStream)}
0772: */
0773: @Deprecated
0774: public static void closeQuietly(InputStream in) {
0775: IOUtilities.closeQuietly(in);
0776: } //}}}
0777:
0778: //{{{ copyStream() method
0779: /**
0780: * Method that will close an {@link OutputStream} ignoring it if it is null and ignoring exceptions.
0781: *
0782: * @param out the OutputStream to close.
0783: * @since jEdit 4.3pre3
0784: * @deprecated use {@link IOUtilities#closeQuietly(java.io.OutputStream)}
0785: */
0786: @Deprecated
0787: public static void closeQuietly(OutputStream out) {
0788: IOUtilities.closeQuietly(out);
0789: } //}}}
0790:
0791: //{{{ fileToClass() method
0792: /**
0793: * Converts a file name to a class name. All slash characters are
0794: * replaced with periods and the trailing '.class' is removed.
0795: * @param name The file name
0796: */
0797: public static String fileToClass(String name) {
0798: char[] clsName = name.toCharArray();
0799: for (int i = clsName.length - 6; i >= 0; i--)
0800: if (clsName[i] == '/')
0801: clsName[i] = '.';
0802: return new String(clsName, 0, clsName.length - 6);
0803: } //}}}
0804:
0805: //{{{ classToFile() method
0806: /**
0807: * Converts a class name to a file name. All periods are replaced
0808: * with slashes and the '.class' extension is added.
0809: * @param name The class name
0810: */
0811: public static String classToFile(String name) {
0812: return name.replace('.', '/').concat(".class");
0813: } //}}}
0814:
0815: //{{{ pathsEqual() method
0816: /**
0817: * @param p1 A path name
0818: * @param p2 A path name
0819: * @return True if both paths are equal, ignoring trailing slashes, as
0820: * well as case insensitivity on Windows.
0821: * @since jEdit 4.3pre2
0822: */
0823: public static boolean pathsEqual(String p1, String p2) {
0824: VFS v1 = VFSManager.getVFSForPath(p1);
0825: VFS v2 = VFSManager.getVFSForPath(p2);
0826:
0827: if (v1 != v2)
0828: return false;
0829:
0830: if (p1.endsWith("/") || p1.endsWith(File.separator))
0831: p1 = p1.substring(0, p1.length() - 1);
0832:
0833: if (p2.endsWith("/") || p2.endsWith(File.separator))
0834: p2 = p2.substring(0, p2.length() - 1);
0835:
0836: if ((v1.getCapabilities() & VFS.CASE_INSENSITIVE_CAP) != 0)
0837: return p1.equalsIgnoreCase(p2);
0838: else
0839: return p1.equals(p2);
0840: } //}}}
0841:
0842: //}}}
0843:
0844: //{{{ Text methods
0845:
0846: //{{{ getLeadingWhiteSpace() method
0847: /**
0848: * Returns the number of leading white space characters in the
0849: * specified string.
0850: * @param str The string
0851: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getLeadingWhiteSpace(String)}
0852: */
0853: @Deprecated
0854: public static int getLeadingWhiteSpace(String str) {
0855: return StandardUtilities.getLeadingWhiteSpace(str);
0856: } //}}}
0857:
0858: //{{{ getTrailingWhiteSpace() method
0859: /**
0860: * Returns the number of trailing whitespace characters in the
0861: * specified string.
0862: * @param str The string
0863: * @since jEdit 2.5pre5
0864: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getTrailingWhiteSpace(String)}
0865: */
0866: @Deprecated
0867: public static int getTrailingWhiteSpace(String str) {
0868: return StandardUtilities.getTrailingWhiteSpace(str);
0869: } //}}}
0870:
0871: //{{{ getLeadingWhiteSpaceWidth() method
0872: /**
0873: * Returns the width of the leading white space in the specified
0874: * string.
0875: * @param str The string
0876: * @param tabSize The tab size
0877: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getLeadingWhiteSpace(String)}
0878: */
0879: @Deprecated
0880: public static int getLeadingWhiteSpaceWidth(String str, int tabSize) {
0881: return StandardUtilities
0882: .getLeadingWhiteSpaceWidth(str, tabSize);
0883: } //}}}
0884:
0885: //{{{ getVirtualWidth() method
0886: /**
0887: * Returns the virtual column number (taking tabs into account) of the
0888: * specified offset in the segment.
0889: *
0890: * @param seg The segment
0891: * @param tabSize The tab size
0892: * @since jEdit 4.1pre1
0893: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getVirtualWidth(javax.swing.text.Segment, int)}
0894: */
0895: @Deprecated
0896: public static int getVirtualWidth(Segment seg, int tabSize) {
0897: return StandardUtilities.getVirtualWidth(seg, tabSize);
0898: } //}}}
0899:
0900: //{{{ getOffsetOfVirtualColumn() method
0901: /**
0902: * Returns the array offset of a virtual column number (taking tabs
0903: * into account) in the segment.
0904: *
0905: * @param seg The segment
0906: * @param tabSize The tab size
0907: * @param column The virtual column number
0908: * @param totalVirtualWidth If this array is non-null, the total
0909: * virtual width will be stored in its first location if this method
0910: * returns -1.
0911: *
0912: * @return -1 if the column is out of bounds
0913: *
0914: * @since jEdit 4.1pre1
0915: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getVirtualWidth(javax.swing.text.Segment, int)}
0916: */
0917: @Deprecated
0918: public static int getOffsetOfVirtualColumn(Segment seg,
0919: int tabSize, int column, int[] totalVirtualWidth) {
0920: return StandardUtilities.getOffsetOfVirtualColumn(seg, tabSize,
0921: column, totalVirtualWidth);
0922: } //}}}
0923:
0924: //{{{ createWhiteSpace() method
0925: /**
0926: * Creates a string of white space with the specified length.<p>
0927: *
0928: * To get a whitespace string tuned to the current buffer's
0929: * settings, call this method as follows:
0930: *
0931: * <pre>myWhitespace = MiscUtilities.createWhiteSpace(myLength,
0932: * (buffer.getBooleanProperty("noTabs") ? 0
0933: * : buffer.getTabSize()));</pre>
0934: *
0935: * @param len The length
0936: * @param tabSize The tab size, or 0 if tabs are not to be used
0937: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#createWhiteSpace(int, int)}
0938: */
0939: @Deprecated
0940: public static String createWhiteSpace(int len, int tabSize) {
0941: return StandardUtilities.createWhiteSpace(len, tabSize, 0);
0942: } //}}}
0943:
0944: //{{{ createWhiteSpace() method
0945: /**
0946: * Creates a string of white space with the specified length.<p>
0947: *
0948: * To get a whitespace string tuned to the current buffer's
0949: * settings, call this method as follows:
0950: *
0951: * <pre>myWhitespace = MiscUtilities.createWhiteSpace(myLength,
0952: * (buffer.getBooleanProperty("noTabs") ? 0
0953: * : buffer.getTabSize()));</pre>
0954: *
0955: * @param len The length
0956: * @param tabSize The tab size, or 0 if tabs are not to be used
0957: * @param start The start offset, for tab alignment
0958: * @since jEdit 4.2pre1
0959: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#createWhiteSpace(int, int, int)}
0960: */
0961: @Deprecated
0962: public static String createWhiteSpace(int len, int tabSize,
0963: int start) {
0964: return StandardUtilities.createWhiteSpace(len, tabSize, start);
0965: } //}}}
0966:
0967: //{{{ globToRE() method
0968: /**
0969: * Converts a Unix-style glob to a regular expression.<p>
0970: *
0971: * ? becomes ., * becomes .*, {aa,bb} becomes (aa|bb).
0972: * @param glob The glob pattern
0973: * @deprecated Use {@link org.gjt.sp.util.StandardUtilities#globToRE(String)}.
0974: */
0975: @Deprecated
0976: public static String globToRE(String glob) {
0977: return StandardUtilities.globToRE(glob);
0978: } //}}}
0979:
0980: //{{{ escapesToChars() method
0981: /**
0982: * Converts "\n" and "\t" escapes in the specified string to
0983: * newlines and tabs.
0984: * @param str The string
0985: * @since jEdit 2.3pre1
0986: */
0987: public static String escapesToChars(String str) {
0988: StringBuffer buf = new StringBuffer();
0989: for (int i = 0; i < str.length(); i++) {
0990: char c = str.charAt(i);
0991: switch (c) {
0992: case '\\':
0993: if (i == str.length() - 1) {
0994: buf.append('\\');
0995: break;
0996: }
0997: c = str.charAt(++i);
0998: switch (c) {
0999: case 'n':
1000: buf.append('\n');
1001: break;
1002: case 't':
1003: buf.append('\t');
1004: break;
1005: default:
1006: buf.append(c);
1007: break;
1008: }
1009: break;
1010: default:
1011: buf.append(c);
1012: }
1013: }
1014: return buf.toString();
1015: } //}}}
1016:
1017: //{{{ charsToEscapes() method
1018: /**
1019: * Escapes newlines, tabs, backslashes, and quotes in the specified
1020: * string.
1021: * @param str The string
1022: * @since jEdit 2.3pre1
1023: */
1024: public static String charsToEscapes(String str) {
1025: return charsToEscapes(str, "\n\t\\\"'");
1026: } //}}}
1027:
1028: //{{{ charsToEscapes() method
1029: /**
1030: * Escapes the specified characters in the specified string.
1031: * @param str The string
1032: * @param toEscape Any characters that require escaping
1033: * @since jEdit 4.1pre3
1034: */
1035: public static String charsToEscapes(String str, String toEscape) {
1036: StringBuffer buf = new StringBuffer();
1037: for (int i = 0; i < str.length(); i++) {
1038: char c = str.charAt(i);
1039: if (toEscape.indexOf(c) != -1) {
1040: if (c == '\n')
1041: buf.append("\\n");
1042: else if (c == '\t')
1043: buf.append("\\t");
1044: else {
1045: buf.append('\\');
1046: buf.append(c);
1047: }
1048: } else
1049: buf.append(c);
1050: }
1051: return buf.toString();
1052: } //}}}
1053:
1054: //{{{ compareVersions() method
1055: /**
1056: * @deprecated Call <code>compareStrings()</code> instead
1057: */
1058: @Deprecated
1059: public static int compareVersions(String v1, String v2) {
1060: return StandardUtilities.compareStrings(v1, v2, false);
1061: } //}}}
1062:
1063: //{{{ compareStrings() method
1064: /**
1065: * Compares two strings.<p>
1066: *
1067: * Unlike <function>String.compareTo()</function>,
1068: * this method correctly recognizes and handles embedded numbers.
1069: * For example, it places "My file 2" before "My file 10".<p>
1070: *
1071: * @param str1 The first string
1072: * @param str2 The second string
1073: * @param ignoreCase If true, case will be ignored
1074: * @return negative If str1 < str2, 0 if both are the same,
1075: * positive if str1 > str2
1076: * @since jEdit 4.0pre1
1077: * @deprecated use {@link org.gjt.sp.util.StandardUtilities#compareStrings(String, String, boolean)}
1078: */
1079: @Deprecated
1080: public static int compareStrings(String str1, String str2,
1081: boolean ignoreCase) {
1082: return StandardUtilities.compareStrings(str1, str2, ignoreCase);
1083: } //}}}
1084:
1085: //{{{ stringsEqual() method
1086: /**
1087: * @deprecated Call <code>objectsEqual()</code> instead.
1088: */
1089: @Deprecated
1090: public static boolean stringsEqual(String s1, String s2) {
1091: return org.gjt.sp.util.StandardUtilities.objectsEqual(s1, s2);
1092: } //}}}
1093:
1094: //{{{ objectsEqual() method
1095: /**
1096: * Returns if two strings are equal. This correctly handles null pointers,
1097: * as opposed to calling <code>o1.equals(o2)</code>.
1098: * @since jEdit 4.2pre1
1099: * @deprecated use {@link StandardUtilities#objectsEqual(Object, Object)}
1100: */
1101: @Deprecated
1102: public static boolean objectsEqual(Object o1, Object o2) {
1103: return StandardUtilities.objectsEqual(o1, o2);
1104: } //}}}
1105:
1106: //{{{ charsToEntities() method
1107: /**
1108: * Converts <, >, & in the string to their HTML entity
1109: * equivalents.
1110: * @param str The string
1111: * @since jEdit 4.2pre1
1112: * @deprecated Use {@link org.gjt.sp.util.XMLUtilities#charsToEntities(String, boolean)}.
1113: */
1114: @Deprecated
1115: public static String charsToEntities(String str) {
1116: return XMLUtilities.charsToEntities(str, false);
1117: } //}}}
1118:
1119: //{{{ formatFileSize() method
1120: public static final DecimalFormat KB_FORMAT = new DecimalFormat(
1121: "#.# kB");
1122: public static final DecimalFormat MB_FORMAT = new DecimalFormat(
1123: "#.# MB");
1124:
1125: /**
1126: * Formats the given file size into a nice string (123 Bytes, 10.6 kB,
1127: * 1.2 MB).
1128: * @param length The size
1129: * @since jEdit 4.2pre1
1130: */
1131: public static String formatFileSize(long length) {
1132: if (length < 1024) {
1133: return length + " Bytes";
1134: } else if (length < 1024 << 10) {
1135: return KB_FORMAT.format((double) length / 1024);
1136: } else {
1137: return MB_FORMAT.format((double) length / 1024 / 1024);
1138: }
1139: } //}}}
1140:
1141: //{{{ getLongestPrefix() method
1142: /**
1143: * Returns the longest common prefix in the given set of strings.
1144: * @param str The strings
1145: * @param ignoreCase If true, case insensitive
1146: * @since jEdit 4.2pre2
1147: */
1148: public static String getLongestPrefix(List str, boolean ignoreCase) {
1149: if (str.size() == 0)
1150: return "";
1151:
1152: int prefixLength = 0;
1153:
1154: loop: for (;;) {
1155: String s = str.get(0).toString();
1156: if (prefixLength >= s.length())
1157: break loop;
1158: char ch = s.charAt(prefixLength);
1159: for (int i = 1; i < str.size(); i++) {
1160: s = str.get(i).toString();
1161: if (prefixLength >= s.length())
1162: break loop;
1163: if (!compareChars(s.charAt(prefixLength), ch,
1164: ignoreCase))
1165: break loop;
1166: }
1167: prefixLength++;
1168: }
1169:
1170: return str.get(0).toString().substring(0, prefixLength);
1171: } //}}}
1172:
1173: //{{{ getLongestPrefix() method
1174: /**
1175: * Returns the longest common prefix in the given set of strings.
1176: * @param str The strings
1177: * @param ignoreCase If true, case insensitive
1178: * @since jEdit 4.2pre2
1179: */
1180: public static String getLongestPrefix(String[] str,
1181: boolean ignoreCase) {
1182: return getLongestPrefix((Object[]) str, ignoreCase);
1183: } //}}}
1184:
1185: //{{{ getLongestPrefix() method
1186: /**
1187: * Returns the longest common prefix in the given set of strings.
1188: * @param str The strings (calls <code>toString()</code> on each object)
1189: * @param ignoreCase If true, case insensitive
1190: * @since jEdit 4.2pre6
1191: */
1192: public static String getLongestPrefix(Object[] str,
1193: boolean ignoreCase) {
1194: if (str.length == 0)
1195: return "";
1196:
1197: int prefixLength = 0;
1198:
1199: String first = str[0].toString();
1200:
1201: loop: for (;;) {
1202: if (prefixLength >= first.length())
1203: break loop;
1204: char ch = first.charAt(prefixLength);
1205: for (int i = 1; i < str.length; i++) {
1206: String s = str[i].toString();
1207: if (prefixLength >= s.length())
1208: break loop;
1209: if (!compareChars(s.charAt(prefixLength), ch,
1210: ignoreCase))
1211: break loop;
1212: }
1213: prefixLength++;
1214: }
1215:
1216: return first.substring(0, prefixLength);
1217: } //}}}
1218:
1219: //}}}
1220:
1221: //{{{ quicksort() deprecated methods
1222: /**
1223: * Sorts the specified array. Equivalent to calling
1224: * <code>Arrays.sort()</code>.
1225: * @param obj The array
1226: * @param compare Compares the objects
1227: * @since jEdit 4.0pre4
1228: * @deprecated use <code>Arrays.sort()</code>
1229: */
1230: @Deprecated
1231: public static void quicksort(Object[] obj, Comparator compare) {
1232: Arrays.sort(obj, compare);
1233: }
1234:
1235: /**
1236: * Sorts the specified vector.
1237: * @param vector The vector
1238: * @param compare Compares the objects
1239: * @since jEdit 4.0pre4
1240: * @deprecated <code>Collections.sort()</code>
1241: */
1242: @Deprecated
1243: public static void quicksort(Vector vector, Comparator compare) {
1244: Collections.sort(vector, compare);
1245: }
1246:
1247: /**
1248: * Sorts the specified list.
1249: * @param list The list
1250: * @param compare Compares the objects
1251: * @since jEdit 4.0pre4
1252: * @deprecated <code>Collections.sort()</code>
1253: */
1254: @Deprecated
1255: public static void quicksort(List list, Comparator compare) {
1256: Collections.sort(list, compare);
1257: }
1258:
1259: /**
1260: * Sorts the specified array. Equivalent to calling
1261: * <code>Arrays.sort()</code>.
1262: * @param obj The array
1263: * @param compare Compares the objects
1264: * @deprecated use <code>Arrays.sort()</code>
1265: */
1266: @Deprecated
1267: public static void quicksort(Object[] obj, Compare compare) {
1268: Arrays.sort(obj, compare);
1269: }
1270:
1271: /**
1272: * Sorts the specified vector.
1273: * @param vector The vector
1274: * @param compare Compares the objects
1275: * @deprecated <code>Collections.sort()</code>
1276: */
1277: @Deprecated
1278: public static void quicksort(Vector vector, Compare compare) {
1279: Collections.sort(vector, compare);
1280: } //}}}
1281:
1282: //{{{ Compare deprecated interface
1283: /**
1284: * An interface for comparing objects. This is a hold-over from
1285: * they days when jEdit had its own sorting API due to JDK 1.1
1286: * compatibility requirements. Use <code>java.util.Comparator</code>
1287: * instead.
1288: * @deprecated
1289: */
1290: @Deprecated
1291: public interface Compare extends Comparator {
1292: int compare(Object obj1, Object obj2);
1293: } //}}}
1294:
1295: //{{{ StringCompare class
1296: /**
1297: * Compares strings.
1298: * @deprecated use {@link org.gjt.sp.util.StandardUtilities.StringCompare}
1299: */
1300: @Deprecated
1301: public static class StringCompare implements Compare {
1302: public int compare(Object obj1, Object obj2) {
1303: return StandardUtilities.compareStrings(obj1.toString(),
1304: obj2.toString(), false);
1305: }
1306: } //}}}
1307:
1308: //{{{ StringICaseCompare class
1309: /**
1310: * Compares strings ignoring case.
1311: */
1312: public static class StringICaseCompare implements
1313: Comparator<Object> {
1314: public int compare(Object obj1, Object obj2) {
1315: return StandardUtilities.compareStrings(obj1.toString(),
1316: obj2.toString(), true);
1317: }
1318: } //}}}
1319:
1320: //{{{ MenuItemCompare class
1321: /**
1322: * Compares menu item labels.
1323: */
1324: public static class MenuItemCompare implements Compare {
1325: public int compare(Object obj1, Object obj2) {
1326: boolean obj1E, obj2E;
1327: obj1E = obj1 instanceof EnhancedMenuItem;
1328: obj2E = obj2 instanceof EnhancedMenuItem;
1329: if (obj1E && !obj2E)
1330: return 1;
1331: else if (obj2E && !obj1E)
1332: return -1;
1333: else
1334: return StandardUtilities.compareStrings(
1335: ((JMenuItem) obj1).getText(),
1336: ((JMenuItem) obj2).getText(), true);
1337: }
1338: } //}}}
1339:
1340: //{{{ buildToVersion() method
1341: /**
1342: * Converts an internal version number (build) into a
1343: * `human-readable' form.
1344: * @param build The build
1345: */
1346: public static String buildToVersion(String build) {
1347: if (build.length() != 11)
1348: return "<unknown version: " + build + ">";
1349: // First 2 chars are the major version number
1350: int major = Integer.parseInt(build.substring(0, 2));
1351: // Second 2 are the minor number
1352: int minor = Integer.parseInt(build.substring(3, 5));
1353: // Then the pre-release status
1354: int beta = Integer.parseInt(build.substring(6, 8));
1355: // Finally the bug fix release
1356: int bugfix = Integer.parseInt(build.substring(9, 11));
1357:
1358: return major
1359: + "."
1360: + minor
1361: + (beta != 99 ? "pre" + beta : (bugfix != 0 ? "."
1362: + bugfix : "final"));
1363: } //}}}
1364:
1365: //{{{ isToolsJarAvailable() method
1366: /**
1367: * If on JDK 1.2 or higher, make sure that tools.jar is available.
1368: * This method should be called by plugins requiring the classes
1369: * in this library.
1370: * <p>
1371: * tools.jar is searched for in the following places:
1372: * <ol>
1373: * <li>the classpath that was used when jEdit was started,
1374: * <li>jEdit's jars folder in the user's home,
1375: * <li>jEdit's system jars folder,
1376: * <li><i>java.home</i>/lib/. In this case, tools.jar is added to
1377: * jEdit's list of known jars using jEdit.addPluginJAR(),
1378: * so that it gets loaded through JARClassLoader.
1379: * </ol><p>
1380: *
1381: * On older JDK's this method does not perform any checks, and returns
1382: * <code>true</code> (even though there is no tools.jar).
1383: *
1384: * @return <code>false</code> if and only if on JDK 1.2 and tools.jar
1385: * could not be found. In this case it prints some warnings on Log,
1386: * too, about the places where it was searched for.
1387: * @since jEdit 3.2.2
1388: */
1389: public static boolean isToolsJarAvailable() {
1390: Log.log(Log.DEBUG, MiscUtilities.class,
1391: "Searching for tools.jar...");
1392:
1393: Vector paths = new Vector();
1394:
1395: //{{{ 1. Check whether tools.jar is in the system classpath:
1396: paths.addElement("System classpath: "
1397: + System.getProperty("java.class.path"));
1398:
1399: try {
1400: // Either class sun.tools.javac.Main or
1401: // com.sun.tools.javac.Main must be there:
1402: try {
1403: Class.forName("sun.tools.javac.Main");
1404: } catch (ClassNotFoundException e1) {
1405: Class.forName("com.sun.tools.javac.Main");
1406: }
1407: Log.log(Log.DEBUG, MiscUtilities.class,
1408: "- is in classpath. Fine.");
1409: return true;
1410: } catch (ClassNotFoundException e) {
1411: //Log.log(Log.DEBUG, MiscUtilities.class,
1412: // "- is not in system classpath.");
1413: } //}}}
1414:
1415: //{{{ 2. Check whether it is in the jEdit user settings jars folder:
1416: String settingsDir = jEdit.getSettingsDirectory();
1417: if (settingsDir != null) {
1418: String toolsPath = constructPath(settingsDir, "jars",
1419: "tools.jar");
1420: paths.addElement(toolsPath);
1421: if (new File(toolsPath).exists()) {
1422: Log.log(Log.DEBUG, MiscUtilities.class,
1423: "- is in the user's jars folder. Fine.");
1424: // jEdit will load it automatically
1425: return true;
1426: }
1427: } //}}}
1428:
1429: //{{{ 3. Check whether it is in jEdit's system jars folder:
1430: String jEditDir = jEdit.getJEditHome();
1431: if (jEditDir != null) {
1432: String toolsPath = constructPath(jEditDir, "jars",
1433: "tools.jar");
1434: paths.addElement(toolsPath);
1435: if (new File(toolsPath).exists()) {
1436: Log.log(Log.DEBUG, MiscUtilities.class,
1437: "- is in jEdit's system jars folder. Fine.");
1438: // jEdit will load it automatically
1439: return true;
1440: }
1441: } //}}}
1442:
1443: //{{{ 4. Check whether it is in <java.home>/lib:
1444: String toolsPath = System.getProperty("java.home");
1445: if (toolsPath.toLowerCase().endsWith(File.separator + "jre"))
1446: toolsPath = toolsPath.substring(0, toolsPath.length() - 4);
1447: toolsPath = constructPath(toolsPath, "lib", "tools.jar");
1448: paths.addElement(toolsPath);
1449:
1450: if (!(new File(toolsPath).exists())) {
1451: Log.log(Log.WARNING, MiscUtilities.class,
1452: "Could not find tools.jar.\n"
1453: + "I checked the following locations:\n"
1454: + paths.toString());
1455: return false;
1456: } //}}}
1457:
1458: //{{{ Load it, if not yet done:
1459: PluginJAR jar = jEdit.getPluginJAR(toolsPath);
1460: if (jar == null) {
1461: Log.log(Log.DEBUG, MiscUtilities.class, "- adding "
1462: + toolsPath + " to jEdit plugins.");
1463: jEdit.addPluginJAR(toolsPath);
1464: } else
1465: Log.log(Log.DEBUG, MiscUtilities.class,
1466: "- has been loaded before.");
1467: //}}}
1468:
1469: return true;
1470: } //}}}
1471:
1472: //{{{ parsePermissions() method
1473: /**
1474: * Parse a Unix-style permission string (rwxrwxrwx).
1475: * @param s The string (must be 9 characters long).
1476: * @since jEdit 4.1pre8
1477: */
1478: public static int parsePermissions(String s) {
1479: int permissions = 0;
1480:
1481: if (s.length() == 9) {
1482: if (s.charAt(0) == 'r')
1483: permissions += 0400;
1484: if (s.charAt(1) == 'w')
1485: permissions += 0200;
1486: if (s.charAt(2) == 'x')
1487: permissions += 0100;
1488: else if (s.charAt(2) == 's')
1489: permissions += 04100;
1490: else if (s.charAt(2) == 'S')
1491: permissions += 04000;
1492: if (s.charAt(3) == 'r')
1493: permissions += 040;
1494: if (s.charAt(4) == 'w')
1495: permissions += 020;
1496: if (s.charAt(5) == 'x')
1497: permissions += 010;
1498: else if (s.charAt(5) == 's')
1499: permissions += 02010;
1500: else if (s.charAt(5) == 'S')
1501: permissions += 02000;
1502: if (s.charAt(6) == 'r')
1503: permissions += 04;
1504: if (s.charAt(7) == 'w')
1505: permissions += 02;
1506: if (s.charAt(8) == 'x')
1507: permissions += 01;
1508: else if (s.charAt(8) == 't')
1509: permissions += 01001;
1510: else if (s.charAt(8) == 'T')
1511: permissions += 01000;
1512: }
1513:
1514: return permissions;
1515: } //}}}
1516:
1517: //{{{ getEncodings() method
1518: /**
1519: * Returns a list of supported character encodings.
1520: * @since jEdit 4.2pre5
1521: * @deprecated See #getEncodings( boolean )
1522: */
1523: @Deprecated
1524: public static String[] getEncodings() {
1525: return getEncodings(false);
1526: } //}}}
1527:
1528: //{{{ getEncodings() method
1529: /**
1530: * Returns a list of supported character encodings.
1531: * @since jEdit 4.3pre5
1532: * @param getSelected Whether to return just the selected encodings or all.
1533: */
1534: public static String[] getEncodings(boolean getSelected) {
1535: Set<String> set;
1536: if (getSelected) {
1537: set = EncodingServer.getSelectedNames();
1538: } else {
1539: set = EncodingServer.getAvailableNames();
1540: }
1541: return set.toArray(new String[0]);
1542: } //}}}
1543:
1544: //{{{ throwableToString() method
1545: /**
1546: * Returns a string containing the stack trace of the given throwable.
1547: * @since jEdit 4.2pre6
1548: */
1549: public static String throwableToString(Throwable t) {
1550: StringWriter s = new StringWriter();
1551: t.printStackTrace(new PrintWriter(s));
1552: return s.toString();
1553: } //}}}
1554:
1555: //{{{ parseXML() method
1556: /**
1557: * Convenience method for parsing an XML file.
1558: *
1559: * @return Whether any error occured during parsing.
1560: * @since jEdit 4.3pre5
1561: * @deprecated Use {@link XMLUtilities#parseXML(InputStream,DefaultHandler)}.
1562: */
1563: @Deprecated
1564: public static boolean parseXML(InputStream in,
1565: DefaultHandler handler) throws IOException {
1566: return XMLUtilities.parseXML(in, handler);
1567: } //}}}
1568:
1569: //{{{ resolveEntity() method
1570: /**
1571: * Tries to find the given systemId in the context of the given
1572: * class.
1573: *
1574: * @deprecated Use {@link XMLUtilities#findEntity(String,String,Class)}.
1575: */
1576: @Deprecated
1577: public static InputSource findEntity(String systemId, String test,
1578: Class where) {
1579: return XMLUtilities.findEntity(systemId, test, where);
1580: } //}}}
1581:
1582: //{{{ Private members
1583: private MiscUtilities() {
1584: }
1585:
1586: //{{{ compareChars()
1587: /** should this be public? */
1588: private static boolean compareChars(char ch1, char ch2,
1589: boolean ignoreCase) {
1590: if (ignoreCase)
1591: return Character.toUpperCase(ch1) == Character
1592: .toUpperCase(ch2);
1593: else
1594: return ch1 == ch2;
1595: } //}}}
1596:
1597: //{{{ getPathStart()
1598: private static int getPathStart(String path) {
1599: int start = 0;
1600: if (path.startsWith("/"))
1601: return 1;
1602: else if (OperatingSystem.isDOSDerived() && path.length() >= 3
1603: && path.charAt(1) == ':'
1604: && (path.charAt(2) == '/' || path.charAt(2) == '\\'))
1605: return 3;
1606: else
1607: return 0;
1608: } //}}}
1609:
1610: //{{{ containsNullCharacter()
1611: private static boolean containsNullCharacter(Reader reader)
1612: throws IOException {
1613: int nbChars = jEdit.getIntegerProperty(
1614: "vfs.binaryCheck.length", 100);
1615: int authorized = jEdit.getIntegerProperty(
1616: "vfs.binaryCheck.count", 1);
1617: for (long i = 0L; i < nbChars; i++) {
1618: int c = reader.read();
1619: if (c == -1)
1620: return false;
1621: if (c == 0) {
1622: authorized--;
1623: if (authorized == 0)
1624: return true;
1625: }
1626: }
1627: return false;
1628: } //}}}
1629:
1630: //}}}
1631: }
|