PageRenderTime 55ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
Java | 1097 lines | 682 code | 102 blank | 313 comment | 108 complexity | 341b6d36ad0a6db7dd728691a8c13550 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, 2000, 2001 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 gnu.regexp.RE;
  27. import javax.swing.JMenuItem;
  28. import java.io.*;
  29. import java.util.*;
  30. import org.gjt.sp.jedit.io.*;
  31. import org.gjt.sp.util.Log;
  32. //}}}
  33. /**
  34. * Class with several useful miscellaneous functions.
  35. *
  36. * @author Slava Pestov
  37. * @version $Id: MiscUtilities.java 3958 2002-01-02 04:49:59Z spestov $
  38. */
  39. public class MiscUtilities
  40. {
  41. //{{{ Path name methods. Mostly for local files only
  42. //{{{ canonPath() method
  43. /**
  44. * Returns the canonical form of the specified path name. Currently
  45. * only expands a leading <code>~</code>. <b>For local path names
  46. * only.</b>
  47. * @param path The path name
  48. * @since jEdit 4.0pre2
  49. */
  50. public static String canonPath(String path)
  51. {
  52. if(File.separatorChar == '\\')
  53. {
  54. // get rid of mixed paths on Windows
  55. path = path.replace('/','\\');
  56. }
  57. if(path.startsWith("~" + File.separator))
  58. {
  59. path = path.substring(2);
  60. String home = System.getProperty("user.home");
  61. if(home.endsWith(File.separator))
  62. return home + path;
  63. else
  64. return home + File.separator + path;
  65. }
  66. else if(path.equals("~"))
  67. return System.getProperty("user.home");
  68. else
  69. return path;
  70. } //}}}
  71. //{{{ constructPath() method
  72. /**
  73. * Constructs an absolute path name from a directory and another
  74. * path name. This method is VFS-aware.
  75. * @param parent The directory
  76. * @param path The path name
  77. */
  78. public static String constructPath(String parent, String path)
  79. {
  80. if(MiscUtilities.isURL(path))
  81. return path;
  82. else if(path.startsWith("~"))
  83. return path;
  84. else
  85. {
  86. File file = new File(path);
  87. if(file.isAbsolute())
  88. {
  89. try
  90. {
  91. return file.getCanonicalPath();
  92. }
  93. catch(IOException io)
  94. {
  95. return path;
  96. }
  97. }
  98. }
  99. if(parent == null)
  100. parent = System.getProperty("user.dir");
  101. VFS vfs = VFSManager.getVFSForPath(parent);
  102. return vfs.constructPath(parent,path);
  103. } //}}}
  104. //{{{ constructPath() method
  105. /**
  106. * Constructs an absolute path name from three path components.
  107. * This method is VFS-aware.
  108. * @param parent The parent directory
  109. * @param path1 The first path
  110. * @param path2 The second path
  111. */
  112. public static String constructPath(String parent,
  113. String path1, String path2)
  114. {
  115. return constructPath(constructPath(parent,path1),path2);
  116. } //}}}
  117. //{{{ concatPath() method
  118. /**
  119. * Like constructPath(), except <code>path</code> will be
  120. * appended to <code>parent</code> even if it is absolute.
  121. * @param path
  122. * @param parent
  123. */
  124. public static String concatPath(String parent, String path)
  125. {
  126. parent = canonPath(parent);
  127. path = canonPath(path);
  128. // Make all child paths relative.
  129. if (path.startsWith(File.separator))
  130. path = path.substring(1);
  131. else if ((path.length() >= 3) && (path.charAt(1) == ':'))
  132. path = path.replace(':', File.separatorChar);
  133. if (parent == null)
  134. parent = System.getProperty("user.dir");
  135. if (parent.endsWith(File.separator))
  136. return parent + path;
  137. else
  138. return parent + File.separator + path;
  139. } //}}}
  140. //{{{ getFileExtension() method
  141. /**
  142. * Returns the extension of the specified filename, or an empty
  143. * string if there is none.
  144. * @param name The file name
  145. */
  146. public static String getFileExtension(String name)
  147. {
  148. int index = name.indexOf('.');
  149. if(index == -1)
  150. return "";
  151. else
  152. return name.substring(index);
  153. } //}}}
  154. //{{{ getFileName() method
  155. /**
  156. * Returns the last component of the specified path.
  157. * This method is VFS-aware.
  158. * @param path The path name
  159. */
  160. public static String getFileName(String path)
  161. {
  162. if(isURL(path))
  163. {
  164. VFS vfs = VFSManager.getVFSForPath(path);
  165. return vfs.getFileName(path);
  166. }
  167. else
  168. return VFSManager.getFileVFS().getFileName(path);
  169. } //}}}
  170. //{{{ getFileParent() method
  171. /**
  172. * @deprecated Call getParentOfPath() instead
  173. */
  174. public static String getFileParent(String path)
  175. {
  176. return getParentOfPath(path);
  177. } //}}}
  178. //{{{ getParentOfPath() method
  179. /**
  180. * Returns the parent of the specified path. This method is VFS-aware.
  181. * @param path The path name
  182. * @since jEdit 2.6pre5
  183. */
  184. public static String getParentOfPath(String path)
  185. {
  186. if(isURL(path))
  187. {
  188. VFS vfs = VFSManager.getVFSForPath(path);
  189. return vfs.getParentOfPath(path);
  190. }
  191. else
  192. return VFSManager.getFileVFS().getParentOfPath(path);
  193. } //}}}
  194. //{{{ getFileProtocol() method
  195. /**
  196. * @deprecated Call getProtocolOfURL() instead
  197. */
  198. public static String getFileProtocol(String url)
  199. {
  200. return getProtocolOfURL(url);
  201. } //}}}
  202. //{{{ getProtocolOfURL() method
  203. /**
  204. * Returns the protocol specified by a URL.
  205. * @param url The URL
  206. * @since jEdit 2.6pre5
  207. */
  208. public static String getProtocolOfURL(String url)
  209. {
  210. return url.substring(0,url.indexOf(':'));
  211. } //}}}
  212. //{{{ isURL() method
  213. /**
  214. * Checks if the specified string is a URL.
  215. * @param str The string to check
  216. * @return True if the string is a URL, false otherwise
  217. */
  218. public static boolean isURL(String str)
  219. {
  220. int fsIndex = Math.max(str.indexOf(File.separatorChar),
  221. str.indexOf('/'));
  222. if(fsIndex == 0) // /etc/passwd
  223. return false;
  224. else if(fsIndex == 2) // C:\AUTOEXEC.BAT
  225. return false;
  226. int cIndex = str.indexOf(':');
  227. if(cIndex <= 1) // D:\WINDOWS
  228. return false;
  229. else if(fsIndex != -1 && cIndex > fsIndex) // /tmp/RTF::read.pm
  230. return false;
  231. return true;
  232. } //}}}
  233. //{{{ saveBackup() method
  234. /**
  235. * Saves a backup (optionally numbered) of a file.
  236. * @param file A local file
  237. * @param backups The number of backups. Must be >= 1. If > 1, backup
  238. * files will be numbered.
  239. * @param backupPrefix The backup file name prefix
  240. * @param backupSuffix The backup file name suffix
  241. * @param backupDirectory The directory where to save backups; if null,
  242. * they will be saved in the same directory as the file itself.
  243. * @since jEdit 4.0pre1
  244. */
  245. public static void saveBackup(File file, int backups,
  246. String backupPrefix, String backupSuffix,
  247. String backupDirectory)
  248. {
  249. if(backupPrefix == null)
  250. backupPrefix = "";
  251. if(backupSuffix == null)
  252. backupSuffix = "";
  253. String name = file.getName();
  254. // If backups is 1, create ~ file
  255. if(backups == 1)
  256. {
  257. file.renameTo(new File(backupDirectory,
  258. backupPrefix + name + backupSuffix));
  259. }
  260. // If backups > 1, move old ~n~ files, create ~1~ file
  261. else
  262. {
  263. new File(backupDirectory,
  264. backupPrefix + name + backupSuffix
  265. + backups + backupSuffix).delete();
  266. for(int i = backups - 1; i > 0; i--)
  267. {
  268. File backup = new File(backupDirectory,
  269. backupPrefix + name + backupSuffix
  270. + i + backupSuffix);
  271. backup.renameTo(new File(backupDirectory,
  272. backupPrefix + name + backupSuffix
  273. + (i+1) + backupSuffix));
  274. }
  275. file.renameTo(new File(backupDirectory,
  276. backupPrefix + name + backupSuffix
  277. + "1" + backupSuffix));
  278. }
  279. } //}}}
  280. //}}}
  281. //{{{ Text methods
  282. //{{{ getLeadingWhiteSpace() method
  283. /**
  284. * Returns the number of leading white space characters in the
  285. * specified string.
  286. * @param str The string
  287. */
  288. public static int getLeadingWhiteSpace(String str)
  289. {
  290. int whitespace = 0;
  291. loop: for(;whitespace < str.length();)
  292. {
  293. switch(str.charAt(whitespace))
  294. {
  295. case ' ': case '\t':
  296. whitespace++;
  297. break;
  298. default:
  299. break loop;
  300. }
  301. }
  302. return whitespace;
  303. } //}}}
  304. //{{{ getTrailingWhiteSpace() method
  305. /**
  306. * Returns the number of trailing whitespace characters in the
  307. * specified string.
  308. * @param str The string
  309. * @since jEdit 2.5pre5
  310. */
  311. public static int getTrailingWhiteSpace(String str)
  312. {
  313. int whitespace = 0;
  314. loop: for(int i = str.length() - 1; i >= 0; i--)
  315. {
  316. switch(str.charAt(i))
  317. {
  318. case ' ': case '\t':
  319. whitespace++;
  320. break;
  321. default:
  322. break loop;
  323. }
  324. }
  325. return whitespace;
  326. } //}}}
  327. //{{{ getLeadingWhiteSpaceWidth() method
  328. /**
  329. * Returns the width of the leading white space in the specified
  330. * string.
  331. * @param str The string
  332. * @param tabSize The tab size
  333. */
  334. public static int getLeadingWhiteSpaceWidth(String str, int tabSize)
  335. {
  336. int whitespace = 0;
  337. loop: for(int i = 0; i < str.length(); i++)
  338. {
  339. switch(str.charAt(i))
  340. {
  341. case ' ':
  342. whitespace++;
  343. break;
  344. case '\t':
  345. whitespace += (tabSize - whitespace % tabSize);
  346. break;
  347. default:
  348. break loop;
  349. }
  350. }
  351. return whitespace;
  352. } //}}}
  353. //{{{ createWhiteSpace() method
  354. /**
  355. * Creates a string of white space with the specified length.
  356. * @param len The length
  357. * @param tabSize The tab size, or 0 if tabs are not to be used
  358. */
  359. public static String createWhiteSpace(int len, int tabSize)
  360. {
  361. StringBuffer buf = new StringBuffer();
  362. if(tabSize == 0)
  363. {
  364. while(len-- > 0)
  365. buf.append(' ');
  366. }
  367. else
  368. {
  369. int count = len / tabSize;
  370. while(count-- > 0)
  371. buf.append('\t');
  372. count = len % tabSize;
  373. while(count-- > 0)
  374. buf.append(' ');
  375. }
  376. return buf.toString();
  377. } //}}}
  378. //{{{ globToRE() method
  379. /**
  380. * Converts a Unix-style glob to a regular expression.
  381. * ? becomes ., * becomes .*, {aa,bb} becomes (aa|bb).
  382. * @param glob The glob pattern
  383. */
  384. public static String globToRE(String glob)
  385. {
  386. StringBuffer buf = new StringBuffer();
  387. boolean backslash = false;
  388. boolean insideGroup = false;
  389. for(int i = 0; i < glob.length(); i++)
  390. {
  391. char c = glob.charAt(i);
  392. if(backslash)
  393. {
  394. buf.append('\\');
  395. buf.append(c);
  396. backslash = false;
  397. continue;
  398. }
  399. switch(c)
  400. {
  401. case '\\':
  402. backslash = true;
  403. break;
  404. case '?':
  405. buf.append('.');
  406. break;
  407. case '.':
  408. buf.append("\\.");
  409. break;
  410. case '*':
  411. buf.append(".*");
  412. break;
  413. case '{':
  414. buf.append('(');
  415. insideGroup = true;
  416. break;
  417. case ',':
  418. if(insideGroup)
  419. buf.append('|');
  420. else
  421. buf.append(',');
  422. break;
  423. case '}':
  424. buf.append(')');
  425. insideGroup = false;
  426. break;
  427. default:
  428. buf.append(c);
  429. }
  430. }
  431. return buf.toString();
  432. } //}}}
  433. //{{{ escapesToChars() method
  434. /**
  435. * Converts "\n" and "\t" escapes in the specified string to
  436. * newlines and tabs.
  437. * @param str The string
  438. * @since jEdit 2.3pre1
  439. */
  440. public static String escapesToChars(String str)
  441. {
  442. StringBuffer buf = new StringBuffer();
  443. for(int i = 0; i < str.length(); i++)
  444. {
  445. char c = str.charAt(i);
  446. switch(c)
  447. {
  448. case '\\':
  449. if(i == str.length() - 1)
  450. {
  451. buf.append('\\');
  452. break;
  453. }
  454. c = str.charAt(++i);
  455. switch(c)
  456. {
  457. case 'n':
  458. buf.append('\n');
  459. break;
  460. case 't':
  461. buf.append('\t');
  462. break;
  463. default:
  464. buf.append(c);
  465. break;
  466. }
  467. break;
  468. default:
  469. buf.append(c);
  470. }
  471. }
  472. return buf.toString();
  473. } //}}}
  474. //{{{ charsToEscapes() method
  475. /**
  476. * Escapes newlines, tabs, backslashes, quotes in the specified
  477. * string.
  478. * @param str The string
  479. * @since jEdit 2.3pre1
  480. */
  481. public static String charsToEscapes(String str)
  482. {
  483. return charsToEscapes(str,false);
  484. } //}}}
  485. //{{{ charsToEscapes() method
  486. /**
  487. * Escapes newlines, tabs, backslashes, quotes in the specified
  488. * string.
  489. * @param str The string
  490. * @param history jEdit history files require additional escaping
  491. * @since jEdit 2.7pre2
  492. */
  493. public static String charsToEscapes(String str, boolean history)
  494. {
  495. StringBuffer buf = new StringBuffer();
  496. for(int i = 0; i < str.length(); i++)
  497. {
  498. char c = str.charAt(i);
  499. switch(c)
  500. {
  501. case '\n':
  502. buf.append("\\n");
  503. break;
  504. case '\t':
  505. buf.append("\\t");
  506. break;
  507. case '[':
  508. if(history)
  509. buf.append("\\[");
  510. else
  511. buf.append(c);
  512. break;
  513. case ']':
  514. if(history)
  515. buf.append("\\]");
  516. else
  517. buf.append(c);
  518. break;
  519. case '"':
  520. if(history)
  521. buf.append(c);
  522. else
  523. buf.append("\\\"");
  524. break;
  525. case '\'':
  526. if(history)
  527. buf.append(c);
  528. else
  529. buf.append("\\\'");
  530. break;
  531. case '\\':
  532. buf.append("\\\\");
  533. break;
  534. default:
  535. buf.append(c);
  536. break;
  537. }
  538. }
  539. return buf.toString();
  540. } //}}}
  541. //{{{ compareVersions() method
  542. /**
  543. * @deprecated Call <code>compareStrings()</code> instead
  544. */
  545. public static int compareVersions(String v1, String v2)
  546. {
  547. return compareStrings(v1,v2,false);
  548. } //}}}
  549. //{{{ compareStrings() method
  550. /**
  551. * A more intelligent version of String.compareTo() that handles
  552. * numbers specially. For example, it places "My file 2" before
  553. * "My file 10".
  554. * @param str1 The first string
  555. * @param str2 The second string
  556. * @param ignoreCase If true, case will be ignored
  557. * @return negative If str1 &lt; str2, 0 if both are the same,
  558. * positive if str1 &gt; str2
  559. * @since jEdit 4.0pre1
  560. */
  561. public static int compareStrings(String str1, String str2, boolean ignoreCase)
  562. {
  563. char[] char1 = str1.toCharArray();
  564. char[] char2 = str2.toCharArray();
  565. int len = Math.min(char1.length,char2.length);
  566. for(int i = 0, j = 0; i < len && j < len; i++, j++)
  567. {
  568. char ch1 = char1[i];
  569. char ch2 = char2[j];
  570. if(Character.isDigit(ch1) && Character.isDigit(ch2)
  571. && ch1 != '0' && ch2 != '0')
  572. {
  573. int _i = i + 1;
  574. int _j = j + 1;
  575. for(; _i < char1.length; _i++)
  576. {
  577. if(!Character.isDigit(char1[_i]))
  578. {
  579. //_i--;
  580. break;
  581. }
  582. }
  583. for(; _j < char2.length; _j++)
  584. {
  585. if(!Character.isDigit(char2[_j]))
  586. {
  587. //_j--;
  588. break;
  589. }
  590. }
  591. int len1 = _i - i;
  592. int len2 = _j - j;
  593. if(len1 > len2)
  594. return 1;
  595. else if(len1 < len2)
  596. return -1;
  597. else
  598. {
  599. for(int k = 0; k < len1; k++)
  600. {
  601. ch1 = char1[i + k];
  602. ch2 = char2[j + k];
  603. if(ch1 != ch2)
  604. return ch1 - ch2;
  605. }
  606. }
  607. i = _i - 1;
  608. j = _j - 1;
  609. }
  610. else
  611. {
  612. if(ignoreCase)
  613. {
  614. ch1 = Character.toLowerCase(ch1);
  615. ch2 = Character.toLowerCase(ch2);
  616. }
  617. if(ch1 != ch2)
  618. return ch1 - ch2;
  619. }
  620. }
  621. return char1.length - char2.length;
  622. } //}}}
  623. //}}}
  624. //{{{ Sorting methods
  625. //{{{ quicksort() method
  626. /**
  627. * Sorts the specified array. Equivalent to calling
  628. * <code>Arrays.sort()</code>.
  629. * @param obj The array
  630. * @param compare Compares the objects
  631. * @since jEdit 4.0pre4
  632. */
  633. public static void quicksort(Object[] obj, Comparator compare)
  634. {
  635. Arrays.sort(obj,compare);
  636. } //}}}
  637. //{{{ quicksort() method
  638. /**
  639. * Sorts the specified vector.
  640. * @param vector The vector
  641. * @param compare Compares the objects
  642. * @since jEdit 4.0pre4
  643. */
  644. public static void quicksort(Vector vector, Comparator compare)
  645. {
  646. quicksort((List)vector,compare);
  647. } //}}}
  648. //{{{ quicksort() method
  649. /**
  650. * Sorts the specified list.
  651. * @param list The list
  652. * @param compare Compares the objects
  653. * @since jEdit 4.0pre4
  654. */
  655. public static void quicksort(List list, Comparator compare)
  656. {
  657. if(list.size() == 0)
  658. return;
  659. quicksort(list,0,list.size() - 1,compare);
  660. } //}}}
  661. //{{{ quicksort() method
  662. /**
  663. * Sorts the specified array. Equivalent to calling
  664. * <code>Arrays.sort()</code>.
  665. * @param obj The array
  666. * @param compare Compares the objects
  667. */
  668. public static void quicksort(Object[] obj, Compare compare)
  669. {
  670. Arrays.sort(obj,compare);
  671. } //}}}
  672. //{{{ quicksort() method
  673. /**
  674. * Sorts the specified vector.
  675. * @param vector The vector
  676. * @param compare Compares the objects
  677. */
  678. public static void quicksort(Vector vector, Compare compare)
  679. {
  680. quicksort((List)vector,(Comparator)compare);
  681. } //}}}
  682. //{{{ Compare interface
  683. /**
  684. * An interface for comparing objects.
  685. */
  686. public interface Compare extends Comparator
  687. {
  688. int compare(Object obj1, Object obj2);
  689. } //}}}
  690. //{{{ StringCompare class
  691. /**
  692. * Compares strings.
  693. */
  694. public static class StringCompare implements Compare
  695. {
  696. public int compare(Object obj1, Object obj2)
  697. {
  698. return compareStrings(obj1.toString(),
  699. obj2.toString(),false);
  700. }
  701. } //}}}
  702. //{{{ StringICaseCompare class
  703. /**
  704. * Compares strings ignoring case.
  705. */
  706. public static class StringICaseCompare implements Compare
  707. {
  708. public int compare(Object obj1, Object obj2)
  709. {
  710. return compareStrings(obj1.toString(),
  711. obj2.toString(),true);
  712. }
  713. } //}}}
  714. //{{{ MenuItemCompare class
  715. public static class MenuItemCompare implements Compare
  716. {
  717. public int compare(Object obj1, Object obj2)
  718. {
  719. return compareStrings(((JMenuItem)obj1).getText(),
  720. ((JMenuItem)obj2).getText(),true);
  721. }
  722. } //}}}
  723. //}}}
  724. //{{{ fileToClass() method
  725. /**
  726. * Converts a file name to a class name. All slash characters are
  727. * replaced with periods and the trailing '.class' is removed.
  728. * @param name The file name
  729. */
  730. public static String fileToClass(String name)
  731. {
  732. char[] clsName = name.toCharArray();
  733. for(int i = clsName.length - 6; i >= 0; i--)
  734. if(clsName[i] == '/')
  735. clsName[i] = '.';
  736. return new String(clsName,0,clsName.length - 6);
  737. } //}}}
  738. //{{{ classToFile() method
  739. /**
  740. * Converts a class name to a file name. All periods are replaced
  741. * with slashes and the '.class' extension is added.
  742. * @param name The class name
  743. */
  744. public static String classToFile(String name)
  745. {
  746. return name.replace('.','/').concat(".class");
  747. } //}}}
  748. //{{{ buildToVersion() method
  749. /**
  750. * Converts an internal version number (build) into a
  751. * `human-readable' form.
  752. * @param build The build
  753. */
  754. public static String buildToVersion(String build)
  755. {
  756. if(build.length() != 11)
  757. return "<unknown version: " + build + ">";
  758. // First 2 chars are the major version number
  759. int major = Integer.parseInt(build.substring(0,2));
  760. // Second 2 are the minor number
  761. int minor = Integer.parseInt(build.substring(3,5));
  762. // Then the pre-release status
  763. int beta = Integer.parseInt(build.substring(6,8));
  764. // Finally the bug fix release
  765. int bugfix = Integer.parseInt(build.substring(9,11));
  766. return "" + major + "." + minor
  767. + (beta != 99 ? "pre" + beta :
  768. (bugfix != 0 ? "." + bugfix : "final"));
  769. } //}}}
  770. //{{{ isToolsJarAvailable() method
  771. /**
  772. * If on JDK 1.2 or higher, make sure that tools.jar is available.
  773. * This method should be called by plugins requiring the classes
  774. * in this library.
  775. * <p>
  776. * tools.jar is searched for in the following places:
  777. * <ol>
  778. * <li>the classpath that was used when jEdit was started,
  779. * <li>jEdit's jars folder in the user's home,
  780. * <li>jEdit's system jars folder,
  781. * <li><i>java.home</i>/lib/. In this case, tools.jar is added to
  782. * jEdit's list of known jars using jEdit.addPluginJAR(),
  783. * so that it gets loaded through JARClassLoader.
  784. * </ol><p>
  785. *
  786. * On older JDK's this method does not perform any checks, and returns
  787. * <code>true</code> (even though there is no tools.jar).
  788. *
  789. * @return <code>false</code> if and only if on JDK 1.2 and tools.jar
  790. * could not be found. In this case it prints some warnings on Log,
  791. * too, about the places where it was searched for.
  792. * @since jEdit 3.2.2
  793. */
  794. public static boolean isToolsJarAvailable()
  795. {
  796. Log.log(Log.DEBUG, MiscUtilities.class,"Searching for tools.jar...");
  797. Vector paths = new Vector();
  798. //{{{ 1. Check whether tools.jar is in the system classpath:
  799. paths.addElement("System classpath: "
  800. + System.getProperty("java.class.path"));
  801. try
  802. {
  803. // Either class sun.tools.javac.Main or
  804. // com.sun.tools.javac.Main must be there:
  805. try
  806. {
  807. Class.forName("sun.tools.javac.Main");
  808. }
  809. catch(ClassNotFoundException e1)
  810. {
  811. Class.forName("com.sun.tools.javac.Main");
  812. }
  813. Log.log(Log.DEBUG, MiscUtilities.class,
  814. "- is in classpath. Fine.");
  815. return true;
  816. }
  817. catch(ClassNotFoundException e)
  818. {
  819. //Log.log(Log.DEBUG, MiscUtilities.class,
  820. // "- is not in system classpath.");
  821. } //}}}
  822. //{{{ 2. Check whether it is in the jEdit user settings jars folder:
  823. String settingsDir = jEdit.getSettingsDirectory();
  824. if(settingsDir != null)
  825. {
  826. String toolsPath = constructPath(settingsDir, "jars",
  827. "tools.jar");
  828. paths.addElement(toolsPath);
  829. if(new File(toolsPath).exists())
  830. {
  831. Log.log(Log.DEBUG, MiscUtilities.class,
  832. "- is in the user's jars folder. Fine.");
  833. // jEdit will load it automatically
  834. return true;
  835. }
  836. } //}}}
  837. //{{{ 3. Check whether it is in jEdit's system jars folder:
  838. String jEditDir = jEdit.getJEditHome();
  839. if(jEditDir != null)
  840. {
  841. String toolsPath = constructPath(jEditDir, "jars", "tools.jar");
  842. paths.addElement(toolsPath);
  843. if(new File(toolsPath).exists())
  844. {
  845. Log.log(Log.DEBUG, MiscUtilities.class,
  846. "- is in jEdit's system jars folder. Fine.");
  847. // jEdit will load it automatically
  848. return true;
  849. }
  850. } //}}}
  851. //{{{ 4. Check whether it is in <java.home>/lib:
  852. String toolsPath = System.getProperty("java.home");
  853. if(toolsPath.toLowerCase().endsWith(File.separator + "jre"))
  854. toolsPath = toolsPath.substring(0, toolsPath.length() - 4);
  855. toolsPath = constructPath(toolsPath, "lib", "tools.jar");
  856. paths.addElement(toolsPath);
  857. if(!(new File(toolsPath).exists()))
  858. {
  859. Log.log(Log.WARNING, MiscUtilities.class,
  860. "Could not find tools.jar.\n"
  861. + "I checked the following locations:\n"
  862. + paths.toString());
  863. return false;
  864. } //}}}
  865. //{{{ Load it, if not yet done:
  866. EditPlugin.JAR jar = jEdit.getPluginJAR(toolsPath);
  867. if(jar == null)
  868. {
  869. Log.log(Log.DEBUG, MiscUtilities.class,
  870. "- adding " + toolsPath + " to jEdit plugins.");
  871. try
  872. {
  873. jEdit.addPluginJAR(new EditPlugin.JAR(toolsPath,
  874. new JARClassLoader(toolsPath)));
  875. }
  876. catch(IOException ioex)
  877. {
  878. Log.log(Log.ERROR, MiscUtilities.class,
  879. "- I/O error loading " + toolsPath);
  880. Log.log(Log.ERROR, MiscUtilities.class, ioex);
  881. return false;
  882. }
  883. }
  884. else
  885. Log.log(Log.DEBUG, MiscUtilities.class,
  886. "- has been loaded before.");
  887. //}}}
  888. return true;
  889. } //}}}
  890. //{{{ listFiles() method
  891. /**
  892. * Returns an array containing the full path names of all files
  893. * within the specified directory that match the specified file
  894. * name glob.
  895. * @param directory The directory path
  896. * @param glob The file name glob
  897. * @param recurse If true, subdirectories will be listed as well
  898. */
  899. public static String[] listDirectory(String directory, String glob,
  900. boolean recurse)
  901. {
  902. Log.log(Log.DEBUG,MiscUtilities.class,"Listing " + directory);
  903. Vector files = new Vector(100);
  904. RE filter;
  905. try
  906. {
  907. filter = new RE(globToRE(glob));
  908. }
  909. catch(Exception e)
  910. {
  911. Log.log(Log.ERROR,MiscUtilities.class,e);
  912. return null;
  913. }
  914. listDirectory(new Vector(),files,new File(directory),filter,recurse);
  915. String[] retVal = new String[files.size()];
  916. files.copyInto(retVal);
  917. quicksort(retVal,new StringICaseCompare());
  918. return retVal;
  919. } //}}}
  920. //{{{ Private members
  921. private MiscUtilities() {}
  922. //{{{ quicksort() method
  923. private static void quicksort(List obj, int _start, int _end, Comparator compare)
  924. {
  925. int start = _start;
  926. int end = _end;
  927. Object mid = obj.get((_start + _end) / 2);
  928. if(_start > _end)
  929. return;
  930. while(start <= end)
  931. {
  932. while((start < _end) && (compare.compare(obj.get(start),mid) < 0))
  933. start++;
  934. while((end > _start) && (compare.compare(obj.get(end),mid) > 0))
  935. end--;
  936. if(start <= end)
  937. {
  938. Object o = obj.get(start);
  939. obj.set(start,obj.get(end));
  940. obj.set(end,o);
  941. start++;
  942. end--;
  943. }
  944. }
  945. if(_start < end)
  946. quicksort(obj,_start,end,compare);
  947. if(start < _end)
  948. quicksort(obj,start,_end,compare);
  949. } //}}}
  950. //{{{ listDirectory() method
  951. private static void listDirectory(Vector stack, Vector files,
  952. File directory, RE filter, boolean recurse)
  953. {
  954. if(stack.contains(directory))
  955. {
  956. Log.log(Log.ERROR,MiscUtilities.class,
  957. "Recursion in listDirectory(): "
  958. + directory.getPath());
  959. return;
  960. }
  961. else
  962. stack.addElement(directory);
  963. File[] _files = directory.listFiles();
  964. if(_files == null)
  965. return;
  966. for(int i = 0; i < _files.length; i++)
  967. {
  968. File file = _files[i];
  969. if(file.isDirectory())
  970. {
  971. if(recurse)
  972. {
  973. // resolve symlinks to avoid loops
  974. try
  975. {
  976. file = new File(file.getCanonicalPath());
  977. }
  978. catch(IOException io)
  979. {
  980. }
  981. listDirectory(stack,files,file,filter,recurse);
  982. }
  983. }
  984. else
  985. {
  986. if(!filter.isMatch(file.getName()))
  987. continue;
  988. String path = file.getPath();
  989. Log.log(Log.DEBUG,MiscUtilities.class,path);
  990. files.addElement(path);
  991. }
  992. }
  993. } //}}}
  994. //}}}
  995. }