Return-Path: Delivered-To: apmail-jakarta-ant-dev-archive@apache.org Received: (qmail 30277 invoked from network); 6 Dec 2002 22:04:03 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 6 Dec 2002 22:04:03 -0000 Received: (qmail 18733 invoked by uid 97); 6 Dec 2002 22:04:59 -0000 Delivered-To: qmlist-jakarta-archive-ant-dev@jakarta.apache.org Received: (qmail 18683 invoked by uid 97); 6 Dec 2002 22:04:58 -0000 Mailing-List: contact ant-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Ant Developers List" Reply-To: "Ant Developers List" Delivered-To: mailing list ant-dev@jakarta.apache.org Received: (qmail 18671 invoked by uid 98); 6 Dec 2002 22:04:58 -0000 X-Antivirus: nagoya (v4218 created Aug 14 2002) Message-ID: <2C6215F38016D511B85800805FBB337A1604C0@mailbackup.ztel.com> From: "Hart, Charles F." To: 'Ant Developers List' Subject: Enhancements to PathConvert and ReplaceRegExp Date: Fri, 6 Dec 2002 17:03:28 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2653.19) Content-Type: multipart/mixed; boundary="----_=_NextPart_000_01C29D73.4EA3E940" X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N ------_=_NextPart_000_01C29D73.4EA3E940 Content-Type: multipart/alternative; boundary="----_=_NextPart_001_01C29D73.4EA3E940" ------_=_NextPart_001_01C29D73.4EA3E940 Content-Type: text/plain; charset="iso-8859-1" I have made a couple of enhancements to PathConvert.java and ReplaceRegExp.java. For PathConvert.java I added support for nested mapper tags to enhance the manipulation that can be performed on a Path object. For ReplaceRegExp.java I added support for taking input from either a property or a referenced Path object. The modifications are attached as well as a build.xml file that demonstrates the new enhancements. I would like to see these enhancements make it into a future version of ant. -- Fred Hart ------_=_NextPart_001_01C29D73.4EA3E940 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Enhancements to PathConvert and ReplaceRegExp

I have made a couple of enhancements to = PathConvert.java and ReplaceRegExp.java. For PathConvert.java I added = support for nested mapper tags to enhance the manipulation that can be = performed on a Path object.  For ReplaceRegExp.java I added = support for taking input from either a property or a referenced Path = object.  The modifications are attached as well as a build.xml = file that demonstrates the new enhancements.

I would like to see these enhancements make it into a = future version of ant.

