
com.tangosol.dev.tools.Replace Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.dev.tools;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Enumeration;
/**
* A global search and replace utility.
*
* @author cp 07/22/98
*/
public class Replace
extends CommandLineTool
{
public static void main(String asArgs[])
{
try
{
// first 3 arguments are required
int cArgs = asArgs.length;
if (cArgs < 3)
{
showInstructions();
return;
}
// parse file spec, old text, and new text (can be blank)
String sFileSpec = asArgs[0];
String sOldText = asArgs[1];
String sNewText = asArgs[2];
if (sFileSpec.length() < 1 || sOldText.length() < 1)
{
showInstructions();
return;
}
// parse for options
boolean fPrompt = false;
boolean fRecurse = false;
boolean fVerbose = false;
for (int i = 3; i < cArgs; ++i)
{
String sOpt = asArgs[i];
if (sOpt.length() < 2 || sOpt.charAt(0) != '-')
{
showInstructions();
return;
}
for (int of = 1; of < sOpt.length(); ++of)
{
switch (sOpt.charAt(of))
{
case 'P':
case 'p':
fPrompt = true;
break;
case 'D':
case 'd':
fRecurse = true;
break;
case 'V':
case 'v':
fVerbose = true;
break;
default:
showInstructions();
return;
}
}
}
if (fVerbose)
{
out();
out("File Spec : \"" + sFileSpec + "\"");
out("Search For : \"" + sOldText + "\"");
out("Replace With: \"" + sNewText + "\"");
out("Selected Options:");
if (fRecurse)
{
out(" -d Recurse sub-directories");
}
if (fPrompt)
{
out(" -p Prompt before making each change");
}
out(" -v Verbose mode");
}
if (fVerbose)
{
out();
out("Selecting files ...");
}
Enumeration enmrFiles = applyFilter(sFileSpec, fRecurse);
if (enmrFiles == null)
{
out();
out("Invalid directory or file specification: " + sFileSpec);
showInstructions();
return;
}
if (fVerbose)
{
out();
out("Processing files ...");
}
int MAXSIZE = 0x1000000; // 16mb
int MINSIZE = 0x10000; // 64k
int cbBuf = MINSIZE;
byte[] abBuf = new byte[cbBuf];
byte[] abOld = getBytes(sOldText);
int cbOld = abOld.length;
byte bTag = abOld[0];
byte[] abNew = getBytes(sNewText);
int cbNew = abNew.length;
while (enmrFiles.hasMoreElements())
{
File file = (File) enmrFiles.nextElement();
boolean fReadable = file.canRead();
boolean fWriteable = file.canWrite();
boolean fHidden = file.isHidden();
boolean fNameShown = false;
int cbFile = (int) file.length(); // assume <4gb
// verbose mode: show file details
if (fVerbose)
{
StringBuffer sb = new StringBuffer();
if (fReadable)
{
sb.append("r");
}
if (fWriteable)
{
sb.append("w");
}
if (fHidden)
{
sb.append("h");
}
out(file.getPath() + ", (" + sb.toString() + "), " + cbFile + " bytes");
fNameShown = true;
}
// verify that the file can be operated on
if (!fReadable || !fWriteable || fHidden || cbFile > MAXSIZE)
{
String sText = "";
if (!fReadable)
{
sText = "(not readable)";
}
else if (!fWriteable)
{
sText = "(not writeable)";
}
else if (fHidden)
{
sText = "(hidden)";
}
else if (cbFile > MAXSIZE)
{
sText = "(too large)";
}
out("Skipping " + file.getPath() + " " + sText);
continue;
}
// make sure buffer is big enough
if (cbFile > cbBuf)
{
cbBuf = cbFile + MINSIZE;
abBuf = new byte[cbBuf];
}
// read entire file into buffer
try
{
FileInputStream in = new FileInputStream(file);
int cbTotal = 0;
while (cbTotal < cbFile)
{
cbTotal += in.read(abBuf, cbTotal, cbFile - cbTotal);
}
in.close();
}
catch (IOException e)
{
out("Skipping " + file.getPath() + " due to IOException:");
out(e);
continue;
}
FileOutputStream out = null;
int ofCur = 0;
int ofMax = cbFile - abOld.length;
int ofLine = 0;
int cbTotal = 0;
int cLines = 1;
int cChanges = 0;
while (ofCur <= ofMax)
{
byte bCur = abBuf[ofCur];
if (bCur == bTag)
{
boolean fMatch = true;
for (int i = 1; i < cbOld; ++i)
{
if (abBuf[ofCur+i] != abOld[i])
{
fMatch = false;
break;
}
}
if (fMatch)
{
if (!fNameShown)
{
out(file.getPath());
fNameShown= true;
}
// verify with user (if prompt option used)
char chAns = 'Y';
if (fPrompt)
{
// keep no more than 40 chars before
boolean fSkip = (ofLine < ofCur - 40);
if (fSkip)
{
ofLine = ofCur - 40;
}
// find end of line (keep no more than 40 chars)
int ofEOL = ofCur + cbOld;
int ofBreak = ofEOL + 40;
boolean fTrunc = false;
while (ofEOL < cbFile)
{
byte b = abBuf[ofEOL];
if (b == '\r' || b == '\n')
{
break;
}
if (ofEOL >= ofBreak)
{
fTrunc = true;
break;
}
++ofEOL;
}
out("(Line " + cLines + ") "
+ (fSkip ? "... " : "")
+ new String(abBuf, ofLine, ofEOL - ofLine)
+ (fTrunc ? " ..." : ""));
chAns = in("Replace (Y/N): ");
}
if (chAns == 'Y' || chAns == 'y')
{
// make sure the file is ready to be written to
if (out == null)
{
if (!file.delete())
{
out("Error deleting " + file.getPath());
return;
}
if (!file.createNewFile())
{
out("Error creating " + file.getPath());
return;
}
out = new FileOutputStream(file);
}
// write up to the point of the found string
if (cbTotal < ofCur)
{
out.write(abBuf, cbTotal, ofCur - cbTotal);
}
// write the new string
out.write(abNew);
ofCur += cbOld;
cbTotal = ofCur;
++cChanges;
continue;
}
}
}
else if (fPrompt && bCur == '\n')
{
ofLine = ofCur + 1;
++cLines;
}
// next character
++ofCur;
}
if (out != null)
{
if (cbTotal < cbFile)
{
// write out remainder of the file
out.write(abBuf, cbTotal, cbFile - cbTotal);
}
// close the file
out.close();
// display number of modifications
out("(" + cChanges + " occurrences replaced)");
}
}
}
catch (Throwable t)
{
out();
out("Caught \"" + t + "\"");
out("(begin stack trace)");
out(t);
out("(end stack trace)");
out();
}
}
static void showInstructions()
{
out();
out("Global search & replace utility");
out();
out("Usage:");
out(" Replace [-p] [-d] [-v]");
out();
out("Options:");
out(" -d Recurse sub-directories");
out(" -p Prompt before making each change");
out(" -v Verbose mode");
out();
out("Example:");
out(" java com.tangosol.dev.tools.Replace \"*.java\" \"import \" \"// import \" -p");
out();
}
static byte[] getBytes(String s)
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
char[] ach = s.toCharArray();
int cch = ach.length;
boolean fEscape = false;
for (int i = 0; i < cch; ++i)
{
char ch = ach[i];
if (fEscape)
{
switch (ch)
{
case 'b':
stream.write((byte) '\b');
break;
case 't':
stream.write((byte) '\t');
break;
case 'n':
stream.write((byte) '\n');
break;
case 'f':
stream.write((byte) '\f');
break;
case 'r':
stream.write((byte) '\r');
break;
case '\"':
case '\'':
case '\\':
stream.write((byte) ch);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{
int cMaxDigits = (ch > '3' ? 2 : 3);
int nChar = 0;
do
{
nChar = (nChar * 8) + (ch - '0');
if (++i >= cch)
{
break;
}
ch = ach[i];
}
while (ch >= '0' && ch <= '7' && --cMaxDigits > 0);
--i;
ch = (char) nChar;
}
stream.write((byte) ch);
break;
case '\r':
case '\n':
throw new IllegalArgumentException("New line in escaped literal!");
default:
throw new IllegalArgumentException("New line in escaped literal!");
}
fEscape = false;
}
else if (ch == '\\')
{
fEscape = true;
}
else
{
stream.write((byte) (ch & 0xFF));
}
}
if (fEscape)
{
throw new IllegalArgumentException("Escaped literal not completed!");
}
return stream.toByteArray();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy