Componentes.Terceros.jvcl/official/3.32/devtools/JvAdjustLineBreaks/crlfutils.pas

287 lines
8.1 KiB
ObjectPascal

unit crlfutils;
{$I jvcl.inc}
interface
procedure Run;
implementation
uses
Windows, SysUtils, {$IFNDEF COMPILER6_UP} JvFunctions, {$ENDIF} Classes;
function IsTextStream(Stream:TStream):Boolean;
const
MaxLineLength = 255;
var
LineBuffer:array[0..MaxLineLength] of Char;
CharFlags:array of Word;
I, Count:Integer;
P, S:PChar;
begin
Result := False;
FillChar(LineBuffer, SizeOf(LineBuffer), 0);
Stream.Position := 0;
if Stream.Size > MaxLineLength then
Count := MaxLineLength
else
Count := Stream.Size;
Stream.Read(LineBuffer, Count);
// see if we can come up with an EOL (unless we read the whole file)
if Count < Stream.Size then
begin
P := StrPos(LineBuffer, #13);
// try the LF variant too
if P = nil then
begin
P := StrPos(LineBuffer,#10);
if P = nil then
Exit;
end;
// terminate the string here
P^ := #0;
// check if there are any terminators prior to where we expect the EOL
S := @LineBuffer;
while S < P do
begin
if S^ = #0 then
Exit;
Inc(S);
end;
end;
Count := StrLen(LineBuffer);
// some editors place a $1A (26) as an EOF marker
if LineBuffer[Count - 1] = Char($1A) then
begin
LineBuffer[Count - 1] := #0;
Dec(Count);
end;
// if first character is $FF, then it's likely not text
if LineBuffer[0] = Char($FF) then
Exit;
// get the char flags
SetLength(CharFlags, Count);
GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, LineBuffer, Count,
CharFlags[0]);
// check the CharFlags array to see if anything looks fishy
for I := Low(CharFlags) to High(CharFlags) do
if ((CharFlags[I] and C1_CNTRL) <> 0) and ((CharFlags[I] and $0F) = 0) then
Exit;
// best guess is that it looks reasonable
Result := True;
end;
function IsTextFile(const FileName:string):Boolean;
var
S:TStream;
begin
Result := False;
if not FileExists(FileName) then
Exit;
S := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
try
Result := IsTextStream(S);
finally
S.Free;
end;
end;
procedure ShowHelp;
begin
writeln('===================================================');
writeln('Usage:');
writeln('crlf [options] <filemask> [options] <filemask> (etc)');
writeln('');
writeln('where [options] can be any combination of:');
writeln(' /s - recurse into sub-folders from this point on');
writeln(' /c - compare before write: only write if file has changed (default)');
writeln(' /u - do NOT compare before write: always write');
writeln(' /l - convert to Linux line breaks (LF) (default on Linux)');
writeln(' /w - convert to Windows line breaks (CRLF) (default on Windows)');
writeln('');
writeln('<filemask> accepts wildcards (* and ?).');
writeln('');
writeln('Example:');
writeln('========');
writeln('crlf /u /l *.pas /c /w /s *.dfm');
writeln('Converts the pas files to LF (always writes) and the dfm files to CRLF (writes if modified). Recurses into sub-folders when searching for dfm''s.');
writeln('');
writeln('Example:');
writeln('========');
writeln('crlf *.pas *.dfm');
writeln('Converts the pas and dfm files to LF on Linux and CRLF on Windows (system default). Always checks before write (no /u option).');
writeln('');
writeln('');
writeln('NOTE: if you compiled using Delphi 5 or earlier, CRLF->LF is NOT supported!');
end;
function ConvertFile(const Filename:string;ToWindows,CompareBeforeWrite,Quiet:boolean):boolean;
{$IFDEF COMPILER6_UP}
const
cStyle:array[boolean] of TTextLineBreakStyle = (tlbsLF,tlbsCRLF);
{$ENDIF COMPILER6_UP}
var
F:TFileStream;
tmp,tmp2:string;
begin
// don't convert binary files
Result := false;
if not IsTextFile(Filename) then Exit;
F := TFileStream.Create(Filename,fmOpenReadWrite or fmShareExclusive );
try
SetLength(tmp,F.Size);
if F.Size > 0 then
begin
F.Read(tmp[1],F.Size);
if CompareBeforeWrite then
tmp2 := tmp;
tmp := AdjustLineBreaks(tmp{$IFDEF COMPILER6_UP},cStyle[ToWindows]{$ENDIF});
if CompareBeforeWrite and (tmp = tmp2) then
begin
if not Quiet then
writeln(ExtractFilename(Filename), ' not converted');
Exit;
end;
F.Size := 0;
F.Write(tmp[1],Length(tmp));
if not Quiet then
writeln(ExtractFilename(Filename), ' converted');
end;
finally
F.Free;
end;
Result := true;
end;
function ConvertFiles(const FileMask:string;ToWindows,CompareBeforeWrite,Recurse,Quiet:boolean):integer;
var
SearchHandle:DWORD;
FindData:TWin32FindData;
APath:string;
begin
Result := 0;
APath := ExtractFilePath(Filemask);
SearchHandle := FindFirstFile(PChar(Filemask),FindData);
if SearchHandle <> INVALID_HANDLE_VALUE then
try
repeat
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = 0) then
begin
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_READONLY = FILE_ATTRIBUTE_READONLY) then
writeln('ERROR: ',FindData.cFileName,' is read-only!')
else if ConvertFile(APath + FindData.cFileName,ToWindows,CompareBeforeWrite,Quiet) then
Inc(Result);
end;
until not FindNextFile(SearchHandle,FindData);
finally
Windows.FindClose(SearchHandle);
end;
// do sub-folders
if Recurse then
begin
SearchHandle := FindFirstFile(PChar(APath + '*.*'),FindData);
if SearchHandle <> INVALID_HANDLE_VALUE then
try
repeat
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY) and (FindData.cFileName[0] <> '.') then
Inc(Result,ConvertFiles(IncludeTrailingPathdelimiter(APath + FindData.cFileName) + ExtractFilename(Filemask),ToWindows,CompareBeforeWrite,true,Quiet));
until not FindNextFile(SearchHandle,FindData);
finally
Windows.FindClose(SearchHandle);
end;
end;
end;
procedure Run;
const
cCurrentOS:array[boolean] of PChar = ('(CRLF->LF)','(LF->CRLF)');
var
ToWindows,CompareBeforeWrite,Recurse,Quiet:boolean;
i,Count:integer;
begin
// cmd line: -l *.pas *.dfm *.txt -c -w *.xfm
// where
// -l - convert CRLF to LF (to linux)
// -w - convert LF to CRLF (to windows)
// -c - check content: only write if file has changed (default)
// -u - never check content: always write
writeln('');
writeln('JEDI CR(LF) version 0.1: LF->CRLF and CRLF->LF converter.');
Count := 0;
if ParamCount = 0 then
begin
ShowHelp;
Exit;
end;
CompareBeforeWrite := true;
Recurse := false;
// set depending on target
ToWindows := true;
{$IFDEF LINUX}
ToWindows := false;
{$ENDIF}
Quiet := false;
for i := 1 to ParamCount do
begin
if SameText(ParamStr(i),'/l') or SameText(ParamStr(i),'-l') then
begin
ToWindows := false;
if not Quiet then
writeln('Converting ', cCurrentOS[ToWindows],':');
Continue;
end
else if SameText(ParamStr(i),'/w') or SameText(ParamStr(i),'-w') then
begin
ToWindows := true;
if not Quiet then
writeln('Converting ', cCurrentOS[ToWindows],':');
Continue;
end
else if SameText(ParamStr(i),'/?') or SameText(ParamStr(i),'-?') or
SameText(ParamStr(i),'/h') or SameText(ParamStr(i),'-h')then
begin
ShowHelp;
Exit;
end
else if SameText(ParamStr(i),'/c') or SameText(ParamStr(i),'-c') then
begin
CompareBeforeWrite := true;
Continue;
end
else if SameText(ParamStr(i),'/u') or SameText(ParamStr(i),'-u') then
begin
CompareBeforeWrite := false;
Continue;
end
else if SameText(ParamStr(i),'/s') or SameText(ParamStr(i),'-s') then
begin
Recurse := true;
Continue;
end
else if SameText(ParamStr(i),'/q') or SameText(ParamStr(i),'-q') then
begin
Quiet := true;
Continue;
end
else
Inc(Count,ConvertFiles(ExpandUNCFilename(ParamStr(i)),ToWindows,CompareBeforeWrite,Recurse,Quiet));
end;
writeln('');
writeln('Done: ', Count, ' files converted.');
end;
end.