| /* |
| * 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. |
| * ==================================================================== |
| * |
| * 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 |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.tools.ant.taskdefs.optional; |
| |
| 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.util.regexp.Regexp; |
| import org.apache.tools.ant.types.RegularExpression; |
| import org.apache.tools.ant.types.Substitution; |
| import org.apache.tools.ant.types.FileSet; |
| import org.apache.tools.ant.util.FileUtils; |
| 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.LineNumberReader; |
| import java.io.PrintWriter; |
| |
| import java.util.Vector; |
| |
| /*** |
| * <pre> |
| * Task to do 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 <code>ant.regexp.regexpimpl</code> |
| * will be the classname of the implementation that will be used (the default |
| * is <code>org.apache.tools.ant.util.regexp.JakartaOroRegexp</code> and |
| * requires the Jakarta Oro Package). |
| * |
| * <pre> |
| * For jdk <= 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 >= 1.4 an additional implementation is available: |
| * org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp |
| * Requires the jdk 1.4 built in regular expression package. |
| * </pre> |
| * |
| * Usage: |
| * |
| * Call Syntax: |
| * |
| * <replaceregexp file="file" |
| * match="pattern" |
| * replace="pattern" |
| * flags="options"? |
| * byline="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) |
| * match --> The Regular expression to match |
| * replace --> The Expression replacement string |
| * flags --> The options to give to the replacement |
| * g = Substitute all occurrences. default is to replace only the first one |
| * i = 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="test.properties" |
| * match="MyProperty=(.*)" |
| * replace="NewProperty=\1" |
| * byline="true" /> |
| * |
| * </pre> |
| * |
| * @author <a href="mailto:mattinger@mindless.com">Matthew Inger</a> |
| */ |
| 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 FileUtils fileUtils = FileUtils.newFileUtils(); |
| |
| /*** |
| * Default Constructor |
| */ |
| public ReplaceRegExp() |
| { |
| super(); |
| this.file = null; |
| this.filesets = new Vector(); |
| this.flags = ""; |
| this.byline = false; |
| |
| this.regex = null; |
| this.subs = null; |
| } |
| |
| public void setFile(File file) |
| { |
| this.file = file; |
| } |
| |
| public void setMatch(String match) |
| { |
| if (regex != null) { |
| throw new BuildException("Only one regular expression is allowed"); |
| } |
| |
| regex = new RegularExpression(); |
| regex.setPattern(match); |
| } |
| |
| public void setReplace(String replace) |
| { |
| if (subs != null) { |
| throw new BuildException("Only one substitution expression is allowed"); |
| } |
| |
| subs = new Substitution(); |
| subs.setExpression(replace); |
| } |
| |
| public void setFlags(String flags) |
| { |
| this.flags = flags; |
| } |
| |
| public void setByLine(String byline) |
| { |
| Boolean res = Boolean.valueOf(byline); |
| if (res == null) { |
| res = Boolean.FALSE; |
| } |
| this.byline = res.booleanValue(); |
| } |
| |
| public void addFileset(FileSet set) |
| { |
| filesets.addElement(set); |
| } |
| |
| public RegularExpression createRegexp() |
| { |
| if (regex != null) { |
| throw new BuildException("Only one regular expression is allowed."); |
| } |
| |
| regex = new RegularExpression(); |
| return regex; |
| } |
| |
| public Substitution createSubstitution() |
| { |
| if (subs != null) { |
| throw new BuildException("Only one substitution expression is allowed"); |
| } |
| |
| subs = new Substitution(); |
| return subs; |
| } |
| |
| |
| protected String doReplace(RegularExpression r, |
| Substitution s, |
| String input, |
| int options) |
| { |
| String res = input; |
| Regexp regexp = r.getRegexp(project); |
| |
| if (regexp.matches(input, options)) |
| { |
| res = regexp.substitute(input, s.getExpression(project), options); |
| } |
| |
| return res; |
| } |
| |
| /*** |
| * Perform the replace on the entire file |
| */ |
| protected void doReplace(File f, int options) |
| throws IOException |
| { |
| File parentDir = new File(new File(f.getAbsolutePath()).getParent()); |
| File temp = fileUtils.createTempFile("replace", ".txt", parentDir); |
| |
| FileReader r = null; |
| FileWriter w = null; |
| |
| try |
| { |
| r = new FileReader(f); |
| w = new FileWriter(temp); |
| |
| BufferedReader br = new BufferedReader(r); |
| BufferedWriter bw = new BufferedWriter(w); |
| PrintWriter pw = new PrintWriter(bw); |
| |
| boolean changes = false; |
| |
| log("Replacing pattern '" + regex.getPattern(project) + "' with '" + subs.getExpression(project) + |
| "' in '" + f.getPath() + "'" + |
| (byline ? " by line" : "") + |
| (flags.length() > 0 ? " with flags: '" + flags + "'" : "") + |
| ".", |
| Project.MSG_WARN); |
| |
| if (byline) |
| { |
| LineNumberReader lnr = new LineNumberReader(br); |
| String line = null; |
| |
| while ((line = lnr.readLine()) != null) |
| { |
| String res = doReplace(regex, subs, line, options); |
| if (! res.equals(line)) { |
| changes = true; |
| } |
| |
| pw.println(res); |
| } |
| pw.flush(); |
| } |
| else |
| { |
| int flen = (int)(f.length()); |
| char tmpBuf[] = new char[flen]; |
| int numread = 0; |
| int totread = 0; |
| while (numread != -1 && totread < flen) |
| { |
| numread = br.read(tmpBuf, totread, flen); |
| totread += numread; |
| } |
| |
| String buf = new String(tmpBuf); |
| |
| String res = doReplace(regex, subs, buf, options); |
| if (! res.equals(buf)) { |
| changes = true; |
| } |
| |
| pw.println(res); |
| pw.flush(); |
| } |
| |
| r.close(); |
| r = null; |
| w.close(); |
| w = null; |
| |
| if (changes) |
| { |
| f.delete(); |
| temp.renameTo(f); |
| } |
| else |
| { |
| temp.delete(); |
| } |
| } |
| finally |
| { |
| try { if (r != null) { |
| r.close(); |
| } } |
| catch (Exception e) { }; |
| |
| try { if (w != null) { |
| r.close(); |
| } } |
| catch (Exception e) { }; |
| } |
| } |
| |
| public void execute() |
| throws BuildException |
| { |
| if (regex == null) { |
| throw new BuildException("No expression to match."); |
| } |
| if (subs == null) { |
| throw new BuildException("Nothing to replace expression with."); |
| } |
| |
| if (file != null && filesets.size() > 0) { |
| throw new BuildException("You cannot supply the 'file' attribute and filesets at the same time."); |
| } |
| |
| |
| int options = 0; |
| |
| if (flags.indexOf('g') != -1) { |
| options |= Regexp.REPLACE_ALL; |
| } |
| |
| if (flags.indexOf('i') != -1) { |
| options |= Regexp.MATCH_CASE_INSENSITIVE; |
| } |
| |
| if (flags.indexOf('m') != -1) { |
| options |= Regexp.MATCH_MULTILINE; |
| } |
| |
| if (flags.indexOf('s') != -1) { |
| options |= Regexp.MATCH_SINGLELINE; |
| } |
| |
| if (file != null && file.exists()) |
| { |
| try |
| { |
| doReplace(file, options); |
| } |
| catch (IOException e) |
| { |
| log("An error occurred processing file: '" + file.getAbsolutePath() + "': " + e.toString(), |
| Project.MSG_ERR); |
| } |
| } |
| else if (file != null) |
| { |
| log("The following file is missing: '" + file.getAbsolutePath() + "'", |
| Project.MSG_ERR); |
| } |
| |
| int sz = filesets.size(); |
| for (int i=0;i<sz;i++) |
| { |
| FileSet fs = (FileSet)(filesets.elementAt(i)); |
| DirectoryScanner ds = fs.getDirectoryScanner(getProject()); |
| |
| String files[] = ds.getIncludedFiles(); |
| for (int j=0;j<files.length;j++) |
| { |
| File f = new File(files[j]); |
| if (f.exists()) |
| { |
| try |
| { |
| doReplace(f, options); |
| } |
| catch (Exception e) |
| { |
| log("An error occurred processing file: '" + f.getAbsolutePath() + "': " + e.toString(), |
| Project.MSG_ERR); |
| } |
| } |
| else |
| { |
| log("The following file is missing: '" + file.getAbsolutePath() + "'", |
| Project.MSG_ERR); |
| } |
| } |
| } |
| } |
| |
| } |
| |
| |