You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by EL...@desknetinc.com on 2000/07/17 19:02:35 UTC

Multiline Replace Task

As this is my first ant-dev posting, please feel free to point out any
mailing list wrongdoings I may be guilty of... :-).

I had a need to do multiline replaces with Ant, but couldn't figure out a
solution using the current <replace> task.  Therefore, I created a new
task, <dnreplace>, that uses nested tasks, <dntoken> and <dnvalue>, to
specify the token and value.

As an example of it's use:

<dnreplace file="foo.txt">
     <dntoken><![CDATA[I am a
multiline
token]]></dntoken>
     <dnvalue><![CDATA[I am a
multiline
value]]></dnvalue>
</dnreplace>

This snippet would replace "I am a\nmultiline\ntoken" with "I am
a\nmultiline\nvalue" in the file foo.txt, where '\n' is os-dependent.

For those that might be interested, here are the 3 source files:

===================================================
 DnToken.java
===================================================
/*
     This task is used with DnReplace.java.
*/

package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.Task;

public class DnToken extends Task {
     String text;

     public Object addText(String text) {
          this.text = text;
          return null;
     }

     public String getText() {
          return text;
     }
}

===================================================
 DnValue.java
===================================================
/*
     This task is used with DnReplace.java.
*/

package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.Task;

public class DnValue extends Task {
     String text;

     public Object addText(String text) {
          this.text = text;
          return null;
     }

     public String getText() {
          return text;
     }
}

===================================================
 DnReplace.java
===================================================
/*
     This task is used to replace a token with a value in a file.  Instead
of using
     attributes to assign the token and value, it uses included tasks.
This allows
     for multi-line tokens and values.

     <dntoken> is required and must have a non-empty value (e.g.,
<dntoken></dntoken) is not allowed)
     if <dnvalue> is not supplied or is supplied with an empty value, the
token will be
     replaced with nothing.

     **NOTE: the length of the file must fit into an integer (we cast from
long to int)

     Example:
          <dnreplace file="foo.txt">
               <dntoken><![CDATA[I am a
                    multiline
                    token]]></dntoken>
               <dnvalue><![CDATA[I am a
                    multiline
                    value]]></dnvalue>
          </dnreplace>
*/

package org.apache.tools.ant.taskdefs;

import java.util.*;
import java.io.*;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.DnToken;
import org.apache.tools.ant.taskdefs.DnValue;

public class DnReplace extends Task {
     private File src = null;
     private File dest = null;
     DnToken dnToken = null;
     DnValue dnValue = null;
     String token = null;
     String value = null;

     // a mutable integer class
     class IntMut {
          int val;

          IntMut(int i) {
               setVal(i);
          }

          void setVal(int i) {
               val = i;
          }

          int getVal() {
               return val;
          }
     }

     // The method executing the task
     public void execute() throws BuildException {
          String token,value;

          // get and check token and value strings
          if (dnToken == null) {
               project.log("A token must be provided using the <dntoken>
element.");
               return;
          }
          token = dnToken.getText();
          if (token == null || token.length() == 0) {
               project.log("The token must have length > 0.");
               return;
          }
          if (dnValue == null) {
               value = null;
          } else {
               value = dnValue.getText();
          }

          // replace properties in token & value
          if (token != null) {
               token =
ProjectHelper.replaceProperties(token,project.getProperties());
          }
          if (value != null) {
               value =
ProjectHelper.replaceProperties(value,project.getProperties());
          }

          // check file
          if (src == null) {
               project.log("The file must not be null.");
          }
          if (dest == null) {
               throw new BuildException("Error creating temp file.");
          }

          // tell the user what we're doing
          project.log("Replacing:\n" + token + "\nwith:\n" + value);

          // do the replace
          try {
               BufferedReader br = new BufferedReader(new FileReader(src));
               BufferedWriter bw = new BufferedWriter(new
FileWriter(dest));

               // read the entire file into a char[]
               int fileLength = (int)(src.length());
               char[] tmpBuf = new char[fileLength];
               int numread = 0;
               int totread = 0;
               while (numread != -1 && totread < fileLength) {
                    numread = br.read(tmpBuf,totread,fileLength);
                    totread += numread;
               }

               // create a String so we can use indexOf
               String buf = new String(tmpBuf);

               // line separators in values and tokens are "\n"
               // in order to compare with the file contents, replace them
as needed
               String linesep = System.getProperty("line.separator");
               if (value != null) {
                    value = stringReplace(value,"\n",linesep,null);
               }
               if (token != null) {
                    token = stringReplace(token,"\n",linesep,null);
               }

               // for each found token, replace with value and write to the
output file
               IntMut numoccur = new IntMut(0);
               buf = stringReplace(buf,token,value,numoccur);
               bw.write(buf,0,buf.length());
               bw.flush();

               // report stats
               System.out.println("Replaced " + numoccur.getVal() + "
occurrence(s).");

               // cleanup
               bw.close();
               br.close();
               src.delete();
               dest.renameTo(src);
          } catch (IOException ioe) {
               ioe.printStackTrace();
          }
     }

     // replace occurrences of str1 in string str with str2
     private String stringReplace(String str, String str1, String str2,
IntMut numoccur) {
          String ret = new String();
          int occur = 0;
          int start = 0;
          int found = str.indexOf(str1);
          while (found >= 0) {
               occur++;

               // write everything up to the found str1
               if (found > start) {
                    ret = ret.concat(str.substring(start,found));
               }

               // write the replacement str2
               if (str2 != null) {
                    ret = ret.concat(str2);
               }

               // search again
               start = found + str1.length();
               found = str.indexOf(str1,start);
          }

          // write the remaining characters
          if (str.length() > start) {
               ret = ret.concat(str.substring(start,str.length()));
          }

          // return results
          if (numoccur != null) {
               numoccur.setVal(occur);
          }
          return ret;
     }

     // print the supplied string as integer values of each character
     // used for debugging only
     public void debugString(String label, String str) {
          System.out.println(label);
          int j = 0;
          while (j < str.length()) {
               System.out.println("str[" + j + "] = " +
(int)str.charAt(j));
               j++;
          }
     }

     // The setter for the "file" attribute
     public void setFile(String file) {
          this.src = project.resolveFile(file);
          this.dest = project.resolveFile(file + ".temp");
     }

     // Create a task for nested dntokens
     public Task createDntoken() {
          dnToken = (DnToken) project.createTask("dntoken");
          return dnToken;
     }

     // Create a task for nested dnvalues
     public Task createDnvalue() {
          dnValue = (DnValue) project.createTask("dnvalue");
          return dnValue;
     }
}
______________________________________________
Erik Langenbach
erik@desknetinc.com


Re: Multiline Replace Task

Posted by Stefan Bodewig <bo...@bost.de>.
Hi Erik,

I think something like this task could be very useful indeed. Having
only a quick glance on the actual code I found a simple issue, your
addText methods need to return void or they will never be called.

Stefan