mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
411 lines
9.9 KiB
ObjectPascal
411 lines
9.9 KiB
ObjectPascal
{ Double Commander
|
|
-------------------------------------------------------------------------
|
|
Detect string parser.
|
|
|
|
Copyright (C) 2008 Dmitry Kolomiets (B4rr4cuda@rambler.ru)
|
|
Based on TMathControl by Vimil Saju
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
}
|
|
|
|
unit uDetectStr;
|
|
{$mode objfpc}{$H+}
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Classes, uTypes,uFileOp,LCLProc,Masks;
|
|
|
|
|
|
type
|
|
TMathtype=(mtnil,mtoperator,mtlbracket,mtrbracket,mtoperand);
|
|
|
|
type
|
|
TMathOperatortype=(monone, // NULL
|
|
moequ, // =
|
|
moneq, // != replaced with #
|
|
moles, // <
|
|
momor, // >
|
|
moand, // &
|
|
moor, // |
|
|
monot // NOT
|
|
);
|
|
|
|
type
|
|
pmathchar = ^Tmathchar;
|
|
TMathChar = record
|
|
case mathtype: Tmathtype of
|
|
mtoperand:(data:shortstring);
|
|
mtoperator:(op:TMathOperatortype);
|
|
end;
|
|
|
|
type
|
|
|
|
{ TParserControl }
|
|
|
|
TParserControl = class
|
|
public
|
|
Function TestFileResult(ptr:PFileRecItem):boolean; overload;
|
|
function TestFileResult(AFileName: string): boolean; overload;
|
|
private
|
|
input,output,stack:array of tmathchar;
|
|
fmathstring:string;
|
|
fptr:PFileRecItem;
|
|
fforce:boolean;
|
|
function getresult:boolean;
|
|
function calculate(operand1,operand2,Aoperator:Tmathchar):string;
|
|
function getoperator(c:char):TMathOperatortype;
|
|
function getoperand(mid:integer;var len:integer):string;
|
|
procedure processstring;
|
|
procedure convertinfixtopostfix;
|
|
function isdigit(c:char):boolean;
|
|
function isoperator(c:char):boolean;
|
|
function getprecedence(mop:TMathOperatortype):integer;
|
|
function BooleanToStr(x:boolean):string;
|
|
function StrToBoolean(s:string):boolean;
|
|
|
|
protected
|
|
published
|
|
property DetectStr:string read fmathstring write fmathstring;
|
|
property IsForce:boolean read fforce write fforce;
|
|
end;
|
|
|
|
implementation
|
|
|
|
|
|
|
|
function TParserControl.calculate(operand1,operand2,Aoperator:Tmathchar):string;
|
|
var tmp:string;
|
|
begin
|
|
result:='false';
|
|
|
|
//Not
|
|
if (operand1.data='NOT') and ((operand2.data='true') or (operand2.data='false')) then
|
|
begin
|
|
Result:=BooleanToStr(Not StrToBoolean(operand2.data));
|
|
end;
|
|
|
|
// & |
|
|
if ((operand1.data='true') or (operand1.data='false')) and
|
|
((operand2.data='true') or (operand2.data='false')) then
|
|
begin
|
|
case Aoperator.op of
|
|
moand: result:= BooleanToStr((StrToBoolean(operand1.data)) and (StrToBoolean(operand2.data)));
|
|
moor: result:=BooleanToStr((StrToBoolean(operand1.data)) or (StrToBoolean(operand2.data)));
|
|
end;
|
|
end;
|
|
|
|
//EXT= EXT!=
|
|
if (operand1.data='EXT') then
|
|
begin
|
|
//---------------------
|
|
tmp:=fptr^.sExt;
|
|
if length(tmp)>0 then delete(tmp,1,1);
|
|
tmp:=UpperCase(tmp);
|
|
tmp:='"'+tmp+'"';
|
|
//---------------------
|
|
case Aoperator.op of
|
|
moequ: Result:=BooleanToStr(MatchesMask(tmp,operand2.data));
|
|
moneq: Result:=BooleanToStr(not MatchesMask(tmp,operand2.data));
|
|
end;
|
|
end;
|
|
|
|
//SIZE > < = !=
|
|
if (operand1.data='SIZE') then
|
|
begin
|
|
tmp:=IntToStr(fptr^.iSize);
|
|
case Aoperator.op of
|
|
moequ: Result:= BooleanToStr(strtoint(tmp)=strtoint(operand2.data));
|
|
moneq: Result:= BooleanToStr(strtoint(tmp)<>strtoint(operand2.data));
|
|
moles: Result:= BooleanToStr(strtoint(tmp)<strtoint(operand2.data));
|
|
momor: Result:= BooleanToStr(strtoint(tmp)>strtoint(operand2.data));
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ case Aoperator.op of
|
|
moneq: ;
|
|
moequ: ;
|
|
moles: ;
|
|
momor: ;
|
|
moor: ;
|
|
moand: ;
|
|
monot: ;
|
|
end;}
|
|
end;
|
|
|
|
function TParserControl.TestFileResult(ptr:PFileRecItem):boolean;
|
|
begin
|
|
fptr:=ptr;
|
|
Result:=getresult;
|
|
end;
|
|
|
|
|
|
function TParserControl.TestFileResult(AFileName: string): boolean;
|
|
var fr:TFileRecItem;
|
|
begin
|
|
fr:=LoadFilebyName(AFileName);
|
|
fptr:=@fr;
|
|
DebugLn('fptr.sExt = '+fptr^.sExt);
|
|
DebugLn('fptr.sExt = '+fr.sExt);
|
|
Result:=getresult;
|
|
end;
|
|
|
|
function TParserControl.getresult:boolean;
|
|
var
|
|
i:integer;
|
|
tmp1,tmp2,tmp3:tmathchar;
|
|
begin
|
|
if fmathstring='' then
|
|
begin
|
|
Result:=true;
|
|
exit;
|
|
end;
|
|
convertinfixtopostfix;
|
|
setlength(stack,0);
|
|
for i:=0 to length(output)-1 do
|
|
begin
|
|
if output[i].mathtype=mtoperand then
|
|
begin
|
|
setlength(stack,length(stack)+1);
|
|
stack[length(stack)-1]:=output[i];
|
|
end
|
|
else if output[i].mathtype=mtoperator then
|
|
begin
|
|
tmp1:=stack[length(stack)-1];
|
|
tmp2:=stack[length(stack)-2];
|
|
setlength(stack,length(stack)-2);
|
|
tmp3.mathtype:=mtoperand;
|
|
tmp3.data:=calculate(tmp2,tmp1,output[i]);
|
|
setlength(stack,length(stack)+1);
|
|
stack[length(stack)-1]:=tmp3;
|
|
end;
|
|
end;
|
|
result:=strToBoolean(stack[0].data);
|
|
setlength(stack,0);
|
|
setlength(input,0);
|
|
setlength(output,0);
|
|
end;
|
|
|
|
function TParserControl.getoperator(c:char):TMathOperatortype;
|
|
begin
|
|
result:=monone;
|
|
if c='<' then
|
|
result:=moles
|
|
else if c='>' then
|
|
result:=momor
|
|
else if c='&' then
|
|
result:=moand
|
|
else if c='=' then
|
|
result:=moequ
|
|
else if c='#' then
|
|
result:=moneq
|
|
else if c='|' then
|
|
result:=moor
|
|
else if c='!' then
|
|
result:=monot;
|
|
end;
|
|
|
|
function TParserControl.getoperand(mid:integer;var len:integer):string;
|
|
var
|
|
i,j:integer;
|
|
tmpnum:string;
|
|
begin
|
|
j:=1;
|
|
for i:=mid to length(fmathstring)-1 do
|
|
begin
|
|
if isdigit(fmathstring[i]) then
|
|
begin
|
|
if j<=20 then
|
|
tmpnum:=tmpnum+fmathstring[i];
|
|
j:=j+1;
|
|
end
|
|
else
|
|
break;
|
|
end;
|
|
result:=tmpnum;
|
|
len:=length(tmpnum);
|
|
end;
|
|
|
|
procedure TParserControl.processstring;
|
|
var
|
|
i:integer;
|
|
numlen:integer;
|
|
begin
|
|
//---------------------
|
|
while pos('!=',fmathstring)>0 do
|
|
begin
|
|
i:=pos('!=',fmathstring);
|
|
delete(fmathstring,i,2);
|
|
insert('#',fmathstring,i);
|
|
end;
|
|
//---------------------
|
|
while pos('FORCE',fmathstring)>0 do
|
|
begin
|
|
i:=pos('FORCE',fmathstring);
|
|
delete(fmathstring,i,length('FORCE'));
|
|
insert(BooleanToStr(fforce),fmathstring,i);
|
|
end;
|
|
//---------------------
|
|
numlen:=1;
|
|
while numlen < length(fmathstring) do
|
|
if (fmathstring[numlen]='!') and (fmathstring[numlen+1]<>'=') then
|
|
begin
|
|
i:=numlen;
|
|
delete(fmathstring,i,1);
|
|
insert('NOT!',fmathstring,i);
|
|
inc(numlen,4);
|
|
end else inc(numlen);
|
|
//---------------------
|
|
|
|
i:=0;
|
|
numlen:=0;
|
|
setlength(output,0);
|
|
setlength(input,0);
|
|
setlength(stack,0);
|
|
|
|
fmathstring:='('+fmathstring+')';
|
|
setlength(input,length(fmathstring));
|
|
while i<=length(fmathstring)-1 do
|
|
begin
|
|
if fmathstring[i+1]='(' then
|
|
begin
|
|
input[i].mathtype:=mtlbracket;
|
|
i:=i+1;
|
|
end
|
|
else if fmathstring[i+1]=')' then
|
|
begin
|
|
input[i].mathtype:=mtrbracket;
|
|
i:=i+1;
|
|
end
|
|
else if isoperator(fmathstring[i+1]) then
|
|
begin
|
|
input[i].mathtype:=mtoperator;
|
|
input[i].op:=getoperator(fmathstring[i+1]);
|
|
i:=i+1;
|
|
end
|
|
else if isdigit(fmathstring[i+1]) then
|
|
begin
|
|
input[i].mathtype:=mtoperand;
|
|
input[i].data:=getoperand(i+1,numlen);
|
|
i:=i+numlen;
|
|
end else {if fmathstring[i+1]=' ' then} inc(i);
|
|
end;
|
|
end;
|
|
|
|
|
|
function TParserControl.isoperator(c:char):boolean;
|
|
begin
|
|
result:=false;
|
|
if (c='=')
|
|
or (c='#')
|
|
or (c='!')
|
|
or (c='&')
|
|
or (c='<')
|
|
or (c='>')
|
|
or (c='|') then
|
|
result:=true;
|
|
end;
|
|
|
|
function TParserControl.isdigit(c:char):boolean;
|
|
begin
|
|
result:=false;
|
|
if (integer(c)>64) or
|
|
(c in ['1','2','3','4','5','6','7','8','9','0','"','*']) then
|
|
result:=true;
|
|
end;
|
|
|
|
function TParserControl.getprecedence(mop:TMathOperatortype):integer;
|
|
begin
|
|
result:=-1;
|
|
case mop of
|
|
moor:result:=1;
|
|
moand:result:=1;
|
|
moequ:result:=2;
|
|
moneq:result:=2;
|
|
moles:result:=2;
|
|
momor:result:=2;
|
|
monot:result:=2;
|
|
end;
|
|
end;
|
|
|
|
function TParserControl.BooleanToStr(x: boolean): string;
|
|
begin
|
|
if x then
|
|
Result:='true'
|
|
else
|
|
Result:='false';
|
|
end;
|
|
|
|
function TParserControl.StrToBoolean(s: string): boolean;
|
|
begin
|
|
if s='true' then Result:=true else
|
|
Result:=false;
|
|
end;
|
|
|
|
procedure TParserControl.convertinfixtopostfix;
|
|
var
|
|
i,j,prec:integer;
|
|
begin
|
|
processstring;
|
|
for i:=0 to length(input)-1 do
|
|
begin
|
|
if input[i].mathtype=mtoperand then
|
|
begin
|
|
setlength(output,length(output)+1);
|
|
output[length(output)-1]:=input[i];
|
|
end
|
|
else if input[i].mathtype=mtlbracket then
|
|
begin
|
|
setlength(stack,length(stack)+1);
|
|
stack[length(stack)-1]:=input[i];
|
|
end
|
|
else if input[i].mathtype=mtoperator then
|
|
begin
|
|
prec:=getprecedence(input[i].op);
|
|
j:=length(stack)-1;
|
|
if j>=0 then
|
|
begin
|
|
while(getprecedence(stack[j].op)>=prec) and (j>=0) do
|
|
begin
|
|
setlength(output,length(output)+1);
|
|
output[length(output)-1]:=stack[j];
|
|
setlength(stack,length(stack)-1);
|
|
j:=j-1;
|
|
end;
|
|
setlength(stack,length(stack)+1);
|
|
stack[length(stack)-1]:=input[i];
|
|
end;
|
|
end
|
|
else if input[i].mathtype=mtrbracket then
|
|
begin
|
|
j:=length(stack)-1;
|
|
if j>=0 then
|
|
begin
|
|
while(stack[j].mathtype<>mtlbracket) and (j>=0) do
|
|
begin
|
|
setlength(output,length(output)+1);
|
|
output[length(output)-1]:=stack[j];
|
|
setlength(stack,length(stack)-1);
|
|
j:=j-1;
|
|
end;
|
|
if j>=0 then
|
|
setlength(stack,length(stack)-1);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|