home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / T-Pascal.70 / SOURCE.ZIP / VALIDATE.PAS < prev    next >
Pascal/Delphi Source File  |  1992-10-30  |  22KB  |  962 lines

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