PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/MiscUtilities.java

#
Java | 1972 lines | 1139 code | 162 blank | 671 comment | 343 complexity | 6283d17e12280140fa2f021207069bfd 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

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file