PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Console/tags/release-2-6/console/DefaultShell.java

#
Java | 558 lines | 461 code | 56 blank | 41 comment | 72 complexity | 24cf1857f32d457836411705c925c7a4 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. * DefaultShell.java - Executes OS commands
  3. * Copyright (C) 1999, 2000, 2001 Slava Pestov
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. package console;
  20. import java.lang.reflect.*;
  21. import java.io.*;
  22. import java.util.Hashtable;
  23. import java.util.Vector;
  24. import org.gjt.sp.jedit.*;
  25. import org.gjt.sp.util.Log;
  26. class DefaultShell extends Shell
  27. {
  28. public DefaultShell()
  29. {
  30. super("Console");
  31. try
  32. {
  33. Class[] classes = { String[].class, String[].class, File.class };
  34. java13exec = Runtime.class.getMethod("exec",classes);
  35. }
  36. catch(Exception e)
  37. {
  38. // do nothing
  39. }
  40. dir = System.getProperty("user.dir");
  41. String osName = System.getProperty("os.name");
  42. appendEXE = (osName.indexOf("Windows") != -1 ||
  43. osName.indexOf("OS/2") != -1);
  44. if(appendEXE)
  45. initTableWinBuiltIns();
  46. }
  47. public void printInfoMessage(Console console)
  48. {
  49. console.printInfo(jEdit.getProperty("console.shell.info"));
  50. }
  51. public void execute(View view, String command, Console console)
  52. {
  53. stop();
  54. ConsolePlugin.clearErrors();
  55. // We replace \ with a non-printable char because
  56. // StreamTokenizer handles \ specially, which causes
  57. // problems on Windows as \ is the file separator
  58. // there.
  59. // After parsing is done, the non printable char is
  60. // changed to \ once again.
  61. // StreamTokenizer needs a way to disable backslash
  62. // handling...
  63. String rawCommand = command;
  64. if(appendEXE)
  65. command = rawCommand.replace('\\',winSlash);
  66. StreamTokenizer st = new StreamTokenizer(new StringReader(command));
  67. st.resetSyntax();
  68. st.wordChars('!',255);
  69. st.whitespaceChars(0,' ');
  70. st.quoteChar('"');
  71. st.quoteChar('\'');
  72. Vector args = new Vector();
  73. StringBuffer buf = new StringBuffer();
  74. try
  75. {
  76. loop: for(;;)
  77. {
  78. switch(st.nextToken())
  79. {
  80. case StreamTokenizer.TT_EOF:
  81. break loop;
  82. case StreamTokenizer.TT_WORD:
  83. case '"':
  84. case '\'':
  85. args.addElement(expandVariables(view,
  86. st.sval,buf));
  87. break;
  88. }
  89. }
  90. }
  91. catch(IOException io)
  92. {
  93. String[] pp = { io.getMessage() };
  94. console.printError(jEdit.getProperty("console.shell.ioerror",pp));
  95. }
  96. if(args.size() == 0)
  97. {
  98. exitStatus = false;
  99. return;
  100. }
  101. String executable = (String)args.elementAt(0);
  102. if(executable.equals("pwd"))
  103. {
  104. if(args.size() != 1)
  105. {
  106. console.printError(jEdit.getProperty("console.shell.pwd-usage"));
  107. exitStatus = false;
  108. }
  109. else
  110. {
  111. console.printPlain(dir);
  112. exitStatus = true;
  113. }
  114. return;
  115. }
  116. else if(executable.equals("cd"))
  117. {
  118. if(java13exec == null)
  119. {
  120. console.printError(jEdit.getProperty("console.shell.cd-unsup"));
  121. exitStatus = false;
  122. }
  123. else if(args.size() != 2)
  124. {
  125. console.printError(jEdit.getProperty("console.shell.cd-usage"));
  126. exitStatus = false;
  127. }
  128. else
  129. {
  130. String newDir = (String)args.elementAt(1);
  131. if(newDir.equals(".."))
  132. newDir = MiscUtilities.getParentOfPath(dir);
  133. else
  134. newDir = MiscUtilities.constructPath(dir,newDir);
  135. String[] pp = { newDir };
  136. if(new File(newDir).exists())
  137. {
  138. dir = newDir;
  139. console.printPlain(jEdit.getProperty("console.shell.cd",pp));
  140. exitStatus = true;
  141. }
  142. else
  143. {
  144. console.printError(jEdit.getProperty("console.shell.cd-error",pp));
  145. exitStatus = false;
  146. }
  147. }
  148. return;
  149. }
  150. else if(appendEXE && tableWinBuiltIns.contains(executable))
  151. {
  152. // which command interpreter?
  153. if(System.getProperty("os.name").indexOf("Windows 9") != -1)
  154. args.insertElementAt("command.com",0);
  155. else
  156. args.insertElementAt("cmd.exe",0);
  157. executable = (String)args.elementAt(0);
  158. args.insertElementAt("/C",1);
  159. }
  160. // Hack to look for executable in current directory
  161. String cdPath = dir + System.getProperty("file.separator");
  162. if( tryExtensions( cdPath, executable, args, console ) == null )
  163. {
  164. // Now try the executable found along the PATH
  165. if( tryExtensions( null, executable, args, console ) == null )
  166. {
  167. exitStatus = false;
  168. return;
  169. }
  170. }
  171. this.command = rawCommand;
  172. this.console = console;
  173. stdout = new StdoutThread();
  174. stderr = new StderrThread();
  175. }
  176. public synchronized void stop()
  177. {
  178. if(command != null)
  179. {
  180. stdout.stop();
  181. stderr.stop();
  182. process.destroy();
  183. String[] args = { command };
  184. console.printError(jEdit.getProperty("console.shell.killed",args));
  185. exitStatus = false;
  186. commandDone();
  187. }
  188. }
  189. public synchronized boolean waitFor()
  190. {
  191. if(command != null)
  192. {
  193. try
  194. {
  195. wait();
  196. }
  197. catch(InterruptedException ie)
  198. {
  199. return false;
  200. }
  201. }
  202. return exitStatus;
  203. }
  204. // private members
  205. private static final char winSlash = 127;
  206. private String command;
  207. private Console console;
  208. private Process process;
  209. private Thread stdout;
  210. private Thread stderr;
  211. private String dir;
  212. private Method java13exec;
  213. private boolean appendEXE;
  214. private int threadDoneCount;
  215. private boolean exitStatus;
  216. // used to store built-in commands
  217. private Hashtable tableWinBuiltIns;
  218. /**
  219. Specical processing for some well known Windows file extensions.
  220. */
  221. private Process tryExtensions( String currentDir,
  222. String executable,
  223. Vector args,
  224. Console console ) {
  225. String[] extensionsToTry;
  226. if(appendEXE && executable.indexOf('.') == -1)
  227. extensionsToTry = new String[] { ".cmd", ".bat", ".com", ".exe" };
  228. else
  229. extensionsToTry = new String[] { "" };
  230. String[] _args = new String[args.size()];
  231. args.copyInto(_args);
  232. for(int i = 0; i < extensionsToTry.length; i++)
  233. {
  234. if( currentDir == null )
  235. {
  236. _args[0] = executable + extensionsToTry[i];
  237. }
  238. else
  239. {
  240. String exeFullPath = currentDir + executable + extensionsToTry[i];
  241. File exeFile = new File( exeFullPath );
  242. if( !exeFile.exists() )
  243. return null;
  244. _args[0] = exeFullPath;
  245. }
  246. try
  247. {
  248. process = _exec(_args);
  249. process.getOutputStream().close();
  250. return process;
  251. }
  252. catch(IOException io)
  253. {
  254. if(i == extensionsToTry.length - 1)
  255. {
  256. String[] tt = { io.getMessage() };
  257. console.printError(jEdit.getProperty("console.shell.ioerror",tt));
  258. exitStatus = false;
  259. return null;
  260. }
  261. }
  262. catch(Throwable t)
  263. {
  264. Log.log(Log.ERROR,this,t);
  265. exitStatus = false;
  266. return null;
  267. }
  268. }
  269. return null;
  270. }
  271. private String expandVariables(View view, String arg, StringBuffer buf)
  272. {
  273. buf.setLength(0);
  274. for(int i = 0; i < arg.length(); i++)
  275. {
  276. char c = arg.charAt(i);
  277. switch(c)
  278. {
  279. case winSlash:
  280. buf.append('\\');
  281. break;
  282. case '$':
  283. if(i == arg.length() - 1)
  284. buf.append(c);
  285. else
  286. {
  287. Buffer buffer = view.getBuffer();
  288. switch(arg.charAt(++i))
  289. {
  290. case 'd':
  291. String path = MiscUtilities.getParentOfPath(
  292. buffer.getPath());
  293. if(path.endsWith("/")
  294. || path.endsWith(File.separator))
  295. path = path.substring(0,
  296. path.length() - 1);
  297. buf.append(path);
  298. break;
  299. case 'u':
  300. path = buffer.getPath();
  301. if(!MiscUtilities.isURL(path))
  302. path = "file:" + path;
  303. buf.append(path);
  304. break;
  305. case 'f':
  306. buf.append(buffer.getPath());
  307. break;
  308. case 'j':
  309. buf.append(jEdit.getJEditHome());
  310. break;
  311. case 'n':
  312. String name = buffer.getName();
  313. int index = name.lastIndexOf('.');
  314. if(index == -1)
  315. buf.append(name);
  316. else
  317. buf.append(name.substring(0,index));
  318. break;
  319. case '$':
  320. buf.append('$');
  321. break;
  322. }
  323. }
  324. break;
  325. case '~':
  326. // insert the home directory if the tilde
  327. // is the last character on the line, or if
  328. // the character after it is whitespace or
  329. // a path separator.
  330. if(i == arg.length() - 1)
  331. {
  332. buf.append(System.getProperty("user.home"));
  333. break;
  334. }
  335. c = arg.charAt(i + 1);
  336. if(c == '/' || c == ' ' || c == File.separatorChar)
  337. {
  338. buf.append(System.getProperty("user.home"));
  339. break;
  340. }
  341. buf.append('~');
  342. break;
  343. default:
  344. buf.append(c);
  345. break;
  346. }
  347. }
  348. return buf.toString();
  349. }
  350. private void initTableWinBuiltIns()
  351. {
  352. String [] elems = { "md", "rd", "del", "dir", "copy",
  353. "move", "erase", "mkdir", "rmdir", "start",
  354. "path", "ver", "vol", "ren", "type"};
  355. this.tableWinBuiltIns = new Hashtable();
  356. for( int i = 0; i < elems.length; ++i)
  357. {
  358. this.tableWinBuiltIns.put(elems[i], elems[i]);
  359. }
  360. }
  361. private void parseLine(String line)
  362. {
  363. if(console == null)
  364. return;
  365. int type = ConsolePlugin.parseLine(line,dir);
  366. switch(type)
  367. {
  368. case ErrorSource.ERROR:
  369. console.printError(line);
  370. break;
  371. case ErrorSource.WARNING:
  372. console.printWarning(line);
  373. break;
  374. default:
  375. console.printPlain(line);
  376. break;
  377. }
  378. }
  379. private synchronized void threadDone()
  380. {
  381. threadDoneCount++;
  382. if(threadDoneCount == 2)
  383. commandDone();
  384. }
  385. private synchronized void commandDone()
  386. {
  387. if(process != null)
  388. {
  389. int exitCode;
  390. try
  391. {
  392. exitCode = process.waitFor();
  393. }
  394. catch(InterruptedException e)
  395. {
  396. Log.log(Log.ERROR,this,"Yo Flav, what is this?");
  397. return;
  398. }
  399. Object[] args = { command, new Integer(exitCode) };
  400. String msg = jEdit.getProperty("console.shell.exited",args);
  401. if(exitCode == 0)
  402. console.printInfo(msg);
  403. else
  404. console.printError(msg);
  405. exitStatus = (exitCode == 0);
  406. }
  407. threadDoneCount = 0;
  408. command = null;
  409. stdout = null;
  410. stderr = null;
  411. process = null;
  412. console = null;
  413. notify();
  414. }
  415. private Process _exec(String[] args) throws Throwable
  416. {
  417. if(java13exec != null)
  418. {
  419. try
  420. {
  421. Object[] params = { args, null, new File(dir) };
  422. return (Process)java13exec.invoke(Runtime.getRuntime(),params);
  423. }
  424. catch(InvocationTargetException e)
  425. {
  426. throw e.getTargetException();
  427. }
  428. }
  429. else
  430. return Runtime.getRuntime().exec(args);
  431. }
  432. class StdoutThread extends Thread
  433. {
  434. StdoutThread()
  435. {
  436. setName(StdoutThread.class + "[" + command + "]");
  437. start();
  438. }
  439. public void run()
  440. {
  441. try
  442. {
  443. BufferedReader in = new BufferedReader(
  444. new InputStreamReader(process
  445. .getInputStream()));
  446. String line;
  447. while((line = in.readLine()) != null)
  448. {
  449. parseLine(line);
  450. }
  451. in.close();
  452. }
  453. catch(IOException io)
  454. {
  455. String[] args = { io.getMessage() };
  456. console.printError(jEdit.getProperty("console.shell.ioerror",args));
  457. }
  458. finally
  459. {
  460. threadDone();
  461. }
  462. }
  463. }
  464. class StderrThread extends Thread
  465. {
  466. StderrThread()
  467. {
  468. setName(StderrThread.class + "[" + command + "]");
  469. start();
  470. }
  471. public void run()
  472. {
  473. try
  474. {
  475. // If process exits really fast, it could
  476. // be null by now. So check first...
  477. if(process == null)
  478. return;
  479. BufferedReader in = new BufferedReader(
  480. new InputStreamReader(process
  481. .getErrorStream()));
  482. String line;
  483. while((line = in.readLine()) != null)
  484. {
  485. parseLine(line);
  486. }
  487. in.close();
  488. }
  489. catch(IOException io)
  490. {
  491. String[] args = { io.getMessage() };
  492. console.printError(jEdit.getProperty("console.shell.ioerror",args));
  493. }
  494. finally
  495. {
  496. threadDone();
  497. }
  498. }
  499. }
  500. }