Hi,

Herewith I am submitting the enhanced code of  Replace task .The existing replace task  has the functionality to replace all occurrences of the string specified in the 'token' attribute .

The enhanced code adds the following functionality's.
 1.'firstoccurence' can be true/false ,default value is false. Only the first occurrence of the string gets replaced .
 2. 'lastoccurence' can be true /false  ,default value is false. Only the lastoccurence of the string gets replaced .
3.'nthoccurence' attribute takes an integer  value  If the int value is 4 , the fourth occurrence of the  string gets replaced
4. 'fromline ' and ' toline' attributes applies the replace task functionality to a specified portion of the file.
   e.g.; if fromline ='4' and toline='7' , the replacement occurs only between line 4 and 7 .

Please find the enhanced code attached along with this. I would be nice  if you let me know the status after review.

Thanks and regards
C.S.Vidhya
SIP Technologies and Exports Ltd. Chennai, India
 

package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Writer;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;

/**
 * Replaces all occurrences of one or more string tokens with given
 * values in the indicated files. Each value can be either a string
 * or the value of a property available in a designated property file.
 * If you want to replace a text that crosses line boundaries, you
 * must use a nested <code>&lt;replacetoken&gt;</code> element.
 * @author Stefano Mazzocchi
 *         <a href="mailto:[EMAIL PROTECTED]">[EMAIL PROTECTED]</a>
 * @author <a href="mailto:[EMAIL PROTECTED]">Erik Langenbach</a>
 *
 * @since Ant 1.1
 *
 * @ant.task category="filesystem"
 */
public class Replace extends MatchingTask {

    private File src = null;
    private NestedString token = null;
    private NestedString value = new NestedString();

    private File propertyFile = null;
    private File replaceFilterFile = null;
    private Properties properties = null;
    private Vector replacefilters = new Vector();

    private File dir = null;

    private int fileCount;
    private int replaceCount;
    private boolean summary = false;
    private boolean firstoccurence = false;
    private boolean lastoccurence = false;
    private int nthoccurence=0;
    private int fromline= 0;
    private int toline = 0;



    /** The encoding used to read and write files - if null, uses default */
    private String encoding = null;

    private FileUtils fileUtils = FileUtils.newFileUtils();

    /**
     * an inline string to use as the replacement text
     */
    public class NestedString {

        private StringBuffer buf = new StringBuffer();

        public void addText(String val) {
            buf.append(val);
        }

        public String getText() {
            return buf.toString();
        }
    }

    /**
     * A filter to apply.
     */
    public class Replacefilter {
        private String token;
        private String value;
        private String property;

        /**
         * validate the filter's configuration
         * @throws BuildException if any part is invalid
         */
        public void validate() throws BuildException {
            //Validate mandatory attributes
            if (token == null) {
                String message = "token is a mandatory attribute "
                    + "of replacefilter.";
                throw new BuildException(message);
            }

            if ("".equals(token)) {
                String message = "The token attribute must not be an empty "
                    + "string.";
                throw new BuildException(message);
            }

            //value and property are mutually exclusive attributes
            if ((value != null) && (property != null)) {
                String message = "Either value or property "
                    + "can be specified, but a replacefilter "
                    + "element cannot have both.";
                throw new BuildException(message);
            }


            if ((property != null)) {
                //the property attribute must have access to a property file
                if (propertyFile == null) {
                    String message = "The replacefilter's property attribute "
                        + "can only be used with the replacetask's "
                        + "propertyFile attribute.";
                    throw new BuildException(message);
                }

                //Make sure property exists in property file
                if (properties == null ||
                    properties.getProperty(property) == null) {
                    String message = "property \"" + property
                        + "\" was not found in " + propertyFile.getPath();
                    throw new BuildException(message);
                }

            }
        }

        /**
         * get the replacement value for this filter token
         * @return
         */
        public String getReplaceValue() {
            if (property != null) {
                return properties.getProperty(property);
            } else if (value != null) {
                return value;
            } else if (Replace.this.value != null) {
                return Replace.this.value.getText();
            } else {
                //Default is empty string
                return new String("");
            }
        }

        /**
         * Set the token to replace
         * @param token token
         */
        public void setToken(String token) {
            this.token = token;
        }

        /**
         * Get the string to search for
         * @return current token
         */
        public String getToken() {
            return token;
        }


         /**
         * The replacement string; required if <code>property<code>
         * is not set
         * @param value value to replace
         */
        public void setValue(String value) {
            this.value = value;
        }

        /**
         * Get replacements string
         * @return replacement or null
         */
        public String getValue() {
            return value;
        }

        /**
         * Set the name of the property whose value is to serve as
         * the replacement value; required if <code>value</code> is not set.
         * @param property propname
         */
        public void setProperty(String property) {
            this.property = property;
        }

