home *** CD-ROM | disk | FTP | other *** search
- Program Chge;
-
- { Copyright 1990 Trevor J Carlsen Version 1.06 24-07-90 }
- { This Program may be used and distributed as if it was in the Public Domain}
- { With the following exceptions: }
- { 1. If you alter it in any way, the copyright notice must not be }
- { changed. }
- { 2. If you use code excerpts in your own Programs, due credit must be }
- { given, along With a copyright notice - }
- { "Parts Copyright 1990 Trevor J Carlsen" }
- { 3. No Charge may be made For any Program using code from this Program.}
-
- { Changes (or deletes) a String in any File. If an .EXE or .COM File then }
- { the change must be of a similar length inorder to retain the executable }
- { integrity. }
-
- { If you find this Program useful here is the author's contact address - }
-
- { Trevor J Carlsen }
- { PO Box 568 }
- { Port Hedland Western Australia 6721 }
- { Voice 61 [0]91 72 2026 }
- { Data 61 [0]91 72 2569 }
-
- Uses
- BmSrch,
- Dos;
-
- Const
- space = #32;
- quote = #34;
- comma = #44;
- copyright1 = 'CHGE - version 1.06 Copyright 1989,1990 Trevor Carlsen';
- copyright2 = 'All rights reserved.';
-
- Var
- dirinfo : SearchRec; { Dos }
- f : File;
- FDir : DirStr; { Dos }
- mask,
- fname,
- oldstr,
- newstr : String;
- oldlen : Byte Absolute oldstr;
- newlen : Byte Absolute newstr;
- changes : Word;
- time : LongInt Absolute $0000:$046C;
- start : LongInt;
-
- Function ElapsedTime(start : LongInt): Real;
- begin
- ElapsedTime := (time - start) / 18.2;
- end; { ElapsedTime }
-
- Procedure ReportError(e : Byte);
- begin
- Writeln('CHGE [path]Filename searchstr replacementstr|NUL');
- Writeln(' eg: CHGE c:\autoexec.bat "color" "colour"');
- Writeln(' CHGE c:\autoexec.bat 12 13,10,13,10,13,10,13,10');
- Writeln(' CHGE c:\wp\test.txt "Trevor" NUL');
- Writeln;
- Writeln('The first example will change every occurrence of the Word "color" to "colour"');
- Writeln('The second will replace every formfeed Character (ascii 12) With 4 sets of');
- Writeln('carriage return/linefeed combinations and the third will delete every');
- Writeln('occurrence of "Trevor"');
- Writeln('The prime requirements are:');
- Writeln(' There MUST always be exactly three space delimiters on the command line -');
- Writeln(' one between the Program name and the Filename, one between the Filename and');
- Writeln(' the search String and another between the search String and the replacement');
- Writeln(' String. Any other spaces may ONLY occur between quote Characters.');
- Writeln(' The Program will not permit you to change the length of an .EXE or .COM File,');
- Writeln(' therefore the replacement String MUST be the same length as the String');
- Writeln(' that it is replacing in these cases.');
- Writeln;
- Writeln(' If using ascii codes, each ascii Character must be separated from another');
- Writeln(' by a comma. The same rule applies to spaces as above - three required - no');
- Writeln(' more - no less. If just deleting the NUL must not be in quotes.');
- halt(e);
- end; { ReportError }
-
- Function StUpCase(Str : String) : String;
- Var
- Count : Integer;
- begin
- For Count := 1 to Length(Str) do
- Str[Count] := UpCase(Str[Count]);
- StUpCase := Str;
- end;
-
- Procedure ParseCommandLine;
- Var
- parstr, { contains the command line }
- temp : String;
- len : Byte Absolute parstr; { the length Byte For parstr }
- tlen : Byte Absolute temp; { the length Byte For temp }
- CommaPos,
- QuotePos,
- SpacePos,
- chval : Byte;
- error : Integer;
- DName : NameStr;
- DExt : ExtStr;
-
- Function right(Var s; n : Byte): String;{ Returns the n right portion of s }
- Var
- st : String Absolute s;
- len: Byte Absolute s;
- begin
- if n >= len then
- right := st
- else
- right := copy(st,succ(len)-n,n);
- end; { right }
-
- begin
- parstr := String(ptr(PrefixSeg,$80)^); { Get the command line }
- if parstr[1] = space then
- delete(parstr,1,1); { First Character is usually a space }
- SpacePos := pos(space,parstr);
- if SpacePos = 0 then { No spaces }
- ReportError(1);
- mask := StUpCase(copy(parstr,1,pred(SpacePos)));
- FSplit(mask,Fdir,DName,DExt); { To enable the directory to be kept }
- delete(parstr,1,SpacePos);
- QuotePos := pos(quote,parstr);
- if QuotePos <> 0 then begin { quotes - so must be quoted Text }
- if parstr[1] <> quote then { so first Char must be quote }
- ReportError(2);
- delete(parstr,1,1); { get rid of the first quote }
- QuotePos := pos(quote,parstr); { and find the next quote }
-
- if QuotePos = 0 then { no more - so it is an error }
- ReportError(3);
- oldstr := copy(parstr,1,pred(QuotePos));{ search String now defined }
- if parstr[QuotePos+1] <> space then { must be space between }
- ReportError(1);
- delete(parstr,1,succ(QuotePos)); { the quotes - else error }
- if parstr[1] <> quote then begin { may be a delete }
- tlen := 3;
- move(parstr[1],temp[1],3);
- if temp <> 'NUL' then { is not a delete }
- ReportError(4) { must be quote after space or NUL }
- else
- newlen := 0; { is a delete - so nul the replacement }
- end
- else begin
- delete(parstr,1,1); { get rid of the quote }
- QuotePos := pos(quote,parstr); { find next quote For end of String }
- if QuotePos = 0 then { None? - then error }
- ReportError(5);
- newstr := copy(parstr,1,pred(QuotePos));{ Replacement String defined }
- end;
- end
- else begin { must be using ascii codes }
- oldlen := 0;
- SpacePos := pos(space,parstr); { Find end of search Characters }
- if SpacePos = 0 then { No space - so error }
- ReportError(6);
- temp := copy(parstr,1,SpacePos-1);
- delete(parstr,1,SpacePos); { get rid of the search Characters }
- CommaPos := pos(comma,temp); { find first comma }
- if CommaPos = 0 then { No comma - so only one ascii code }
- CommaPos := succ(tlen);
- Repeat { create the search String }
- val(copy(temp,1,CommaPos-1),chval,error); { convert to a numeral and }
- if error <> 0 then { if there is an error bomb out }
- ReportError(7);
- inc(oldlen);
- oldstr[oldlen] := Char(chval);{ add latest Char to the search String }
- delete(temp,1,CommaPos);
- CommaPos := pos(comma,temp);
- if CommaPos = 0 then
- CommaPos := succ(tlen);
- Until tlen = 0;
- newlen := 0;
- CommaPos := pos(comma,parstr);
- if CommaPos = 0 then
- CommaPos := succ(len);
- Repeat { create the replacement String }
- val(copy(parstr,1,pred(CommaPos)),chval,error);
- if error <> 0 then { must be ascii code }
- ReportError(8);
- inc(newlen);
- newstr[newlen] := Char(chval);
- delete(parstr,1,CommaPos);
- CommaPos := pos(comma,parstr);
- if CommaPos = 0 then CommaPos := len+1;
- Until len = 0;
- end; { else }
- if ((right(mask,3) = 'COM') or (right(mask,3) = 'EXE')) and
- (newlen <> oldlen) then
- ReportError(16);
- end; { ParseCommandLine }
-
- Function OpenFile(fn : String): Boolean;
- begin
- assign(f,fn);
- {$I-} reset(f,1); {$I+}
- OpenFile := IOResult = 0;
- end; { OpenFile }
-
- Procedure CloseFile;
- begin
- {$I-}
- truncate(f);
- Close(f);
- if IOResult <> 0 then; { dummy call to IOResult }
- {$I+}
- end; { CloseFile }
-
- Procedure ChangeFile(Var chge : Word);
- Const
- bufflen = 65000; { This is the limit For BMSearch }
- searchlen = bufflen - 1000; { Allow space For extra Characters in }
- Type { the replacement String }
- buffer = Array[0..pred(bufflen)] of Byte;
- buffptr = ^buffer;
- Var
- table : BTable; { Boyer-Moore search table }
- old, { Pointer to old buffer }
- nu : buffptr; { Pointer to new buffer }
- count,
- result,
- oldpos,
- newpos : Word;
- oldfpos,
- newfpos : LongInt;
- finished : Boolean;
-
- Procedure AllocateMemory(Var p; size : Word);
- Var
- buff : Pointer Absolute p;
- begin
- if MaxAvail >= size then
- GetMem(buff,size)
- else begin
- Writeln('Insufficient memory available.');
- halt(10);
- end;
- end; { AllocateMemory }
-
- begin
- oldfpos := 0; newfpos := 0;
- chge := 0;
- AllocateMemory(old,searchlen);
- AllocateMemory(nu,bufflen); { make room on the heap For the buffers }
- BMMakeTable(oldstr,table); { Create a Boyer-Moore search table }
- {$I-}
- BlockRead(f,old^,searchlen,result); { Fill old buffer }
- oldfpos := FilePos(f);
- {$I+}
- if IOResult <> 0 then begin
- CloseFile; ReportError(11);
- end;
- Repeat
- oldpos := 0; newpos := 0; count := 0;
- finished := (result < searchlen); { if buffer<>full then no more reads }
- Repeat { Do a BM search For search String }
- count := BMSearch(old^[oldpos],result-oldpos,table,oldstr);
- if count = $FFFF then begin { search String not found so copy rest }
- move(old^[oldpos],nu^[newpos],result-oldpos); { of buffer to new }
- inc(newpos,result-oldpos); { buffer and update the buffer markers }
- inc(oldpos,result-oldpos);
- end
- else begin { search String found }
- if count <> 0 then begin { not at position one in the buffer }
- move(old^[oldpos],nu^[newpos],count);{ transfer everything prior }
- inc(oldpos,count); { to the search String to new buffer }
- inc(newpos,count); { and update the buffer markers }
- end;
- move(newstr[1],nu^[newpos],newlen); { copy the replacement String }
- inc(oldpos,oldlen); { to the new buffer and update the buffer }
- inc(newpos,newlen); { markers }
- inc(chge);
- end;
- Until oldpos >= result; { keep going Until end of buffer }
- if not finished then begin { Fill 'er up again For another round }
- {$I-}
- seek(f,oldfpos);
- BlockRead(f,old^,searchlen,result);
- oldfpos := FilePos(f);
- {$I+}
- if IOResult <> 0 then begin
- CloseFile; ReportError(13);
- end; { if IOResult }
- end; { if not finished }
- {$I-}
- seek(f,newfpos);
- BlockWrite(f,nu^,newpos); { Write new buffer to File }
- newfpos := FilePos(f);
- {$I+}
- if IOResult <> 0 then begin
- CloseFile; ReportError(12);
- end;
- Until finished;
- FreeMem(old, searchlen); FreeMem(nu,bufflen);
- end; { ChangeFiles }
-
- Procedure Find_and_change_all_Files;
- Var
- Filefound : Boolean;
-
- Function padstr(ch : Char; len : Byte): String;
-
- Var
- temp : String;
-
- begin
- FillChar(temp[1],len,ch);
- temp[0] := chr(len);
- padstr := temp;
- end; { padstr }
-
- begin
- Filefound := False;
- FindFirst(mask,AnyFile,dirinfo);
- While DosError = 0 do begin
- Filefound := True;
- start := time;
- fname := FDir + dirinfo.name;
- if OpenFile(fname) then begin
- Write(fname,PadStr(space,30-length(fname)),FileSize(f):7,' ');
- ChangeFile(changes);
- CloseFile;
- if changes = 0 then
- Writeln
- else
- Writeln('Made ',changes,' changes in ',ElapsedTime(start):4:2,' seconds.')
- end
- else
- Writeln('Unable to process ',fname);
- FindNext(dirinfo);
- end; { While DosError = 0 }
- if not Filefound then
- Writeln('No Files found.');
- end; { Find_and_change_all_Files }
-
- begin { main }
- Writeln(copyright1);
- Writeln(copyright2);
- ParseCommandLine;
- Find_and_change_all_Files;
- end.
-