home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Pascal / TP.7_1 / TP / SOURCE / VALIDATE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-05  |  21.5 KB  |  964 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.       SubPic: String;
  438.       Itr, K, L, OldJ: Byte;
  439.       Rslt: TPicResult;
  440.       NewTermCh: Byte;
  441.     begin
  442.       Itr := 0;
  443.       Iteration := prError;
  444.  
  445.       Inc(I);  { Skip '*' }
  446.  
  447.       { Retrieve number }
  448.  
  449.       while IsNumber(Pic^[I]) do
  450.       begin
  451.         Itr := Itr * 10 + Byte(Pic^[I]) - Byte('0');
  452.         Inc(I);
  453.       end;
  454.  
  455.       if I > TermCh then
  456.       begin
  457.         Iteration := prSyntax;
  458.         Exit;
  459.       end;
  460.  
  461.       K := I;
  462.       NewTermCh := CalcTerm;
  463.  
  464.       { If Itr is 0 allow any number, otherwise enforce the number }
  465.       if Itr <> 0 then
  466.       begin
  467.         for L := 1 to Itr do
  468.         begin
  469.           I := K;
  470.           Rslt := Process(NewTermCh);
  471.           if not IsComplete(Rslt) then
  472.           begin
  473.             { Empty means incomplete since all are required }
  474.             if Rslt = prEmpty then Rslt := prIncomplete;
  475.             Iteration := Rslt;
  476.             Exit;
  477.           end;
  478.         end;
  479.       end
  480.       else
  481.       begin
  482.         repeat
  483.           I := K;
  484.           OldJ := J;
  485.           Rslt := Process(NewTermCh);
  486.         until not IsComplete(Rslt);
  487.         if (Rslt = prEmpty) or (Rslt = prError) then
  488.         begin
  489.           Inc(I);
  490.           Rslt := prAmbiguous;
  491.         end;
  492.       end;
  493.       I := NewTermCh;
  494.       Iteration := Rslt;
  495.     end;
  496.  
  497.     { Process a picture group }
  498.  
  499.     function Group: TPicResult;
  500.     var
  501.       Rslt: TPicResult;
  502.       TermCh: Byte;
  503.     begin
  504.       TermCh := CalcTerm;
  505.       Inc(I);
  506.       Rslt := Process(TermCh - 1);
  507.       if not IsIncomplete(Rslt) then I := TermCh;
  508.       Group := Rslt;
  509.     end;
  510.  
  511.     function CheckComplete(Rslt: TPicResult): TPicResult;
  512.     var
  513.       J: Byte;
  514.     begin
  515.       J := I;
  516.       if IsIncomplete(Rslt) then
  517.       begin
  518.         { Skip optional pieces }
  519.         while True do
  520.           case Pic^[J] of
  521.             '[': ToGroupEnd(J);
  522.             '*':
  523.               if not IsNumber(Pic^[J + 1]) then
  524.               begin
  525.                 Inc(J);
  526.                 ToGroupEnd(J);
  527.               end
  528.               else
  529.                 Break;
  530.           else
  531.             Break;
  532.           end;
  533.  
  534.         if J = TermCh then Rslt := prAmbiguous;
  535.       end;
  536.       CheckComplete := Rslt;
  537.     end;
  538.  
  539.     function Scan: TPicResult;
  540.     var
  541.       Ch: Char;
  542.       Rslt: TPicResult;
  543.     begin
  544.       Scan := prError;
  545.       Rslt := prEmpty;
  546.       while (I <> TermCh) and (Pic^[I] <> ',') do
  547.       begin
  548.         if J > Length(Input) then
  549.         begin
  550.           Scan := CheckComplete(Rslt);
  551.           Exit;
  552.         end;
  553.  
  554.         Ch := Input[J];
  555.         case Pic^[I] of
  556.           '#': if not IsNumber(Ch) then Exit
  557.                else Consume(Ch);
  558.           '?': if not IsLetter(Ch) then Exit
  559.                else Consume(Ch);
  560.           '&': if not IsLetter(Ch) then Exit
  561.                else Consume(UpCase(Ch));
  562.           '!': Consume(UpCase(Ch));
  563.           '@': Consume(Ch);
  564.           '*':
  565.             begin
  566.               Rslt := Iteration;
  567.               if not IsComplete(Rslt) then
  568.               begin
  569.                 Scan := Rslt;
  570.                 Exit;
  571.               end;
  572.               if Rslt = prError then Rslt := prAmbiguous;
  573.             end;
  574.           '{':
  575.             begin
  576.               Rslt := Group;
  577.               if not IsComplete(Rslt) then
  578.               begin
  579.                 Scan := Rslt;
  580.                 Exit;
  581.               end;
  582.             end;
  583.           '[':
  584.             begin
  585.               Rslt := Group;
  586.               if IsIncomplete(Rslt) then
  587.               begin
  588.                 Scan := Rslt;
  589.                 Exit;
  590.               end;
  591.               if Rslt = prError then Rslt := prAmbiguous;
  592.             end;
  593.         else
  594.           if Pic^[I] = ';' then Inc(I);
  595.           if UpCase(Pic^[I]) <> UpCase(Ch) then
  596.             if Ch = ' ' then Ch := Pic^[I]
  597.             else Exit;
  598.           Consume(Pic^[I]);
  599.         end;
  600.  
  601.         if Rslt = prAmbiguous then
  602.           Rslt := prIncompNoFill
  603.         else
  604.           Rslt := prIncomplete;
  605.       end;
  606.  
  607.       if Rslt = prIncompNoFill then
  608.         Scan := prAmbiguous
  609.       else
  610.         Scan := prComplete;
  611.     end;
  612.  
  613.   begin
  614.     Incomp := False;
  615.     OldI := I;
  616.     OldJ := J;
  617.     repeat
  618.       Rslt := Scan;
  619.  
  620.       { Only accept completes if they make it farther in the input
  621.         stream from the last incomplete }
  622.       if (Rslt in [prComplete, prAmbiguous]) and Incomp and (J < IncompJ) then
  623.       begin
  624.         Rslt := prIncomplete;
  625.         J := IncompJ;
  626.       end;
  627.  
  628.       if (Rslt = prError) or (Rslt = prIncomplete) then
  629.       begin
  630.         Process := Rslt;
  631.         if not Incomp and (Rslt = prIncomplete) then
  632.         begin
  633.           Incomp := True;
  634.           IncompI := I;
  635.           IncompJ := J;
  636.         end;
  637.         I := OldI;
  638.         J := OldJ;
  639.         if not SkipToComma then
  640.         begin
  641.           if Incomp then
  642.           begin
  643.             Process := prIncomplete;
  644.             I := IncompI;
  645.             J := IncompJ;
  646.           end;
  647.           Exit;
  648.         end;
  649.         OldI := I;
  650.       end;
  651.     until (Rslt <> prError) and (Rslt <> prIncomplete);
  652.  
  653.     if (Rslt = prComplete) and Incomp then
  654.       Process := prAmbiguous
  655.     else
  656.       Process := Rslt;
  657.   end;
  658.  
  659.   function SyntaxCheck: Boolean;
  660.   var
  661.     I: Integer;
  662.     BrkLevel, BrcLevel: Integer;
  663.   begin
  664.     SyntaxCheck := False;
  665.  
  666.     if Pic^ = '' then Exit;
  667.  
  668.     if Pic^[Length(Pic^)] = ';' then Exit;
  669.     if (Pic^[Length(Pic^)] = '*') and (Pic^[Length(Pic^) - 1] <> ';') then
  670.       Exit;
  671.  
  672.     I := 1;
  673.     BrkLevel := 0;
  674.     BrcLevel := 0;
  675.     while I <= Length(Pic^) do
  676.     begin
  677.       case Pic^[I] of
  678.         '[': Inc(BrkLevel);
  679.         ']': Dec(BrkLevel);
  680.         '{': Inc(BrcLevel);
  681.         '}': Dec(BrcLevel);
  682.         ';': Inc(I);
  683.       end;
  684.       Inc(I);
  685.     end;
  686.     if (BrkLevel <> 0) or (BrcLevel <> 0) then Exit;
  687.  
  688.     SyntaxCheck := True;
  689.   end;
  690.  
  691.  
  692. begin
  693.   Picture := prSyntax;
  694.   if not SyntaxCheck then Exit;
  695.  
  696.   Picture := prEmpty;
  697.   if Input = '' then Exit;
  698.  
  699.   J := 1;
  700.   I := 1;
  701.  
  702.   Rslt := Process(Length(Pic^) + 1);
  703.   if (Rslt <> prError) and (Rslt <> prSyntax) and (J <= Length(Input)) then
  704.     Rslt := prError;
  705.  
  706.   if (Rslt = prIncomplete) and AutoFill then
  707.   begin
  708.     Reprocess := False;
  709.     while (I <= Length(Pic^)) and
  710.       not IsSpecial(Pic^[I], '#?&!@*{}[],'#0) do
  711.     begin
  712.       if Pic^[I] = ';' then Inc(I);
  713.       Input := Input + Pic^[I];
  714.       Inc(I);
  715.       Reprocess := True;
  716.     end;
  717.     J := 1;
  718.     I := 1;
  719.     if Reprocess then
  720.       Rslt := Process(Length(Pic^) + 1)
  721.   end;
  722.  
  723.   if Rslt = prAmbiguous then
  724.     Picture := prComplete
  725.   else if Rslt = prIncompNoFill then
  726.     Picture := prIncomplete
  727.   else
  728.     Picture := Rslt;
  729. end;
  730.  
  731. procedure TPXPictureValidator.Store(var S: TStream);
  732. begin
  733.   inherited Store(S);
  734.   S.WriteStr(Pic);
  735. end;
  736.  
  737. { TFilterValidator }
  738.  
  739. constructor TFilterValidator.Init(AValidChars: TCharSet);
  740. begin
  741.   inherited Init;
  742.   ValidChars := AValidChars;
  743. end;
  744.  
  745. constructor TFilterValidator.Load(var S: TStream);
  746. begin
  747.   inherited Load(S);
  748.   S.Read(ValidChars, SizeOf(TCharSet));
  749. end;
  750.  
  751. function TFilterValidator.IsValid(const S: string): Boolean;
  752. var
  753.   I: Integer;
  754. begin
  755.   I := 1;
  756.   while S[I] in ValidChars do Inc(I);
  757.   IsValid := I > Length(S);
  758. end;
  759.  
  760. function TFilterValidator.IsValidInput(var S: string; SuppressFill: Boolean): Boolean;
  761. var
  762.   I: Integer;
  763. begin
  764.   I := 1;
  765.   while S[I] in ValidChars do Inc(I);
  766.   IsValidInput := I > Length(S);
  767. end;
  768.  
  769. procedure TFilterValidator.Store(var S: TStream);
  770. begin
  771.   inherited Store(S);
  772.   S.Write(ValidChars, SizeOf(TCharSet));
  773. end;
  774.  
  775. {$IFDEF Windows}
  776.  
  777. procedure TFilterValidator.Error;
  778. begin
  779.   MessageBox(0, 'Invalid character in input', 'Validator', mb_IconExclamation or mb_Ok);
  780. end;
  781.  
  782. {$ELSE}
  783.  
  784. procedure TFilterValidator.Error;
  785. begin
  786.   MessageBox('Invalid character in input', nil, mfError + mfOKButton);
  787. end;
  788.  
  789. {$ENDIF Windows}
  790.  
  791. { TRangeValidator }
  792.  
  793. constructor TRangeValidator.Init(AMin, AMax: LongInt);
  794. begin
  795.   inherited Init(['0'..'9','+','-']);
  796.   if AMin >= 0 then ValidChars := ValidChars - ['-'];
  797.   Min := AMin;
  798.   Max := AMax;
  799. end;
  800.  
  801. constructor TRangeValidator.Load(var S: TStream);
  802. begin
  803.   inherited Load(S);
  804.   S.Read(Min, SizeOf(Max) + SizeOf(Min));
  805. end;
  806.  
  807. {$IFDEF Windows}
  808.  
  809. procedure TRangeValidator.Error;
  810. var
  811.   Params: array[0..1] of Longint;
  812.   MsgStr: array[0..80] of Char;
  813. begin
  814.   Params[0] := Min;
  815.   Params[1] := Max;
  816.   wvsprintf(MsgStr, 'Value is not in the range %ld to %ld.', Params);
  817.   MessageBox(0, MsgStr, 'Validator', mb_IconExclamation or mb_Ok);
  818. end;
  819.  
  820. {$ELSE}
  821.  
  822. procedure TRangeValidator.Error;
  823. var
  824.   Params: array[0..1] of Longint;
  825. begin
  826.   Params[0] := Min;
  827.   Params[1] := Max;
  828.   MessageBox('Value not in the range %d to %d', @Params,
  829.     mfError + mfOKButton);
  830. end;
  831.  
  832. {$ENDIF Windows}
  833.  
  834. function TRangeValidator.IsValid(const S: string): Boolean;
  835. var
  836.   Value: LongInt;
  837.   Code: Integer;
  838. begin
  839.   IsValid := False;
  840.   if inherited IsValid(S) then
  841.   begin
  842.     Val(S, Value, Code);
  843.     if (Code = 0) and (Value >= Min) and (Value <= Max) then
  844.       IsValid := True;
  845.   end;
  846. end;
  847.  
  848. procedure TRangeValidator.Store(var S: TStream);
  849. begin
  850.   inherited Store(S);
  851.   S.Write(Min, SizeOf(Max) + SizeOf(Min));
  852. end;
  853.  
  854. function TRangeValidator.Transfer(var S: String; Buffer: Pointer;
  855.   Flag: TVTransfer): Word;
  856. var
  857.   Value: LongInt;
  858.   Code: Integer;
  859. begin
  860.   if Options and voTransfer <> 0 then
  861.   begin
  862.     Transfer := SizeOf(Value);
  863.     case Flag of
  864.      vtGetData:
  865.        begin
  866.          Val(S, Value, Code);
  867.          LongInt(Buffer^) := Value;
  868.        end;
  869.      vtSetData:
  870.        Str(LongInt(Buffer^), S);
  871.     end;
  872.   end
  873.   else
  874.     Transfer := 0;
  875. end;
  876.  
  877. { TLookupValidator }
  878.  
  879. function TLookupValidator.IsValid(const S: string): Boolean;
  880. begin
  881.   IsValid := Lookup(S);
  882. end;
  883.  
  884. function TLookupValidator.Lookup(const S: string): Boolean;
  885. begin
  886.   Lookup := True;
  887. end;
  888.  
  889. { TStringLookupValidator }
  890.  
  891. constructor TStringLookupValidator.Init(AStrings: PStringCollection);
  892. begin
  893.   inherited Init;
  894.   Strings := AStrings;
  895. end;
  896.  
  897. constructor TStringLookupValidator.Load(var S: TStream);
  898. begin
  899.   inherited Load(S);
  900.   Strings := PStringCollection(S.Get);
  901. end;
  902.  
  903. destructor TStringLookupValidator.Done;
  904. begin
  905.   NewStringList(nil);
  906.   inherited Done;
  907. end;
  908.  
  909. {$IFDEF Windows}
  910.  
  911. procedure TStringLookupValidator.Error;
  912. begin
  913.   MessageBox(0, 'Input not in valid-list', 'Validator',
  914.     mb_IconExclamation or mb_Ok);
  915. end;
  916.  
  917. {$ELSE}
  918.  
  919. procedure TStringLookupValidator.Error;
  920. begin
  921.   MessageBox('Input not in valid-list', nil, mfError + mfOKButton);
  922. end;
  923.  
  924. {$ENDIF Windows}
  925.  
  926. function TStringLookupValidator.Lookup(const S: string): Boolean;
  927. var
  928.   Index: Integer;
  929.   Str: PString;
  930. begin
  931.   asm
  932.         LES     DI,S
  933.         MOV     Str.Word[0], DI
  934.         MOV     Str.Word[2], ES
  935.   end;
  936.   Lookup := False;
  937.   if Strings <> nil then
  938.     Lookup := Strings^.Search(Str, Index);
  939. end;
  940.  
  941. procedure TStringLookupValidator.NewStringList(AStrings: PStringCollection);
  942. begin
  943.   if Strings <> nil then Dispose(Strings, Done);
  944.   Strings := AStrings;
  945. end;
  946.  
  947. procedure TStringLookupValidator.Store(var S: TStream);
  948. begin
  949.   inherited Store(S);
  950.   S.Put(Strings);
  951. end;
  952.  
  953. { Validate registration procedure }
  954.  
  955. procedure RegisterValidate;
  956. begin
  957.   RegisterType(RPXPictureValidator);
  958.   RegisterType(RFilterValidator);
  959.   RegisterType(RRangeValidator);
  960.   RegisterType(RStringLookupValidator);
  961. end;
  962.  
  963. end.
  964.