        /**
         * Get the name of the property whose value is to serve as
         * the replacement value;
         * @return property or null
         */
        public String getProperty() {
            return property;
        }
    }

    /**
     * Do the execution.
     * @throws BuildException if we cant build
     */
    public void execute() throws BuildException {

        Vector savedFilters = (Vector) replacefilters.clone();
        Properties savedProperties =
            properties == null ? null : (Properties) properties.clone();

        try {
            if (replaceFilterFile != null) {
                Properties props = getProperties(replaceFilterFile);
                Enumeration enum = props.keys();
                while (enum.hasMoreElements()){
                    String token =  enum.nextElement().toString();
                    Replacefilter replaceFilter = createReplacefilter();
                    replaceFilter.setToken(token);
                    replaceFilter.setValue(props.getProperty(token));
                }
            }

            validateAttributes();

            if (propertyFile != null) {
                properties = getProperties(propertyFile);
            }

            validateReplacefilters();
            fileCount = 0;
            replaceCount = 0;

            if (src != null) {
                processFile(src);
            }

            if (dir != null) {
                DirectoryScanner ds = super.getDirectoryScanner(dir);
                String[] srcs = ds.getIncludedFiles();

                for (int i = 0; i < srcs.length; i++) {
                    File file = new File(dir, srcs[i]);
                    processFile(file);
                }
            }

            if (summary) {
                log("Replaced " + replaceCount + " occurrences in "
                    + fileCount + " files.", Project.MSG_INFO);
            }
        } finally {
            replacefilters = savedFilters;
            properties = savedProperties;
        } // end of finally

    }

    /**
     * Validate attributes provided for this task in .xml build file.
     *
     * @exception BuildException if any supplied attribute is invalid or any
     * mandatory attribute is missing
     */
    public void validateAttributes() throws BuildException {
        if (src == null && dir == null) {
            String message = "Either the file or the dir attribute "
                + "must be specified";
            throw new BuildException(message, location);
        }
        if (propertyFile != null && !propertyFile.exists()) {
            String message = "Property file " + propertyFile.getPath()
                + " does not exist.";
            throw new BuildException(message, location);
        }
        if (token == null && replacefilters.size() == 0) {
            String message = "Either token or a nested replacefilter "
                + "must be specified";
            throw new BuildException(message, location);
        }
        if (token != null && "".equals(token.getText())) {
            String message = "The token attribute must not be an empty string.";
            throw new BuildException(message, location);
         }

    }

    /**
     * Validate nested elements.
     *
     * @exception BuildException if any supplied attribute is invalid or any
     * mandatory attribute is missing
     */
    public void validateReplacefilters()
            throws BuildException {
        for (int i = 0; i < replacefilters.size(); i++) {
            Replacefilter element =
                (Replacefilter) replacefilters.elementAt(i);
            element.validate();
        }
    }

    /**
     * helper method to load a properties file and throw a build exception
     * if it cannot be loaded
     * @param propertyFile
     * @return loaded properties collection
     * @throws BuildException if the file could not be found or read
     */
    public Properties getProperties(File propertyFile) throws BuildException {
        Properties properties = new Properties();

        try {
            properties.load(new FileInputStream(propertyFile));
        } catch (FileNotFoundException e) {
            String message = "Property file (" + propertyFile.getPath()
                + ") not found.";
            throw new BuildException(message);
        } catch (IOException e) {
            String message = "Property file (" + propertyFile.getPath()
                + ") cannot be loaded.";
            throw new BuildException(message);
        }

        return properties;
    }

