Index: src/net/sf/antcontrib/cpptasks/borland/BorlandLibrarian.java =================================================================== RCS file: /cvsroot/ant-contrib/cpptasks/src/net/sf/antcontrib/cpptasks/borland/BorlandLibrarian.java,v retrieving revision 1.15 diff -c -r1.15 BorlandLibrarian.java *** src/net/sf/antcontrib/cpptasks/borland/BorlandLibrarian.java 28 Feb 2004 20:00:01 -0000 1.15 --- src/net/sf/antcontrib/cpptasks/borland/BorlandLibrarian.java 12 Mar 2004 18:08:04 -0000 *************** *** 18,25 **** --- 18,27 ---- import java.io.File; import java.util.Vector; + import net.sf.antcontrib.cpptasks.CCTask; import net.sf.antcontrib.cpptasks.CUtil; import net.sf.antcontrib.cpptasks.compiler.CommandLineLinker; + import net.sf.antcontrib.cpptasks.compiler.CommandLineLinkerConfiguration; import net.sf.antcontrib.cpptasks.compiler.LinkType; import net.sf.antcontrib.cpptasks.compiler.Linker; /** *************** *** 56,61 **** --- 58,115 ---- } public String[] getLibraryPatterns(String[] libnames) { return BorlandProcessor.getLibraryPatterns(libnames); + } + /* + * @inheritDoc + * @author: RFHH + */ + protected String[] prepareArguments( + CCTask task, + String outputDir, + String outputFile, + String[] sourceFiles, + CommandLineLinkerConfiguration config) { + + String[] preargs = config.getPreArguments(); + String[] endargs = config.getEndArguments(); + String outputSwitch[] = getOutputFileSwitch(task, outputFile); + int allArgsCount = preargs.length + 1 + 1 + outputSwitch.length + + sourceFiles.length + endargs.length; + /* Cannot reach libtool. I think N/A for Borland anyway + if (isLibtool) { + allArgsCount++; + } + */ + String[] allArgs = new String[allArgsCount]; + int index = 0; + /* Cannot reach libtool. I think N/A for Borland anyway + if (isLibtool) { + allArgs[index++] = "libtool"; + } + */ + allArgs[index++] = this.getCommand(); + + StringBuffer buf = new StringBuffer(); + + // + // output file name + // + String outputFileName = new File(outputDir, outputFile).toString(); + allArgs[index++] = BorlandProcessor.quoteFilename(outputFileName); + + for (int i = 0; i < preargs.length; i++) { + allArgs[index++] = decorateLinkerOption(buf, preargs[i]); + } + for (int i = 0; i < outputSwitch.length; i++) { + allArgs[index++] = outputSwitch[i]; + } + for (int i = 0; i < sourceFiles.length; i++) { + allArgs[index++] = "+-" + BorlandProcessor.quoteFilename(prepareFilename(buf,outputDir,sourceFiles[i])); + } + for (int i = 0; i < endargs.length; i++) { + allArgs[index++] = decorateLinkerOption(buf, endargs[i]); + } + return allArgs; } public Linker getLinker(LinkType type) { return BorlandLinker.getInstance().getLinker(type); Index: src/net/sf/antcontrib/cpptasks/borland/BorlandLinker.java =================================================================== RCS file: /cvsroot/ant-contrib/cpptasks/src/net/sf/antcontrib/cpptasks/borland/BorlandLinker.java,v retrieving revision 1.17 diff -c -r1.17 BorlandLinker.java *** src/net/sf/antcontrib/cpptasks/borland/BorlandLinker.java 28 Feb 2004 20:00:01 -0000 1.17 --- src/net/sf/antcontrib/cpptasks/borland/BorlandLinker.java 12 Mar 2004 18:08:04 -0000 *************** *** 21,26 **** --- 21,27 ---- import java.util.Enumeration; import java.util.Vector; + import net.sf.antcontrib.cpptasks.CCTask; import net.sf.antcontrib.cpptasks.CUtil; import net.sf.antcontrib.cpptasks.compiler.CommandLineLinker; import net.sf.antcontrib.cpptasks.compiler.CommandLineLinkerConfiguration; *************** *** 30,35 **** --- 31,40 ---- * Adapter for the Borland(r) ilink32 linker * * @author Curt Arnold + * + * Change it to use bcc32. This is much simpler, and the additional + * functionality (control over map, base, stack) is not used anyway. + * @author Rutger Hofman, VU Amsterdam (RFHH) */ public final class BorlandLinker extends CommandLineLinker { private static final BorlandLinker dllLinker = new BorlandLinker(".dll"); *************** *** 38,80 **** return instance; } private BorlandLinker(String outputSuffix) { ! super("ilink32", "-r", new String[]{".obj", ".lib", ".res"}, ! new String[]{".map", ".pdb", ".lnk"}, outputSuffix, false, null); } protected void addBase(long base, Vector args) { - if (base >= 0) { - String baseAddr = Long.toHexString(base); - args.addElement("-b:" + baseAddr); - } } protected void addFixed(Boolean fixed, Vector args) { } protected void addImpliedArgs(boolean debug, LinkType linkType, Vector args) { if (linkType.isExecutable()) { if (linkType.isSubsystemConsole()) { ! args.addElement("/ap"); ! } else { ! if (linkType.isSubsystemGUI()) { ! args.addElement("/Tpe"); ! } } ! } ! if (linkType.isSharedLibrary()) { ! args.addElement("/Tpd"); } } protected void addIncremental(boolean incremental, Vector args) { } protected void addMap(boolean map, Vector args) { - if (!map) { - args.addElement("-x"); - } } protected void addStack(int stack, Vector args) { - if (stack >= 0) { - String stackStr = Integer.toHexString(stack); - args.addElement("-S:" + stackStr); - } } public String getCommandFileSwitch(String commandFile) { return "@" + commandFile; --- 43,70 ---- return instance; } private BorlandLinker(String outputSuffix) { ! super("bcc32", "", new String[] { ".obj", ".lib", ".res" }, ! new String[] { ".map", ".pdb", ".lnk" }, outputSuffix, ! false, null); } protected void addBase(long base, Vector args) { } protected void addFixed(Boolean fixed, Vector args) { } protected void addImpliedArgs(boolean debug, LinkType linkType, Vector args) { if (linkType.isExecutable()) { if (linkType.isSubsystemConsole()) { ! args.addElement("/W"); } ! } else if (linkType.isSharedLibrary()) { ! args.addElement("/WD"); } } protected void addIncremental(boolean incremental, Vector args) { } protected void addMap(boolean map, Vector args) { } protected void addStack(int stack, Vector args) { } public String getCommandFileSwitch(String commandFile) { return "@" + commandFile; *************** *** 83,89 **** return "Borland Linker"; } public File[] getLibraryPath() { ! return BorlandProcessor.getEnvironmentPath("ilink32", 'L', new String[]{"..\\lib"}); } public String[] getLibraryPatterns(String[] libnames) { --- 73,79 ---- return "Borland Linker"; } public File[] getLibraryPath() { ! return BorlandProcessor.getEnvironmentPath("bcc32", 'L', new String[]{"..\\lib"}); } public String[] getLibraryPatterns(String[] libnames) { *************** *** 105,119 **** return BorlandProcessor.getOutputFileSwitch(outFile); } protected String getStartupObject(LinkType linkType) { - if (linkType.isSharedLibrary()) { - return "c0d32.obj"; - } - if (linkType.isSubsystemGUI()) { - return "c0w32.obj"; - } - if (linkType.isSubsystemConsole()) { - return "c0x32.obj"; - } return null; } public boolean isCaseSensitive() { --- 95,100 ---- *************** *** 130,137 **** * linker arguments * @return arguments for runTask */ ! protected String[] prepareArguments(String outputDir, String outputName, ! String[] sourceFiles, CommandLineLinkerConfiguration config) { String[] preargs = config.getPreArguments(); String[] endargs = config.getEndArguments(); Vector execArgs = new Vector(preargs.length + endargs.length + 10 --- 111,119 ---- * linker arguments * @return arguments for runTask */ ! protected String[] prepareArguments(CCTask task, String outputDir, ! String outputName, String[] sourceFiles, ! CommandLineLinkerConfiguration config) { String[] preargs = config.getPreArguments(); String[] endargs = config.getEndArguments(); Vector execArgs = new Vector(preargs.length + endargs.length + 10 *************** *** 143,171 **** for (int i = 0; i < endargs.length; i++) { execArgs.addElement(endargs[i]); } // ! // see if the input files have any known startup obj files ! // ! String startup = null; ! for (int i = 0; i < sourceFiles.length; i++) { ! String filename = new File(sourceFiles[i]).getName().toLowerCase(); ! if (startup != null && filename.substring(0, 2).equals("c0") ! && filename.substring(3, 5).equals("32") ! && filename.substring(filename.length() - 4).equals(".obj")) { ! startup = sourceFiles[i]; ! } ! } // ! // c0w32.obj, c0x32.obj or c0d32.obj depending on ! // link type ! if (startup == null) { ! startup = config.getStartupObject(); ! } ! execArgs.addElement(startup); Vector resFiles = new Vector(); Vector libFiles = new Vector(); String defFile = null; - StringBuffer buf = new StringBuffer(); for (int i = 0; i < sourceFiles.length; i++) { String last4 = sourceFiles[i] .substring(sourceFiles[i].length() - 4).toLowerCase(); --- 125,139 ---- for (int i = 0; i < endargs.length; i++) { execArgs.addElement(endargs[i]); } + StringBuffer buf = new StringBuffer(); // ! // output file name // ! String outputFileName = new File(outputDir, outputName).toString(); ! execArgs.addElement("-e" + quoteFilename(buf,outputFileName)); Vector resFiles = new Vector(); Vector libFiles = new Vector(); String defFile = null; for (int i = 0; i < sourceFiles.length; i++) { String last4 = sourceFiles[i] .substring(sourceFiles[i].length() - 4).toLowerCase(); *************** *** 184,206 **** } } // - // output file name - // - String outputFileName = new File(outputDir, outputName).toString(); - execArgs.addElement("," + quoteFilename(buf, outputFileName)); - if (config.getMap()) { - int lastPeriod = outputFileName.lastIndexOf('.'); - String mapName; - if (lastPeriod < outputFileName.length() - 4) { - mapName = outputFileName + ".map"; - } else { - mapName = outputFileName.substring(0, lastPeriod) + ".map"; - } - execArgs.addElement("," + quoteFilename(buf, mapName) + ","); - } else { - execArgs.addElement(",,"); - } - // // add all the libraries // Enumeration libEnum = libFiles.elements(); --- 152,157 ---- *************** *** 208,218 **** String libName = (String) libEnum.nextElement(); execArgs.addElement(quoteFilename(buf, libName)); } - if (defFile == null) { - execArgs.addElement(",,"); - } else { - execArgs.addElement("," + quoteFilename(buf, defFile) + ","); - } Enumeration resEnum = resFiles.elements(); while (resEnum.hasMoreElements()) { String resName = (String) resEnum.nextElement(); --- 159,164 ---- *************** *** 220,225 **** --- 166,172 ---- } String[] execArguments = new String[execArgs.size()]; execArgs.copyInto(execArguments); + return execArguments; } /** Index: src/net/sf/antcontrib/cpptasks/borland/BorlandProcessor.java =================================================================== RCS file: /cvsroot/ant-contrib/cpptasks/src/net/sf/antcontrib/cpptasks/borland/BorlandProcessor.java,v retrieving revision 1.15 diff -c -r1.15 BorlandProcessor.java *** src/net/sf/antcontrib/cpptasks/borland/BorlandProcessor.java 28 Feb 2004 20:00:01 -0000 1.15 --- src/net/sf/antcontrib/cpptasks/borland/BorlandProcessor.java 12 Mar 2004 18:08:05 -0000 *************** *** 26,32 **** /** * A add-in class for Borland(r) processor adapters * ! * */ public final class BorlandProcessor { public static void addWarningSwitch(Vector args, int level) { --- 26,33 ---- /** * A add-in class for Borland(r) processor adapters * ! * @author Curt Arnold(?) ! * @author Rutger Hofman, VU Amsterdam (RFHH) */ public final class BorlandProcessor { public static void addWarningSwitch(Vector args, int level) { *************** *** 147,152 **** --- 148,167 ---- patterns[i] = buf.toString(); } return patterns; + } + /* + * Borland's command line characters operate also within path names: + * e.g. - . Quote such paths. RFHH + */ + static String quoteFilename(String path) { + if (path.charAt(0) == '"') { + return path; + } + if (path.indexOf(' ') != -1 || path.indexOf('-') != -1 || + path.indexOf('+') != -1 || path.indexOf('*') != -1) { + return "\"" + path + "\""; + } + return path; } public static String[] getOutputFileSwitch(String outFile) { return new String[0]; Index: src/net/sf/antcontrib/cpptasks/compiler/CaptureStreamHandler.java =================================================================== RCS file: /cvsroot/ant-contrib/cpptasks/src/net/sf/antcontrib/cpptasks/compiler/CaptureStreamHandler.java,v retrieving revision 1.12 diff -c -r1.12 CaptureStreamHandler.java *** src/net/sf/antcontrib/cpptasks/compiler/CaptureStreamHandler.java 28 Feb 2004 20:00:40 -0000 1.12 --- src/net/sf/antcontrib/cpptasks/compiler/CaptureStreamHandler.java 12 Mar 2004 18:08:05 -0000 *************** *** 29,34 **** --- 29,37 ---- * array of strings * * @author Curt Arnold + * + * Asynchronous reading of the output streams + * @author Rutger Hofman, VU Amsterdam (RFHH) */ public class CaptureStreamHandler implements ExecuteStreamHandler { /** *************** *** 48,83 **** } return handler.getOutput(); } - private InputStream errorStream; - private InputStream fromProcess; public CaptureStreamHandler() { } ! public String[] getOutput() { ! String[] output; ! if (fromProcess != null) { ! Vector lines = new Vector(10); ! try { ! BufferedReader reader = new BufferedReader( ! new InputStreamReader(errorStream)); ! for (int i = 0; i < 2; i++) { ! for (int j = 0; j < 100; j++) { ! String line = reader.readLine(); ! if (line == null) { ! reader = new BufferedReader(new InputStreamReader( ! fromProcess)); ! break; ! } ! lines.addElement(line); ! } ! } ! } catch (IOException ex) { ! } ! output = new String[lines.size()]; ! lines.copyInto(output); ! return output; } ! output = new String[0]; return output; } /** * Install a handler for the error stream of the subprocess. --- 51,162 ---- } return handler.getOutput(); } public CaptureStreamHandler() { } ! /** ! * For each of the Process's output streams, start a thread to ! * read that stream. The thread stores the output lines in field ! * output[stream_count] to be read by the Execute instance. ! * Because we do not know how much output is going to arrive from ! * each of the streams (may be none or may be huge) there is no ! * choice but to completely uncouple reading it. ! */ ! private static final int STDOUT = 0; ! private static final int STDERR = 1; ! private static final int STREAMS = 2; ! private InputStream[] is = new InputStream[STREAMS]; ! private String[][] output = new String[STREAMS][]; ! private Thread[] listener = new Thread[STREAMS]; ! private static final boolean DEBUG = false; ! private class Listener implements Runnable { ! int stream; ! Listener(int stream) { ! this.stream = stream; ! } ! public void run() { ! String[] out = getOutput(is[stream]); ! synchronized (CaptureStreamHandler.this) { ! output[stream] = out; ! CaptureStreamHandler.this.notifyAll(); ! } ! } ! }; ! private String[] getOutput(InputStream s) { ! String[] output; ! if (s != null) { ! Vector lines = new Vector(10); ! try { ! BufferedReader reader = new BufferedReader(new InputStreamReader(s)); ! while (true) { ! String line = reader.readLine(); ! if (line == null) { ! // End of file, says BufferedReader.javadoc ! break; ! } ! if (DEBUG) { ! System.err.println("Read line \"" + line + "\""); ! } ! lines.addElement(line); ! } ! } catch(IOException ex) { } ! output = new String[lines.size()]; ! lines.copyInto(output); return output; + } + output = new String[0]; + return output; + } + private boolean anyNull(String[][] output) { + for (int i = 0; i < output.length; i++) { + if (output[i] == null) { + return true; + } + } + + return false; + } + public synchronized String[] getOutput() { + if (DEBUG) { + System.err.println("App wants to read output; it is:"); + for (int s = 0; s < STREAMS; s++) { + System.err.println((s == STDOUT) ? "[stdout]" : "[stderr]"); + if (output[s] == null) { + System.err.println(output[s]); + } else { + for (int line = 0; line < output[s].length; line++) { + System.err.println("'" + output[s][line] + "'"); + } + } + } + } + while (anyNull(output)) { + try { + wait(); + } catch (InterruptedException e) { + } + } + int lines = 0; + for (int s = 0; s < STREAMS; s++) { + if (output[s] != null) { + lines += output[s].length; + } + } + /* Append the lines of output from each of the streams. + * stderr seems to be higher-prio than stdout, so do that + * first. */ + String[] res = new String[lines]; + int off = 0; + for (int s = STREAMS - 1; s >= 0; s--) { + if (output[s] != null) { + for (int line = 0; line < output[s].length; line++) { + res[line + off] = output[s][line]; + } + off += output[s].length; + output[s] = null; // GC hint + } + } + return res; } /** * Install a handler for the error stream of the subprocess. *************** *** 87,93 **** * subprocess */ public void setProcessErrorStream(InputStream is) throws IOException { ! errorStream = is; } /** * Install a handler for the input stream of the subprocess. --- 166,172 ---- * subprocess */ public void setProcessErrorStream(InputStream is) throws IOException { ! this.is[STDERR] = is; } /** * Install a handler for the input stream of the subprocess. *************** *** 107,118 **** * subprocess */ public void setProcessOutputStream(InputStream is) throws IOException { ! fromProcess = is; } /** * Start handling of the streams. */ public void start() throws IOException { } /** * Stop handling of the streams - will not be restarted. --- 186,201 ---- * subprocess */ public void setProcessOutputStream(InputStream is) throws IOException { ! this.is[STDOUT] = is; } /** * Start handling of the streams. */ public void start() throws IOException { + for (int i = 0; i < STREAMS; i++) { + listener[i] = new Thread(new Listener(i)); + listener[i].start(); + } } /** * Stop handling of the streams - will not be restarted.