-- Fred Hart

  ------_=_NextPart_001_01C29D73.4EA3E940-- ------_=_NextPart_000_01C29D73.4EA3E940 Content-Type: application/octet-stream; name="build.xml" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="build.xml" =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= =0A= ------_=_NextPart_000_01C29D73.4EA3E940 Content-Type: application/octet-stream; name="PathConvert.java" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="PathConvert.java" /* * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software = itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Ant", and "Apache Software * Foundation" must not be used to endorse or promote products = derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.apache.tools.ant.taskdefs; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.condition.Os; import org.apache.tools.ant.types.DirSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileList; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Mapper; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.util.FileNameMapper; import org.apache.tools.ant.util.FlatFileNameMapper; import org.apache.tools.ant.util.IdentityMapper; import java.util.StringTokenizer; import java.util.Vector; import java.io.File; /** * Converts path and classpath information to a specific target OS * format. The resulting formatted path is placed into the specified = property. * * @author Larry Streepy * streepy@healthlanguage.com * @since Ant 1.4 * @ant.task category=3D"utility" */ public class PathConvert extends Task { // Members /** * Path to be converted */ private Path path =3D null; /** * Reference to path/fileset to convert */ private Reference refid =3D null; /** * The target OS type */ private String targetOS =3D null; /** * Set when targetOS is set to windows */ private boolean targetWindows =3D false; /** * Set if we're running on windows */ private boolean onWindows =3D false; /** * Set if we should create a new property even if the result is = empty */ private boolean setonempty =3D true; /** * The property to receive the conversion */ private String property =3D null;// /** * Path prefix map */ private Vector prefixMap =3D new Vector(); /** * User override on path sep char */ private String pathSep =3D null; /** * User override on directory sep char */ private String dirSep =3D null; protected Mapper mapperElement =3D null; /** * constructor */ public PathConvert() { onWindows =3D Os.isFamily("dos"); } /** * Helper class, holds the nested <map> values. Elements will = look like * this: <map from=3D"d:" to=3D"/foo"/> * * When running on windows, the prefix comparison will be case * insensitive. */ public class MapEntry { /** Set the "from" attribute of the map entry */ /** * the prefix string to search for; required. * Note that this value is case-insensitive when the build is * running on a Windows platform and case-sensitive when = running on * a Unix platform. * @param from */ public void setFrom(String from) { this.from =3D from; } /** * The replacement text to use when from is matched; required. * @param to new prefix */ public void setTo(String to) { this.to =3D to; } /** * Apply this map entry to a given path element * * @param elem Path element to process * @return String Updated path element after mapping */ public String apply(String elem) { if (from =3D=3D null || to =3D=3D null) { throw new BuildException("Both 'from' and 'to' must be = set " + "in a map entry"); } // If we're on windows, then do the comparison ignoring = case String cmpElem =3D onWindows ? elem.toLowerCase() : elem; String cmpFrom =3D onWindows ? from.toLowerCase() : from; // If the element starts with the configured prefix, then // convert the prefix to the configured 'to' value. if (cmpElem.startsWith(cmpFrom)) { int len =3D from.length(); if (len >=3D elem.length()) { elem =3D to; } else { elem =3D to + elem.substring(len); } } return elem; } // Members private String from =3D null; private String to =3D null; } /** * an enumeration of supported targets: * windows", "unix", "netware", and "os/2". */ public static class TargetOs extends EnumeratedAttribute { public String[] getValues() { return new String[]{"windows", "unix", "netware", "os/2"}; } } /** Create a nested PATH element */ public Path createPath() { if (isReference()) { throw noChildrenAllowed(); } if (path =3D=3D null) { path =3D new Path(getProject()); } return path.createPath(); } /** * Create a nested MAP element * @return a Map to configure */ public MapEntry createMap() { MapEntry entry =3D new MapEntry(); prefixMap.addElement(entry); return entry; } /** * Set targetos to a platform to one of * "windows", "unix", "netware", or "os/2"; required unless * unless pathsep and/or dirsep are specified. * * @deprecated use the method taking a TargetOs argument instead * @see #setTargetos(TargetOs) */ public void setTargetos(String target) { TargetOs to =3D new TargetOs(); to.setValue(target); setTargetos(to); } /** * Set targetos to a platform to one of * "windows", "unix", "netware", or "os/2"; required unless * unless pathsep and/or dirsep are specified. * * @since Ant 1.5 */ public void setTargetos(TargetOs target) { targetOS =3D target.getValue(); // Currently, we deal with only two path formats: Unix and = Windows // And Unix is everything that is not Windows // for NetWare and OS/2, piggy-back on Windows, since in the // validateSetup code, the same assumptions can be made as // with windows - that ; is the path separator targetWindows =3D !targetOS.equals("unix"); } /** * Set setonempty * * If false, don't set the new property if the result is the empty = string. * @param setonempty true or false * * @since Ant 1.5 */ public void setSetonempty(boolean setonempty) { this.setonempty =3D setonempty; } /** * The property into which the converted path will be placed. */ public void setProperty(String p) { property =3D p; } /** * Adds a reference to a Path, FileSet, DirSet, or FileList defined * elsewhere. */ public void setRefid(Reference r) { if (path !=3D null) { throw noChildrenAllowed(); } refid =3D r; } /** * Set the default path separator string; * defaults to current JVM * {@link java.io.File#pathSeparator File.pathSeparator} * @param sep path separator string */ public void setPathSep(String sep) { pathSep =3D sep; } /** * Set the default directory separator string; * defaults to current JVM {@link java.io.File#separator = File.separator} * @param sep directory separator string */ public void setDirSep(String sep) { dirSep =3D sep; } /** * Defines the mapper to map source to destination files. */ public Mapper createMapper() throws BuildException { if (mapperElement !=3D null) { throw new BuildException("Cannot define more than one = mapper", location); } mapperElement =3D new Mapper(project); return mapperElement; } protected Path applyMapper(Path names, FileNameMapper mapper) { // Get the list of path components in canonical form log("Applying mapper"); String[] elems =3D names.list(); Path result =3D new Path(null); for (int i =3D 0; i < elems.length; i++) { String[] results =3D mapper.mapFileName(elems[i]); String logPrefix =3D " processing: "+elems[i]; if ( results !=3D null ) { for (int j =3D 0; j < results.length; j++) { log(logPrefix+" =3D> '"+results[j]+"'"); logPrefix =3D ""; result.setPath(results[j]); } } else { log(logPrefix+" =3D> ''"); } } return result; } /** * Has the refid attribute of this element been set? * @return true if refid is valid */ public boolean isReference() { return refid !=3D null; } /** Do the execution. * @throws BuildException if something is invalid */ public void execute() throws BuildException { Path savedPath =3D path; String savedPathSep =3D pathSep;// may be altered in = validateSetup String savedDirSep =3D dirSep;// may be altered in = validateSetup try { // If we are a reference, create a Path from the reference if (isReference()) { path =3D new Path(getProject()).createPath(); Object obj =3D refid.getReferencedObject(getProject()); if (obj instanceof Path) { path.setRefid(refid); } else if (obj instanceof FileSet) { FileSet fs =3D (FileSet) obj; path.addFileset(fs); } else if (obj instanceof DirSet) { DirSet ds =3D (DirSet) obj; path.addDirset(ds); } else if (obj instanceof FileList) { FileList fl =3D (FileList) obj; path.addFilelist(fl); } else { throw new BuildException("'refid' does not refer to = a " + "path, fileset, dirset, or " + "filelist."); } } validateSetup();// validate our setup // Currently, we deal with only two path formats: Unix and = Windows // And Unix is everything that is not Windows // (with the exception for NetWare and OS/2 below) // for NetWare and OS/2, piggy-back on Windows, since here = and // in the apply code, the same assumptions can be made as = with // windows - that \\ is an OK separator, and do comparisons // case-insensitive. String fromDirSep =3D onWindows ? "\\" : "/"; StringBuffer rslt =3D new StringBuffer(100); if (mapperElement !=3D null) { path=3DapplyMapper(path, = mapperElement.getImplementation()); } // Get the list of path components in canonical form String[] elems =3D path.list(); for (int i =3D 0; i < elems.length; i++) { String elem =3D elems[i]; elem =3D mapElement(elem);// Apply the path prefix map // Now convert the path and file separator characters = from the // current os to the target os. if (i !=3D 0) { rslt.append(pathSep); } StringTokenizer stDirectory =3D new StringTokenizer(elem, fromDirSep, true); String token =3D null; while (stDirectory.hasMoreTokens()) { token =3D stDirectory.nextToken(); if (fromDirSep.equals(token)) { rslt.append(dirSep); } else { rslt.append(token); } } } // Place the result into the specified property, // unless setonempty =3D=3D false String value =3D rslt.toString(); if(setonempty) { log("Set property " + property + " =3D " + value, Project.MSG_VERBOSE); getProject().setNewProperty(property, value); } else { if(rslt.length() > 0) { log("Set property " + property + " =3D " + value, Project.MSG_VERBOSE); getProject().setNewProperty(property, value); } } } finally { path =3D savedPath; dirSep =3D savedDirSep; pathSep =3D savedPathSep; } } /** * Apply the configured map to a path element. The map is used to = convert * between Windows drive letters and Unix paths. If no map is = configured, * then the input string is returned unchanged. * * @param elem The path element to apply the map to * @return String Updated element */ private String mapElement(String elem) { int size =3D prefixMap.size(); if (size !=3D 0) { // Iterate over the map entries and apply each one. // Stop when one of the entries actually changes the = element. for (int i =3D 0; i < size; i++) { MapEntry entry =3D (MapEntry) prefixMap.elementAt(i); String newElem =3D entry.apply(elem); // Note I'm using "!=3D" to see if we got a new object = back from // the apply method. if (newElem !=3D elem) { elem =3D newElem; break;// We applied one, so we're done } } } return elem; } /** * Validate that all our parameters have been properly initialized. * * @throws BuildException if something is not setup properly */ private void validateSetup() throws BuildException { if (path =3D=3D null) { throw new BuildException("You must specify a path to = convert"); } if (property =3D=3D null) { throw new BuildException("You must specify a property"); } // Must either have a target OS or both a dirSep and pathSep if (targetOS =3D=3D null && pathSep =3D=3D null && dirSep = =3D=3D null) { throw new BuildException("You must specify at least one of = " + "targetOS, dirSep, or pathSep"); } // Determine the separator strings. The dirsep and pathsep = attributes // override the targetOS settings. String dsep =3D File.separator; String psep =3D File.pathSeparator; if (targetOS !=3D null) { psep =3D targetWindows ? ";" : ":"; dsep =3D targetWindows ? "\\" : "/"; } if (pathSep !=3D null) {// override with pathsep=3D psep =3D pathSep; } if (dirSep !=3D null) {// override with dirsep=3D dsep =3D dirSep; } pathSep =3D psep; dirSep =3D dsep; } /** * Creates an exception that indicates that this XML element must = not have * child elements if the refid attribute is set. */ private BuildException noChildrenAllowed() { return new BuildException("You must not specify nested " + "elements when using the refid attribute."); } } ------_=_NextPart_000_01C29D73.4EA3E940 Content-Type: application/octet-stream; name="ReplaceRegExp.java" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="ReplaceRegExp.java" /* * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software = itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Ant", and "Apache Software * Foundation" must not be used to endorse or promote products = derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ package org.apache.tools.ant.taskdefs.optional; import java.io.StringReader; import java.io.StringWriter; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.DirSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileList; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.RegularExpression; import org.apache.tools.ant.types.Substitution; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.regexp.Regexp; /** * Performs regular expression string replacements in a text * file. The input file(s) must be able to be properly processed by * a Reader instance. That is, they must be text only, no binary. * * The syntax of the regular expression depends on the implemtation = that * you choose to use. The system property = ant.regexp.regexpimpl * will be the classname of the implementation that will be used (the = default * is org.apache.tools.ant.util.regexp.JakartaOroRegexp = and * requires the Jakarta Oro Package). * *

 * For jdk  <=3D 1.3, there are two available implementations:
 *   org.apache.tools.ant.util.regexp.JakartaOroRegexp (the default)
 *        Requires  the jakarta-oro package
 *
 *   org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
 *        Requires the jakarta-regexp package
 *
 * For jdk >=3D 1.4 an additional implementation is available:
 *   org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp
 *        Requires the jdk 1.4 built in regular expression package.
 *
 * Usage:
 *
 *   Call Syntax:
 *
 *     <replaceregexp file=3D"file"
 *                    match=3D"pattern"=20
 *                    replace=3D"pattern"=20
 *                    flags=3D"options"?
 *                    byline=3D"true|false"? >
 *       regexp?
 *       substitution?
 *       fileset*
 *     </replaceregexp>
 *
 *    NOTE: You must have either the file attribute specified, or at =
least one fileset subelement
 *    to operation on.  You may not have the file attribute specified =
if you nest fileset elements
 *    inside this task.  Also, you cannot specify both match and a =
regular expression subelement at
 *    the same time, nor can you specify the replace attribute and the =
substitution subelement at
 *    the same time.
 *
 *   Attributes:
 *
 *     file    --> A single file to operation on (mutually exclusive =
with the fileset subelements)
 *     refid   --> A reference to a path-like object to to which to =
apply the replacement
 *     inputproperty --> A property whose value will be modifed and =
stored in the outputproperty
 *     outputproperty --> A property that will receive the results =
whe the input is a reference or property
 *     match   --> The Regular expression to match=20
 *     replace --> The Expression replacement string=20
 *     flags   --> The options to give to the replacement=20
 *                 g =3D Substitute all occurrences. default is to =
replace only the first one
 *                 i =3D Case insensitive match
 *
 *     byline  --> Should this file be processed a single line at a =
time (default is false)
 *                 "true" indicates to perform replacement on a line by =
line basis
 *                 "false" indicates to perform replacement on the =
whole file at once.
 *
 *  Example:
 *
 *     The following call could be used to replace an old property name =
in a ".properties"
 *     file with a new name.  In the replace attribute, you can refer =
to any part of the
 *     match expression in parenthesis using backslash followed by a =
number like '\1'.
 *
 *     <replaceregexp file=3D"test.properties"
 *                    match=3D"MyProperty=3D(.*)"
 *                    replace=3D"NewProperty=3D\1"
 *                    byline=3D"true" />
 *
 * 
* * @author Matthew Inger */ public class ReplaceRegExp extends Task { private File file; private String flags; private boolean byline; private Vector filesets;// Keep jdk 1.1 compliant so others can use = this private RegularExpression regex; private Substitution subs; private String inputprop; private String outputprop; /** * Reference to path/fileset to convert */ private Reference refid =3D null; /** * Path to be converted */ private Path path =3D null; private FileUtils fileUtils =3D FileUtils.newFileUtils(); /** Default Constructor */ public ReplaceRegExp() { super(); this.file =3D null; this.filesets =3D new Vector(); this.flags =3D ""; this.byline =3D false; this.regex =3D null; this.subs =3D null; } /** * file for which the regular expression should be replaced; * required unless a nested fileset is supplied. */ public void setFile(File file) { this.file =3D file; } /** * the regular expression pattern to match in the file(s); * required if no nested <regexp> is used */ public void setMatch(String match) { if (regex !=3D null) { throw new BuildException("Only one regular expression is = allowed"); } regex =3D new RegularExpression(); regex.setPattern(match); } /** * The substitution pattern to place in the file(s) in place * of the regular expression. * Required if no nested <substitution> is used */ =20 public void setReplace(String replace) { if (subs !=3D null) { throw new BuildException("Only one substitution expression = is " + "allowed"); } subs =3D new Substitution(); subs.setExpression(replace); } /** * The flags to use when matching the regular expression. For more * information, consult the Perl5 syntax. *
    *
  • g : Global replacement. Replace all occurences found *
  • i : Case Insensitive. Do not consider case in the match *
  • m : Multiline. Treat the string as multiple lines of = input,=20 * using "^" and "$" as the start or end of any line, = respectively, rather than start or end of string. *
  • s : Singleline. Treat the string as a single line of = input, using * "." to match any character, including a newline, which = normally, it would not match. *
*/ =20 public void setFlags(String flags) { this.flags =3D flags; } /** * Process the file(s) one line at a time, executing the = replacement * on one line at a time. This is useful if you * want to only replace the first occurence of a regular expression = on * each line, which is not easy to do when processing the file as a = whole. * Defaults to false. */ public void setByLine(String byline) { Boolean res =3D Boolean.valueOf(byline); if (res =3D=3D null) { res =3D Boolean.FALSE; } this.byline =3D res.booleanValue(); } /** * list files to apply the replacement to */ public void addFileset(FileSet set) { filesets.addElement(set); } /** * A regular expression. * You can use this element to refer to a previously * defined regular expression datatype instance */ public RegularExpression createRegexp() { if (regex !=3D null) { throw new BuildException("Only one regular expression is = allowed."); } regex =3D new RegularExpression(); return regex; } /** * A substitution pattern. You can use this element to refer to a = previously * defined substitution pattern datatype instance. */ public Substitution createSubstitution() { if (subs !=3D null) { throw new BuildException("Only one substitution expression = is " + "allowed"); } subs =3D new Substitution(); return subs; } /** * Property name whose value should be set to the output of * the process. Only valid when the input is not a file (i.e. * a property or path) */ public void setOutputproperty(String outputprop) { this.outputprop =3D outputprop; } /** * Make the input to be replaced a reference to a Path, FileSet, * DirSet, or FileList defined elsewhere. The output will be sent * to a new property set specified using the outputproperty * attribute */ public void setRefid(Reference r) { if (path !=3D null) { throw noChildrenAllowed(); } refid =3D r; } /** Create a nested PATH element */ public Path createPath() { if (refid !=3D null) { throw noChildrenAllowed(); } if (path =3D=3D null) { path =3D new Path(getProject()); } return path.createPath(); } /** * Property name whose value should be the input to * the process. Cannot be combined with the file attribute */ public void setInputproperty(String inputprop) { this.inputprop =3D inputprop; } protected String doReplace(RegularExpression r, Substitution s, String input, int options) { String res =3D input; Regexp regexp =3D r.getRegexp(getProject()); if (regexp.matches(input, options)) { res =3D regexp.substitute(input, = s.getExpression(getProject()),=20 options); } return res; } protected void doReplace(String input, String outputprop, int options) throws IOException { if (outputprop =3D=3D null) { throw new BuildException("You must supply the = 'outputproperty' "+ "attribute when using the = inputproperty"+ "or path."); } String result =3D input; StringReader r =3D null; StringWriter w =3D null; try { r =3D new StringReader(result); w =3D new StringWriter(result.length()); BufferedReader br =3D new BufferedReader(r); BufferedWriter bw =3D new BufferedWriter(w); PrintWriter pw =3D new PrintWriter(bw); boolean changes =3D false; log("Replacing pattern '" + regex.getPattern(getProject()) = + "' with '" + subs.getExpression(getProject()) + "' in '" + input + "' to property '" + outputprop +=20 "'" + (byline ? " by line" : "") + (flags.length() > 0 ? " with flags: '" + flags + "'" : = "") + ".", Project.MSG_VERBOSE); if (byline) { StringBuffer linebuf =3D new StringBuffer(); String line =3D null; String res =3D null; int c; boolean hasCR =3D false; do { c =3D br.read(); if (c =3D=3D '\r') { if (hasCR) { // second CR -> EOL + possibly empty line line =3D linebuf.toString(); res =3D doReplace(regex, subs, line, = options); if (!res.equals(line)) { changes =3D true; } pw.print(res); pw.print('\r'); linebuf.setLength(0); // hasCR is still true (for the second one) } else { // first CR in this line hasCR =3D true; } } else if (c =3D=3D '\n') { // LF -> EOL line =3D linebuf.toString(); res =3D doReplace(regex, subs, line, options); if (!res.equals(line)) { changes =3D true; } pw.print(res); if (hasCR) { pw.print('\r'); hasCR =3D false; } pw.print('\n'); linebuf.setLength(0); } else { // any other char if ((hasCR) || (c < 0)) { // Mac-style linebreak or EOF (or both) line =3D linebuf.toString(); res =3D doReplace(regex, subs, line, = options); if (!res.equals(line)) { changes =3D true; } pw.print(res); if (hasCR) { pw.print('\r'); hasCR =3D false; } linebuf.setLength(0); } if (c >=3D 0) { linebuf.append((char) c); } } } while (c >=3D 0); pw.flush(); } else { int flen =3D (int) result.length(); char tmpBuf[] =3D new char[flen]; int numread =3D 0; int totread =3D 0; while (numread !=3D -1 && totread < flen) { numread =3D br.read(tmpBuf, totread, flen); totread +=3D numread; } String buf =3D new String(tmpBuf); String res =3D doReplace(regex, subs, buf, options); if (!res.equals(buf)) { changes =3D true; } pw.print(res); pw.flush(); } if (changes) { result=3Dw.toString(); } } finally { try { if (r !=3D null) { r.close(); } } catch (Exception e) { } =20 try { if (w !=3D null) { w.close(); } } catch (Exception e) { } } project.setNewProperty(outputprop, result); } /** Perform the replace on the entire file */ protected void doReplace(File f, int options) throws IOException { File parentDir =3D fileUtils.getParentFile(f); File temp =3D fileUtils.createTempFile("replace", ".txt", = parentDir); FileReader r =3D null; FileWriter w =3D null; try { r =3D new FileReader(f); w =3D new FileWriter(temp); BufferedReader br =3D new BufferedReader(r); BufferedWriter bw =3D new BufferedWriter(w); PrintWriter pw =3D new PrintWriter(bw); boolean changes =3D false; log("Replacing pattern '" + regex.getPattern(getProject()) = + "' with '" + subs.getExpression(getProject()) + "' in '" + f.getPath() + "'" + (byline ? " by line" : "") + (flags.length() > 0 ? " with flags: '" + flags + "'" : = "") + ".", Project.MSG_VERBOSE); if (byline) { StringBuffer linebuf =3D new StringBuffer(); String line =3D null; String res =3D null; int c; boolean hasCR =3D false; do { c =3D br.read(); if (c =3D=3D '\r') { if (hasCR) { // second CR -> EOL + possibly empty line line =3D linebuf.toString(); res =3D doReplace(regex, subs, line, = options); if (!res.equals(line)) { changes =3D true; } pw.print(res); pw.print('\r'); linebuf.setLength(0); // hasCR is still true (for the second one) } else { // first CR in this line hasCR =3D true; } } else if (c =3D=3D '\n') { // LF -> EOL line =3D linebuf.toString(); res =3D doReplace(regex, subs, line, options); if (!res.equals(line)) { changes =3D true; } pw.print(res); if (hasCR) { pw.print('\r'); hasCR =3D false; } pw.print('\n'); linebuf.setLength(0); } else { // any other char if ((hasCR) || (c < 0)) { // Mac-style linebreak or EOF (or both) line =3D linebuf.toString(); res =3D doReplace(regex, subs, line, = options); if (!res.equals(line)) { changes =3D true; } pw.print(res); if (hasCR) { pw.print('\r'); hasCR =3D false; } linebuf.setLength(0); } if (c >=3D 0) { linebuf.append((char) c); } } } while (c >=3D 0); pw.flush(); } else { int flen =3D (int) f.length(); char tmpBuf[] =3D new char[flen]; int numread =3D 0; int totread =3D 0; while (numread !=3D -1 && totread < flen) { numread =3D br.read(tmpBuf, totread, flen); totread +=3D numread; } String buf =3D new String(tmpBuf); String res =3D doReplace(regex, subs, buf, options); if (!res.equals(buf)) { changes =3D true; } pw.print(res); pw.flush(); } r.close(); r =3D null; w.close(); w =3D null; if (changes) { if (!f.delete()) { throw new BuildException("Couldn't delete " + f, getLocation()); } if (!temp.renameTo(f)) { throw new BuildException("Couldn't rename temporary = file "=20 + temp, getLocation()); } temp =3D null; } } finally { try { if (r !=3D null) { r.close(); } } catch (Exception e) { } try { if (w !=3D null) { w.close(); } } catch (Exception e) { } if (temp !=3D null) { temp.delete(); } } } public void execute() throws BuildException { if (regex =3D=3D null) { throw new BuildException("No expression to match."); } if (subs =3D=3D null) { throw new BuildException("Nothing to replace expression = with."); } if (file !=3D null && filesets.size() > 0) { throw new BuildException("You cannot supply the 'file' = attribute " + "and filesets at the same = time."); } if (inputprop !=3D null && filesets.size() > 0) { throw new BuildException("You cannot supply the 'inputprop' = " + "attribute and filesets at the = same time."); } if (file !=3D null && inputprop !=3D null) { throw new BuildException("You cannot supply the 'file' = attribute " + "and input/output properties."); } int options =3D 0; if (flags.indexOf('g') !=3D -1) { options |=3D Regexp.REPLACE_ALL; } if (flags.indexOf('i') !=3D -1) { options |=3D Regexp.MATCH_CASE_INSENSITIVE; } if (flags.indexOf('m') !=3D -1) { options |=3D Regexp.MATCH_MULTILINE; } if (flags.indexOf('s') !=3D -1) { options |=3D Regexp.MATCH_SINGLELINE; } if (refid !=3D null) { path =3D new Path(getProject()).createPath(); =20 Object obj =3D refid.getReferencedObject(getProject()); =20 if (obj instanceof Path) { path.setRefid(refid); } else if (obj instanceof FileSet) { FileSet fs =3D (FileSet) obj; path.addFileset(fs); } else if (obj instanceof DirSet) { DirSet ds =3D (DirSet) obj; path.addDirset(ds); } else if (obj instanceof FileList) { FileList fl =3D (FileList) obj; path.addFilelist(fl); } else { throw new BuildException("'refid' does not refer to a " + "path, fileset, dirset, or " + "filelist."); } } if (path !=3D null) { try { doReplace(path.toString(), outputprop, options); } catch (IOException e) { log("An error occurred processing input property: '"=20 + inputprop + "': " + e.toString(), Project.MSG_ERR); } } else if (inputprop !=3D null) { try { doReplace(getProject().getProperty(inputprop),=20 outputprop, options); } catch (IOException e) { log("An error occurred processing input property: '"=20 + inputprop + "': " + e.toString(), Project.MSG_ERR); } } else if (file !=3D null && file.exists()) { try { doReplace(file, options); } catch (IOException e) { log("An error occurred processing file: '"=20 + file.getAbsolutePath() + "': " + e.toString(), Project.MSG_ERR); } } else if (file !=3D null) { log("The following file is missing: '"=20 + file.getAbsolutePath() + "'", Project.MSG_ERR); } int sz =3D filesets.size(); for (int i =3D 0; i < sz; i++) { FileSet fs =3D (FileSet) (filesets.elementAt(i)); DirectoryScanner ds =3D = fs.getDirectoryScanner(getProject()); String files[] =3D ds.getIncludedFiles(); for (int j =3D 0; j < files.length; j++) { File f =3D new File(fs.getDir(getProject()), files[j]); if (f.exists()) { try { doReplace(f, options); } catch (Exception e) { log("An error occurred processing file: '"=20 + f.getAbsolutePath() + "': " + = e.toString(), Project.MSG_ERR); } } else { log("The following file is missing: '"=20 + f.getAbsolutePath() + "'", Project.MSG_ERR); } } } } /** * Creates an exception that indicates that this XML element must = not have * child elements if the refid attribute is set. */ private BuildException noChildrenAllowed() { return new BuildException("You must not specify nested " + "elements when using the refid attribute."); } } ------_=_NextPart_000_01C29D73.4EA3E940 Content-Type: text/plain; charset=us-ascii -- To unsubscribe, e-mail: For additional commands, e-mail: ------_=_NextPart_000_01C29D73.4EA3E940--