287 lines
8.1 KiB
ObjectPascal
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.
|