ajayshah@aludra.usc.edu (Ajay Shah) (05/06/90)
Briefly, the command
patch -v command.com DIR @#$
finds every occurence of DIR inside command.com, shows you the
context on screen, and replaces by @#$ if you say yes. Skip the
-v flag and the replacement is automatic.
It is pretty useful as compared with the standard
alternative, which is usually hunting for strings with nu and
precariously editing on screen there... full information on how to
use it is embedded in the code (procedure help).
---------------------------------------------------------------------------
program PatchFiles;
uses crt, dos;
const
MaxTableEntries = 1000;
type
fnstring = string[65];
rawtable = array[1..MaxTableEntries] of longint;
tabletype = ^rawtable;
ByteFile = file of byte;
CharFile = file of char;
var
verbose : boolean;
function exist(fn:fnstring):boolean;
begin
exist := fsearch(fn, '.') <> ''
end;
procedure Patch(var f:CharFile;
where:longint;
replacestring:string);
var
i:byte;
begin
writeln('Patching at ', where);
seek(f, where);
for i := 1 to length(replacestring) do
write(f, replacestring[i])
end;
procedure SilentPatch(fname:fnstring;
table:tabletype;
entries:integer;
rs:string);
var i:1..MaxTableEntries;
inf:CharFile;
begin
assign(inf, fname); reset(inf);
for i := 1 to entries do
Patch(inf, table^[i], rs);
close(inf)
end;
function max(i,j:longint):longint;
begin
if i >= j then max := i
else max := j
end;
function min(i,j:longint):longint;
begin
if i <= j then min := i
else min := j
end;
function printable(c:char):boolean;
const
PrintableCharacters : set of char
= [#32..#255];
begin
printable := c in PrintableCharacters
end;
procedure Display(var f:CharFile;
rmin, rmax, focus : longint;
highlightlength:byte);
var i:longint;
outc, c:char;
begin
seek(f, rmin);
for i := rmin to rmax do
begin
read(f, c);
if printable(c) then outc := c
else outc := #254;
if (i >= focus) and (i <= (focus+highlightlength))
then textattr := 15
else textattr := 7;
write(outc)
end;
end;
procedure InteractivePatch(fname:fnstring;
table:tabletype;
entries : integer;
rs:string);
var
inf:CharFile;
rmin, rmax, UpperLimit : longint;
i : 1..MaxTableEntries;
begin
assign(inf, fname); reset(inf);
Upperlimit := filesize(inf);
for i := 1 to entries do
begin
rmin := max (0, table^[i] - 30);
rmax := min (Upperlimit, table^[i] + 30);
Display(inf, rmin, rmax, table^[i], length(rs)-1);
writeln;
write('Replace? ');
if upcase(readkey) = 'Y' then
Patch(inf, table^[i], rs);
writeln
end;
end;
procedure Work(fname:fnstring;
sstring, rstring:string;
verbose:boolean);
label done;
var inf:CharFile;
entries : integer;
table : tabletype;
address : longint;
i : byte;
c : char;
destruct : boolean;
begin
write('Searching...');
entries := 0; new(table);
assign(inf, fname); reset(inf);
repeat
repeat
if eof(inf) then goto done;
read(inf, c);
until c = sstring[1];
address := filepos(inf);
{We'll now "try out" that chappie.}
destruct := false;
i := 2;
repeat
if eof(inf) then goto done;
read(inf, c);
if c <> sstring[i] then destruct := true;
inc(i);
until (i > length(sstring)) or destruct;
if destruct
then seek(inf, address)
else {we have a occurence of searchstring}
begin
inc(entries); write('.');
table^[entries] := address - 1
end
until eof(inf);
done:
close(inf);
if entries = 0 then
begin
writeln('No occurences of ', sstring, ' found.');
halt(0)
end;
writeln('Finished searching.');
if verbose then InteractivePatch(fname, table, entries, rstring)
else SilentPatch(fname, table, entries, rstring)
{talk to stdout, though}
end;
procedure help;
const
NumStrings = 11;
Strings : array[1..NumStrings] of string
= ('Usage:',
' patch [-v] filename string1 string2',
'',
'filename is the file which is patched.',
'You must have length(string1) = length(string2).',
'',
'Without the verbose flag, every occurence of string1 is replaced by string2.',
'',
'With verbose on:',
'Every occurence of string1 is displayed on screen, along with it''s context.',
'Iff you give a goahead, then the patch is made.');
var i:byte;
begin
for i := 1 to NumStrings do writeln(Strings[i]);
halt(1)
end;
procedure courtesy;
begin
writeln('Say');
writeln(' patch');
writeln('for more help.');
halt(1)
end;
var
firstparam : string;
filename : fnstring;
searchstring, replacestring : string;
i : byte;
begin
if (paramcount = 0) or (paramcount > 4) then help;
verbose := false;
firstparam := paramstr(1);
if firstparam[1] = '-' then {might have a -v here}
begin
if upcase(firstparam[2]) = 'V'
then verbose := true
else help;
filename := paramstr(2);
searchstring := paramstr(3);
replacestring := paramstr(4);
end
else {first parameter isn't -*}
begin
filename := paramstr(1);
searchstring := paramstr(2);
replacestring := paramstr(3)
end;
if length(searchstring) <> length(replacestring) then
begin
writeln('Searchstring and Replacestring must be of same length.');
courtesy
end;
if length(searchstring) = 0 then
begin
writeln('You have to specify some searchstring.'); courtesy
end;
if not exist(filename) then
begin
writeln('File ', filename, ' not found.'); courtesy
end;
{Now we have all the raw materials.}
Work(filename, searchstring, replacestring, verbose)
end.
_______________________________________________________________________________
Ajay Shah, (213)747-9991, ajayshah@usc.edu
The more things change, the more they stay insane.
_______________________________________________________________________________