962 lines
22 KiB
Plaintext
962 lines
22 KiB
Plaintext
|
|
||
|
{*******************************************************}
|
||
|
{ }
|
||
|
{ Turbo Pascal Version 7.0 }
|
||
|
{ Turbo Vision Unit }
|
||
|
{ }
|
||
|
{ Copyright (c) 1992 Borland International }
|
||
|
{ }
|
||
|
{*******************************************************}
|
||
|
|
||
|
unit Validate;
|
||
|
|
||
|
{$O+,F+,X+,I-,S-}
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses Objects;
|
||
|
|
||
|
const
|
||
|
|
||
|
{ TValidator Status constants }
|
||
|
|
||
|
vsOk = 0;
|
||
|
vsSyntax = 1; { Error in the syntax of either a TPXPictureValidator
|
||
|
or a TDBPictureValidator }
|
||
|
|
||
|
{ Validator option flags }
|
||
|
voFill = $0001;
|
||
|
voTransfer = $0002;
|
||
|
voOnAppend = $0004;
|
||
|
voReserved = $00F8;
|
||
|
|
||
|
{ TVTransfer constants }
|
||
|
|
||
|
type
|
||
|
TVTransfer = (vtDataSize, vtSetData, vtGetData);
|
||
|
|
||
|
{ Abstract TValidator object }
|
||
|
|
||
|
PValidator = ^TValidator;
|
||
|
TValidator = object(TObject)
|
||
|
Status: Word;
|
||
|
Options: Word;
|
||
|
constructor Init;
|
||
|
constructor Load(var S: TStream);
|
||
|
procedure Error; virtual;
|
||
|
function IsValidInput(var S: string;
|
||
|
SuppressFill: Boolean): Boolean; virtual;
|
||
|
function IsValid(const S: string): Boolean; virtual;
|
||
|
procedure Store(var S: TStream);
|
||
|
function Transfer(var S: String; Buffer: Pointer;
|
||
|
Flag: TVTransfer): Word; virtual;
|
||
|
function Valid(const S: string): Boolean;
|
||
|
end;
|
||
|
|
||
|
{ TPXPictureValidator result type }
|
||
|
|
||
|
TPicResult = (prComplete, prIncomplete, prEmpty, prError, prSyntax,
|
||
|
prAmbiguous, prIncompNoFill);
|
||
|
|
||
|
{ TPXPictureValidator }
|
||
|
|
||
|
PPXPictureValidator = ^TPXPictureValidator;
|
||
|
TPXPictureValidator = object(TValidator)
|
||
|
Pic: PString;
|
||
|
constructor Init(const APic: string; AutoFill: Boolean);
|
||
|
constructor Load(var S: TStream);
|
||
|
destructor Done; virtual;
|
||
|
procedure Error; virtual;
|
||
|
function IsValidInput(var S: string;
|
||
|
SuppressFill: Boolean): Boolean; virtual;
|
||
|
function IsValid(const S: string): Boolean; virtual;
|
||
|
function Picture(var Input: string;
|
||
|
AutoFill: Boolean): TPicResult; virtual;
|
||
|
procedure Store(var S: TStream);
|
||
|
end;
|
||
|
|
||
|
{ TFilterValidator }
|
||
|
|
||
|
PFilterValidator = ^TFilterValidator;
|
||
|
TFilterValidator = object(TValidator)
|
||
|
ValidChars: TCharSet;
|
||
|
constructor Init(AValidChars: TCharSet);
|
||
|
constructor Load(var S: TStream);
|
||
|
procedure Error; virtual;
|
||
|
function IsValid(const S: string): Boolean; virtual;
|
||
|
function IsValidInput(var S: string;
|
||
|
SuppressFill: Boolean): Boolean; virtual;
|
||
|
procedure Store(var S: TStream);
|
||
|
end;
|
||
|
|
||
|
{ TRangeValidator }
|
||
|
|
||
|
PRangeValidator = ^TRangeValidator;
|
||
|
TRangeValidator = object(TFilterValidator)
|
||
|
Min, Max: LongInt;
|
||
|
constructor Init(AMin, AMax: LongInt);
|
||
|
constructor Load(var S: TStream);
|
||
|
procedure Error; virtual;
|
||
|
function IsValid(const S: string): Boolean; virtual;
|
||
|
procedure Store(var S: TStream);
|
||
|
function Transfer(var S: String; Buffer: Pointer;
|
||
|
Flag: TVTransfer): Word; virtual;
|
||
|
end;
|
||
|
|
||
|
{ TLookupValidator }
|
||
|
|
||
|
PLookupValidator = ^TLookupValidator;
|
||
|
TLookupValidator = object(TValidator)
|
||
|
function IsValid(const S: string): Boolean; virtual;
|
||
|
function Lookup(const S: string): Boolean; virtual;
|
||
|
end;
|
||
|
|
||
|
{ TStringLookupValidator }
|
||
|
|
||
|
PStringLookupValidator = ^TStringLookupValidator;
|
||
|
TStringLookupValidator = object(TLookupValidator)
|
||
|
Strings: PStringCollection;
|
||
|
constructor Init(AStrings: PStringCollection);
|
||
|
constructor Load(var S: TStream);
|
||
|
destructor Done; virtual;
|
||
|
procedure Error; virtual;
|
||
|
function Lookup(const S: string): Boolean; virtual;
|
||
|
procedure NewStringList(AStrings: PStringCollection);
|
||
|
procedure Store(var S: TStream);
|
||
|
end;
|
||
|
|
||
|
{ Validate registration procedure }
|
||
|
|
||
|
procedure RegisterValidate;
|
||
|
|
||
|
{ Stream registration records }
|
||
|
|
||
|
const
|
||
|
RPXPictureValidator: TStreamRec = (
|
||
|
ObjType: 80;
|
||
|
VmtLink: Ofs(TypeOf(TPXPictureValidator)^);
|
||
|
Load: @TPXPictureValidator.Load;
|
||
|
Store: @TPXPictureValidator.Store
|
||
|
);
|
||
|
|
||
|
const
|
||
|
RFilterValidator: TStreamRec = (
|
||
|
ObjType: 81;
|
||
|
VmtLink: Ofs(TypeOf(TFilterValidator)^);
|
||
|
Load: @TFilterValidator.Load;
|
||
|
Store: @TFilterValidator.Store
|
||
|
);
|
||
|
|
||
|
const
|
||
|
RRangeValidator: TStreamRec = (
|
||
|
ObjType: 82;
|
||
|
VmtLink: Ofs(TypeOf(TRangeValidator)^);
|
||
|
Load: @TRangeValidator.Load;
|
||
|
Store: @TRangeValidator.Store
|
||
|
);
|
||
|
|
||
|
const
|
||
|
RStringLookupValidator: TStreamRec = (
|
||
|
ObjType: 83;
|
||
|
VmtLink: Ofs(TypeOf(TStringLookupValidator)^);
|
||
|
Load: @TStringLookupValidator.Load;
|
||
|
Store: @TStringLookupValidator.Store
|
||
|
);
|
||
|
|
||
|
implementation
|
||
|
|
||
|
{$IFDEF Windows}
|
||
|
uses WinTypes, WinProcs, Strings, OWindows;
|
||
|
{$ELSE}
|
||
|
uses MsgBox;
|
||
|
{$ENDIF Windows}
|
||
|
|
||
|
{ TValidator }
|
||
|
|
||
|
constructor TValidator.Init;
|
||
|
begin
|
||
|
inherited Init;
|
||
|
Status := 0;
|
||
|
Options := 0;
|
||
|
end;
|
||
|
|
||
|
constructor TValidator.Load(var S:TStream);
|
||
|
begin
|
||
|
inherited Init;
|
||
|
Status := 0;
|
||
|
S.Read(Options, SizeOf(Options));
|
||
|
end;
|
||
|
|
||
|
procedure TValidator.Error;
|
||
|
begin
|
||
|
end;
|
||
|
|
||
|
function TValidator.IsValidInput(var S: string; SuppressFill: Boolean):
|
||
|
Boolean;
|
||
|
begin
|
||
|
IsValidInput := True;
|
||
|
end;
|
||
|
|
||
|
function TValidator.IsValid(const S: string): Boolean;
|
||
|
begin
|
||
|
IsValid := True;
|
||
|
end;
|
||
|
|
||
|
procedure TValidator.Store(var S: TStream);
|
||
|
begin
|
||
|
S.Write(Options, SizeOf(Options));
|
||
|
end;
|
||
|
|
||
|
function TValidator.Transfer(var S: String; Buffer: Pointer;
|
||
|
Flag: TVTransfer): Word;
|
||
|
begin
|
||
|
Transfer := 0;
|
||
|
end;
|
||
|
|
||
|
function TValidator.Valid(const S: string): Boolean;
|
||
|
begin
|
||
|
Valid := False;
|
||
|
if not IsValid(S) then
|
||
|
begin
|
||
|
Error;
|
||
|
Exit;
|
||
|
end;
|
||
|
Valid := True;
|
||
|
end;
|
||
|
|
||
|
{ TPXPictureValidator }
|
||
|
|
||
|
constructor TPXPictureValidator.Init(const APic: string;
|
||
|
AutoFill: Boolean);
|
||
|
var
|
||
|
S: String;
|
||
|
begin
|
||
|
inherited Init;
|
||
|
Pic := NewStr(APic);
|
||
|
Options := voOnAppend;
|
||
|
if AutoFill then Options := Options or voFill;
|
||
|
S := '';
|
||
|
if Picture(S, False) <> prEmpty then
|
||
|
Status := vsSyntax;
|
||
|
end;
|
||
|
|
||
|
constructor TPXPictureValidator.Load(var S: TStream);
|
||
|
begin
|
||
|
inherited Load(S);
|
||
|
Pic := S.ReadStr;
|
||
|
end;
|
||
|
|
||
|
destructor TPXPictureValidator.Done;
|
||
|
begin
|
||
|
DisposeStr(Pic);
|
||
|
inherited Done;
|
||
|
end;
|
||
|
|
||
|
{$IFDEF Windows}
|
||
|
|
||
|
procedure TPXPictureValidator.Error;
|
||
|
var
|
||
|
MsgStr: array[0..255] of Char;
|
||
|
begin
|
||
|
StrPCopy(StrECopy(MsgStr,
|
||
|
'Input does not conform to picture:'#10' '), Pic^);
|
||
|
MessageBox(0, MsgStr, 'Validator', mb_IconExclamation or mb_Ok);
|
||
|
end;
|
||
|
|
||
|
{$ELSE}
|
||
|
|
||
|
procedure TPXPictureValidator.Error;
|
||
|
begin
|
||
|
MessageBox('Input does not conform to picture:'#13' %s', @Pic,
|
||
|
mfError + mfOKButton);
|
||
|
end;
|
||
|
|
||
|
{$ENDIF Windows}
|
||
|
|
||
|
function TPXPictureValidator.IsValidInput(var S: string;
|
||
|
SuppressFill: Boolean): Boolean;
|
||
|
begin
|
||
|
IsValidInput := (Pic = nil) or
|
||
|
(Picture(S, (Options and voFill <> 0) and not SuppressFill) <> prError);
|
||
|
end;
|
||
|
|
||
|
function TPXPictureValidator.IsValid(const S: string): Boolean;
|
||
|
var
|
||
|
Str: String;
|
||
|
Rslt: TPicResult;
|
||
|
begin
|
||
|
Str := S;
|
||
|
Rslt := Picture(Str, False);
|
||
|
IsValid := (Pic = nil) or (Rslt = prComplete) or (Rslt = prEmpty);
|
||
|
end;
|
||
|
|
||
|
function IsNumber(Chr: Char): Boolean; near; assembler;
|
||
|
asm
|
||
|
XOR AL,AL
|
||
|
MOV Ch,Chr
|
||
|
CMP Ch,'0'
|
||
|
JB @@1
|
||
|
CMP Ch,'9'
|
||
|
JA @@1
|
||
|
INC AL
|
||
|
@@1:
|
||
|
end;
|
||
|
|
||
|
function IsLetter(Chr: Char): Boolean; near; assembler;
|
||
|
asm
|
||
|
XOR AL,AL
|
||
|
MOV Cl,Chr
|
||
|
AND Cl,0DFH
|
||
|
CMP Cl,'A'
|
||
|
JB @@2
|
||
|
CMP Cl,'Z'
|
||
|
JA @@2
|
||
|
@@1: INC AL
|
||
|
@@2:
|
||
|
end;
|
||
|
|
||
|
function IsSpecial(Chr: Char; const Special: string): Boolean; near;
|
||
|
assembler;
|
||
|
asm
|
||
|
XOR AH,AH
|
||
|
LES DI,Special
|
||
|
MOV AL,ES:[DI]
|
||
|
INC DI
|
||
|
MOV CH,AH
|
||
|
MOV CL,AL
|
||
|
MOV AL,Chr
|
||
|
REPNE SCASB
|
||
|
JCXZ @@1
|
||
|
INC AH
|
||
|
@@1: MOV AL,AH
|
||
|
end;
|
||
|
|
||
|
{ This helper function will be used for a persistant TInputLine mask.
|
||
|
It will be moved to DIALOGS.PAS when needed. }
|
||
|
|
||
|
function NumChar(Chr: Char; const S: string): Byte; near; assembler;
|
||
|
asm
|
||
|
XOR AH,AH
|
||
|
LES DI,S
|
||
|
MOV AL,ES:[DI]
|
||
|
INC DI
|
||
|
MOV CH,AH
|
||
|
MOV CL,AL
|
||
|
MOV AL,Chr
|
||
|
@@1: REPNE SCASB
|
||
|
JCXZ @@2
|
||
|
INC AH
|
||
|
JMP @@1
|
||
|
@@2: MOV AL,AH
|
||
|
end;
|
||
|
|
||
|
function IsComplete(Rslt: TPicResult): Boolean;
|
||
|
begin
|
||
|
IsComplete := Rslt in [prComplete, prAmbiguous];
|
||
|
end;
|
||
|
|
||
|
function IsIncomplete(Rslt: TPicResult): Boolean;
|
||
|
begin
|
||
|
IsIncomplete := Rslt in [prIncomplete, prIncompNoFill];
|
||
|
end;
|
||
|
|
||
|
function TPXPictureValidator.Picture(var Input: string;
|
||
|
AutoFill: Boolean): TPicResult;
|
||
|
var
|
||
|
I, J: Byte;
|
||
|
Rslt: TPicResult;
|
||
|
Reprocess: Boolean;
|
||
|
|
||
|
function Process(TermCh: Byte): TPicResult;
|
||
|
var
|
||
|
Rslt: TPicResult;
|
||
|
Incomp: Boolean;
|
||
|
OldI, OldJ, IncompJ, IncompI: Byte;
|
||
|
|
||
|
{ Consume input }
|
||
|
|
||
|
procedure Consume(Ch: Char);
|
||
|
begin
|
||
|
Input[J] := Ch;
|
||
|
Inc(J);
|
||
|
Inc(I);
|
||
|
end;
|
||
|
|
||
|
{ Skip a character or a picture group }
|
||
|
|
||
|
procedure ToGroupEnd(var I: Byte);
|
||
|
var
|
||
|
BrkLevel, BrcLevel: Integer;
|
||
|
begin
|
||
|
BrkLevel := 0;
|
||
|
BrcLevel := 0;
|
||
|
repeat
|
||
|
if I = TermCh then Exit;
|
||
|
case Pic^[I] of
|
||
|
'[': Inc(BrkLevel);
|
||
|
']': Dec(BrkLevel);
|
||
|
'{': Inc(BrcLevel);
|
||
|
'}': Dec(BrcLevel);
|
||
|
';': Inc(I);
|
||
|
'*':
|
||
|
begin
|
||
|
Inc(I);
|
||
|
while IsNumber(Pic^[I]) do Inc(I);
|
||
|
ToGroupEnd(I);
|
||
|
Continue;
|
||
|
end;
|
||
|
end;
|
||
|
Inc(I);
|
||
|
until (BrkLevel = 0) and (BrcLevel = 0);
|
||
|
end;
|
||
|
|
||
|
{ Find the a comma separator }
|
||
|
|
||
|
function SkipToComma: Boolean;
|
||
|
begin
|
||
|
repeat ToGroupEnd(I) until (I = TermCh) or (Pic^[I] = ',');
|
||
|
if Pic^[I] = ',' then Inc(I);
|
||
|
SkipToComma := I < TermCh;
|
||
|
end;
|
||
|
|
||
|
{ Calclate the end of a group }
|
||
|
|
||
|
function CalcTerm: Byte;
|
||
|
var
|
||
|
K: Byte;
|
||
|
begin
|
||
|
K := I;
|
||
|
ToGroupEnd(K);
|
||
|
CalcTerm := K;
|
||
|
end;
|
||
|
|
||
|
{ The next group is repeated X times }
|
||
|
|
||
|
function Iteration: TPicResult;
|
||
|
var
|
||
|
Itr, K, L: Byte;
|
||
|
Rslt: TPicResult;
|
||
|
NewTermCh: Byte;
|
||
|
begin
|
||
|
Itr := 0;
|
||
|
Iteration := prError;
|
||
|
|
||
|
Inc(I); { Skip '*' }
|
||
|
|
||
|
{ Retrieve number }
|
||
|
|
||
|
while IsNumber(Pic^[I]) do
|
||
|
begin
|
||
|
Itr := Itr * 10 + Byte(Pic^[I]) - Byte('0');
|
||
|
Inc(I);
|
||
|
end;
|
||
|
|
||
|
if I > TermCh then
|
||
|
begin
|
||
|
Iteration := prSyntax;
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
K := I;
|
||
|
NewTermCh := CalcTerm;
|
||
|
|
||
|
{ If Itr is 0 allow any number, otherwise enforce the number }
|
||
|
if Itr <> 0 then
|
||
|
begin
|
||
|
for L := 1 to Itr do
|
||
|
begin
|
||
|
I := K;
|
||
|
Rslt := Process(NewTermCh);
|
||
|
if not IsComplete(Rslt) then
|
||
|
begin
|
||
|
{ Empty means incomplete since all are required }
|
||
|
if Rslt = prEmpty then Rslt := prIncomplete;
|
||
|
Iteration := Rslt;
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
begin
|
||
|
repeat
|
||
|
I := K;
|
||
|
Rslt := Process(NewTermCh);
|
||
|
until not IsComplete(Rslt);
|
||
|
if (Rslt = prEmpty) or (Rslt = prError) then
|
||
|
begin
|
||
|
Inc(I);
|
||
|
Rslt := prAmbiguous;
|
||
|
end;
|
||
|
end;
|
||
|
I := NewTermCh;
|
||
|
Iteration := Rslt;
|
||
|
end;
|
||
|
|
||
|
{ Process a picture group }
|
||
|
|
||
|
function Group: TPicResult;
|
||
|
var
|
||
|
Rslt: TPicResult;
|
||
|
TermCh: Byte;
|
||
|
begin
|
||
|
TermCh := CalcTerm;
|
||
|
Inc(I);
|
||
|
Rslt := Process(TermCh - 1);
|
||
|
if not IsIncomplete(Rslt) then I := TermCh;
|
||
|
Group := Rslt;
|
||
|
end;
|
||
|
|
||
|
function CheckComplete(Rslt: TPicResult): TPicResult;
|
||
|
var
|
||
|
J: Byte;
|
||
|
begin
|
||
|
J := I;
|
||
|
if IsIncomplete(Rslt) then
|
||
|
begin
|
||
|
{ Skip optional pieces }
|
||
|
while True do
|
||
|
case Pic^[J] of
|
||
|
'[': ToGroupEnd(J);
|
||
|
'*':
|
||
|
if not IsNumber(Pic^[J + 1]) then
|
||
|
begin
|
||
|
Inc(J);
|
||
|
ToGroupEnd(J);
|
||
|
end
|
||
|
else
|
||
|
Break;
|
||
|
else
|
||
|
Break;
|
||
|
end;
|
||
|
|
||
|
if J = TermCh then Rslt := prAmbiguous;
|
||
|
end;
|
||
|
CheckComplete := Rslt;
|
||
|
end;
|
||
|
|
||
|
function Scan: TPicResult;
|
||
|
var
|
||
|
Ch: Char;
|
||
|
Rslt: TPicResult;
|
||
|
begin
|
||
|
Scan := prError;
|
||
|
Rslt := prEmpty;
|
||
|
while (I <> TermCh) and (Pic^[I] <> ',') do
|
||
|
begin
|
||
|
if J > Length(Input) then
|
||
|
begin
|
||
|
Scan := CheckComplete(Rslt);
|
||
|
Exit;
|
||
|
end;
|
||
|
|
||
|
Ch := Input[J];
|
||
|
case Pic^[I] of
|
||
|
'#': if not IsNumber(Ch) then Exit
|
||
|
else Consume(Ch);
|
||
|
'?': if not IsLetter(Ch) then Exit
|
||
|
else Consume(Ch);
|
||
|
'&': if not IsLetter(Ch) then Exit
|
||
|
else Consume(UpCase(Ch));
|
||
|
'!': Consume(UpCase(Ch));
|
||
|
'@': Consume(Ch);
|
||
|
'*':
|
||
|
begin
|
||
|
Rslt := Iteration;
|
||
|
if not IsComplete(Rslt) then
|
||
|
begin
|
||
|
Scan := Rslt;
|
||
|
Exit;
|
||
|
end;
|
||
|
if Rslt = prError then Rslt := prAmbiguous;
|
||
|
end;
|
||
|
'{':
|
||
|
begin
|
||
|
Rslt := Group;
|
||
|
if not IsComplete(Rslt) then
|
||
|
begin
|
||
|
Scan := Rslt;
|
||
|
Exit;
|
||
|
end;
|
||
|
end;
|
||
|
'[':
|
||
|
begin
|
||
|
Rslt := Group;
|
||
|
if IsIncomplete(Rslt) then
|
||
|
begin
|
||
|
Scan := Rslt;
|
||
|
Exit;
|
||
|
end;
|
||
|
if Rslt = prError then Rslt := prAmbiguous;
|
||
|
end;
|
||
|
else
|
||
|
if Pic^[I] = ';' then Inc(I);
|
||
|
if UpCase(Pic^[I]) <> UpCase(Ch) then
|
||
|
if Ch = ' ' then Ch := Pic^[I]
|
||
|
else Exit;
|
||
|
Consume(Pic^[I]);
|
||
|
end;
|
||
|
|
||
|
if Rslt = prAmbiguous then
|
||
|
Rslt := prIncompNoFill
|
||
|
else
|
||
|
Rslt := prIncomplete;
|
||
|
end;
|
||
|
|
||
|
if Rslt = prIncompNoFill then
|
||
|
Scan := prAmbiguous
|
||
|
else
|
||
|
Scan := prComplete;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
Incomp := False;
|
||
|
OldI := I;
|
||
|
OldJ := J;
|
||
|
repeat
|
||
|
Rslt := Scan;
|
||
|
|
||
|
{ Only accept completes if they make it farther in the input
|
||
|
stream from the last incomplete }
|
||
|
if (Rslt in [prComplete, prAmbiguous]) and Incomp and (J < IncompJ) then
|
||
|
begin
|
||
|
Rslt := prIncomplete;
|
||
|
J := IncompJ;
|
||
|
end;
|
||
|
|
||
|
if (Rslt = prError) or (Rslt = prIncomplete) then
|
||
|
begin
|
||
|
Process := Rslt;
|
||
|
if not Incomp and (Rslt = prIncomplete) then
|
||
|
begin
|
||
|
Incomp := True;
|
||
|
IncompI := I;
|
||
|
IncompJ := J;
|
||
|
end;
|
||
|
I := OldI;
|
||
|
J := OldJ;
|
||
|
if not SkipToComma then
|
||
|
begin
|
||
|
if Incomp then
|
||
|
begin
|
||
|
Process := prIncomplete;
|
||
|
I := IncompI;
|
||
|
J := IncompJ;
|
||
|
end;
|
||
|
Exit;
|
||
|
end;
|
||
|
OldI := I;
|
||
|
end;
|
||
|
until (Rslt <> prError) and (Rslt <> prIncomplete);
|
||
|
|
||
|
if (Rslt = prComplete) and Incomp then
|
||
|
Process := prAmbiguous
|
||
|
else
|
||
|
Process := Rslt;
|
||
|
end;
|
||
|
|
||
|
function SyntaxCheck: Boolean;
|
||
|
var
|
||
|
I: Integer;
|
||
|
BrkLevel, BrcLevel: Integer;
|
||
|
begin
|
||
|
SyntaxCheck := False;
|
||
|
|
||
|
if Pic^ = '' then Exit;
|
||
|
|
||
|
if Pic^[Length(Pic^)] = ';' then Exit;
|
||
|
if (Pic^[Length(Pic^)] = '*') and (Pic^[Length(Pic^) - 1] <> ';') then
|
||
|
Exit;
|
||
|
|
||
|
I := 1;
|
||
|
BrkLevel := 0;
|
||
|
BrcLevel := 0;
|
||
|
while I <= Length(Pic^) do
|
||
|
begin
|
||
|
case Pic^[I] of
|
||
|
'[': Inc(BrkLevel);
|
||
|
']': Dec(BrkLevel);
|
||
|
'{': Inc(BrcLevel);
|
||
|
'}': Dec(BrcLevel);
|
||
|
';': Inc(I);
|
||
|
end;
|
||
|
Inc(I);
|
||
|
end;
|
||
|
if (BrkLevel <> 0) or (BrcLevel <> 0) then Exit;
|
||
|
|
||
|
SyntaxCheck := True;
|
||
|
end;
|
||
|
|
||
|
|
||
|
begin
|
||
|
Picture := prSyntax;
|
||
|
if not SyntaxCheck then Exit;
|
||
|
|
||
|
Picture := prEmpty;
|
||
|
if Input = '' then Exit;
|
||
|
|
||
|
J := 1;
|
||
|
I := 1;
|
||
|
|
||
|
Rslt := Process(Length(Pic^) + 1);
|
||
|
if (Rslt <> prError) and (Rslt <> prSyntax) and (J <= Length(Input)) then
|
||
|
Rslt := prError;
|
||
|
|
||
|
if (Rslt = prIncomplete) and AutoFill then
|
||
|
begin
|
||
|
Reprocess := False;
|
||
|
while (I <= Length(Pic^)) and
|
||
|
not IsSpecial(Pic^[I], '#?&!@*{}[],'#0) do
|
||
|
begin
|
||
|
if Pic^[I] = ';' then Inc(I);
|
||
|
Input := Input + Pic^[I];
|
||
|
Inc(I);
|
||
|
Reprocess := True;
|
||
|
end;
|
||
|
J := 1;
|
||
|
I := 1;
|
||
|
if Reprocess then
|
||
|
Rslt := Process(Length(Pic^) + 1)
|
||
|
end;
|
||
|
|
||
|
if Rslt = prAmbiguous then
|
||
|
Picture := prComplete
|
||
|
else if Rslt = prIncompNoFill then
|
||
|
Picture := prIncomplete
|
||
|
else
|
||
|
Picture := Rslt;
|
||
|
end;
|
||
|
|
||
|
procedure TPXPictureValidator.Store(var S: TStream);
|
||
|
begin
|
||
|
inherited Store(S);
|
||
|
S.WriteStr(Pic);
|
||
|
end;
|
||
|
|
||
|
{ TFilterValidator }
|
||
|
|
||
|
constructor TFilterValidator.Init(AValidChars: TCharSet);
|
||
|
begin
|
||
|
inherited Init;
|
||
|
ValidChars := AValidChars;
|
||
|
end;
|
||
|
|
||
|
constructor TFilterValidator.Load(var S: TStream);
|
||
|
begin
|
||
|
inherited Load(S);
|
||
|
S.Read(ValidChars, SizeOf(TCharSet));
|
||
|
end;
|
||
|
|
||
|
function TFilterValidator.IsValid(const S: string): Boolean;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
I := 1;
|
||
|
while S[I] in ValidChars do Inc(I);
|
||
|
IsValid := I > Length(S);
|
||
|
end;
|
||
|
|
||
|
function TFilterValidator.IsValidInput(var S: string; SuppressFill: Boolean): Boolean;
|
||
|
var
|
||
|
I: Integer;
|
||
|
begin
|
||
|
I := 1;
|
||
|
while S[I] in ValidChars do Inc(I);
|
||
|
IsValidInput := I > Length(S);
|
||
|
end;
|
||
|
|
||
|
procedure TFilterValidator.Store(var S: TStream);
|
||
|
begin
|
||
|
inherited Store(S);
|
||
|
S.Write(ValidChars, SizeOf(TCharSet));
|
||
|
end;
|
||
|
|
||
|
{$IFDEF Windows}
|
||
|
|
||
|
procedure TFilterValidator.Error;
|
||
|
begin
|
||
|
MessageBox(0, 'Invalid character in input', 'Validator', mb_IconExclamation or mb_Ok);
|
||
|
end;
|
||
|
|
||
|
{$ELSE}
|
||
|
|
||
|
procedure TFilterValidator.Error;
|
||
|
begin
|
||
|
MessageBox('Invalid character in input', nil, mfError + mfOKButton);
|
||
|
end;
|
||
|
|
||
|
{$ENDIF Windows}
|
||
|
|
||
|
{ TRangeValidator }
|
||
|
|
||
|
constructor TRangeValidator.Init(AMin, AMax: LongInt);
|
||
|
begin
|
||
|
inherited Init(['0'..'9','+','-']);
|
||
|
if AMin >= 0 then ValidChars := ValidChars - ['-'];
|
||
|
Min := AMin;
|
||
|
Max := AMax;
|
||
|
end;
|
||
|
|
||
|
constructor TRangeValidator.Load(var S: TStream);
|
||
|
begin
|
||
|
inherited Load(S);
|
||
|
S.Read(Min, SizeOf(Max) + SizeOf(Min));
|
||
|
end;
|
||
|
|
||
|
{$IFDEF Windows}
|
||
|
|
||
|
procedure TRangeValidator.Error;
|
||
|
var
|
||
|
Params: array[0..1] of Longint;
|
||
|
MsgStr: array[0..80] of Char;
|
||
|
begin
|
||
|
Params[0] := Min;
|
||
|
Params[1] := Max;
|
||
|
wvsprintf(MsgStr, 'Value is not in the range %ld to %ld.', Params);
|
||
|
MessageBox(0, MsgStr, 'Validator', mb_IconExclamation or mb_Ok);
|
||
|
end;
|
||
|
|
||
|
{$ELSE}
|
||
|
|
||
|
procedure TRangeValidator.Error;
|
||
|
var
|
||
|
Params: array[0..1] of Longint;
|
||
|
begin
|
||
|
Params[0] := Min;
|
||
|
Params[1] := Max;
|
||
|
MessageBox('Value not in the range %d to %d', @Params,
|
||
|
mfError + mfOKButton);
|
||
|
end;
|
||
|
|
||
|
{$ENDIF Windows}
|
||
|
|
||
|
function TRangeValidator.IsValid(const S: string): Boolean;
|
||
|
var
|
||
|
Value: LongInt;
|
||
|
Code: Integer;
|
||
|
begin
|
||
|
IsValid := False;
|
||
|
if inherited IsValid(S) then
|
||
|
begin
|
||
|
Val(S, Value, Code);
|
||
|
if (Code = 0) and (Value >= Min) and (Value <= Max) then
|
||
|
IsValid := True;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure TRangeValidator.Store(var S: TStream);
|
||
|
begin
|
||
|
inherited Store(S);
|
||
|
S.Write(Min, SizeOf(Max) + SizeOf(Min));
|
||
|
end;
|
||
|
|
||
|
function TRangeValidator.Transfer(var S: String; Buffer: Pointer;
|
||
|
Flag: TVTransfer): Word;
|
||
|
var
|
||
|
Value: LongInt;
|
||
|
Code: Integer;
|
||
|
begin
|
||
|
if Options and voTransfer <> 0 then
|
||
|
begin
|
||
|
Transfer := SizeOf(Value);
|
||
|
case Flag of
|
||
|
vtGetData:
|
||
|
begin
|
||
|
Val(S, Value, Code);
|
||
|
LongInt(Buffer^) := Value;
|
||
|
end;
|
||
|
vtSetData:
|
||
|
Str(LongInt(Buffer^), S);
|
||
|
end;
|
||
|
end
|
||
|
else
|
||
|
Transfer := 0;
|
||
|
end;
|
||
|
|
||
|
{ TLookupValidator }
|
||
|
|
||
|
function TLookupValidator.IsValid(const S: string): Boolean;
|
||
|
begin
|
||
|
IsValid := Lookup(S);
|
||
|
end;
|
||
|
|
||
|
function TLookupValidator.Lookup(const S: string): Boolean;
|
||
|
begin
|
||
|
Lookup := True;
|
||
|
end;
|
||
|
|
||
|
{ TStringLookupValidator }
|
||
|
|
||
|
constructor TStringLookupValidator.Init(AStrings: PStringCollection);
|
||
|
begin
|
||
|
inherited Init;
|
||
|
Strings := AStrings;
|
||
|
end;
|
||
|
|
||
|
constructor TStringLookupValidator.Load(var S: TStream);
|
||
|
begin
|
||
|
inherited Load(S);
|
||
|
Strings := PStringCollection(S.Get);
|
||
|
end;
|
||
|
|
||
|
destructor TStringLookupValidator.Done;
|
||
|
begin
|
||
|
NewStringList(nil);
|
||
|
inherited Done;
|
||
|
end;
|
||
|
|
||
|
{$IFDEF Windows}
|
||
|
|
||
|
procedure TStringLookupValidator.Error;
|
||
|
begin
|
||
|
MessageBox(0, 'Input not in valid-list', 'Validator',
|
||
|
mb_IconExclamation or mb_Ok);
|
||
|
end;
|
||
|
|
||
|
{$ELSE}
|
||
|
|
||
|
procedure TStringLookupValidator.Error;
|
||
|
begin
|
||
|
MessageBox('Input not in valid-list', nil, mfError + mfOKButton);
|
||
|
end;
|
||
|
|
||
|
{$ENDIF Windows}
|
||
|
|
||
|
function TStringLookupValidator.Lookup(const S: string): Boolean;
|
||
|
var
|
||
|
Index: Integer;
|
||
|
Str: PString;
|
||
|
begin
|
||
|
asm
|
||
|
LES DI,S
|
||
|
MOV Str.Word[0], DI
|
||
|
MOV Str.Word[2], ES
|
||
|
end;
|
||
|
Lookup := False;
|
||
|
if Strings <> nil then
|
||
|
Lookup := Strings^.Search(Str, Index);
|
||
|
end;
|
||
|
|
||
|
procedure TStringLookupValidator.NewStringList(AStrings: PStringCollection);
|
||
|
begin
|
||
|
if Strings <> nil then Dispose(Strings, Done);
|
||
|
Strings := AStrings;
|
||
|
end;
|
||
|
|
||
|
procedure TStringLookupValidator.Store(var S: TStream);
|
||
|
begin
|
||
|
inherited Store(S);
|
||
|
S.Put(Strings);
|
||
|
end;
|
||
|
|
||
|
{ Validate registration procedure }
|
||
|
|
||
|
procedure RegisterValidate;
|
||
|
begin
|
||
|
RegisterType(RPXPictureValidator);
|
||
|
RegisterType(RFilterValidator);
|
||
|
RegisterType(RRangeValidator);
|
||
|
RegisterType(RStringLookupValidator);
|
||
|
end;
|
||
|
|
||
|
end.
|