PageRenderTime 65ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/branches/jedit43_nostrings/org/gjt/sp/jedit/MiscUtilities.java

#
Java | 1838 lines | 1013 code | 152 blank | 673 comment | 310 complexity | 4a49b2212aa47141641b816f980fa6cc MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * MiscUtilities.java - Various miscallaneous utility functions
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2005 Slava Pestov
  7. * Portions copyright (C) 2000 Richard S. Hall
  8. * Portions copyright (C) 2001 Dirk Moebius
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24. package org.gjt.sp.jedit;
  25. //{{{ Imports
  26. import javax.swing.text.Segment;
  27. import javax.swing.JMenuItem;
  28. import java.io.*;
  29. import java.net.MalformedURLException;
  30. import java.net.URL;
  31. import java.nio.charset.Charset;
  32. import java.text.DecimalFormat;
  33. import java.util.*;
  34. import java.util.regex.Matcher;
  35. import java.util.regex.Pattern;
  36. import java.util.zip.GZIPInputStream;
  37. import org.xml.sax.InputSource;
  38. import org.xml.sax.helpers.DefaultHandler;
  39. import org.gjt.sp.jedit.io.*;
  40. import org.gjt.sp.util.Log;
  41. import org.gjt.sp.util.ProgressObserver;
  42. import org.gjt.sp.util.StandardUtilities;
  43. import org.gjt.sp.util.IOUtilities;
  44. import org.gjt.sp.util.XMLUtilities;
  45. import org.gjt.sp.jedit.menu.EnhancedMenuItem;
  46. import org.gjt.sp.jedit.bufferio.BufferIORequest;
  47. import org.gjt.sp.jedit.buffer.JEditBuffer;
  48. //}}}
  49. /**
  50. * Path name manipulation, string manipulation, and more.<p>
  51. *
  52. * The most frequently used members of this class are:<p>
  53. *
  54. * <b>Some path name methods:</b><p>
  55. * <ul>
  56. * <li>{@link #getFileName(String)}</li>
  57. * <li>{@link #getParentOfPath(String)}</li>
  58. * <li>{@link #constructPath(String,String)}</li>
  59. * </ul>
  60. * <b>String comparison:</b><p>
  61. * A {@link #compareStrings(String,String,boolean)} method that unlike
  62. * <function>String.compareTo()</function>, correctly recognizes and handles
  63. * embedded numbers.<p>
  64. *
  65. * This class also defines several inner classes for use with the
  66. * sorting features of the Java collections API:
  67. *
  68. * <ul>
  69. * <li>{@link MiscUtilities.StringCompare}</li>
  70. * <li>{@link MiscUtilities.StringICaseCompare}</li>
  71. * <li>{@link MiscUtilities.MenuItemCompare}</li>
  72. * </ul>
  73. *
  74. * For example, you might call:<p>
  75. *
  76. * <code>Arrays.sort(myListOfStrings,
  77. * new MiscUtilities.StringICaseCompare());</code>
  78. *
  79. * @author Slava Pestov
  80. * @author John Gellene (API documentation)
  81. * @version $Id: MiscUtilities.java 9112 2007-03-09 06:50:09Z vanza $
  82. */
  83. public class MiscUtilities
  84. {
  85. /**
  86. * This encoding is not supported by Java, yet it is useful.
  87. * A UTF-8 file that begins with 0xEFBBBF.
  88. */
  89. public static final String UTF_8_Y = "UTF-8Y";
  90. //{{{ Path name methods
  91. //{{{ canonPath() method
  92. /**
  93. * @return the canonical form of the specified path name. Currently
  94. * only expands a leading <code>~</code>. <b>For local path names
  95. * only.</b>
  96. * @param path The path name
  97. * @since jEdit 4.0pre2
  98. */
  99. public static String canonPath(String path)
  100. {
  101. if(path.length() == 0)
  102. return path;
  103. if(path.startsWith("file://"))
  104. path = path.substring("file://".length());
  105. else if(path.startsWith("file:"))
  106. path = path.substring("file:".length());
  107. else if(isURL(path))
  108. return path;
  109. if(File.separatorChar == '\\')
  110. {
  111. // get rid of mixed paths on Windows
  112. path = path.replace('/','\\');
  113. // also get rid of trailing spaces on Windows
  114. int trim = path.length();
  115. while(path.charAt(trim - 1) == ' ')
  116. trim--;
  117. if (path.charAt(trim - 1) == '\\')
  118. while (trim > 1 && path.charAt(trim - 2) == '\\')
  119. {
  120. trim--;
  121. }
  122. path = path.substring(0,trim);
  123. }
  124. else if(OperatingSystem.isMacOS())
  125. {
  126. // do the same on OS X
  127. path = path.replace(':','/');
  128. }
  129. if(path.startsWith('~' + File.separator))
  130. {
  131. path = path.substring(2);
  132. String home = System.getProperty("user.home");
  133. if(home.endsWith(File.separator))
  134. return home + path;
  135. else
  136. return home + File.separator + path;
  137. }
  138. else if(path.equals("~"))
  139. return System.getProperty("user.home");
  140. else
  141. return path;
  142. } //}}}
  143. //{{{ expandVariables() method
  144. static final String varPatternString = "(\\$([a-zA-Z0-9_]+))";
  145. static final String varPatternString2 = "(\\$\\{([^}]+)\\})";
  146. static final Pattern varPattern = Pattern.compile(varPatternString);
  147. static final Pattern varPattern2 = Pattern.compile(varPatternString2);
  148. /** Accepts a string from the user which may contain variables of various syntaxes.
  149. * The goal is to support the following:
  150. * $varname
  151. * ${varname}
  152. * And expand each of these by looking at the system environment variables for possible
  153. * expansions.
  154. * @return a string which is either the unchanged input string, or one with expanded variables.
  155. * @since 4.3pre7
  156. * @author ezust
  157. */
  158. public static String expandVariables(String arg)
  159. {
  160. Pattern p = varPattern;
  161. Matcher m = p.matcher(arg);
  162. if (!m.find())
  163. {
  164. p = varPattern2;
  165. m = p.matcher(arg);
  166. if (!m.find()) // no variables to substitute
  167. return arg;
  168. }
  169. String varName = m.group(2);
  170. String expansion = System.getenv(varName);
  171. if (expansion == null)
  172. { // try everything uppercase?
  173. varName = varName.toUpperCase();
  174. String uparg = arg.toUpperCase();
  175. m = p.matcher(uparg);
  176. expansion = System.getenv(varName);
  177. }
  178. if (expansion != null)
  179. {
  180. expansion = expansion.replace("\\", "\\\\");
  181. return m.replaceFirst(expansion);
  182. }
  183. return arg;
  184. } //}}}
  185. //{{{ resolveSymlinks() method
  186. /**
  187. * Resolves any symbolic links in the path name specified
  188. * using <code>File.getCanonicalPath()</code>. <b>For local path
  189. * names only.</b>
  190. * @since jEdit 4.2pre1
  191. */
  192. public static String resolveSymlinks(String path)
  193. {
  194. if(isURL(path))
  195. return path;
  196. // 2 aug 2003: OS/2 Java has a broken getCanonicalPath()
  197. if(OperatingSystem.isOS2())
  198. return path;
  199. // 18 nov 2003: calling this on a drive letter on Windows causes
  200. // drive access
  201. if(OperatingSystem.isDOSDerived())
  202. {
  203. if(path.length() == 2 || path.length() == 3)
  204. {
  205. if(path.charAt(1) == ':')
  206. return path;
  207. }
  208. }
  209. try
  210. {
  211. return new File(path).getCanonicalPath();
  212. }
  213. catch(IOException io)
  214. {
  215. return path;
  216. }
  217. } //}}}
  218. //{{{ isAbsolutePath() method
  219. /**
  220. * Returns if the specified path name is an absolute path or URL.
  221. * @since jEdit 4.1pre11
  222. */
  223. public static boolean isAbsolutePath(String path)
  224. {
  225. if(isURL(path))
  226. return true;
  227. else if(path.startsWith("~/") || path.startsWith("~" + File.separator) || path.equals("~"))
  228. return true;
  229. else if(OperatingSystem.isDOSDerived())
  230. {
  231. if(path.length() == 2 && path.charAt(1) == ':')
  232. return true;
  233. if(path.length() > 2 && path.charAt(1) == ':'
  234. && (path.charAt(2) == '\\'
  235. || path.charAt(2) == '/'))
  236. return true;
  237. if(path.startsWith("\\\\")
  238. || path.startsWith("//"))
  239. return true;
  240. }
  241. // not sure if this is correct for OpenVMS.
  242. else if(OperatingSystem.isUnix()
  243. || OperatingSystem.isVMS())
  244. {
  245. // nice and simple
  246. if(path.length() > 0 && path.charAt(0) == '/')
  247. return true;
  248. }
  249. return false;
  250. } //}}}
  251. //{{{ constructPath() method
  252. /**
  253. * Constructs an absolute path name from a directory and another
  254. * path name. This method is VFS-aware.
  255. * @param parent The directory
  256. * @param path The path name
  257. */
  258. public static String constructPath(String parent, String path)
  259. {
  260. if(isAbsolutePath(path))
  261. return canonPath(path);
  262. // have to handle this case specially on windows.
  263. // insert \ between, eg A: and myfile.txt.
  264. if(OperatingSystem.isDOSDerived())
  265. {
  266. if(path.length() == 2 && path.charAt(1) == ':')
  267. return path;
  268. else if(path.length() > 2 && path.charAt(1) == ':'
  269. && path.charAt(2) != '\\')
  270. {
  271. path = path.substring(0,2) + '\\'
  272. + path.substring(2);
  273. return canonPath(path);
  274. }
  275. }
  276. String dd = ".." + File.separator;
  277. String d = '.' + File.separator;
  278. if(parent == null)
  279. parent = System.getProperty("user.dir");
  280. for(;;)
  281. {
  282. if(path.equals("."))
  283. return parent;
  284. else if(path.equals(".."))
  285. return getParentOfPath(parent);
  286. else if(path.startsWith(dd) || path.startsWith("../"))
  287. {
  288. parent = getParentOfPath(parent);
  289. path = path.substring(3);
  290. }
  291. else if(path.startsWith(d) || path.startsWith("./"))
  292. path = path.substring(2);
  293. else
  294. break;
  295. }
  296. if(OperatingSystem.isDOSDerived()
  297. && !isURL(parent)
  298. && path.charAt(0) == '\\')
  299. parent = parent.substring(0,2);
  300. VFS vfs = VFSManager.getVFSForPath(parent);
  301. return canonPath(vfs.constructPath(parent,path));
  302. } //}}}
  303. //{{{ constructPath() method
  304. /**
  305. * Constructs an absolute path name from three path components.
  306. * This method is VFS-aware.
  307. * @param parent The parent directory
  308. * @param path1 The first path
  309. * @param path2 The second path
  310. */
  311. public static String constructPath(String parent,
  312. String path1, String path2)
  313. {
  314. return constructPath(constructPath(parent,path1),path2);
  315. } //}}}
  316. //{{{ concatPath() method
  317. /**
  318. * Like {@link #constructPath}, except <code>path</code> will be
  319. * appended to <code>parent</code> even if it is absolute.
  320. * <b>For local path names only.</b>.
  321. *
  322. * @param path
  323. * @param parent
  324. */
  325. public static String concatPath(String parent, String path)
  326. {
  327. parent = canonPath(parent);
  328. path = canonPath(path);
  329. // Make all child paths relative.
  330. if (path.startsWith(File.separator))
  331. path = path.substring(1);
  332. else if ((path.length() >= 3) && (path.charAt(1) == ':'))
  333. path = path.replace(':', File.separatorChar);
  334. if (parent == null)
  335. parent = System.getProperty("user.dir");
  336. if (parent.endsWith(File.separator))
  337. return parent + path;
  338. else
  339. return parent + File.separator + path;
  340. } //}}}
  341. //{{{ getFirstSeparatorIndex() method
  342. /**
  343. * Return the first index of either / or the OS-specific file
  344. * separator.
  345. * @param path The path
  346. * @since jEdit 4.3pre3
  347. */
  348. public static int getFirstSeparatorIndex(String path)
  349. {
  350. int start = getPathStart(path);
  351. int index = path.indexOf('/',start);
  352. if(index == -1)
  353. index = path.indexOf(File.separatorChar,start);
  354. return index;
  355. } //}}}
  356. //{{{ getLastSeparatorIndex() method
  357. /**
  358. * Return the last index of either / or the OS-specific file
  359. * separator.
  360. * @param path The path
  361. * @since jEdit 4.3pre3
  362. */
  363. public static int getLastSeparatorIndex(String path)
  364. {
  365. int start = getPathStart(path);
  366. if(start != 0)
  367. path = path.substring(start);
  368. int index = Math.max(path.lastIndexOf('/'),
  369. path.lastIndexOf(File.separatorChar));
  370. if(index == -1)
  371. return index;
  372. else
  373. return index + start;
  374. } //}}}
  375. //{{{ getFileExtension() method
  376. /**
  377. * Returns the extension of the specified filename, or an empty
  378. * string if there is none.
  379. * @param path The path
  380. */
  381. public static String getFileExtension(String path)
  382. {
  383. int fsIndex = getLastSeparatorIndex(path);
  384. int index = path.indexOf('.',fsIndex);
  385. if(index == -1)
  386. return "";
  387. else
  388. return path.substring(index);
  389. } //}}}
  390. //{{{ getFileName() method
  391. /**
  392. * Returns the last component of the specified path.
  393. * This method is VFS-aware.
  394. * @param path The path name
  395. */
  396. public static String getFileName(String path)
  397. {
  398. return VFSManager.getVFSForPath(path).getFileName(path);
  399. } //}}}
  400. //{{{ getFileNameNoExtension() method
  401. /**
  402. * Returns the last component of the specified path name without the
  403. * trailing extension (if there is one).
  404. * @param path The path name
  405. * @since jEdit 4.0pre8
  406. */
  407. public static String getFileNameNoExtension(String path)
  408. {
  409. String name = getFileName(path);
  410. int index = name.indexOf('.');
  411. if(index == -1)
  412. return name;
  413. else
  414. return name.substring(0,index);
  415. } //}}}
  416. //{{{ getFileParent() method
  417. /**
  418. * @deprecated Call getParentOfPath() instead
  419. */
  420. @Deprecated
  421. public static String getFileParent(String path)
  422. {
  423. return getParentOfPath(path);
  424. } //}}}
  425. //{{{ getParentOfPath() method
  426. /**
  427. * Returns the parent of the specified path. This method is VFS-aware.
  428. * @param path The path name
  429. * @since jEdit 2.6pre5
  430. */
  431. public static String getParentOfPath(String path)
  432. {
  433. return VFSManager.getVFSForPath(path).getParentOfPath(path);
  434. } //}}}
  435. //{{{ getFileProtocol() method
  436. /**
  437. * @deprecated Call getProtocolOfURL() instead
  438. */
  439. @Deprecated
  440. public static String getFileProtocol(String url)
  441. {
  442. return getProtocolOfURL(url);
  443. } //}}}
  444. //{{{ getProtocolOfURL() method
  445. /**
  446. * Returns the protocol specified by a URL.
  447. * @param url The URL
  448. * @since jEdit 2.6pre5
  449. */
  450. public static String getProtocolOfURL(String url)
  451. {
  452. return url.substring(0,url.indexOf(':'));
  453. } //}}}
  454. //{{{ isURL() method
  455. /**
  456. * Checks if the specified string is a URL.
  457. * @param str The string to check
  458. * @return True if the string is a URL, false otherwise
  459. */
  460. public static boolean isURL(String str)
  461. {
  462. int fsIndex = getLastSeparatorIndex(str);
  463. if(fsIndex == 0) // /etc/passwd
  464. return false;
  465. else if(fsIndex == 2) // C:\AUTOEXEC.BAT
  466. return false;
  467. int cIndex = str.indexOf(':');
  468. if(cIndex <= 1) // D:\WINDOWS, or doesn't contain : at all
  469. return false;
  470. String protocol = str.substring(0,cIndex);
  471. VFS vfs = VFSManager.getVFSForProtocol(protocol);
  472. if(vfs != null && !(vfs instanceof UrlVFS))
  473. return true;
  474. try
  475. {
  476. new URL(str);
  477. return true;
  478. }
  479. catch(MalformedURLException mf)
  480. {
  481. return false;
  482. }
  483. } //}}}
  484. //{{{ saveBackup() method
  485. /**
  486. * Saves a backup (optionally numbered) of a file.
  487. * @param file A local file
  488. * @param backups The number of backups. Must be >= 1. If > 1, backup
  489. * files will be numbered.
  490. * @param backupPrefix The backup file name prefix
  491. * @param backupSuffix The backup file name suffix
  492. * @param backupDirectory The directory where to save backups; if null,
  493. * they will be saved in the same directory as the file itself.
  494. * @since jEdit 4.0pre1
  495. */
  496. public static void saveBackup(File file, int backups,
  497. String backupPrefix, String backupSuffix,
  498. String backupDirectory)
  499. {
  500. saveBackup(file,backups,backupPrefix,backupSuffix,backupDirectory,0);
  501. } //}}}
  502. //{{{ saveBackup() method
  503. /**
  504. * Saves a backup (optionally numbered) of a file.
  505. * @param file A local file
  506. * @param backups The number of backups. Must be >= 1. If > 1, backup
  507. * files will be numbered.
  508. * @param backupPrefix The backup file name prefix
  509. * @param backupSuffix The backup file name suffix
  510. * @param backupDirectory The directory where to save backups; if null,
  511. * they will be saved in the same directory as the file itself.
  512. * @param backupTimeDistance The minimum time in minutes when a backup
  513. * version 1 shall be moved into version 2; if 0, backups are always
  514. * moved.
  515. * @since jEdit 4.2pre5
  516. */
  517. public static void saveBackup(File file, int backups,
  518. String backupPrefix, String backupSuffix,
  519. String backupDirectory, int backupTimeDistance)
  520. {
  521. if(backupPrefix == null)
  522. backupPrefix = "";
  523. if(backupSuffix == null)
  524. backupSuffix = "";
  525. String name = file.getName();
  526. // If backups is 1, create ~ file
  527. if(backups == 1)
  528. {
  529. File backupFile = new File(backupDirectory,
  530. backupPrefix + name + backupSuffix);
  531. long modTime = backupFile.lastModified();
  532. /* if backup file was created less than
  533. * 'backupTimeDistance' ago, we do not
  534. * create the backup */
  535. if(System.currentTimeMillis() - modTime
  536. >= backupTimeDistance)
  537. {
  538. backupFile.delete();
  539. if (!file.renameTo(backupFile))
  540. IOUtilities.moveFile(file, backupFile);
  541. }
  542. }
  543. // If backups > 1, move old ~n~ files, create ~1~ file
  544. else
  545. {
  546. /* delete a backup created using above method */
  547. new File(backupDirectory,
  548. backupPrefix + name + backupSuffix
  549. + backups + backupSuffix).delete();
  550. File firstBackup = new File(backupDirectory,
  551. backupPrefix + name + backupSuffix
  552. + "1" + backupSuffix);
  553. long modTime = firstBackup.lastModified();
  554. /* if backup file was created less than
  555. * 'backupTimeDistance' ago, we do not
  556. * create the backup */
  557. if(System.currentTimeMillis() - modTime
  558. >= backupTimeDistance)
  559. {
  560. for(int i = backups - 1; i > 0; i--)
  561. {
  562. File backup = new File(backupDirectory,
  563. backupPrefix + name
  564. + backupSuffix + i
  565. + backupSuffix);
  566. backup.renameTo(
  567. new File(backupDirectory,
  568. backupPrefix + name
  569. + backupSuffix + (i+1)
  570. + backupSuffix));
  571. }
  572. File backupFile = new File(backupDirectory,
  573. backupPrefix + name + backupSuffix
  574. + "1" + backupSuffix);
  575. if (!file.renameTo(backupFile))
  576. IOUtilities.moveFile(file, backupFile);
  577. }
  578. }
  579. } //}}}
  580. //{{{ moveFile() method
  581. /**
  582. * Moves the source file to the destination.
  583. *
  584. * If the destination cannot be created or is a read-only file, the
  585. * method returns <code>false</code>. Otherwise, the contents of the
  586. * source are copied to the destination, the source is deleted,
  587. * and <code>true</code> is returned.
  588. *
  589. * @param source The source file to move.
  590. * @param dest The destination where to move the file.
  591. * @return true on success, false otherwise.
  592. *
  593. * @since jEdit 4.3pre1
  594. * @deprecated use {@link org.gjt.sp.util.IOUtilities#moveFile(java.io.File, java.io.File)}
  595. */
  596. @Deprecated
  597. public static boolean moveFile(File source, File dest)
  598. {
  599. return IOUtilities.moveFile(source, dest);
  600. } //}}}
  601. //{{{ copyStream() method
  602. /**
  603. * Copy an input stream to an output stream.
  604. *
  605. * @param bufferSize the size of the buffer
  606. * @param progress the progress observer it could be null
  607. * @param in the input stream
  608. * @param out the output stream
  609. * @param canStop if true, the copy can be stopped by interrupting the thread
  610. * @return <code>true</code> if the copy was done, <code>false</code> if it was interrupted
  611. * @throws IOException IOException If an I/O error occurs
  612. * @since jEdit 4.3pre3
  613. * @deprecated use {@link IOUtilities#copyStream(int, org.gjt.sp.util.ProgressObserver, java.io.InputStream, java.io.OutputStream, boolean)}
  614. */
  615. @Deprecated
  616. public static boolean copyStream(int bufferSize, ProgressObserver progress,
  617. InputStream in, OutputStream out, boolean canStop)
  618. throws IOException
  619. {
  620. return IOUtilities.copyStream(bufferSize, progress, in, out, canStop);
  621. } //}}}
  622. //{{{ copyStream() method
  623. /**
  624. * Copy an input stream to an output stream with a buffer of 4096 bytes.
  625. *
  626. * @param progress the progress observer it could be null
  627. * @param in the input stream
  628. * @param out the output stream
  629. * @param canStop if true, the copy can be stopped by interrupting the thread
  630. * @return <code>true</code> if the copy was done, <code>false</code> if it was interrupted
  631. * @throws IOException IOException If an I/O error occurs
  632. * @since jEdit 4.3pre3
  633. * @deprecated use {@link IOUtilities#copyStream(org.gjt.sp.util.ProgressObserver, java.io.InputStream, java.io.OutputStream, boolean)}
  634. */
  635. @Deprecated
  636. public static boolean copyStream(ProgressObserver progress, InputStream in, OutputStream out, boolean canStop)
  637. throws IOException
  638. {
  639. return IOUtilities.copyStream(4096,progress, in, out, canStop);
  640. } //}}}
  641. //{{{ isBinaryFile() method
  642. /**
  643. * Check if a Reader is binary.
  644. * To check if a file is binary, we will check the first characters 100
  645. * (jEdit property vfs.binaryCheck.length)
  646. * If more than 1 (jEdit property vfs.binaryCheck.count), the
  647. * file is declared binary.
  648. * This is not 100% because sometimes the autodetection could fail.
  649. * This method will not close your reader. You have to do it yourself
  650. *
  651. * @param reader the reader
  652. * @return <code>true</code> if the Reader was detected as binary
  653. * @throws IOException IOException If an I/O error occurs
  654. * @since jEdit 4.3pre5
  655. */
  656. public static boolean isBinary(Reader reader)
  657. throws IOException
  658. {
  659. int nbChars = jEdit.getIntegerProperty("vfs.binaryCheck.length",100);
  660. int authorized = jEdit.getIntegerProperty("vfs.binaryCheck.count",1);
  661. for (long i = 0L;i < nbChars;i++)
  662. {
  663. int c = reader.read();
  664. if (c == -1)
  665. return false;
  666. if (c == 0)
  667. {
  668. authorized--;
  669. if (authorized == 0)
  670. return true;
  671. }
  672. }
  673. return false;
  674. } //}}}
  675. //{{{ isBackup() method
  676. /**
  677. * Check if the filename is a backup file.
  678. * @param filename the filename to check
  679. * @return true if this is a backup file.
  680. * @since jEdit 4.3pre5
  681. */
  682. public static boolean isBackup( String filename ) {
  683. if (filename.startsWith("#")) return true;
  684. if (filename.endsWith("~")) return true;
  685. if (filename.endsWith(".bak")) return true;
  686. return false;
  687. } //}}}
  688. //{{{ autodetect() method
  689. /**
  690. * Tries to detect if the stream is gzipped, and if it has an encoding
  691. * specified with an XML PI.
  692. *
  693. * @param in the input stream reader that must be autodetected
  694. * @param buffer a buffer. It can be null if you only want to autodetect the encoding of a file
  695. * @return a Reader using the detected encoding
  696. * @throws IOException io exception during read
  697. * @since jEdit 4.3pre5
  698. */
  699. public static Reader autodetect(InputStream in, Buffer buffer) throws IOException
  700. {
  701. in = new BufferedInputStream(in,
  702. BufferIORequest.getByteIOBufferSize());
  703. String encoding;
  704. if (buffer == null)
  705. encoding = System.getProperty("file.encoding");
  706. else
  707. encoding = buffer.getStringProperty(JEditBuffer.ENCODING);
  708. if(!in.markSupported())
  709. Log.log(Log.WARNING,MiscUtilities.class,"Mark not supported: " + in);
  710. else if(buffer == null || buffer.getBooleanProperty(Buffer.ENCODING_AUTODETECT))
  711. {
  712. in.mark(BufferIORequest.XML_PI_LENGTH);
  713. int b1 = in.read();
  714. int b2 = in.read();
  715. int b3 = in.read();
  716. if(b1 == BufferIORequest.GZIP_MAGIC_1 && b2 == BufferIORequest.GZIP_MAGIC_2)
  717. {
  718. in.reset();
  719. Log.log(Log.DEBUG, MiscUtilities.class, "Stream is Gzipped");
  720. in = new GZIPInputStream(in);
  721. if (buffer != null)
  722. buffer.setBooleanProperty(Buffer.GZIPPED,true);
  723. // auto-detect encoding within the gzip stream.
  724. return autodetect(in, buffer);
  725. }
  726. else if (b1 == BufferIORequest.UNICODE_MAGIC_1
  727. && b2 == BufferIORequest.UNICODE_MAGIC_2)
  728. {
  729. in.reset();
  730. in.read();
  731. in.read();
  732. encoding = "UTF-16";
  733. if (buffer != null)
  734. {
  735. buffer.setProperty(JEditBuffer.ENCODING,encoding);
  736. buffer.setProperty(BufferIORequest.BOM_PROP,BufferIORequest.UTF_BOM.BE);
  737. }
  738. }
  739. else if (b1 == BufferIORequest.UNICODE_MAGIC_2
  740. && b2 == BufferIORequest.UNICODE_MAGIC_1)
  741. {
  742. in.reset();
  743. in.read();
  744. in.read();
  745. encoding = "UTF-16";
  746. if (buffer != null)
  747. {
  748. buffer.setProperty(JEditBuffer.ENCODING,encoding);
  749. buffer.setProperty(BufferIORequest.BOM_PROP,BufferIORequest.UTF_BOM.LE);
  750. }
  751. }
  752. else if(b1 == BufferIORequest.UTF8_MAGIC_1 && b2 == BufferIORequest.UTF8_MAGIC_2
  753. && b3 == BufferIORequest.UTF8_MAGIC_3)
  754. {
  755. // do not reset the stream and just treat it
  756. // like a normal UTF-8 file.
  757. if (buffer != null)
  758. buffer.setProperty(JEditBuffer.ENCODING, MiscUtilities.UTF_8_Y);
  759. encoding = "UTF-8";
  760. }
  761. else
  762. {
  763. in.reset();
  764. byte[] _xmlPI = new byte[BufferIORequest.XML_PI_LENGTH];
  765. int offset = 0;
  766. int count;
  767. while((count = in.read(_xmlPI,offset,
  768. BufferIORequest.XML_PI_LENGTH - offset)) != -1)
  769. {
  770. offset += count;
  771. if(offset == BufferIORequest.XML_PI_LENGTH)
  772. break;
  773. }
  774. String xmlEncoding = getXMLEncoding(new String(
  775. _xmlPI,0,offset,"ASCII"));
  776. if (xmlEncoding == null)
  777. {
  778. if (Options.X_AUTODETECT)
  779. {
  780. in.reset();
  781. String coding = xAutodetect(in);
  782. if (coding != null)
  783. encoding = coding;
  784. }
  785. }
  786. else
  787. {
  788. encoding = xmlEncoding;
  789. if (buffer != null)
  790. buffer.setProperty(JEditBuffer.ENCODING,encoding);
  791. }
  792. if(encoding.equals(MiscUtilities.UTF_8_Y))
  793. encoding = "UTF-8";
  794. in.reset();
  795. }
  796. }
  797. Log.log(Log.DEBUG, MiscUtilities.class, "Stream encoding detected is " + encoding);
  798. return new InputStreamReader(in, encoding);
  799. } //}}}
  800. //{{{ getXMLEncoding() method
  801. private static String xAutodetect(InputStream in) throws IOException
  802. {
  803. BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  804. int i = 0;
  805. while (i < 10)
  806. {
  807. i++;
  808. String line = reader.readLine();
  809. if (line == null)
  810. return null;
  811. int pos = line.indexOf(":encoding=");
  812. if (pos != -1)
  813. {
  814. int p2 = line.indexOf(':', pos + 10);
  815. String encoding = line.substring(pos + 10, p2);
  816. return encoding;
  817. }
  818. }
  819. return null;
  820. } //}}}
  821. //{{{ getXMLEncoding() method
  822. /**
  823. * Extract XML encoding name from PI.
  824. */
  825. private static String getXMLEncoding(String xmlPI)
  826. {
  827. if(!xmlPI.startsWith("<?xml"))
  828. return null;
  829. int index = xmlPI.indexOf("encoding=");
  830. if(index == -1 || index + 9 == xmlPI.length())
  831. return null;
  832. char ch = xmlPI.charAt(index + 9);
  833. int endIndex = xmlPI.indexOf(ch,index + 10);
  834. if(endIndex == -1)
  835. return null;
  836. String encoding = xmlPI.substring(index + 10,endIndex);
  837. if(Charset.isSupported(encoding))
  838. return encoding;
  839. else
  840. {
  841. Log.log(Log.WARNING,MiscUtilities.class,"XML PI specifies "
  842. + "unsupported encoding: " + encoding);
  843. return null;
  844. }
  845. } //}}}
  846. //{{{ closeQuietly() method
  847. /**
  848. * Method that will close an {@link InputStream} ignoring it if it is null and ignoring exceptions.
  849. *
  850. * @param in the InputStream to close.
  851. * @since jEdit 4.3pre3
  852. * @deprecated use {@link IOUtilities#closeQuietly(java.io.InputStream)}
  853. */
  854. @Deprecated
  855. public static void closeQuietly(InputStream in)
  856. {
  857. IOUtilities.closeQuietly(in);
  858. } //}}}
  859. //{{{ copyStream() method
  860. /**
  861. * Method that will close an {@link OutputStream} ignoring it if it is null and ignoring exceptions.
  862. *
  863. * @param out the OutputStream to close.
  864. * @since jEdit 4.3pre3
  865. * @deprecated use {@link IOUtilities#closeQuietly(java.io.OutputStream)}
  866. */
  867. @Deprecated
  868. public static void closeQuietly(OutputStream out)
  869. {
  870. IOUtilities.closeQuietly(out);
  871. } //}}}
  872. //{{{ fileToClass() method
  873. /**
  874. * Converts a file name to a class name. All slash characters are
  875. * replaced with periods and the trailing '.class' is removed.
  876. * @param name The file name
  877. */
  878. public static String fileToClass(String name)
  879. {
  880. char[] clsName = name.toCharArray();
  881. for(int i = clsName.length - 6; i >= 0; i--)
  882. if(clsName[i] == '/')
  883. clsName[i] = '.';
  884. return new String(clsName,0,clsName.length - 6);
  885. } //}}}
  886. //{{{ classToFile() method
  887. /**
  888. * Converts a class name to a file name. All periods are replaced
  889. * with slashes and the '.class' extension is added.
  890. * @param name The class name
  891. */
  892. public static String classToFile(String name)
  893. {
  894. return name.replace('.','/').concat(".class");
  895. } //}}}
  896. //{{{ pathsEqual() method
  897. /**
  898. * @param p1 A path name
  899. * @param p2 A path name
  900. * @return True if both paths are equal, ignoring trailing slashes, as
  901. * well as case insensitivity on Windows.
  902. * @since jEdit 4.3pre2
  903. */
  904. public static boolean pathsEqual(String p1, String p2)
  905. {
  906. VFS v1 = VFSManager.getVFSForPath(p1);
  907. VFS v2 = VFSManager.getVFSForPath(p2);
  908. if(v1 != v2)
  909. return false;
  910. if(p1.endsWith("/") || p1.endsWith(File.separator))
  911. p1 = p1.substring(0,p1.length() - 1);
  912. if(p2.endsWith("/") || p2.endsWith(File.separator))
  913. p2 = p2.substring(0,p2.length() - 1);
  914. if((v1.getCapabilities() & VFS.CASE_INSENSITIVE_CAP) != 0)
  915. return p1.equalsIgnoreCase(p2);
  916. else
  917. return p1.equals(p2);
  918. } //}}}
  919. //}}}
  920. //{{{ Text methods
  921. //{{{ getLeadingWhiteSpace() method
  922. /**
  923. * Returns the number of leading white space characters in the
  924. * specified string.
  925. * @param str The string
  926. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getLeadingWhiteSpace(String)}
  927. */
  928. @Deprecated
  929. public static int getLeadingWhiteSpace(String str)
  930. {
  931. return StandardUtilities.getLeadingWhiteSpace(str);
  932. } //}}}
  933. //{{{ getTrailingWhiteSpace() method
  934. /**
  935. * Returns the number of trailing whitespace characters in the
  936. * specified string.
  937. * @param str The string
  938. * @since jEdit 2.5pre5
  939. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getTrailingWhiteSpace(String)}
  940. */
  941. @Deprecated
  942. public static int getTrailingWhiteSpace(String str)
  943. {
  944. return StandardUtilities.getTrailingWhiteSpace(str);
  945. } //}}}
  946. //{{{ getLeadingWhiteSpaceWidth() method
  947. /**
  948. * Returns the width of the leading white space in the specified
  949. * string.
  950. * @param str The string
  951. * @param tabSize The tab size
  952. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getLeadingWhiteSpace(String)}
  953. */
  954. @Deprecated
  955. public static int getLeadingWhiteSpaceWidth(String str, int tabSize)
  956. {
  957. return StandardUtilities.getLeadingWhiteSpaceWidth(str, tabSize);
  958. } //}}}
  959. //{{{ getVirtualWidth() method
  960. /**
  961. * Returns the virtual column number (taking tabs into account) of the
  962. * specified offset in the segment.
  963. *
  964. * @param seg The segment
  965. * @param tabSize The tab size
  966. * @since jEdit 4.1pre1
  967. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getVirtualWidth(javax.swing.text.Segment, int)}
  968. */
  969. @Deprecated
  970. public static int getVirtualWidth(Segment seg, int tabSize)
  971. {
  972. return StandardUtilities.getVirtualWidth(seg, tabSize);
  973. } //}}}
  974. //{{{ getOffsetOfVirtualColumn() method
  975. /**
  976. * Returns the array offset of a virtual column number (taking tabs
  977. * into account) in the segment.
  978. *
  979. * @param seg The segment
  980. * @param tabSize The tab size
  981. * @param column The virtual column number
  982. * @param totalVirtualWidth If this array is non-null, the total
  983. * virtual width will be stored in its first location if this method
  984. * returns -1.
  985. *
  986. * @return -1 if the column is out of bounds
  987. *
  988. * @since jEdit 4.1pre1
  989. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#getVirtualWidth(javax.swing.text.Segment, int)}
  990. */
  991. @Deprecated
  992. public static int getOffsetOfVirtualColumn(Segment seg, int tabSize,
  993. int column, int[] totalVirtualWidth)
  994. {
  995. return StandardUtilities.getOffsetOfVirtualColumn(seg, tabSize, column, totalVirtualWidth);
  996. } //}}}
  997. //{{{ createWhiteSpace() method
  998. /**
  999. * Creates a string of white space with the specified length.<p>
  1000. *
  1001. * To get a whitespace string tuned to the current buffer's
  1002. * settings, call this method as follows:
  1003. *
  1004. * <pre>myWhitespace = MiscUtilities.createWhiteSpace(myLength,
  1005. * (buffer.getBooleanProperty("noTabs") ? 0
  1006. * : buffer.getTabSize()));</pre>
  1007. *
  1008. * @param len The length
  1009. * @param tabSize The tab size, or 0 if tabs are not to be used
  1010. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#createWhiteSpace(int, int)}
  1011. */
  1012. @Deprecated
  1013. public static String createWhiteSpace(int len, int tabSize)
  1014. {
  1015. return StandardUtilities.createWhiteSpace(len,tabSize,0);
  1016. } //}}}
  1017. //{{{ createWhiteSpace() method
  1018. /**
  1019. * Creates a string of white space with the specified length.<p>
  1020. *
  1021. * To get a whitespace string tuned to the current buffer's
  1022. * settings, call this method as follows:
  1023. *
  1024. * <pre>myWhitespace = MiscUtilities.createWhiteSpace(myLength,
  1025. * (buffer.getBooleanProperty("noTabs") ? 0
  1026. * : buffer.getTabSize()));</pre>
  1027. *
  1028. * @param len The length
  1029. * @param tabSize The tab size, or 0 if tabs are not to be used
  1030. * @param start The start offset, for tab alignment
  1031. * @since jEdit 4.2pre1
  1032. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#createWhiteSpace(int, int, int)}
  1033. */
  1034. @Deprecated
  1035. public static String createWhiteSpace(int len, int tabSize, int start)
  1036. {
  1037. return StandardUtilities.createWhiteSpace(len, tabSize, start);
  1038. } //}}}
  1039. //{{{ globToRE() method
  1040. /**
  1041. * Converts a Unix-style glob to a regular expression.<p>
  1042. *
  1043. * ? becomes ., * becomes .*, {aa,bb} becomes (aa|bb).
  1044. * @param glob The glob pattern
  1045. * @deprecated Use {@link org.gjt.sp.util.StandardUtilities#globToRE(String)}.
  1046. */
  1047. @Deprecated
  1048. public static String globToRE(String glob)
  1049. {
  1050. return StandardUtilities.globToRE(glob);
  1051. } //}}}
  1052. //{{{ escapesToChars() method
  1053. /**
  1054. * Converts "\n" and "\t" escapes in the specified string to
  1055. * newlines and tabs.
  1056. * @param str The string
  1057. * @since jEdit 2.3pre1
  1058. */
  1059. public static String escapesToChars(String str)
  1060. {
  1061. StringBuffer buf = new StringBuffer();
  1062. for(int i = 0; i < str.length(); i++)
  1063. {
  1064. char c = str.charAt(i);
  1065. switch(c)
  1066. {
  1067. case '\\':
  1068. if(i == str.length() - 1)
  1069. {
  1070. buf.append('\\');
  1071. break;
  1072. }
  1073. c = str.charAt(++i);
  1074. switch(c)
  1075. {
  1076. case 'n':
  1077. buf.append('\n');
  1078. break;
  1079. case 't':
  1080. buf.append('\t');
  1081. break;
  1082. default:
  1083. buf.append(c);
  1084. break;
  1085. }
  1086. break;
  1087. default:
  1088. buf.append(c);
  1089. }
  1090. }
  1091. return buf.toString();
  1092. } //}}}
  1093. //{{{ charsToEscapes() method
  1094. /**
  1095. * Escapes newlines, tabs, backslashes, and quotes in the specified
  1096. * string.
  1097. * @param str The string
  1098. * @since jEdit 2.3pre1
  1099. */
  1100. public static String charsToEscapes(String str)
  1101. {
  1102. return charsToEscapes(str,"\n\t\\\"'");
  1103. } //}}}
  1104. //{{{ charsToEscapes() method
  1105. /**
  1106. * Escapes the specified characters in the specified string.
  1107. * @param str The string
  1108. * @param toEscape Any characters that require escaping
  1109. * @since jEdit 4.1pre3
  1110. */
  1111. public static String charsToEscapes(String str, String toEscape)
  1112. {
  1113. StringBuffer buf = new StringBuffer();
  1114. for(int i = 0; i < str.length(); i++)
  1115. {
  1116. char c = str.charAt(i);
  1117. if(toEscape.indexOf(c) != -1)
  1118. {
  1119. if(c == '\n')
  1120. buf.append("\\n");
  1121. else if(c == '\t')
  1122. buf.append("\\t");
  1123. else
  1124. {
  1125. buf.append('\\');
  1126. buf.append(c);
  1127. }
  1128. }
  1129. else
  1130. buf.append(c);
  1131. }
  1132. return buf.toString();
  1133. } //}}}
  1134. //{{{ compareVersions() method
  1135. /**
  1136. * @deprecated Call <code>compareStrings()</code> instead
  1137. */
  1138. @Deprecated
  1139. public static int compareVersions(String v1, String v2)
  1140. {
  1141. return StandardUtilities.compareStrings(v1,v2,false);
  1142. } //}}}
  1143. //{{{ compareStrings() method
  1144. /**
  1145. * Compares two strings.<p>
  1146. *
  1147. * Unlike <function>String.compareTo()</function>,
  1148. * this method correctly recognizes and handles embedded numbers.
  1149. * For example, it places "My file 2" before "My file 10".<p>
  1150. *
  1151. * @param str1 The first string
  1152. * @param str2 The second string
  1153. * @param ignoreCase If true, case will be ignored
  1154. * @return negative If str1 &lt; str2, 0 if both are the same,
  1155. * positive if str1 &gt; str2
  1156. * @since jEdit 4.0pre1
  1157. * @deprecated use {@link org.gjt.sp.util.StandardUtilities#compareStrings(String, String, boolean)}
  1158. */
  1159. @Deprecated
  1160. public static int compareStrings(String str1, String str2, boolean ignoreCase)
  1161. {
  1162. return StandardUtilities.compareStrings(str1, str2, ignoreCase);
  1163. } //}}}
  1164. //{{{ stringsEqual() method
  1165. /**
  1166. * @deprecated Call <code>objectsEqual()</code> instead.
  1167. */
  1168. @Deprecated
  1169. public static boolean stringsEqual(String s1, String s2)
  1170. {
  1171. return org.gjt.sp.util.StandardUtilities.objectsEqual(s1,s2);
  1172. } //}}}
  1173. //{{{ objectsEqual() method
  1174. /**
  1175. * Returns if two strings are equal. This correctly handles null pointers,
  1176. * as opposed to calling <code>o1.equals(o2)</code>.
  1177. * @since jEdit 4.2pre1
  1178. * @deprecated use {@link StandardUtilities#objectsEqual(Object, Object)}
  1179. */
  1180. @Deprecated
  1181. public static boolean objectsEqual(Object o1, Object o2)
  1182. {
  1183. return StandardUtilities.objectsEqual(o1, o2);
  1184. } //}}}
  1185. //{{{ charsToEntities() method
  1186. /**
  1187. * Converts &lt;, &gt;, &amp; in the string to their HTML entity
  1188. * equivalents.
  1189. * @param str The string
  1190. * @since jEdit 4.2pre1
  1191. * @deprecated Use {@link org.gjt.sp.util.XMLUtilities#charsToEntities(String, boolean)}.
  1192. */
  1193. @Deprecated
  1194. public static String charsToEntities(String str)
  1195. {
  1196. return XMLUtilities.charsToEntities(str,false);
  1197. } //}}}
  1198. //{{{ formatFileSize() method
  1199. public static final DecimalFormat KB_FORMAT = new DecimalFormat("#.# KB");
  1200. public static final DecimalFormat MB_FORMAT = new DecimalFormat("#.# MB");
  1201. /**
  1202. * Formats the given file size into a nice string (123 bytes, 10.6 KB,
  1203. * 1.2 MB).
  1204. * @param length The size
  1205. * @since jEdit 4.2pre1
  1206. */
  1207. public static String formatFileSize(long length)
  1208. {
  1209. if(length < 1024)
  1210. return length + " bytes";
  1211. else if(length < 1024 << 10)
  1212. return KB_FORMAT.format((double)length / 1024);
  1213. else
  1214. return MB_FORMAT.format((double)length / 1024 / 1024);
  1215. } //}}}
  1216. //{{{ getLongestPrefix() method
  1217. /**
  1218. * Returns the longest common prefix in the given set of strings.
  1219. * @param str The strings
  1220. * @param ignoreCase If true, case insensitive
  1221. * @since jEdit 4.2pre2
  1222. */
  1223. public static String getLongestPrefix(List str, boolean ignoreCase)
  1224. {
  1225. if(str.size() == 0)
  1226. return "";
  1227. int prefixLength = 0;
  1228. loop: for(;;)
  1229. {
  1230. String s = str.get(0).toString();
  1231. if(prefixLength >= s.length())
  1232. break loop;
  1233. char ch = s.charAt(prefixLength);
  1234. for(int i = 1; i < str.size(); i++)
  1235. {
  1236. s = str.get(i).toString();
  1237. if(prefixLength >= s.length())
  1238. break loop;
  1239. if(!compareChars(s.charAt(prefixLength),ch,ignoreCase))
  1240. break loop;
  1241. }
  1242. prefixLength++;
  1243. }
  1244. return str.get(0).toString().substring(0,prefixLength);
  1245. } //}}}
  1246. //{{{ getLongestPrefix() method
  1247. /**
  1248. * Returns the longest common prefix in the given set of strings.
  1249. * @param str The strings
  1250. * @param ignoreCase If true, case insensitive
  1251. * @since jEdit 4.2pre2
  1252. */
  1253. public static String getLongestPrefix(String[] str, boolean ignoreCase)
  1254. {
  1255. return getLongestPrefix((Object[])str,ignoreCase);
  1256. } //}}}
  1257. //{{{ getLongestPrefix() method
  1258. /**
  1259. * Returns the longest common prefix in the given set of strings.
  1260. * @param str The strings (calls <code>toString()</code> on each object)
  1261. * @param ignoreCase If true, case insensitive
  1262. * @since jEdit 4.2pre6
  1263. */
  1264. public static String getLongestPrefix(Object[] str, boolean ignoreCase)
  1265. {
  1266. if(str.length == 0)
  1267. return "";
  1268. int prefixLength = 0;
  1269. String first = str[0].toString();
  1270. loop: for(;;)
  1271. {
  1272. if(prefixLength >= first.length())
  1273. break loop;
  1274. char ch = first.charAt(prefixLength);
  1275. for(int i = 1; i < str.length; i++)
  1276. {
  1277. String s = str[i].toString();
  1278. if(prefixLength >= s.length())
  1279. break loop;
  1280. if(!compareChars(s.charAt(prefixLength),ch,ignoreCase))
  1281. break loop;
  1282. }
  1283. prefixLength++;
  1284. }
  1285. return first.substring(0,prefixLength);
  1286. } //}}}
  1287. //}}}
  1288. //{{{ quicksort() deprecated methods
  1289. /**
  1290. * Sorts the specified array. Equivalent to calling
  1291. * <code>Arrays.sort()</code>.
  1292. * @param obj The array
  1293. * @param compare Compares the objects
  1294. * @since jEdit 4.0pre4
  1295. * @deprecated use <code>Arrays.sort()</code>
  1296. */
  1297. @Deprecated
  1298. public static void quicksort(Object[] obj, Comparator compare)
  1299. {
  1300. Arrays.sort(obj,compare);
  1301. }
  1302. /**
  1303. * Sorts the specified vector.
  1304. * @param vector The vector
  1305. * @param compare Compares the objects
  1306. * @since jEdit 4.0pre4
  1307. * @deprecated <code>Collections.sort()</code>
  1308. */
  1309. @Deprecated
  1310. public static void quicksort(Vector vector, Comparator compare)
  1311. {
  1312. Collections.sort(vector,compare);
  1313. }
  1314. /**
  1315. * Sorts the specified list.
  1316. * @param list The list
  1317. * @param compare Compares the objects
  1318. * @since jEdit 4.0pre4
  1319. * @deprecated <code>Collections.sort()</code>
  1320. */
  1321. @Deprecated
  1322. public static void quicksort(List list, Comparator compare)
  1323. {
  1324. Collections.sort(list,compare);
  1325. }
  1326. /**
  1327. * Sorts the specified array. Equivalent to calling
  1328. * <code>Arrays.sort()</code>.
  1329. * @param obj The array
  1330. * @param compare Compares the objects
  1331. * @deprecated use <code>Arrays.sort()</code>
  1332. */
  1333. @Deprecated
  1334. public static void quicksort(Object[] obj, Compare compare)
  1335. {
  1336. Arrays.sort(obj,compare);
  1337. }
  1338. /**
  1339. * Sorts the specified vector.
  1340. * @param vector The vector
  1341. * @param compare Compares the objects
  1342. * @deprecated <code>Collections.sort()</code>
  1343. */
  1344. @Deprecated
  1345. public static void quicksort(Vector vector, Compare compare)
  1346. {
  1347. Collections.sort(vector,compare);
  1348. } //}}}
  1349. //{{{ Compare deprecated interface
  1350. /**
  1351. * An interface for comparing objects. This is a hold-over from
  1352. * they days when jEdit had its own sorting API due to JDK 1.1
  1353. * compatibility requirements. Use <code>java.util.Comparator</code>
  1354. * instead.
  1355. * @deprecated
  1356. */
  1357. @Deprecated
  1358. public interface Compare extends Comparator
  1359. {
  1360. int compare(Object obj1, Object obj2);
  1361. } //}}}
  1362. //{{{ StringCompare class
  1363. /**
  1364. * Compares strings.
  1365. * @deprecated use {@link org.gjt.sp.util.StandardUtilities.StringCompare}
  1366. */
  1367. @Deprecated
  1368. public static class StringCompare implements Compare
  1369. {
  1370. public int compare(Object obj1, Object obj2)
  1371. {
  1372. return StandardUtilities.compareStrings(obj1.toString(),
  1373. obj2.toString(),false);
  1374. }
  1375. } //}}}
  1376. //{{{ StringICaseCompare class
  1377. /**
  1378. * Compares strings ignoring case.
  1379. */
  1380. public static class StringICaseCompare implements Comparator<Object>
  1381. {
  1382. public int compare(Object obj1, Object obj2)
  1383. {
  1384. return StandardUtilities.compareStrings(obj1.toString(), obj2.toString(), true);
  1385. }
  1386. } //}}}
  1387. //{{{ MenuItemCompare class
  1388. /**
  1389. * Compares menu item labels.
  1390. */
  1391. public static class MenuItemCompare implements Compare
  1392. {
  1393. public int compare(Object obj1, Object obj2)
  1394. {
  1395. boolean obj1E, obj2E;
  1396. obj1E = obj1 instanceof EnhancedMenuItem;
  1397. obj2E = obj2 instanceof EnhancedMenuItem;
  1398. if(obj1E && !obj2E)
  1399. return 1;
  1400. else if(obj2E && !obj1E)
  1401. return -1;
  1402. else
  1403. return StandardUtilities.compareStrings(((JMenuItem)obj1).getText(),
  1404. ((JMenuItem)obj2).getText(),true);
  1405. }
  1406. } //}}}
  1407. //{{{ buildToVersion() method
  1408. /**
  1409. * Converts an internal version number (build) into a
  1410. * `human-readable' form.
  1411. * @param build The build
  1412. */
  1413. public static String buildToVersion(String build)
  1414. {
  1415. if(build.length() != 11)
  1416. return "<unknown version: " + build + ">";
  1417. // First 2 chars are the major version number
  1418. int major = Integer.parseInt(build.substring(0,2));
  1419. // Second 2 are the minor number
  1420. int minor = Integer.parseInt(build.substring(3,5));
  1421. // Then the pre-release status
  1422. int beta = Integer.parseInt(build.substring(6,8));
  1423. // Finally the bug fix release
  1424. int bugfix = Integer.parseInt(build.substring(9,11));
  1425. return major + "." + minor
  1426. + (beta != 99 ? "pre" + beta :
  1427. (bugfix != 0 ? "." + bugfix : "final"));
  1428. } //}}}
  1429. //{{{ isToolsJarAvailable() method
  1430. /**
  1431. * If on JDK 1.2 or higher, make sure that tools.jar is available.
  1432. * This method should be called by plugins requiring the classes
  1433. * in this library.
  1434. * <p>
  1435. * tools.jar is searched for in the following places:
  1436. * <ol>
  1437. * <li>the classpath that was used when jEdit was started,
  1438. * <li>jEdit's jars folder in the user's home,
  1439. * <li>jEdit's system jars folder,
  1440. * <li><i>java.home</i>/lib/. In this case, tools.jar is added to
  1441. * jEdit's list of known jars using jEdit.addPluginJAR(),
  1442. * so that it gets loaded through JARClassLoader.
  1443. * </ol><p>
  1444. *
  1445. * On older JDK's this method does not perform any checks, and returns
  1446. * <code>true</code> (even though there is no tools.jar).
  1447. *
  1448. * @return <code>false</code> if and only if on JDK 1.2 and tools.jar
  1449. * could not be found. In this case it prints some warnings on Log,
  1450. * too, about the places where it was searched for.
  1451. * @since jEdit 3.2.2
  1452. */
  1453. public static boolean isToolsJarAvailable()
  1454. {
  1455. Log.log(Log.DEBUG, MiscUtilities.class,"Searching for tools.jar...");
  1456. Vector paths = new Vector();
  1457. //{{{ 1. Check whether tools.jar is in the system classpath:
  1458. paths.addElement("System classpath: "
  1459. + System.getProperty("java.class.path"));
  1460. try
  1461. {
  1462. // Either class sun.tools.javac.Main or
  1463. // com.sun.tools.javac.Main must be there:
  1464. try
  1465. {
  1466. Class.forName("sun.tools.javac.Main");
  1467. }
  1468. catch(ClassNotFoundException e1)
  1469. {
  1470. Class.forName("com.sun.tools.javac.Main");
  1471. }
  1472. Log.log(Log.DEBUG, MiscUtilities.class,
  1473. "- is in classpath. Fine.");
  1474. return true;
  1475. }
  1476. catch(ClassNotFoundException e)
  1477. {
  1478. //Log.log(Log.DEBUG, MiscUtilities.class,
  1479. // "- is not in system classpath.");
  1480. } //}}}
  1481. //{{{ 2. Check whether it is in the jEdit user settings jars folder:
  1482. String settingsDir = jEdit.getSettingsDirectory();
  1483. if(settingsDir != null)
  1484. {
  1485. String toolsPath = constructPath(settingsDir, "jars",
  1486. "tools.jar");
  1487. paths.addElement(toolsPath);
  1488. if(new File(toolsPath).exists())
  1489. {
  1490. Log.log(Log.DEBUG, MiscUtilities.class,
  1491. "- is in the user's jars folder. Fine.");
  1492. // jEdit will load it automatically
  1493. return true;
  1494. }
  1495. } //}}}
  1496. //{{{ 3. Check whether it is in jEdit's system jars folder:
  1497. String jEditDir = jEdit.getJEditHome();
  1498. if(jEditDir != null)
  1499. {
  1500. String toolsPath = constructPath(jEditDir, "jars", "tools.jar");
  1501. paths.addElement(toolsPath);
  1502. if(new File(toolsPath).exists())
  1503. {
  1504. Log.log(Log.DEBUG, MiscUtilities.class,
  1505. "- is in jEdit's system jars folder. Fine.");
  1506. // jEdit will load it automatically
  1507. return true;
  1508. }
  1509. } //}}}
  1510. //{{{ 4. Check whether it is in <java.home>/lib:
  1511. String toolsPath = System.getProperty("java.home");
  1512. if(toolsPath.toLowerCase().endsWith(File.separator + "jre"))
  1513. toolsPath = toolsPath.substring(0, toolsPath.length() - 4);
  1514. toolsPath = constructPath(toolsPath, "lib", "tools.jar");
  1515. paths.addElement(toolsPath);
  1516. if(!(new File(toolsPath).exists()))
  1517. {
  1518. Log.log(Log.WARNING, MiscUtilities.class,
  1519. "Could not find tools.jar.\n"
  1520. + "I checked the following locations:\n"
  1521. + paths.toString());
  1522. return false;
  1523. } //}}}
  1524. //{{{ Load it, if not yet done:
  1525. PluginJAR jar = jEdit.getPluginJAR(toolsPath);
  1526. if(jar == null)
  1527. {
  1528. Log.log(Log.DEBUG, MiscUtilities.class,
  1529. "- adding " + toolsPath + " to jEdit plugins.");
  1530. jEdit.addPluginJAR(toolsPath);
  1531. }
  1532. else
  1533. Log.log(Log.DEBUG, MiscUtilities.class,
  1534. "- has been loaded before.");
  1535. //}}}
  1536. return true;
  1537. } //}}}
  1538. //{{{ parsePermissions() method
  1539. /**
  1540. * Parse a Unix-style permission string (rwxrwxrwx).
  1541. * @param s The string (must be 9 characters long).
  1542. * @since jEdit 4.1pre8
  1543. */
  1544. public static int parsePermissions(String s)
  1545. {
  1546. int permissions = 0;
  1547. if(s.length() == 9)
  1548. {
  1549. if(s.charAt(0) == 'r')
  1550. permissions += 0400;
  1551. if(s.charAt(1) == 'w')
  1552. permissions += 0200;
  1553. if(s.charAt(2) == 'x')
  1554. permissions += 0100;
  1555. else if(s.charAt(2) == 's')
  1556. permissions += 04100;
  1557. else if(s.charAt(2) == 'S')
  1558. permissions += 04000;
  1559. if(s.charAt(3) == 'r')
  1560. permissions += 040;
  1561. if(s.charAt(4) == 'w')
  1562. permissions += 020;
  1563. if(s.charAt(5) == 'x')
  1564. permissions += 010;
  1565. else if(s.charAt(5) == 's')
  1566. permissions += 02010;
  1567. else if(s.charAt(5) == 'S')
  1568. permissions += 02000;
  1569. if(s.charAt(6) == 'r')
  1570. permissions += 04;
  1571. if(s.charAt(7) == 'w')
  1572. permissions += 02;
  1573. if(s.charAt(8) == 'x')
  1574. permissions += 01;
  1575. else if(s.charAt(8) == 't')
  1576. permissions += 01001;
  1577. else if(s.charAt(8) == 'T')
  1578. permissions += 01000;
  1579. }
  1580. return permissions;
  1581. } //}}}
  1582. //{{{ getEncodings() method
  1583. /**
  1584. * Returns a list of supported character encodings.
  1585. * @since jEdit 4.2pre5
  1586. * @deprecated See #getEncodings( boolean )
  1587. */
  1588. @Deprecated
  1589. public static String[] getEncodings()
  1590. {
  1591. return getEncodings(false);
  1592. } //}}}
  1593. //{{{ getEncodings() method
  1594. /**
  1595. * Returns a list of supported character encodings.
  1596. * @since jEdit 4.3pre5
  1597. * @param getSelected Whether to return just the selected encodings or all.
  1598. */
  1599. public static String[] getEncodings(boolean getSelected)
  1600. {
  1601. List returnValue = new ArrayList();
  1602. Map map = Charset.availableCharsets();
  1603. Iterator iter = map.keySet().iterator();
  1604. if ((getSelected && !jEdit.getBooleanProperty("encoding.opt-out."+UTF_8_Y,false)) ||
  1605. !getSelected)
  1606. {
  1607. returnValue.add(UTF_8_Y);
  1608. }
  1609. while(iter.hasNext())
  1610. {
  1611. String encoding = (String)iter.next();
  1612. if ((getSelected && !jEdit.getBooleanProperty("encoding.opt-out."+encoding,false)) ||
  1613. !getSelected)
  1614. {
  1615. returnValue.add(encoding);
  1616. }
  1617. }
  1618. return (String[])returnValue.toArray(
  1619. new String[returnValue.size()]);
  1620. } //}}}
  1621. //{{{ throwableToString() method
  1622. /**
  1623. * Returns a string containing the stack trace of the given throwable.
  1624. * @since jEdit 4.2pre6
  1625. */
  1626. public static String throwableToString(Throwable t)
  1627. {
  1628. StringWriter s = new StringWriter();
  1629. t.printStackTrace(new PrintWriter(s));
  1630. return s.toString();
  1631. } //}}}
  1632. //{{{ parseXML() method
  1633. /**
  1634. * Convenience method for parsing an XML file.
  1635. *
  1636. * @return Whether any error occured during parsing.
  1637. * @since jEdit 4.3pre5
  1638. * @deprecated Use {@link XMLUtilities#parseXML(InputStream,DefaultHandler)}.
  1639. */
  1640. @Deprecated
  1641. public static boolean parseXML(InputStream in, DefaultHandler handler)
  1642. throws IOException
  1643. {
  1644. return XMLUtilities.parseXML(in, handler);
  1645. } //}}}
  1646. //{{{ resolveEntity() method
  1647. /**
  1648. * Tries to find the given systemId in the context of the given
  1649. * class.
  1650. *
  1651. * @deprecated Use {@link XMLUtilities#findEntity(String,String,Class)}.
  1652. */
  1653. @Deprecated
  1654. public static InputSource findEntity(String systemId, String test, Class where)
  1655. {
  1656. return XMLUtilities.findEntity(systemId, test, where);
  1657. } //}}}
  1658. //{{{ Private members
  1659. private MiscUtilities() {}
  1660. //{{{ compareChars()
  1661. /** should this be public? */
  1662. private static boolean compareChars(char ch1, char ch2, boolean ignoreCase)
  1663. {
  1664. if(ignoreCase)
  1665. return Character.toUpperCase(ch1) == Character.toUpperCase(ch2);
  1666. else
  1667. return ch1 == ch2;
  1668. } //}}}
  1669. //{{{ getPathStart()
  1670. private static int getPathStart(String path)
  1671. {
  1672. int start = 0;
  1673. if(path.startsWith("/"))
  1674. return 1;
  1675. else if(OperatingSystem.isDOSDerived()
  1676. && path.length() >= 3
  1677. && path.charAt(1) == ':'
  1678. && (path.charAt(2) == '/'
  1679. || path.charAt(2) == '\\'))
  1680. return 3;
  1681. else
  1682. return 0;
  1683. } //}}}
  1684. //}}}
  1685. }