home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vp21beta.zip / ARTLSRC.RAR / VALIDATE.PAS < prev    next >
Pascal/Delphi Source File  |  2000-08-15  |  22KB  |  961 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Turbo Pascal Version 7.0                        }
  5. {       Turbo Vision Unit                               }
  6. {                                                       }
  7. {       Copyright (c) 1992 Borland International        }
  8. {                                                       }
  9. {       Virtual Pascal v2.1                             }
  10. {       Copyright (C) 1996-2000 vpascal.com             }
  11. {                                                       }
  12. {*******************************************************}
  13.  
  14. unit Validate;
  15.  
  16. {$X+,I-,S-,Cdecl-,Use32+}
  17.  
  18. interface
  19.  
  20. uses Objects;
  21.  
  22. const
  23.  
  24. { TValidator Status constants }
  25.  
  26.   vsOk     =  0;
  27.   vsSyntax =  1;      { Error in the syntax of either a TPXPictureValidator
  28.                         or a TDBPictureValidator }
  29.  
  30.   { Validator option flags }
  31.   voFill     =  $0001;
  32.   voTransfer =  $0002;
  33.   voOnAppend =  $0004;
  34.   voReserved =  $00F8;
  35.  
  36. { TVTransfer constants }
  37.  
  38. type
  39.   TVTransfer = (vtDataSize, vtSetData, vtGetData);
  40.  
  41. { Abstract TValidator object }
  42.  
  43.   PValidator = ^TValidator;
  44.   TValidator = object(TObject)
  45.     Status: Word;
  46.     Options: Word;
  47.     constructor Init;
  48.     constructor Load(var S: TStream);
  49.     procedure Error; virtual;
  50.     function IsValidInput(var S: string;
  51.       SuppressFill: Boolean): Boolean; virtual;
  52.     function IsValid(const S: string): Boolean; virtual;
  53.     procedure Store(var S: TStream);
  54.     function Transfer(var S: String; Buffer: Pointer;
  55.       Flag: TVTransfer): Word; virtual;
  56.     function Valid(const S: string): Boolean;
  57.   end;
  58.  
  59. { TPXPictureValidator result type }
  60.  
  61.   TPicResult = (prComplete, prIncomplete, prEmpty, prError, prSyntax,
  62.     prAmbiguous, prIncompNoFill);
  63.  
  64. { TPXPictureValidator }
  65.  
  66.   PPXPictureValidator = ^TPXPictureValidator;
  67.   TPXPictureValidator = object(TValidator)
  68.     Pic: PString;
  69.     constructor Init(const APic: string; AutoFill: Boolean);
  70.     constructor Load(var S: TStream);
  71.     destructor Done; virtual;
  72.     procedure Error; virtual;
  73.     function IsValidInput(var S: string;
  74.       SuppressFill: Boolean): Boolean; virtual;
  75.     function IsValid(const S: string): Boolean; virtual;
  76.     function Picture(var Input: string;
  77.       AutoFill: Boolean): TPicResult; virtual;
  78.     procedure Store(var S: TStream);
  79.   end;
  80.  
  81. { TFilterValidator }
  82.  
  83.   PFilterValidator = ^TFilterValidator;
  84.   TFilterValidator = object(TValidator)
  85.     ValidChars: TCharSet;
  86.     constructor Init(AValidChars: TCharSet);
  87.     constructor Load(var S: TStream);
  88.     procedure Error; virtual;
  89.     function IsValid(const S: string): Boolean; virtual;
  90.     function IsValidInput(var S: string;
  91.       SuppressFill: Boolean): Boolean; virtual;
  92.     procedure Store(var S: TStream);
  93.   end;
  94.  
  95. { TRangeValidator }
  96.  
  97.   PRangeValidator = ^TRangeValidator;
  98.   TRangeValidator = object(TFilterValidator)
  99.     Min, Max: LongInt;
  100.     constructor Init(AMin, AMax: LongInt);
  101.     constructor Load(var S: TStream);
  102.     procedure Error; virtual;
  103.     function IsValid(const S: string): Boolean; virtual;
  104.     procedure Store(var S: TStream);
  105.     function Transfer(var S: String; Buffer: Pointer;
  106.       Flag: TVTransfer): Word; virtual;
  107.   end;
  108.  
  109. { TLookupValidator }
  110.  
  111.   PLookupValidator = ^TLookupValidator;
  112.   TLookupValidator = object(TValidator)
  113.     function IsValid(const S: string): Boolean; virtual;
  114.     function Lookup(const S: string): Boolean; virtual;
  115.   end;
  116.  
  117. { TStringLookupValidator }
  118.  
  119.   PStringLookupValidator = ^TStringLookupValidator;
  120.   TStringLookupValidator = object(TLookupValidator)
  121.     Strings: PStringCollection;
  122.     constructor Init(AStrings: PStringCollection);
  123.     constructor Load(var S: TStream);
  124.     destructor Done; virtual;
  125.     procedure Error; virtual;
  126.     function Lookup(const S: string): Boolean; virtual;
  127.     procedure NewStringList(AStrings: PStringCollection);
  128.     procedure Store(var S: TStream);
  129.   end;
  130.  
  131. { Validate registration procedure }
  132.  
  133. procedure RegisterValidate;
  134.  
  135. { Stream registration records }
  136.  
  137. const
  138.   RPXPictureValidator: TStreamRec = (
  139.     ObjType: 80;
  140.     VmtLink: Ofs(TypeOf(TPXPictureValidator)^);
  141.     Load: @TPXPictureValidator.Load;
  142.     Store: @TPXPictureValidator.Store
  143.   );
  144.  
  145. const
  146.   RFilterValidator: TStreamRec = (
  147.     ObjType: 81;
  148.     VmtLink: Ofs(TypeOf(TFilterValidator)^);
  149.     Load: @TFilterValidator.Load;
  150.     Store: @TFilterValidator.Store
  151.   );
  152.  
  153. const
  154.   RRangeValidator: TStreamRec = (
  155.     ObjType: 82;
  156.     VmtLink: Ofs(TypeOf(TRangeValidator)^);
  157.     Load: @TRangeValidator.Load;
  158.     Store: @TRangeValidator.Store
  159.   );
  160.  
  161. const
  162.   RStringLookupValidator: TStreamRec = (
  163.     ObjType: 83;
  164.     VmtLink: Ofs(TypeOf(TStringLookupValidator)^);
  165.     Load: @TStringLookupValidator.Load;
  166.     Store: @TStringLookupValidator.Store
  167.   );
  168.  
  169. implementation
  170.  
  171. uses
  172. {$IFDEF OWL}
  173.   WinTypes, WinProcs, Strings;
  174. {$ELSE}
  175.   MsgBox;
  176. {$ENDIF}
  177.  
  178. { TValidator }
  179.  
  180. constructor TValidator.Init;
  181. begin
  182.   inherited Init;
  183.   Status := 0;
  184.   Options := 0;
  185. end;
  186.  
  187. constructor TValidator.Load(var S:TStream);
  188. begin
  189.   inherited Init;
  190.   Status := 0;
  191.   S.Read(Options, SizeOf(Options));
  192. end;
  193.  
  194. procedure TValidator.Error;
  195. begin
  196. end;
  197.  
  198. function TValidator.IsValidInput(var S: string; SuppressFill: Boolean):
  199.   Boolean;
  200. begin
  201.   IsValidInput := True;
  202. end;
  203.  
  204. function TValidator.IsValid(const S: string): Boolean;
  205. begin
  206.   IsValid := True;
  207. end;
  208.  
  209. procedure TValidator.Store(var S: TStream);
  210. begin
  211.   S.Write(Options, SizeOf(Options));
  212. end;
  213.  
  214. function TValidator.Transfer(var S: String; Buffer: Pointer;
  215.   Flag: TVTransfer): Word;
  216. begin
  217.   Transfer := 0;
  218. end;
  219.  
  220. function TValidator.Valid(const S: string): Boolean;
  221. begin
  222.   Valid := False;
  223.   if not IsValid(S) then
  224.   begin
  225.     Error;
  226.     Exit;
  227.   end;
  228.   Valid := True;
  229. end;
  230.  
  231. { TPXPictureValidator }
  232.  
  233. constructor TPXPictureValidator.Init(const APic: string;
  234.   AutoFill: Boolean);
  235. var
  236.   S: String;
  237. begin
  238.   inherited Init;
  239.   Pic := NewStr(APic);
  240.   Options := voOnAppend;
  241.   if AutoFill then Options := Options or voFill;
  242.   S := '';
  243.   if Picture(S, False) <> prEmpty then
  244.     Status := vsSyntax;
  245. end;
  246.  
  247. constructor TPXPictureValidator.Load(var S: TStream);
  248. begin
  249.   inherited Load(S);
  250.   Pic := S.ReadStr;
  251. end;
  252.  
  253. destructor TPXPictureValidator.Done;
  254. begin
  255.   DisposeStr(Pic);
  256.   inherited Done;
  257. end;
  258.  
  259. {$IFDEF OWL}
  260.  
  261. procedure TPXPictureValidator.Error;
  262. var
  263.   MsgStr: array[0..255] of Char;
  264. begin
  265.   StrPCopy(StrECopy(MsgStr,
  266.     'Input does not conform to picture:'#10'    '), Pic^);
  267.   MessageBox(0, MsgStr, 'Validator', mb_IconExclamation or mb_Ok);
  268. end;
  269.  
  270. {$ELSE}
  271.  
  272. procedure TPXPictureValidator.Error;
  273. begin
  274.   MessageBox('Input does not conform to picture:'#13' %s', @Pic,
  275.     mfError + mfOKButton);
  276. end;
  277.  
  278. {$ENDIF}
  279.  
  280. function TPXPictureValidator.IsValidInput(var S: string;
  281.   SuppressFill: Boolean): Boolean;
  282. begin
  283.   IsValidInput := (Pic = nil) or
  284.      (Picture(S, (Options and voFill <> 0)  and not SuppressFill) <> prError);
  285. end;
  286.  
  287. function TPXPictureValidator.IsValid(const S: string): Boolean;
  288. var
  289.   Str: String;
  290.   Rslt: TPicResult;
  291. begin
  292.   Str := S;
  293.   Rslt := Picture(Str, False);
  294.   IsValid := (Pic = nil) or (Rslt = prComplete) or (Rslt = prEmpty);
  295. end;
  296.  
  297. function IsNumber(Chr: Char): Boolean; assembler; {$USES None} {$FRAME-}
  298. asm
  299.                 xor     al,al
  300.                 mov     ah,Chr
  301.                 cmp     ah,'0'
  302.                 jb      @@1
  303.                 cmp     ah,'9'
  304.                 setbe   al
  305.               @@1:
  306. end;
  307.  
  308. function IsLetter(Chr: Char): Boolean; assembler; {$USES None} {$FRAME-}
  309. asm
  310.                 xor     al,al
  311.                 mov     ah,Chr
  312.                 and     ah,0DFH                 { To upper }
  313.                 cmp     ah,'A'
  314.                 jb      @@1
  315.                 cmp     ah,'Z'
  316.                 setbe   al
  317.               @@1:
  318. end;
  319.  
  320. {$USES edi} {$FRAME-}
  321.  
  322. function IsSpecial(Chr: Char; const Special: String): Boolean; assembler;
  323. asm
  324.                 xor     ecx,ecx
  325.                 mov     edi,Special
  326.                 mov     cl,[edi]
  327.                 inc     edi
  328.                 mov     al,Chr
  329.                 cld
  330.                 repne   scasb
  331.                 sete    al
  332. end;
  333.  
  334. { This helper function will be used for a persistant TInputLine mask.
  335.   It will be moved to DIALOGS.PAS when needed. }
  336.  
  337. {$USES edi} {$FRAME-}
  338.  
  339. function NumChar(Chr: Char; const S: String): Byte; assembler;
  340. asm
  341.                 xor     ecx,ecx
  342.                 xor     eax,eax
  343.                 mov     edi,S
  344.                 mov     cl,[edi]
  345.                 mov     al,Chr
  346.               @@1:
  347.                 repne   scasb
  348.                 jne     @@2
  349.                 inc     ah
  350.                 test    ecx,ecx
  351.                 jnz     @@1
  352.               @@2:
  353.                 mov     al,ah
  354. end;
  355.  
  356. function IsComplete(Rslt: TPicResult): Boolean;
  357. begin
  358.   IsComplete := Rslt in [prComplete, prAmbiguous];
  359. end;
  360.  
  361. function IsIncomplete(Rslt: TPicResult): Boolean;
  362. begin
  363.   IsIncomplete := Rslt in [prIncomplete, prIncompNoFill];
  364. end;
  365.  
  366. function TPXPictureValidator.Picture(var Input: string;
  367.   AutoFill: Boolean): TPicResult;
  368. var
  369.   I, J: Byte;
  370.   Rslt: TPicResult;
  371.   Reprocess: Boolean;
  372.  
  373.   function Process(TermCh: Byte): TPicResult;
  374.   var
  375.     Rslt: TPicResult;
  376.     Incomp: Boolean;
  377.     OldI, OldJ, IncompJ, IncompI: Byte;
  378.  
  379.     { Consume input }
  380.  
  381.     procedure Consume(Ch: Char);
  382.     begin
  383.       Input[J] := Ch;
  384.       Inc(J);
  385.       Inc(I);
  386.     end;
  387.  
  388.     { Skip a character or a picture group }
  389.  
  390.     procedure ToGroupEnd(var I: Byte);
  391.     var
  392.       BrkLevel, BrcLevel: Integer;
  393.     begin
  394.       BrkLevel := 0;
  395.       BrcLevel := 0;
  396.       repeat
  397.         if I = TermCh then Exit;
  398.         case Pic^[I] of
  399.           '[': Inc(BrkLevel);
  400.           ']': Dec(BrkLevel);
  401.           '{': Inc(BrcLevel);
  402.           '}': Dec(BrcLevel);
  403.           ';': Inc(I);
  404.           '*':
  405.             begin
  406.               Inc(I);
  407.               while IsNumber(Pic^[I]) do Inc(I);
  408.               ToGroupEnd(I);
  409.               Continue;
  410.             end;
  411.         end;
  412.         Inc(I);
  413.       until (BrkLevel = 0) and (BrcLevel = 0);
  414.     end;
  415.  
  416.     { Find the a comma separator }
  417.  
  418.     function SkipToComma: Boolean;
  419.     begin
  420.       repeat ToGroupEnd(I) until (I = TermCh) or (Pic^[I] = ',');
  421.       if (I < TermCh) and (Pic^[I] = ',') then Inc(I);
  422.       SkipToComma := I < TermCh;
  423.     end;
  424.  
  425.     { Calclate the end of a group }
  426.  
  427.     function CalcTerm: Byte;
  428.     var
  429.       K: Byte;
  430.     begin
  431.       K := I;
  432.       ToGroupEnd(K);
  433.       CalcTerm := K;
  434.     end;
  435.  
  436.     { The next group is repeated X times }
  437.  
  438.     function Iteration: TPicResult;
  439.     var
  440.       Itr, K, L: Byte;
  441.       Rslt: TPicResult;
  442.       NewTermCh: Byte;
  443.     begin
  444.       Itr := 0;
  445.       Iteration := prError;
  446.  
  447.       Inc(I);  { Skip '*' }
  448.  
  449.       { Retrieve number }
  450.  
  451.       while IsNumber(Pic^[I]) do
  452.       begin
  453.         Itr := Itr * 10 + Byte(Pic^[I]) - Byte('0');
  454.         Inc(I);
  455.       end;
  456.  
  457.       if I > TermCh then
  458.       begin
  459.         Iteration := prSyntax;
  460.         Exit;
  461.       end;
  462.  
  463.       K := I;
  464.       NewTermCh := CalcTerm;
  465.  
  466.       { If Itr is 0 allow any number, otherwise enforce the number }
  467.       if Itr <> 0 then
  468.       begin
  469.         for L := 1 to Itr do
  470.         begin
  471.           I := K;
  472.           Rslt := Process(NewTermCh);
  473.           if not IsComplete(Rslt) then
  474.           begin
  475.             { Empty means incomplete since all are required }
  476.             if Rslt = prEmpty then Rslt := prIncomplete;
  477.             Iteration := Rslt;
  478.             Exit;
  479.           end;
  480.         end;
  481.       end
  482.       else
  483.       begin
  484.         repeat
  485.           I := K;
  486.           Rslt := Process(NewTermCh);
  487.         until not IsComplete(Rslt);
  488.         if (Rslt = prEmpty) or (Rslt = prError) then
  489.         begin
  490.           Inc(I);
  491.           Rslt := prAmbiguous;
  492.         end;
  493.       end;
  494.       I := NewTermCh;
  495.       Iteration := Rslt;
  496.     end;
  497.  
  498.     { Process a picture group }
  499.  
  500.     function Group: TPicResult;
  501.     var
  502.       Rslt: TPicResult;
  503.       TermCh: Byte;
  504.     begin
  505.       TermCh := CalcTerm;
  506.       Inc(I);
  507.       Rslt := Process(TermCh - 1);
  508.       if not IsIncomplete(Rslt) then I := TermCh;
  509.       Group := Rslt;
  510.     end;
  511.  
  512.     function CheckComplete(Rslt: TPicResult): TPicResult;
  513.     var
  514.       J: Byte;
  515.     begin
  516.       J := I;
  517.       if IsIncomplete(Rslt) then
  518.       begin
  519.         { Skip optional pieces }
  520.         while True do
  521.           case Pic^[J] of
  522.             '[': ToGroupEnd(J);
  523.             '*':
  524.               if not IsNumber(Pic^[J + 1]) then
  525.               begin
  526.                 Inc(J);
  527.                 ToGroupEnd(J);
  528.               end
  529.               else
  530.                 Break;
  531.           else
  532.             Break;
  533.           end;
  534.  
  535.         if J = TermCh then Rslt := prAmbiguous;
  536.       end;
  537.       CheckComplete := Rslt;
  538.     end;
  539.  
  540.     function Scan: TPicResult;
  541.     var
  542.       Ch: Char;
  543.       Rslt: TPicResult;
  544.     begin
  545.       Scan := prError;
  546.       Rslt := prEmpty;
  547.       while (I <> TermCh) and (Pic^[I] <> ',') do
  548.       begin
  549.         if J > Length(Input) then
  550.         begin
  551.           Scan := CheckComplete(Rslt);
  552.           Exit;
  553.         end;
  554.  
  555.         Ch := Input[J];
  556.         case Pic^[I] of
  557.           '#': if not IsNumber(Ch) then Exit
  558.                else Consume(Ch);
  559.           '?': if not IsLetter(Ch) then Exit
  560.                else Consume(Ch);
  561.           '&': if not IsLetter(Ch) then Exit
  562.                else Consume(UpCase(Ch));
  563.           '!': Consume(UpCase(Ch));
  564.           '@': Consume(Ch);
  565.           '*':
  566.             begin
  567.               Rslt := Iteration;
  568.               if not IsComplete(Rslt) then
  569.               begin
  570.                 Scan := Rslt;
  571.                 Exit;
  572.               end;
  573.               if Rslt = prError then Rslt := prAmbiguous;
  574.             end;
  575.           '{':
  576.             begin
  577.               Rslt := Group;
  578.               if not IsComplete(Rslt) then
  579.               begin
  580.                 Scan := Rslt;
  581.                 Exit;
  582.               end;
  583.             end;
  584.           '[':
  585.             begin
  586.               Rslt := Group;
  587.               if IsIncomplete(Rslt) then
  588.               begin
  589.                 Scan := Rslt;
  590.                 Exit;
  591.               end;
  592.               if Rslt = prError then Rslt := prAmbiguous;
  593.             end;
  594.         else
  595.           if Pic^[I] = ';' then Inc(I);
  596.           if UpCase(Pic^[I]) <> UpCase(Ch) then
  597.             if Ch = ' ' then Ch := Pic^[I]
  598.             else Exit;
  599.           Consume(Pic^[I]);
  600.         end;
  601.  
  602.         if Rslt = prAmbiguous then
  603.           Rslt := prIncompNoFill
  604.         else
  605.           Rslt := prIncomplete;
  606.       end;
  607.  
  608.       if Rslt = prIncompNoFill then
  609.         Scan := prAmbiguous
  610.       else
  611.         Scan := prComplete;
  612.     end;
  613.  
  614.   begin
  615.     Incomp := False;
  616.     OldI := I;
  617.     OldJ := J;
  618.     repeat
  619.       Rslt := Scan;
  620.  
  621.       { Only accept completes if they make it farther in the input
  622.         stream from the last incomplete }
  623.       if (Rslt in [prComplete, prAmbiguous]) and Incomp and (J < IncompJ) then
  624.       begin
  625.         Rslt := prIncomplete;
  626.         J := IncompJ;
  627.       end;
  628.  
  629.       if (Rslt = prError) or (Rslt = prIncomplete) then
  630.       begin
  631.         Process := Rslt;
  632.         if not Incomp and (Rslt = prIncomplete) then
  633.         begin
  634.           Incomp := True;
  635.           IncompI := I;
  636.           IncompJ := J;
  637.         end;
  638.         I := OldI;
  639.         J := OldJ;
  640.         if not SkipToComma then
  641.         begin
  642.           if Incomp then
  643.           begin
  644.             Process := prIncomplete;
  645.             I := IncompI;
  646.             J := IncompJ;
  647.           end;
  648.           Exit;
  649.         end;
  650.         OldI := I;
  651.       end;
  652.     until (Rslt <> prError) and (Rslt <> prIncomplete);
  653.  
  654.     if (Rslt = prComplete) and Incomp then
  655.       Process := prAmbiguous
  656.     else
  657.       Process := Rslt;
  658.   end;
  659.  
  660.   function SyntaxCheck: Boolean;
  661.   var
  662.     I: Integer;
  663.     BrkLevel, BrcLevel: Integer;
  664.   begin
  665.     SyntaxCheck := False;
  666.  
  667.     if Pic^ = '' then Exit;
  668.  
  669.     if Pic^[Length(Pic^)] = ';' then Exit;
  670.     if (Pic^[Length(Pic^)] = '*') and (Pic^[Length(Pic^) - 1] <> ';') then
  671.       Exit;
  672.  
  673.     I := 1;
  674.     BrkLevel := 0;
  675.     BrcLevel := 0;
  676.     while I <= Length(Pic^) do
  677.     begin
  678.       case Pic^[I] of
  679.         '[': Inc(BrkLevel);
  680.         ']': Dec(BrkLevel);
  681.         '{': Inc(BrcLevel);
  682.         '}': Dec(BrcLevel);
  683.         ';': Inc(I);
  684.       end;
  685.       Inc(I);
  686.     end;
  687.     if (BrkLevel <> 0) or (BrcLevel <> 0) then Exit;
  688.  
  689.     SyntaxCheck := True;
  690.   end;
  691.  
  692.  
  693. begin
  694.   Picture := prSyntax;
  695.   if not SyntaxCheck then Exit;
  696.  
  697.   Picture := prEmpty;
  698.   if Input = '' then Exit;
  699.  
  700.   J := 1;
  701.   I := 1;
  702.  
  703.   Rslt := Process(Length(Pic^) + 1);
  704.   if (Rslt <> prError) and (Rslt <> prSyntax) and (J <= Length(Input)) then
  705.     Rslt := prError;
  706.  
  707.   if (Rslt = prIncomplete) and AutoFill then
  708.   begin
  709.     Reprocess := False;
  710.     while (I <= Length(Pic^)) and
  711.       not IsSpecial(Pic^[I], '#?&!@*{}[],'#0) do
  712.     begin
  713.       if Pic^[I] = ';' then Inc(I);
  714.       Input := Input + Pic^[I];
  715.       Inc(I);
  716.       Reprocess := True;
  717.     end;
  718.     J := 1;
  719.     I := 1;
  720.     if Reprocess then
  721.       Rslt := Process(Length(Pic^) + 1)
  722.   end;
  723.  
  724.   if Rslt = prAmbiguous then
  725.     Picture := prComplete
  726.   else if Rslt = prIncompNoFill then
  727.     Picture := prIncomplete
  728.   else
  729.     Picture := Rslt;
  730. end;
  731.  
  732. procedure TPXPictureValidator.Store(var S: TStream);
  733. begin
  734.   inherited Store(S);
  735.   S.WriteStr(Pic);
  736. end;
  737.  
  738. { TFilterValidator }
  739.  
  740. constructor TFilterValidator.Init(AValidChars: TCharSet);
  741. begin
  742.   inherited Init;
  743.   ValidChars := AValidChars;
  744. end;
  745.  
  746. constructor TFilterValidator.Load(var S: TStream);
  747. begin
  748.   inherited Load(S);
  749.   S.Read(ValidChars, SizeOf(TCharSet));
  750. end;
  751.  
  752. function TFilterValidator.IsValid(const S: string): Boolean;
  753. var
  754.   I: Integer;
  755. begin
  756.   I := 1;
  757.   while S[I] in ValidChars do Inc(I);
  758.   IsValid := I > Length(S);
  759. end;
  760.  
  761. function TFilterValidator.IsValidInput(var S: string; SuppressFill: Boolean): Boolean;
  762. var
  763.   I: Integer;
  764. begin
  765.   I := 1;
  766.   while S[I] in ValidChars do Inc(I);
  767.   IsValidInput := I > Length(S);
  768. end;
  769.  
  770. procedure TFilterValidator.Store(var S: TStream);
  771. begin
  772.   inherited Store(S);
  773.   S.Write(ValidChars, SizeOf(TCharSet));
  774. end;
  775.  
  776. {$IFDEF OWL}
  777.  
  778. procedure TFilterValidator.Error;
  779. begin
  780.   MessageBox(0, 'Invalid character in input', 'Validator', mb_IconExclamation or mb_Ok);
  781. end;
  782.  
  783. {$ELSE}
  784.  
  785. procedure TFilterValidator.Error;
  786. begin
  787.   MessageBox('Invalid character in input', nil, mfError + mfOKButton);
  788. end;
  789.  
  790. {$ENDIF}
  791.  
  792. { TRangeValidator }
  793.  
  794. constructor TRangeValidator.Init(AMin, AMax: LongInt);
  795. begin
  796.   inherited Init(['0'..'9','+','-']);
  797.   if AMin >= 0 then ValidChars := ValidChars - ['-'];
  798.   Min := AMin;
  799.   Max := AMax;
  800. end;
  801.  
  802. constructor TRangeValidator.Load(var S: TStream);
  803. begin
  804.   inherited Load(S);
  805.   S.Read(Min, SizeOf(Max) + SizeOf(Min));
  806. end;
  807.  
  808. {$IFDEF OWL}
  809.  
  810. procedure TRangeValidator.Error;
  811. var
  812.   Params: array[0..1] of Longint;
  813.   MsgStr: array[0..80] of Char;
  814. begin
  815.   Params[0] := Min;
  816.   Params[1] := Max;
  817.   wvsprintf(MsgStr, 'Value is not in the range %ld to %ld.', Params);
  818.   MessageBox(0, MsgStr, 'Validator', mb_IconExclamation or mb_Ok);
  819. end;
  820.  
  821. {$ELSE}
  822.  
  823. procedure TRangeValidator.Error;
  824. var
  825.   Params: array[0..1] of Longint;
  826. begin
  827.   Params[0] := Min;
  828.   Params[1] := Max;
  829.   MessageBox('Value not in the range %d to %d', @Params,
  830.     mfError + mfOKButton);
  831. end;
  832.  
  833. {$ENDIF}
  834.  
  835. function TRangeValidator.IsValid(const S: string): Boolean;
  836. var
  837.   Value: LongInt;
  838.   Code: Integer;
  839. begin
  840.   IsValid := False;
  841.   if inherited IsValid(S) then
  842.   begin
  843.     Val(S, Value, Code);
  844.     if (Code = 0) and (Value >= Min) and (Value <= Max) then
  845.       IsValid := True;
  846.   end;
  847. end;
  848.  
  849. procedure TRangeValidator.Store(var S: TStream);
  850. begin
  851.   inherited Store(S);
  852.   S.Write(Min, SizeOf(Max) + SizeOf(Min));
  853. end;
  854.  
  855. function TRangeValidator.Transfer(var S: String; Buffer: Pointer;
  856.   Flag: TVTransfer): Word;
  857. var
  858.   Value: LongInt;
  859.   Code: Integer;
  860. begin
  861.   if Options and voTransfer <> 0 then
  862.   begin
  863.     Transfer := SizeOf(Value);
  864.     case Flag of
  865.      vtGetData:
  866.        begin
  867.          Val(S, Value, Code);
  868.          LongInt(Buffer^) := Value;
  869.        end;
  870.      vtSetData:
  871.        Str(LongInt(Buffer^), S);
  872.     end;
  873.   end
  874.   else
  875.     Transfer := 0;
  876. end;
  877.  
  878. { TLookupValidator }
  879.  
  880. function TLookupValidator.IsValid(const S: string): Boolean;
  881. begin
  882.   IsValid := Lookup(S);
  883. end;
  884.  
  885. function TLookupValidator.Lookup(const S: string): Boolean;
  886. begin
  887.   Lookup := True;
  888. end;
  889.  
  890. { TStringLookupValidator }
  891.  
  892. constructor TStringLookupValidator.Init(AStrings: PStringCollection);
  893. begin
  894.   inherited Init;
  895.   Strings := AStrings;
  896. end;
  897.  
  898. constructor TStringLookupValidator.Load(var S: TStream);
  899. begin
  900.   inherited Load(S);
  901.   Strings := PStringCollection(S.Get);
  902. end;
  903.  
  904. destructor TStringLookupValidator.Done;
  905. begin
  906.   NewStringList(nil);
  907.   inherited Done;
  908. end;
  909.  
  910. {$IFDEF OWL}
  911.  
  912. procedure TStringLookupValidator.Error;
  913. begin
  914.   MessageBox(0, 'Input not in valid-list', 'Validator',
  915.     mb_IconExclamation or mb_Ok);
  916. end;
  917.  
  918. {$ELSE}
  919.  
  920. procedure TStringLookupValidator.Error;
  921. begin
  922.   MessageBox('Input not in valid-list', nil, mfError + mfOKButton);
  923. end;
  924.  
  925. {$ENDIF}
  926.  
  927. function TStringLookupValidator.Lookup(const S: string): Boolean;
  928. var
  929.   Index: Integer;
  930.   Str: PString;
  931. begin
  932.   Str := @S;
  933.   Lookup := False;
  934.   if Strings <> nil then
  935.     Lookup := Strings^.Search(Str, Index);
  936. end;
  937.  
  938. procedure TStringLookupValidator.NewStringList(AStrings: PStringCollection);
  939. begin
  940.   if Strings <> nil then Dispose(Strings, Done);
  941.   Strings := AStrings;
  942. end;
  943.  
  944. procedure TStringLookupValidator.Store(var S: TStream);
  945. begin
  946.   inherited Store(S);
  947.   S.Put(Strings);
  948. end;
  949.  
  950. { Validate registration procedure }
  951.  
  952. procedure RegisterValidate;
  953. begin
  954.   RegisterType(RPXPictureValidator);
  955.   RegisterType(RFilterValidator);
  956.   RegisterType(RRangeValidator);
  957.   RegisterType(RStringLookupValidator);
  958. end;
  959.  
  960. end.
  961.