001: /*
002: * CompilationBuffer.java
003: *
004: * Copyright (C) 1998-2004 Peter Graves
005: * $Id: CompilationBuffer.java,v 1.18 2004/05/21 22:44:44 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.io.BufferedReader;
025: import java.io.IOException;
026: import java.io.InputStream;
027: import java.io.InputStreamReader;
028: import java.util.ArrayList;
029: import javax.swing.SwingUtilities;
030:
031: public final class CompilationBuffer extends CompilationErrorBuffer
032: implements Runnable {
033: private String command;
034: private String expandedCommand;
035: private Position posEndOfBuffer;
036: private File currentDir;
037: private Process process;
038: private int exitValue;
039: private File exitValueFile;
040:
041: public CompilationBuffer(String command, File directory) {
042: setCommand(command);
043: currentDir = directory;
044: mode = CompilationMode.getMode();
045: try {
046: lockWrite();
047: } catch (InterruptedException e) {
048: Log.debug(e);
049: return;
050: }
051: try {
052: appendLine("");
053: renumber();
054: } finally {
055: unlockWrite();
056: }
057: setLoaded(true);
058: posEndOfBuffer = new Position(getFirstLine(), 0);
059: }
060:
061: public synchronized final void initialize() {
062: setTitle(expandedCommand = expandCommand(command));
063: setInitialized(true);
064: }
065:
066: public final void setCommand(String command) {
067: this .command = command;
068: }
069:
070: public final int exitValue() {
071: return exitValue;
072: }
073:
074: public void empty() {
075: try {
076: lockWrite();
077: } catch (InterruptedException e) {
078: Log.debug(e);
079: return;
080: }
081: try {
082: super .empty();
083: appendLine("");
084: renumber();
085: setLoaded(true);
086: posEndOfBuffer = new Position(getFirstLine(), 0);
087: setCurrentError(null);
088: } finally {
089: unlockWrite();
090: }
091: for (EditorIterator it = new EditorIterator(); it.hasNext();) {
092: Editor ed = it.nextEditor();
093: if (ed.getBuffer() == this ) {
094: ed.setDot(getFirstLine(), 0);
095: ed.setTopLine(getFirstLine());
096: ed.setMark(null);
097: }
098: }
099: }
100:
101: public void run() {
102: long start = System.currentTimeMillis();
103: if (expandedCommand.startsWith("(")) {
104: // Lisp.
105: FastStringBuffer sb = new FastStringBuffer();
106: sb.append("(with-output-to-string (s) ");
107: sb.append("(let ((*standard-output* s)) ");
108: sb.append(expandedCommand);
109: sb.append(" ))");
110: try {
111: org.armedbear.lisp.LispObject result = JLisp
112: .runLispCommand(sb.toString());
113: appendLater(result.getStringValue());
114: } catch (Throwable t) {
115: Log.debug(t);
116: }
117: } else {
118: startProcess();
119: if (process != null) {
120: CompilationBufferReaderThread stdoutThread = new CompilationBufferReaderThread(
121: process.getInputStream());
122: stdoutThread.start();
123: CompilationBufferReaderThread stderrThread = new CompilationBufferReaderThread(
124: process.getErrorStream());
125: stderrThread.start();
126: try {
127: exitValue = process.waitFor();
128: if (exitValueFile != null && exitValueFile.isFile()) {
129: exitValue = getExitValueFromFile(exitValueFile);
130: exitValueFile.delete();
131: exitValueFile = null;
132: }
133: stdoutThread.join();
134: stderrThread.join();
135: long elapsed = System.currentTimeMillis() - start;
136: FastStringBuffer sb = new FastStringBuffer();
137: sb.append("\nCompilation ");
138: if (exitValue == 0) {
139: sb.append("finished (");
140: sb.append(String.valueOf(elapsed));
141: sb.append(" milliseconds)");
142: } else
143: sb.append("exited abnormally");
144: sb.append("\n");
145: appendLater(sb.toString());
146: } catch (InterruptedException e) {
147: Log.error(e);
148: }
149: } else
150: appendLater("Unable to start compilation process\n");
151: }
152: Editor.getTagFileManager().setEnabled(true);
153: }
154:
155: private void startProcess() {
156: process = null;
157: exitValue = -1;
158: try {
159: if (Platform.isPlatformWindows()) {
160: String cmd = "cd /d \"" + currentDir.canonicalPath()
161: + "\" && " + expandedCommand;
162: ArrayList list = new ArrayList();
163: list.add("cmd.exe");
164: list.add("/c");
165: list.addAll(Utilities.tokenize(cmd));
166: final int size = list.size();
167: String[] cmdarray = new String[size];
168: for (int i = 0; i < size; i++)
169: cmdarray[i] = (String) list.get(i);
170: process = Runtime.getRuntime().exec(cmdarray);
171: } else {
172: // Not Windows. Assume Unix.
173: if (Utilities.haveJpty()) {
174: exitValueFile = Utilities.getTempFile();
175: FastStringBuffer sb = new FastStringBuffer();
176: sb.append("(\\cd \"");
177: sb.append(currentDir.canonicalPath());
178: sb.append("\" && ");
179: sb.append(expandedCommand);
180: sb.append("; echo $? > ");
181: sb.append(exitValueFile.canonicalPath());
182: sb.append(')');
183: final String cmd = sb.toString();
184: String[] cmdarray = { "jpty", "/bin/sh", "-c", cmd };
185: process = Runtime.getRuntime().exec(cmdarray);
186: } else {
187: String cmd = "(\\cd \""
188: + currentDir.canonicalPath() + "\" && "
189: + expandedCommand + ")";
190: String[] cmdarray = { "/bin/sh", "-c", cmd };
191: process = Runtime.getRuntime().exec(cmdarray);
192: }
193: }
194: } catch (Throwable t) {
195: Log.error(t);
196: }
197: }
198:
199: private String expandCommand(String s) {
200: int length = s.length();
201: FastStringBuffer sb = new FastStringBuffer();
202: boolean inQuote = false;
203: for (int i = 0; i < length; i++) {
204: char c = s.charAt(i);
205: if (inQuote) {
206: sb.append(c);
207: if (c == '"')
208: inQuote = false;
209: } else {
210: // Not in quote.
211: if (c == '"') {
212: sb.append(c);
213: inQuote = true;
214: } else if (c == 'h') {
215: boolean replaced = false;
216: if (s.regionMatches(i, "here", 0, 4)) {
217: // "here" must be delimited by spaces.
218: if (i == 0 || s.charAt(i - 1) == ' ') {
219: if (i + 4 == length
220: || s.charAt(i + 4) == ' ') {
221: File file = parentBuffer.getFile();
222: if (file != null) {
223: String cp = file.canonicalPath();
224: if (cp.indexOf(' ') >= 0) {
225: // Enclose filename in double quotes
226: // since it contains an embedded space.
227: sb.append('"');
228: sb.append(cp);
229: sb.append('"');
230: } else
231: sb.append(cp);
232: replaced = true;
233: }
234: }
235: }
236: }
237: if (replaced)
238: i += 3;
239: else
240: sb.append(c);
241: } else
242: sb.append(c);
243: }
244: }
245: return sb.toString();
246: }
247:
248: private int getExitValueFromFile(File file) {
249: int ret = -1;
250: if (file != null) {
251: try {
252: InputStream inputStream = file.getInputStream();
253: BufferedReader reader = new BufferedReader(
254: new InputStreamReader(inputStream));
255: String s = reader.readLine();
256: reader.close();
257: try {
258: ret = Integer.parseInt(s);
259: } catch (NumberFormatException e) {
260: }
261: } catch (IOException e) {
262: }
263: }
264: return ret;
265: }
266:
267: public static void killCompilation() {
268: for (BufferIterator it = new BufferIterator(); it.hasNext();) {
269: Buffer buf = it.nextBuffer();
270: if (buf instanceof CompilationBuffer) {
271: ((CompilationBuffer) buf).killProcess();
272: break;
273: }
274: }
275: }
276:
277: private synchronized void killProcess() {
278: if (process != null) {
279: process.destroy();
280: try {
281: process.waitFor();
282: process = null;
283: } catch (InterruptedException e) {
284: Log.error(e);
285: }
286: }
287: }
288:
289: public void dispose() {
290: killProcess();
291: }
292:
293: private void appendLater(final String s) {
294: Runnable runnable = new Runnable() {
295: public void run() {
296: Position pos = posEndOfBuffer;
297: insertString(pos, s);
298: if (needsRenumbering())
299: renumber();
300: for (EditorIterator it = new EditorIterator(); it
301: .hasNext();) {
302: Editor ed = it.nextEditor();
303: if (ed.getBuffer() == CompilationBuffer.this ) {
304: ed.eob();
305: ed.getDisplay().setReframe(-2);
306: ed.setUpdateFlag(REPAINT);
307: ed.updateDisplay();
308: }
309: }
310: resetUndo();
311: }
312: };
313: SwingUtilities.invokeLater(runnable);
314: }
315:
316: public String getFileNameForDisplay() {
317: return getTitle();
318: }
319:
320: public File getCurrentDirectory() {
321: return currentDir;
322: }
323:
324: public void setCurrentDirectory(File directory) {
325: currentDir = directory;
326: }
327:
328: // For the buffer list.
329: public String toString() {
330: return command;
331: }
332:
333: private class CompilationBufferReaderThread extends ReaderThread {
334: public CompilationBufferReaderThread(InputStream inputStream) {
335: super (inputStream);
336: }
337:
338: public void update(final String s) {
339: appendLater(s);
340: }
341: }
342: }
|