3 * Copyright 2001-2004 The Ant-Contrib project
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 package net
.sf
.antcontrib
.cpptasks
;
19 import java
.io
.IOException
;
20 import java
.util
.Enumeration
;
21 import java
.util
.Hashtable
;
22 import java
.util
.StringTokenizer
;
23 import java
.util
.Vector
;
25 import org
.apache
.tools
.ant
.BuildException
;
26 import org
.apache
.tools
.ant
.Project
;
27 import org
.apache
.tools
.ant
.taskdefs
.Execute
;
28 import org
.apache
.tools
.ant
.taskdefs
.LogStreamHandler
;
29 import org
.apache
.tools
.ant
.types
.Commandline
;
30 import org
.apache
.tools
.ant
.types
.Environment
;
32 * Some utilities used by the CC and Link tasks.
34 * @author Adam Murdoch
38 * A class that splits a white-space, comma-separated list into a String
39 * array. Used for task attributes.
41 public static final class StringArrayBuilder
{
42 private String
[] _value
;
43 public StringArrayBuilder(String value
) {
44 // Split the defines up
45 StringTokenizer tokens
= new StringTokenizer(value
, ", ");
46 Vector vallist
= new Vector();
47 while (tokens
.hasMoreTokens()) {
48 String val
= tokens
.nextToken().trim();
49 if (val
.length() == 0) {
52 vallist
.addElement(val
);
54 _value
= new String
[vallist
.size()];
55 vallist
.copyInto(_value
);
57 public String
[] getValue() {
62 * Adds the elements of the array to the given vector
64 public static void addAll(Vector dest
, Object
[] src
) {
68 for (int i
= 0; i
< src
.length
; i
++) {
69 dest
.addElement(src
[i
]);
73 * Checks a array of names for non existent or non directory entries and
76 * @return Count of non-null elements
78 public static int checkDirectoryArray(String
[] names
) {
80 for (int i
= 0; i
< names
.length
; i
++) {
81 if (names
[i
] != null) {
82 File dir
= new File(names
[i
]);
83 if (dir
.exists() && dir
.isDirectory()) {
93 * Extracts the basename of a file, removing the extension, if present
95 public static String
getBasename(File file
) {
96 String path
= file
.getPath();
97 // Remove the extension
98 String basename
= file
.getName();
99 int pos
= basename
.lastIndexOf('.');
101 basename
= basename
.substring(0, pos
);
106 * Gets the parent directory for the executable file name using the current
107 * directory and system executable path
110 * Name of executable such as "cl.exe"
111 * @return parent directory or null if not located
113 public static File
getExecutableLocation(String exeName
) {
115 // must add current working directory to the
116 // from of the path from the "path" environment variable
117 File currentDir
= new File(System
.getProperty("user.dir"));
118 if (new File(currentDir
, exeName
).exists()) {
121 File
[] envPath
= CUtil
.getPathFromEnvironment("PATH",
123 for (int i
= 0; i
< envPath
.length
; i
++) {
124 if (new File(envPath
[i
], exeName
).exists()) {
131 * Extracts the parent of a file
133 public static String
getParentPath(String path
) {
134 int pos
= path
.lastIndexOf(File
.separator
);
138 return path
.substring(0, pos
);
141 * Returns an array of File for each existing directory in the specified
142 * environment variable
145 * environment variable name such as "LIB" or "INCLUDE"
147 * delimitor used to separate parts of the path, typically ";"
149 * @return array of File's for each part that is an existing directory
151 public static File
[] getPathFromEnvironment(String envVariable
, String delim
) {
152 // OS/4000 does not support the env command.
153 if (System
.getProperty("os.name").equals("OS/400"))
155 Vector osEnv
= Execute
.getProcEnvironment();
156 String match
= envVariable
.concat("=");
157 for (Enumeration e
= osEnv
.elements(); e
.hasMoreElements();) {
158 String entry
= ((String
) e
.nextElement()).trim();
159 if (entry
.length() > match
.length()) {
160 String entryFrag
= entry
.substring(0, match
.length());
161 if (entryFrag
.equalsIgnoreCase(match
)) {
162 String path
= entry
.substring(match
.length());
163 return parsePath(path
, delim
);
167 File
[] noPath
= new File
[0];
171 * Returns a relative path for the targetFile relative to the base
174 * @param canonicalBase
175 * base directory as returned by File.getCanonicalPath()
178 * @return relative path of target file. Returns targetFile if there were
179 * no commonalities between the base and the target
181 * @author Curt Arnold
183 public static String
getRelativePath(String base
, File targetFile
) {
186 // remove trailing file separator
188 String canonicalBase
= base
;
189 if (base
.charAt(base
.length() - 1) == File
.separatorChar
) {
190 canonicalBase
= base
.substring(0, base
.length() - 1);
193 // get canonical name of target and remove trailing separator
195 String canonicalTarget
;
196 if (System
.getProperty("os.name").equals("OS/400"))
197 canonicalTarget
= targetFile
.getPath();
199 canonicalTarget
= targetFile
.getCanonicalPath();
200 if (canonicalTarget
.charAt(canonicalTarget
.length() - 1) == File
.separatorChar
) {
201 canonicalTarget
= canonicalTarget
.substring(0, canonicalTarget
204 if (canonicalTarget
.equals(canonicalBase
)) {
208 // see if the prefixes are the same
210 if (canonicalBase
.substring(0, 2).equals("\\\\")) {
212 // UNC file name, if target file doesn't also start with same
213 // server name, don't go there
214 int endPrefix
= canonicalBase
.indexOf('\\', 2);
215 String prefix1
= canonicalBase
.substring(0, endPrefix
);
216 String prefix2
= canonicalTarget
.substring(0, endPrefix
);
217 if (!prefix1
.equals(prefix2
)) {
218 return canonicalTarget
;
221 if (canonicalBase
.substring(1, 3).equals(":\\")) {
223 String prefix1
= canonicalBase
.substring(0, endPrefix
);
224 String prefix2
= canonicalTarget
.substring(0, endPrefix
);
225 if (!prefix1
.equals(prefix2
)) {
226 return canonicalTarget
;
229 if (canonicalBase
.charAt(0) == '/') {
230 if (canonicalTarget
.charAt(0) != '/') {
231 return canonicalTarget
;
236 char separator
= File
.separatorChar
;
237 int lastSeparator
= -1;
238 int minLength
= canonicalBase
.length();
239 if (canonicalTarget
.length() < minLength
) {
240 minLength
= canonicalTarget
.length();
242 int firstDifference
= minLength
+ 1;
244 // walk to the shorter of the two paths
245 // finding the last separator they have in common
246 for (int i
= 0; i
< minLength
; i
++) {
247 if (canonicalTarget
.charAt(i
) == canonicalBase
.charAt(i
)) {
248 if (canonicalTarget
.charAt(i
) == separator
) {
252 firstDifference
= lastSeparator
+ 1;
256 StringBuffer relativePath
= new StringBuffer(50);
258 // walk from the first difference to the end of the base
259 // adding "../" for each separator encountered
261 if (canonicalBase
.length() > firstDifference
) {
262 relativePath
.append("..");
263 for (int i
= firstDifference
; i
< canonicalBase
.length(); i
++) {
264 if (canonicalBase
.charAt(i
) == separator
) {
265 relativePath
.append(separator
);
266 relativePath
.append("..");
270 if (canonicalTarget
.length() > firstDifference
) {
272 // append the rest of the target
275 if (relativePath
.length() > 0) {
276 relativePath
.append(separator
);
278 relativePath
.append(canonicalTarget
.substring(firstDifference
));
280 return relativePath
.toString();
281 } catch (IOException ex
) {
283 return targetFile
.toString();
285 public static boolean isActive(Project p
, String ifCond
, String unlessCond
)
286 throws BuildException
{
287 if (ifCond
!= null) {
288 String ifValue
= p
.getProperty(ifCond
);
289 if (ifValue
== null) {
292 if (ifValue
.equals("false") || ifValue
.equals("no")) {
293 throw new BuildException("if condition \"" + ifCond
294 + "\" has suspicious value \"" + ifValue
);
298 if (unlessCond
!= null) {
299 String unlessValue
= p
.getProperty(unlessCond
);
300 if (unlessValue
!= null) {
301 if (unlessValue
.equals("false") || unlessValue
.equals("no")) {
302 throw new BuildException("unless condition \"" + unlessCond
303 + "\" has suspicious value \"" + unlessValue
);
311 * Parse a string containing directories into an File[]
314 * path string, for example ".;c:\something\include"
316 * delimiter, typically ; or :
318 public static File
[] parsePath(String path
, String delim
) {
319 Vector libpaths
= new Vector();
321 for (int startPos
= 0; startPos
< path
.length(); startPos
= delimPos
323 delimPos
= path
.indexOf(delim
, startPos
);
325 delimPos
= path
.length();
328 // don't add an entry for zero-length paths
330 if (delimPos
> startPos
) {
331 String dirName
= path
.substring(startPos
, delimPos
);
332 File dir
= new File(dirName
);
333 if (dir
.exists() && dir
.isDirectory()) {
334 libpaths
.addElement(dir
);
338 File
[] paths
= new File
[libpaths
.size()];
339 libpaths
.copyInto(paths
);
343 * This method is exposed so test classes can overload and test the
344 * arguments without actually spawning the compiler
346 public static int runCommand(CCTask task
, File workingDir
,
347 String
[] cmdline
, boolean newEnvironment
, Environment env
)
348 throws BuildException
{
350 task
.log(Commandline
.toString(cmdline
), Project
.MSG_VERBOSE
);
351 Execute exe
= new Execute(new LogStreamHandler(task
,
352 Project
.MSG_INFO
, Project
.MSG_ERR
));
353 if (System
.getProperty("os.name").equals("OS/390"))
354 exe
.setVMLauncher(false);
355 exe
.setAntRun(task
.getProject());
356 exe
.setCommandline(cmdline
);
357 exe
.setWorkingDirectory(workingDir
);
359 String
[] environment
= env
.getVariables();
360 if (environment
!= null) {
361 for (int i
= 0; i
< environment
.length
; i
++) {
362 task
.log("Setting environment variable: "
363 + environment
[i
], Project
.MSG_VERBOSE
);
366 exe
.setEnvironment(environment
);
368 exe
.setNewenvironment(newEnvironment
);
369 return exe
.execute();
370 } catch (java
.io
.IOException exc
) {
371 throw new BuildException("Could not launch " + cmdline
[0] + ": "
372 + exc
, task
.getLocation());
376 * Compares the contents of 2 arrays for equaliy.
378 public static boolean sameList(Object
[] a
, Object
[] b
) {
379 if (a
== null || b
== null || a
.length
!= b
.length
) {
382 for (int i
= 0; i
< a
.length
; i
++) {
383 if (!a
[i
].equals(b
[i
])) {
390 * Compares the contents of an array and a Vector for equality.
392 public static boolean sameList(Vector v
, Object
[] a
) {
393 if (v
== null || a
== null || v
.size() != a
.length
) {
396 for (int i
= 0; i
< a
.length
; i
++) {
398 if (!o
.equals(v
.elementAt(i
))) {
405 * Compares the contents of an array and a Vector for set equality. Assumes
406 * input array and vector are sets (i.e. no duplicate entries)
408 public static boolean sameSet(Object
[] a
, Vector b
) {
409 if (a
== null || b
== null || a
.length
!= b
.size()) {
415 // Convert the array into a set
416 Hashtable t
= new Hashtable();
417 for (int i
= 0; i
< a
.length
; i
++) {
420 for (int i
= 0; i
< b
.size(); i
++) {
421 Object o
= b
.elementAt(i
);
422 if (t
.remove(o
) == null) {
426 return (t
.size() == 0);
429 * Converts a vector to a string array.
431 public static String
[] toArray(Vector src
) {
432 String
[] retval
= new String
[src
.size()];
433 src
.copyInto(retval
);
437 * Replaces any embedded quotes in the string so that the value can be
438 * placed in an attribute in an XML file
441 * value to be expressed
442 * @return equivalent attribute literal
445 public static String
xmlAttribEncode(String attrValue
) {
446 int quotePos
= attrValue
.indexOf('\"');
451 StringBuffer buf
= new StringBuffer(attrValue
.length() + 20);
452 while (quotePos
>= 0) {
453 buf
.append(attrValue
.substring(startPos
, quotePos
));
454 buf
.append(""");
455 startPos
= quotePos
+ 1;
456 quotePos
= attrValue
.indexOf('\"', startPos
);
458 buf
.append(attrValue
.substring(startPos
));
459 return buf
.toString();