602 lines
18 KiB
ObjectPascal
602 lines
18 KiB
ObjectPascal
unit uDAExpressionEvaluator;
|
|
|
|
{----------------------------------------------------------------------------}
|
|
{ Data Abstract Library - Core Library }
|
|
{ }
|
|
{ compiler: Delphi 6 and up, Kylix 3 and up }
|
|
{ platform: Win32, Linux }
|
|
{ }
|
|
{ (c)opyright RemObjects Software. all rights reserved. }
|
|
{ }
|
|
{ Using this code requires a valid license of the Data Abstract }
|
|
{ which can be obtained at http://www.remobjects.com. }
|
|
{----------------------------------------------------------------------------}
|
|
|
|
{$I DataAbstract.inc}
|
|
|
|
interface
|
|
uses
|
|
SysUtils, Classes, uDAMacros;
|
|
|
|
type
|
|
EDAEvaluationException = class(Exception);
|
|
TDAExpressionEvaluator = class;
|
|
TDAEEGetValue = procedure (Sender: TDAExpressionEvaluator; const aIdentifier: string; out aValue: Variant) of object;
|
|
TDAEEFunctionCall = procedure (Sender: TDAExpressionEvaluator; const aIdentifier: string; const Args: array of Variant; out aValue: Variant) of object;
|
|
TDAEEFunction = class(TObject)
|
|
private
|
|
fName: string;
|
|
fOnCall: TDAEEFunctionCall;
|
|
fNameHash: Integer;
|
|
procedure SetName(const Value: string);
|
|
public
|
|
property Name: string read fName write SetName;
|
|
property NameHash: Integer read fNameHash;
|
|
property OnCall: TDAEEFunctionCall read fOnCall write fOnCall;
|
|
end;
|
|
|
|
TDAEEFunctionList = class(TObject)
|
|
private
|
|
fItems: TList;
|
|
function GetCount: Integer;
|
|
function GetItem(i: Integer): TDAEEFunction;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
property Count: Integer read GetCount;
|
|
property Items[I: Integer]: TDAEEFunction read GetItem; default;
|
|
|
|
function Add(const aName: string): TDAEEFunction;
|
|
procedure Delete(I: Integer);
|
|
procedure Clear;
|
|
end;
|
|
|
|
TDAExpressionEvaluator = class(TObject)
|
|
private
|
|
fOnUnknownFunctionCall: TDAEEFunctionCall;
|
|
fOnGetValue: TDAEEGetValue;
|
|
fFunctionList: TDAEEFunctionList;
|
|
fParser: TROPascalParser;
|
|
function EvaluateProcCall(const aIdentifier: string; const Args: Variant): Variant;
|
|
function EvaluateValue(const aIdentifier: string): Variant;
|
|
|
|
function Op_In(const V1, V2: Variant): Variant;
|
|
function Op_Like(const V1, V2: Variant): Variant;
|
|
function ParseBooleanExpression: Variant;
|
|
function ParseComparisonExpression: Variant;
|
|
function ParseFactor: Variant;
|
|
function ParseSimpleExpression: Variant;
|
|
function ParseTerm: Variant;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
property OnGetValue: TDAEEGetValue read fOnGetValue write fOnGetValue;
|
|
property OnUnknownFunctionCall: TDAEEFunctionCall read fOnUnknownFunctionCall write fOnUnknownFunctionCall;
|
|
property FunctionList: TDAEEFunctionList read fFunctionList;
|
|
|
|
function Evaluate(const aString: string): Variant;
|
|
end;
|
|
|
|
TDAStdExpressionEvaluator = class(TDAExpressionEvaluator)
|
|
private
|
|
procedure Convert(Sender: TDAExpressionEvaluator; const aIdentifier: string; const Args: array of Variant; out aValue: Variant);
|
|
procedure Len(Sender: TDAExpressionEvaluator; const aIdentifier: string; const Args: array of Variant; out aValue: Variant);
|
|
procedure IsNull(Sender: TDAExpressionEvaluator; const aIdentifier: string; const Args: array of Variant; out aValue: Variant);
|
|
procedure IIF(Sender: TDAExpressionEvaluator; const aIdentifier: string; const Args: array of Variant; out aValue: Variant);
|
|
procedure Trim(Sender: TDAExpressionEvaluator; const aIdentifier: string; const Args: array of Variant; out aValue: Variant);
|
|
procedure Substring(Sender: TDAExpressionEvaluator; const aIdentifier: string; const Args: array of Variant; out aValue: Variant);
|
|
public
|
|
constructor Create;
|
|
end;
|
|
implementation
|
|
|
|
uses Variants;
|
|
|
|
{ TDAExpressionEvaluator }
|
|
|
|
constructor TDAExpressionEvaluator.Create;
|
|
begin
|
|
inherited Create;
|
|
fFunctionList := TDAEEFunctionList.Create;
|
|
end;
|
|
|
|
destructor TDAExpressionEvaluator.Destroy;
|
|
begin
|
|
fFunctionList.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.Evaluate(const aString: string): Variant;
|
|
begin
|
|
fParser := TROPascalParser.Create;
|
|
fParser.OpenBlockEscape := true;
|
|
try
|
|
fParser.SetText(aString);
|
|
Result := ParseBooleanExpression;
|
|
|
|
if fParser.CurrtokenId <> CSTI_EOF then
|
|
raise EDAEvaluationException.Create('End of expression expected');
|
|
finally
|
|
fParser.Free;
|
|
end;
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.EvaluateProcCall(const aIdentifier: string;
|
|
const Args: Variant): Variant;
|
|
var
|
|
s: string;
|
|
h, i: Integer;
|
|
lFunction: TDAEEFunction;
|
|
lRealArgs: array of Variant;
|
|
begin
|
|
if not VarIsArray(Args) then begin
|
|
SetLength(lRealArgs, 1);
|
|
lRealArgs[0] := args;
|
|
end else begin
|
|
SetLength(lRealArgs, VarArrayHighBound(Args, 1)+1);
|
|
for i := 0 to Length(lRealArgs) -1 do begin
|
|
lRealArgs[i] := Args[i];
|
|
end;
|
|
end;
|
|
s := FastUppercase(aIdentifier);
|
|
h := MakeHash(s);
|
|
for i := 0 to fFunctionList.Count -1 do begin
|
|
lFunction := fFunctionList[i];
|
|
if (lFunction.NameHash = h) and (lFunction.Name = s) and (assigned(lFunction.OnCall)) then begin
|
|
lFunction.OnCall(self, aIdentifier, lRealArgs, Result);
|
|
exit;
|
|
end;
|
|
end;
|
|
if assigned(fOnUnknownFunctionCall) then
|
|
fOnUnknownFunctionCall(Self, aIdentifier, Args, Result)
|
|
else
|
|
raise EDAEvaluationException('Unknown function: '+aIdentifier);
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.EvaluateValue(const aIdentifier: string): Variant;
|
|
begin
|
|
if assigned(fOnGetValue) then
|
|
fOnGetValue(Self, aIdentifier, Result)
|
|
else
|
|
raise EDAEvaluationException('Unknown identifier: '+aIdentifier);
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.ParseComparisonExpression: Variant;
|
|
var
|
|
V1, V2: Variant;
|
|
lTok: TROPasToken;
|
|
begin
|
|
V1 := ParseSimpleExpression;
|
|
lTok := fParser.CurrTokenId;
|
|
while (lTok = CSTII_In) or
|
|
(lTok = CSTII_Like) or
|
|
(lTok = CSTI_Greater ) or
|
|
(lTok = CSTI_GreaterEqual) or
|
|
(lTok = CSTI_Smaller ) or
|
|
(lTok = CSTI_SmallerEqual) or
|
|
(lTok = CSTI_Equal) or
|
|
(lTok =CSTI_NotEqual) do
|
|
begin
|
|
FParser.Next;
|
|
V2 := ParseSimpleExpression;
|
|
|
|
case lTok of
|
|
CSTII_In: V1 := Op_In(v1, v2);
|
|
CSTII_Like: V1 := Op_Like(v1, v2);
|
|
CSTI_Greater: v1 := v1 > v2;
|
|
CSTI_GreaterEqual: v1 := v1 >= v2;
|
|
CSTI_Smaller: v1 := v1 <= v2;
|
|
CSTI_SmallerEqual: v1 := v1 <= v2;
|
|
CSTI_Equal: v1 := v1 = v2;
|
|
//CSTI_notEqual:
|
|
else v1 := v1 <> v2;
|
|
end;
|
|
lTok := fParser.CurrTokenId;
|
|
end;
|
|
Result := V1;
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.ParseSimpleExpression: Variant;
|
|
var
|
|
V1, V2: Variant;
|
|
lTok: TROPasToken;
|
|
begin
|
|
V1 := ParseTerm;
|
|
lTok := fParser.CurrTokenId;
|
|
while (lTok = CSTI_Plus) or
|
|
(lTok = CSTI_Minus) do
|
|
begin
|
|
FParser.Next;
|
|
V2 := ParseTerm;
|
|
|
|
case lTok of
|
|
CSTI_Minus: V1 := V1 - V2;
|
|
else v1 := v1 + v2; // CSTI_plus
|
|
end;
|
|
lTok := fParser.CurrTokenId;
|
|
end;
|
|
Result := V1;
|
|
end;
|
|
|
|
function ParseDate(s: string): TDateTime;
|
|
begin
|
|
s := copy(S,2,Length(s)-2);
|
|
if length(s) = 10 then begin
|
|
if (s[3] <> '/') or (s[6] <> '/') then raise EDAEvaluationException.Create('Invalid date format');
|
|
Result := EncodeDate(StrToInt(copy(s, 7, 4)), StrToInt(copy(S, 1, 2)), StrToInt(copy(s, 4, 2)));
|
|
end else
|
|
raise EDAEvaluationException.Create('Invalid date format');
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.ParseFactor: Variant;
|
|
var
|
|
tmp: TList;
|
|
pv: PVariant;
|
|
i: Integer;
|
|
e: Extended;
|
|
s: string;
|
|
begin
|
|
case fParser.CurrTokenId of
|
|
CSTII_Not: begin
|
|
FParser.Next;
|
|
Result := not ParseFactor;
|
|
end;
|
|
CSTI_Plus: begin
|
|
FParser.Next;
|
|
Result := + ParseFactor;
|
|
end;
|
|
CSTI_Minus: begin
|
|
FParser.Next;
|
|
Result := - ParseFactor;
|
|
end;
|
|
CSTI_OpenRound: begin
|
|
FParser.Next;
|
|
Result := ParseBooleanExpression;
|
|
if fParser.CurrTokenId = CSTI_Comma then begin
|
|
tmp := TList.Create;
|
|
New(pv);
|
|
pv^ := Result;
|
|
tmp.Add(pv);
|
|
while FPArser.CurrTokenId = CSTI_Comma do begin
|
|
FParser.Next;
|
|
try
|
|
result := ParseBooleanExpression;
|
|
New(pv);
|
|
pv^ := Result;
|
|
tmp.Add(pv);
|
|
except
|
|
for i := 0 to tmp.Count -1 do begin
|
|
pv := tmp[i];
|
|
dispose(pv);
|
|
end;
|
|
tmp.Free;
|
|
raise;
|
|
end;
|
|
end;
|
|
Result := VarArrayCreate([0, tmp.Count -1], varVariant);
|
|
for i := 0 to tmp.Count -1 do begin
|
|
pv := tmp[i];
|
|
Result[i] := pv^;
|
|
dispose(pv);
|
|
end;
|
|
tmp.Free;
|
|
end;
|
|
if fParser.CurrTokenId <> CSTI_CloseRound then
|
|
raise EDAEvaluationException.Create('Closing parenthesis expected');
|
|
FParser.Next;
|
|
end;
|
|
CSTI_HexInt, CSTI_Integer: begin
|
|
Result := StrToInt64(FParser.OriginalToken);
|
|
FParser.Next;
|
|
end;
|
|
CSTI_Real: begin
|
|
Val(FParser.OriginalToken, e, i); Result := e;
|
|
FParser.Next;
|
|
end;
|
|
CSTI_String: begin
|
|
Result := StringReplace(FParser.OriginalToken, #39#39, #39, [rfReplaceAll]);
|
|
Result := Copy(Result, 2, Length(Result) -2);
|
|
Fparser.Next;
|
|
end;
|
|
CSTI_Date: begin
|
|
Result := ParseDate(FParser.OriginalToken);
|
|
FParser.Next;
|
|
end;
|
|
CSTI_Identifier: begin
|
|
s := FPArser.OriginalToken;
|
|
FParser.Next;
|
|
if FParser.CurrTokenID = CSTI_OpenRound then
|
|
Result := EvaluateProcCall(s, ParseFactor)
|
|
else
|
|
Result := EvaluateValue(s)
|
|
end;
|
|
else
|
|
raise EDAEvaluationException.Create('Syntax error');
|
|
end;
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.ParseBooleanExpression: Variant;
|
|
var
|
|
V1, V2: Variant;
|
|
lTok: TROPasToken;
|
|
begin
|
|
V1 := ParseComparisonExpression;
|
|
lTok := fParser.CurrTokenId;
|
|
while (lTok = CSTII_and) or
|
|
(lTok = CSTII_or) or
|
|
(lTok = CSTII_xor) do
|
|
begin
|
|
FParser.Next;
|
|
V2 := ParseComparisonExpression;
|
|
|
|
case lTok of
|
|
CSTII_or: V1 := V1 or V2;
|
|
CSTII_xor: V1 := V1 xor V2;
|
|
else v1 := v1 and v2; // CSTII_and
|
|
end;
|
|
lTok := fParser.CurrTokenId;
|
|
end;
|
|
Result := V1;
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.ParseTerm: Variant;
|
|
var
|
|
V1, V2: Variant;
|
|
lTok: TROPasToken;
|
|
begin
|
|
V1 := ParseFactor;
|
|
lTok := fParser.CurrTokenId;
|
|
while (lTok = CSTI_multiply) or
|
|
(lTok = CSTI_divide) or
|
|
(lTok = CSTI_Modulus) do
|
|
begin
|
|
FParser.Next;
|
|
V2 := ParseFactor;
|
|
|
|
case lTok of
|
|
CSTI_Multiply: V1 := V1 * V2;
|
|
CSTI_Divide: V1 := V1 / V2;
|
|
else v1 := v1 mod v2; // CSTI_modulus
|
|
end;
|
|
lTok := fParser.CurrTokenId;
|
|
end;
|
|
Result := V1;
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.Op_In(const V1, V2: Variant): Variant;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if VarIsArray(V2) then begin
|
|
for i := VarArrayLowBound(V2, 1) to VarArrayHighBound(V2, 1) do begin
|
|
if v2[i] = v1 then begin Result := true; exit; end;
|
|
end;
|
|
Result := False;
|
|
end else
|
|
raise EDAEvaluationException.Create('Array expected for IN expression');
|
|
end;
|
|
|
|
function WidePos(const iSubString, iString:WideString): Integer; overload;
|
|
var i,j:integer;
|
|
LenS,LenS1:integer;
|
|
b: Boolean;
|
|
begin
|
|
LenS1 := Length(iSubString);
|
|
LenS := Length(iString);
|
|
|
|
i := 1;
|
|
while i <= LenS-LenS1+1 do begin
|
|
|
|
{ IsCandidate }
|
|
b := true;
|
|
for j := 1 to LenS1 do begin
|
|
if iString[i+j-1] <> iSubString[j] then begin
|
|
b := false;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
if b then begin
|
|
result := i;
|
|
exit;
|
|
end;
|
|
|
|
inc(i);
|
|
end;
|
|
result := 0;
|
|
end;
|
|
|
|
function TDAExpressionEvaluator.Op_Like(const V1, V2: Variant): Variant;
|
|
var
|
|
w1, w2: WideString;
|
|
begin
|
|
w1 := WideUppercase(V1);
|
|
W2 := WideUppercase(V2);
|
|
if Length(W2) = 0 then begin Result := False; exit; end;
|
|
|
|
if (Length(W2) > 0) and ((W2[1] = '%') or (W2[1] = '*')) then begin
|
|
if ((W2[Length(W2)] = '%') or (W2[Length(W2)] = '*')) then begin
|
|
W2 := Copy(W2, 2, Length(W2) -2);
|
|
Result := WidePos(W2, W1) > 0;
|
|
end else begin
|
|
W2 := Copy(W2, 2, Length(W2) -1);
|
|
Result := Copy(W1, LEngth(W1) - Length(W2)+1, Length(W2)) = W2;
|
|
end;
|
|
end else if (Length(W2)> 0) and ((W2[Length(W2)] = '%') or (W2[Length(W2)] = '*')) then begin
|
|
W2 := copy(W2, 1, Length(W2)-1);
|
|
result := Copy(W1, 1, Length(W2)) = W2;
|
|
end else
|
|
result := w1 = w2;
|
|
end;
|
|
|
|
{ TDAEEFunction }
|
|
|
|
procedure TDAEEFunction.SetName(const Value: string);
|
|
begin
|
|
fName := FastUppercase(Value);
|
|
fNameHash := MakeHash(fName);
|
|
end;
|
|
|
|
{ TDAEEFunctionList }
|
|
|
|
function TDAEEFunctionList.Add(const aName: string): TDAEEFunction;
|
|
begin
|
|
result := TDAEEFunction.Create;
|
|
Result.Name := aName;
|
|
fItems.Add(Result);
|
|
end;
|
|
|
|
procedure TDAEEFunctionList.Clear;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := fItems.Count -1 downto 0 do begin
|
|
TDAEEFunction(fItems[i]).Free;
|
|
end;
|
|
fItems.Clear;
|
|
end;
|
|
|
|
constructor TDAEEFunctionList.Create;
|
|
begin
|
|
inherited Create;
|
|
fItems := TList.Create;
|
|
end;
|
|
|
|
procedure TDAEEFunctionList.Delete(I: Integer);
|
|
begin
|
|
TDAEEFunction(fItems[i]).Free;
|
|
fItems.Delete(i);
|
|
end;
|
|
|
|
destructor TDAEEFunctionList.Destroy;
|
|
begin
|
|
Clear;
|
|
fItems.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TDAEEFunctionList.GetCount: Integer;
|
|
begin
|
|
result := fItems.Count;
|
|
end;
|
|
|
|
function TDAEEFunctionList.GetItem(i: Integer): TDAEEFunction;
|
|
begin
|
|
result := TDAEEFunction(fItems[i]);
|
|
end;
|
|
|
|
{ TDAStdExpressionEvaluator }
|
|
|
|
procedure TDAStdExpressionEvaluator.Convert(Sender: TDAExpressionEvaluator;
|
|
const aIdentifier: string; const Args: array of Variant;
|
|
out aValue: Variant);
|
|
var
|
|
aType: TVarType;
|
|
s: string;
|
|
begin
|
|
if Length(Args) <> 2 then raise EDAEvaluationException.Create('2 arguments expected for "Convert"');
|
|
s := FastUppercase(args[1]);
|
|
if (s = 'SYSTEM.BYTE') or (s = 'BYTE') then aType := varByte else
|
|
if (s = 'SYSTEM.SBYTE') or (s = 'SBYTE') then aType := varShortInt else
|
|
if (s = 'SYSTEM.INT16') or (s = 'INT16') then aType := varSmallint else
|
|
if (s = 'SYSTEM.UINT16') or (s = 'UINT16') then aType := varWord else
|
|
if (s = 'SYSTEM.INT32') or (s = 'INT32') then aType := varInteger else
|
|
if (s = 'SYSTEM.UINT32') or (s = 'UINT32') then aType := varLongWord else
|
|
if (s = 'SYSTEM.INT64') or (s = 'INT64') then aType := varInt64 else
|
|
if (s = 'SYSTEM.UINT64') or (s = 'UINT64') then aType := VarInt64 else
|
|
if (s = 'SYSTEM.STRING') or (s = 'STRING') then aType := varOleStr else
|
|
if (s = 'SYSTEM.SINGLE') or (s = 'SINGLE') then aType := varSIngle else
|
|
if (s = 'SYSTEM.DOUBLE') or (s = 'DOUBLE') then aType := varDouble else
|
|
if (s = 'SYSTEM.CHAR') or (s = 'CHAR') then aType := varOleStr else
|
|
if (s = 'SYSTEM.DATETIME') or (s = 'DATETIME') then aType := varDate else
|
|
raise EDAEvaluationException.Create('Unknown type used for conversion: "'+args[1]+'"');
|
|
VarCast(aValue, Args[0], aType);
|
|
end;
|
|
|
|
constructor TDAStdExpressionEvaluator.Create;
|
|
begin
|
|
inherited Create;
|
|
FunctionList.Add('Convert').OnCall := Convert;
|
|
FunctionList.Add('Len').OnCall := Len;
|
|
FunctionList.Add('IsNull').OnCall := IsNull;
|
|
FunctionList.Add('IIF').OnCall := IIF;
|
|
FunctionList.Add('Trim').OnCall := Trim;
|
|
FunctionList.Add('SubString').OnCall := SubString;
|
|
end;
|
|
|
|
procedure TDAStdExpressionEvaluator.IIF(Sender: TDAExpressionEvaluator;
|
|
const aIdentifier: string; const Args: array of Variant;
|
|
out aValue: Variant);
|
|
begin
|
|
if Length(Args) <> 3 then raise EDAEvaluationException.Create('3 arguments expected for "IIF"');
|
|
if Args[0] then
|
|
aValue := Args[1]
|
|
else
|
|
aValue := Args[2];
|
|
end;
|
|
|
|
procedure TDAStdExpressionEvaluator.IsNull(Sender: TDAExpressionEvaluator;
|
|
const aIdentifier: string; const Args: array of Variant;
|
|
out aValue: Variant);
|
|
begin
|
|
if Length(Args) <> 2 then raise EDAEvaluationException.Create('2 arguments expected for "IsNull"');
|
|
if VarIsError(Args[0]) or VarIsNull(Args[0]) then
|
|
aValue := Args[1]
|
|
else
|
|
aValue := Args[0];
|
|
end;
|
|
|
|
procedure TDAStdExpressionEvaluator.Len(Sender: TDAExpressionEvaluator;
|
|
const aIdentifier: string; const Args: array of Variant;
|
|
out aValue: Variant);
|
|
begin
|
|
if Length(Args) <> 1 then raise EDAEvaluationException.Create('1 argument expected for "Len"');
|
|
aValue := Length(WideString(Args[0]));
|
|
end;
|
|
|
|
procedure TDAStdExpressionEvaluator.Substring(
|
|
Sender: TDAExpressionEvaluator; const aIdentifier: string;
|
|
const Args: array of Variant; out aValue: Variant);
|
|
var
|
|
w: WideString;
|
|
s: string;
|
|
begin
|
|
if Length(Args) <> 3 then raise EDAEvaluationException.Create('3 arguments expected for "Substring"');
|
|
if VarType(Args[0]) = varOleStr then begin
|
|
w := Args[0];
|
|
aValue := Copy(w, Integer(args[1])-1, Integer(Args[2])); // zero based
|
|
end else begin
|
|
s := Args[0];
|
|
aValue := Copy(s, Integer(args[1])-1, Integer(Args[2])); // zero based
|
|
end;end;
|
|
|
|
procedure TDAStdExpressionEvaluator.Trim(Sender: TDAExpressionEvaluator;
|
|
const aIdentifier: string; const Args: array of Variant;
|
|
out aValue: Variant);
|
|
var
|
|
w: WideString;
|
|
s: string;
|
|
begin
|
|
if Length(Args) <> 1 then raise EDAEvaluationException.Create('1 argument expected for "Trim"');
|
|
if VarType(Args[0]) = varOleStr then begin
|
|
w := Args[0];
|
|
while (length(w) > 0) and ((w[1] = #13) or (w[1] = #10) or (w[1] = #9) or (w[1] = #32)) do
|
|
Delete(w, 1, 1);
|
|
while (length(w) > 0) and ((w[Length(w)] = #13) or (w[Length(w)] = #10) or (w[Length(w)] = #9) or (w[Length(w)] = #32)) do
|
|
Delete(w, Length(w), 1);
|
|
aValue := w;
|
|
end else begin
|
|
s := Args[0];
|
|
while (length(s) > 0) and ((s[1] = #13) or (s[1] = #10) or (s[1] = #9) or (s[1] = #32)) do
|
|
Delete(s, 1, 1);
|
|
while (length(s) > 0) and ((s[Length(s)] = #13) or (s[Length(s)] = #10) or (s[Length(s)] = #9) or (s[Length(s)] = #32)) do
|
|
Delete(s, Length(s), 1);
|
|
aValue := s;
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|