    /**
     * Perform the replacement on the given file.
     *
     * The replacement is performed on a temporary file which then
     * replaces the original file.
     *
     * @param src the source file
     */
    private void processFile(File src) throws BuildException {
        if (!src.exists()) {
            throw new BuildException("Replace: source file " + src.getPath()
                                     + " doesn't exist", location);
        }

        File temp = fileUtils.createTempFile("rep", ".tmp",
                                             fileUtils.getParentFile(src));

        Reader reader = null;
        Writer writer = null;
        try {
            reader = encoding == null ? new FileReader(src)
                : new InputStreamReader(new FileInputStream(src), encoding);
            writer = encoding == null ? new FileWriter(temp)
                : new OutputStreamWriter(new FileOutputStream(temp), encoding);

            BufferedReader br = new BufferedReader(reader);
            BufferedWriter bw = new BufferedWriter(writer);

            // read the entire file into a StringBuffer
            //   size of work buffer may be bigger than needed
            //   when multibyte characters exist in the source file
            //   but then again, it might be smaller than needed on
            //   platforms like Windows where length can't be trusted
            int fileLengthInBytes = (int) src.length();
            StringBuffer tmpBuf = new StringBuffer(fileLengthInBytes);
            int readChar = 0;
            int totread  = 0;
            int i=1;

            //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and 
Exports Ltd, INDIA
            //reads a part of the file specified by
            // fromline and toline into foundpart
            StringBuffer part1=new StringBuffer();
            StringBuffer foundpart=new StringBuffer();
            StringBuffer part2 = new StringBuffer();
            StringBuffer fullbuf= new StringBuffer();
            String tmpstr= new String();
            String nstring= new String();

            /* if from and to lines are specified*/

            if(fromline!=0 && toline!=0){
                if(i!=fromline){
                        for(i=1; i<fromline;i++){
                        tmpstr=(String)br.readLine();
                        part1.append(tmpstr).append("\n");
                        }
                }
                for(i=fromline;i<=toline;i++){
                        tmpstr=(String)br.readLine();
                        if(tmpstr==null)break;
                        foundpart.append(tmpstr).append("\n");
                }
                /*contains the string between the lines from and to*/

                nstring = foundpart.toString();
                while(true){
                        tmpstr=br.readLine();
                        if(tmpstr==null) break;
                        part2.append(tmpstr).append("\n");
                }

            }

            while (true) {
                readChar = br.read();
                if (readChar < 0) { break; }
                tmpBuf.append((char) readChar);
                totread++;
            }



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

            //Preserve original string (buf) so we can compare the result
            String newString = new String(buf);

            if (token != null) {
                // line separators in values and tokens are "\n"
                // in order to compare with the file contents, replace them
                // as needed
                String val = stringReplace(value.getText(), "\n",
                                           StringUtils.LINE_SEP);
                String tok = stringReplace(token.getText(), "\n",
                                           StringUtils.LINE_SEP);


                // for each found token, replace with value
                log("Replacing in " + src.getPath() + ": " + token.getText()
                    + " --> " + value.getText(), Project.MSG_VERBOSE);
                //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and 
Exports Ltd, INDIA
                 if(fromline!=0 && toline!=0)
                  nstring=stringReplace(nstring,tok,val);
                 else
                  newString = stringReplace(newString, tok, val);
            }



            if (replacefilters.size() > 0) {
            if (fromline !=0 && toline!=0)
              nstring=processReplacefilters(nstring,src.getPath());
            else
                newString = processReplacefilters(newString, src.getPath());
            }
            //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and 
Exports Ltd, INDIA
            if(fromline!=0 && toline!=0){
                if(part1!=null) newString=part1.toString()+nstring.toString();
                else newString=nstring.toString();
                if(part2!=null) newString+=part2.toString();
            }



             boolean changes = !newString.equals(buf);

             if (changes) {
                bw.write(newString, 0, newString.length());
                bw.flush();

            }

            // cleanup
            bw.close();
            writer = null;
            br.close();
            reader = null;

            // If there were changes, move the new one to the old one;
            // otherwise, delete the new one
            if (changes) {
                ++fileCount;
                if (!src.delete()) {
                    throw new BuildException("Couldn't delete " + src,
                                             getLocation());
                }
                if (!temp.renameTo(src)) {
                    throw new BuildException("Couldn't rename temporary file "
                                             + temp, getLocation());
                }
                temp = null;
            }
        } catch (IOException ioe) {
            throw new BuildException("IOException in " + src + " - " +
                                     ioe.getClass().getName() + ":"
                                     + ioe.getMessage(), ioe, location);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {}
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {}
            }
            if (temp != null) {
                temp.delete();
            }
        }

    }

    /**
     * apply all replace filters to a buffer
     * @param buffer string to filter
     * @param filename filename for logging purposes
     * @return filtered string
     */
    private String processReplacefilters(String buffer, String filename) {
        String newString = new String(buffer);

        for (int i = 0; i < replacefilters.size(); i++) {
            Replacefilter filter = (Replacefilter) replacefilters.elementAt(i);

            //for each found token, replace with value
            log("Replacing in " + filename + ": " + filter.getToken()
                + " --> " + filter.getReplaceValue(), Project.MSG_VERBOSE);
            newString = stringReplace(newString, filter.getToken(),
                                      filter.getReplaceValue());
        }

        return newString;
    }


    /**
     * Set the source file; required unless <code>dir</code> is set.
     * @param file source file
     */
    public void setFile(File file) {
        this.src = file;
    }

    /**
     * Indicates whether a summary of the replace operation should be
     * produced, detailing how many token occurrences and files were
     * processed; optional, default=false
     *
     * @param summary true if you would like a summary logged of the
     * replace operation
     */
    public void setSummary(boolean summary) {
        this.summary = summary;


    }




    /**
     * Sets the name of a property file containing filters; optional.
     * Each property will be treated as a
     * replacefilter where token is the name of the property and value
     * is the value of the property.
     * @param filename file to load
     */
    public void setReplaceFilterFile(File filename) {
        replaceFilterFile = filename;
    }

    /**
     * The base directory to use when replacing a token in multiple files;
     * required if <code>file</code> is not defined.
     * @param dir base dir
     */
    public void setDir(File dir) {
        this.dir = dir;
    }

    /**
     * Set the string token to replace;
     * required unless a nested
     * <code>replacetoken</code> element or the <code>replacefilterfile</code>
     * attribute is used.
     * @param token token string
     */
    public void setToken(String token) {
        createReplaceToken().addText(token);
    }

    /**
     * Set the string value to use as token replacement;
     * optional, default is the empty string ""
     * @param value replacement value
     */
        public void setValue(String value) {
                createReplaceValue().addText(value);
        }


        //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and Exports 
