program stripcmts;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes, SysUtils, CustApp, Process,
RegExpr;
type
{ TStripComments }
TStripComments = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
procedure WriteHelp; virtual;
end;
var
FileName, NewFileName, OpenProgram: String;
FileContent: TStringList;
RegEx: TRegExpr;
i: integer;
{ TStripComments }
procedure TStripComments.DoRun;
var
ErrorMsg: String;
procedure RemoveExtraBlankLines(CodeLines: TStringList);
var
i: integer;
BlankLineFound: Boolean;
begin
BlankLineFound := False;
i := 0;
while i < CodeLines.Count do
begin
if Trim(CodeLines[i]) = '' then
begin
if BlankLineFound then CodeLines.Delete(i) else
begin
BlankLineFound := True;
Inc(i);
end;
end else
begin
BlankLineFound := False;
Inc(i);
end;
end;
end;
begin
// quick check parameters
ErrorMsg:=CheckOptions('h', 'help');
if ErrorMsg<>'' then begin
ShowException(Exception.Create(ErrorMsg));
Terminate;
Exit;
end;
// parse parameters
if HasOption('h', 'help') then begin
WriteHelp;
Terminate;
Exit;
end;
if ParamCount < 1 then
begin
WriteLn('Usage: ./stripcmts <filename> [program to open unit]');
WriteLn('The second parameter is optional');
Terminate;
Exit;
end;
FileName := ParamStr(1);
if ParamCount >= 2 then
OpenProgram := ParamStr(2)
else
OpenProgram := 'xed'; // default program
FileContent := TStringList.Create;
try
FileContent.LoadFromFile(FileName);
RegEx := TRegExpr.Create;
RegEx.ModifierM:=TRUE;
try
RegEx.Expression := '\/\/.*';
RegEx.ModifierI := TRUE; // case-insensitive
for i := 0 to FileContent.Count - 1 do
begin
if RegEx.Exec(FileContent[i]) then FileContent[i] := StringReplace(FileContent[i], RegEx.Match[0], '', []);
end;
RegEx.Expression := '\{\s*[^\s\$].*?\}|\(\*.*\*\)';
RegEx.ModifierS := TRUE;
FileContent.Text := RegEx.Replace(FileContent.Text, '', FALSE);
finally
RegEx.Free;
end;
// Remove extra blank lines
RemoveExtraBlankLines(FileContent);
NewFileName := ChangeFileExt(FileName, '_CmtFree.pas');
FileContent.SaveToFile(NewFileName);
// Launch the new file in xed editor
with TProcess.Create(nil) do
try
Executable := OpenProgram;
Parameters.Add(NewFileName);
Options := Options + [poWaitOnExit];
Execute;
finally
Free;
end;
finally
FileContent.Free;
end;
// stop program loop
Terminate;
end;
constructor TStripComments.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
StopOnException:=True;
end;
procedure TStripComments.WriteHelp;
begin
writeln('Usage: ', ExeName, ' <filename> [program to open unit]');
writeln;
writeln('Description:');
writeln(' This program strips comments from a Free Pascal source file.');
writeln(' It supports single-line comments (//), multi-line comments ({...}),');
writeln(' and Pascal-style block comments ( (* ... *) ). The cleaned file');
writeln(' is saved with a "_CmtFree" suffix added to the original filename.');
writeln;
writeln('Parameters:');
writeln(' <filename> The name of the file to process.');
writeln(' [program to open unit] Optional. The program to use to open the cleaned file.');
writeln(' If not specified, the default program "xed" will be used.');
writeln;
writeln('Examples:');
writeln(' ', ExeName, ' myfile.pas');
writeln(' Strips comments from "myfile.pas" and opens the result with the default program.');
writeln;
writeln(' ', ExeName, ' myfile.pas nano');
writeln(' Strips comments from "myfile.pas" and opens the result with "codeeditor".');
end;
var
Application: TStripComments;
begin
Application:=TStripComments.Create(nil);
Application.Title:='Strip Comments';
Application.Run;
Application.Free;
end.