Ltd, INDIA
        public void setFirstOccurence(boolean firstoccurence){
                this.firstoccurence= firstoccurence;
        }

        //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and Exports 
Ltd, INDIA
        public void setLastOccurence(boolean lastoccurence){
                this.lastoccurence=lastoccurence;
        }
        //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and Exports 
Ltd, INDIA
        public void setNthoccurence(int nthoccurence){
                this.nthoccurence= nthoccurence;

        }
        //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and Exports 
Ltd, INDIA
        public void setFromLine(int fromline){
              this.fromline = fromline;
        }
        //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and Exports 
Ltd, INDIA
        public void setToLine(int toline){
               this.toline= toline;
        }




    /**
     * Set the file encoding to use on the files read and written by the task;
     * optional, defaults to default JVM encoding
     *
     * @param encoding the encoding to use on the files
     */
    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    /**
     * the token to filter as the text of a nested element
     * @return nested token to configure
     */
    public NestedString createReplaceToken() {
        if (token == null) {
            token = new NestedString();
        }
        return token;
       }

    /**
     * the string to replace the token as the text of a nested element
     * @return replacement value to configure
     */
    public NestedString createReplaceValue() {
        return value;
    }

    /**
     * The name of a property file from which properties specified using
     * nested <code>&lt;replacefilter&gt;</code> elements are drawn;
     * Required only if <i>property</i> attribute of
     * <code>&lt;replacefilter&gt;</code> is used.
     * @param filename file to load
     */
    public void setPropertyFile(File filename) {
        propertyFile = filename;
    }

    /**
     * Add a nested &lt;replacefilter&gt; element.
     */
    public Replacefilter createReplacefilter() {
        Replacefilter filter = new Replacefilter();
        replacefilters.addElement(filter);
        return filter;
    }

    /**
     Replace occurrences of str1 in string str with str2*/
  private String stringReplace(String str, String str1, String str2) {

        StringBuffer ret = new StringBuffer();
        int start = 0;
        int found = str.indexOf(str1);
        int count=1;
        int lfound=str.lastIndexOf(str1);

        //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and Exports 
Ltd, INDIA
        while (found >= 0) {
            appendString(ret,str.substring(start,found));
            //replaces the first occurence if firstoccurence is true and count
            //is equal to one.
            if(firstoccurence && count == 1) {
                appendString(ret,str2);
                //breaks the loop only if firstoccurence attribute is specified
                //as true and nthoccurence is zero or not specified and also
                //if lastoccurence is false
                if(firstoccurence && !lastoccurence && nthoccurence == 0) {
                    start = found + str1.length();
                    break;
                }
            }else if(nthoccurence == count) {
                //replaces the nth occurence if nth occurence and count
                //is equal.

                      appendString(ret,str2);
                if(!firstoccurence && !lastoccurence && nthoccurence != 0) {
                    start = found + str1.length();
                    break;
                }

            }else if(!firstoccurence && !lastoccurence && nthoccurence == 0) {
                //if no attributes firstoccurence, lastoccurence &
                //nth occurence is specified then it replaces all token with the
                //specified value.
                appendString(ret,str2);
            }else {
                //breaks the loop only if lastoccurence attribute is specified
                //as true and nthoccurence is zero or not specified and also
                //if firstoccurence is false
                if(!firstoccurence && lastoccurence && nthoccurence == 0) {
                    appendString(ret,str.substring(found,lfound));
                    appendString(ret,str2);
                    start = lfound + str1.length();
                    break;
                }else if(lfound == found && lastoccurence) {
                    //replaces the last occurence
                    appendString(ret,str2);
                }else {
                    appendString(ret,str1);
                }
            }

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

        if(str.length() > start) {
            appendString(ret,str.substring(start, str.length()));
        }

        return ret.toString();

    }

    //added by C.S.Vidhya<[EMAIL PROTECTED]> SIP Technologies and Exports Ltd, 
INDIA
    //method that appends the string to the stringbuffer after
    //checking for null.
    private void appendString(StringBuffer sb, String str) {
        if(str != null) {
            sb.append(str);
        }
    }
}

Reply via email to