home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / pascal / shdk_1.zip / SHUTILPK.PAS < prev    next >
Pascal/Delphi Source File  |  1992-03-23  |  23KB  |  709 lines

  1. {$O+,A-}
  2. unit ShUtilPk;
  3. {
  4.                                 ShUtilPk
  5.  
  6.                              A Utility Unit
  7.  
  8.                                    by
  9.  
  10.                               Bill Madison
  11.  
  12.                    W. G. Madison and Associates, Ltd.
  13.                           13819 Shavano Downs
  14.                             P.O. Box 780956
  15.                        San Antonio, TX 78278-0956
  16.                              (512)492-2777
  17.                              CIS 73240,342
  18.  
  19.                   Copyright 1991 Madison & Associates
  20.                           All Rights Reserved
  21.  
  22.         This file may  be used and distributed  only in accord-
  23.         ance with the provisions described on the title page of
  24.                   the accompanying documentation file
  25.                               SKYHAWK.DOC
  26. }
  27.  
  28. Interface
  29.  
  30. Uses
  31.   TpCrt,
  32.   TpString,
  33.   TpDos,
  34.   Dos;
  35.  
  36. type
  37.   CharSet = set of char;
  38.  
  39. const
  40.   DelimSet  : CharSet = [#0..#32];
  41.  
  42. {*****************************************************************}
  43. { !!!!!!!!!!!!!!!!! NEVER MODIFY THESE VARIABLES !!!!!!!!!!!!!!!!!}
  44. {*****************************************************************}
  45. Var
  46.   StartingMode : Byte;
  47. {Initial video mode of the system (Mono, CO80, BW40, ...)}
  48.  
  49.   StartingAttr : Byte;
  50. {Initial video attribute of the system}
  51.  
  52. {*****************************************************************}
  53. {*****************************************************************}
  54.  
  55. function BetwS(Lower, Item, Upper  : LongInt) : boolean;
  56. {Performs a SIGNED test of the condition that Lower <= Item <= Upper,
  57.  returning TRUE if and only if the condition is met. Lower, Item, and
  58.  Upper can be any combination of 1, 2, and 4-byte entities.}
  59.  
  60. {**********************************************************************}
  61.  
  62. function BetwU(Lower, Item, Upper  : LongInt) : boolean;
  63. {Performs an UNSIGNED test of the condition that Lower <= Item <= Upper,
  64.  returning TRUE if and only if the condition is met. Lower, Item, and
  65.  Upper can be any combination of 1, 2, and 4-byte entities.}
  66.  
  67. {**********************************************************************}
  68.  
  69. Function StarString(Pattern, Target : String) : Boolean;
  70. {This function performs a generalization of the wildcard string
  71.  matching usually performed by DOS. A '*' wild card can be placed
  72.  anywhere within the pattern string, and will represent its usual
  73.  'zero or more of any characters'. Scanning will not be terminated
  74.  at that point, however, but will continue. Thus, '*B*EFG' will match
  75.  'ABCDEFG', but '*B*EGF' will not. Similarly, '*ABC*' will match, but
  76.  '*ABC' will not.}
  77.  
  78. {**********************************************************************}
  79.  
  80. Function WhoAmI : String;
  81. {Returns the fully qualified path to the currently executing file.
  82.  *** DOS 3.x or above, ONLY ***}
  83.  
  84. {**********************************************************************}
  85.  
  86. function SearchEnvironment(Code : String) : String;
  87. {Searches the environment space for "CODE" and returns the corresponding
  88.  string.}
  89.  
  90. {**********************************************************************}
  91.  
  92. Function LoWord(LI : LongInt) : Word;
  93. {Returns the low order word of a LongInt.}
  94.  
  95. {**********************************************************************}
  96.  
  97. Function HiWord(LI : LongInt) : Word;
  98. {Returns the high order word of a LongInt.}
  99.  
  100. {**********************************************************************}
  101.  
  102. Function LI(Ilo, Ihi : Word) : LongInt;
  103. {Converts two Word vbls to a LongInt}
  104.  
  105. {**********************************************************************}
  106.  
  107. Function HEX(A : LongInt) : String;
  108. {Converts a byte vbl into a string correspnoding to the hex value.}
  109. {NOTE: The parameter A may be of any Integer type (ShortInt, Byte,
  110.  Integer, Word, or LongInt}
  111. {HEX will return either a 2, 4, or 8 character string, depending on
  112.  whether the actual value of the parameter is representable as a
  113.                           1 byte value (ShortInt, Byte)
  114.                           2 byte value (Integer, Word)
  115.                           4 byte value (LongInt)
  116.  Note that a negative value will always be returned as an 8 character
  117.  string.}
  118.  
  119. {**********************************************************************}
  120.  
  121. Function Pmod(x, modulus : LongInt) : LongInt;
  122. {Returns the mod as a positive number, regardless of the sign of X.
  123.  Recall that, e.g., -1 is congruent to (modulus-1). Thus, for example,
  124.  Pmod(-2, 7) will return 5 as the function value.}
  125.  
  126. {**********************************************************************}
  127.  
  128.   Procedure RepAll(S1, FS, SS : string; var S2 : string);
  129.   {In string S1 replace all occurrences of FS with SS, giving S2}
  130.  
  131.   function RepAllF(S1, FS, SS : string) : string;
  132.  
  133. {**********************************************************************}
  134.  
  135.   Procedure DelAll(S1, DS : string; var S2 : string);
  136.   {In string S1 delete all occurrences of DS, giving S2}
  137.  
  138.   function DelAllF(S1, DS : string) : string;
  139.  
  140. {**********************************************************************}
  141.  
  142. function PosSet(A : CharSet; S : string) : byte;
  143. {Returns the position of the first occurrance of any member of A in S}
  144.  
  145. {**********************************************************************}
  146.  
  147.   Procedure GetNext(var S1, S2 : String);
  148.   {Extracts the next substring from S1 delimited by a member of DelimSet
  149.   and returns it in S2. S1 is returned with the sub-string stripped off.
  150.   If S1 is empty on entry, both S1 and S2 will be empty on return.}
  151.  
  152.   function GetNextF(var S1 : string) : string;
  153.  
  154. {**********************************************************************}
  155.  
  156.  
  157. function UniqueFileName(Path : string; AddExt : boolean) : string;
  158. {Returns a file name which will be unique in the directory specified
  159.  by PATH. On return, the file name will be appended to PATH. If AddExt
  160.  is TRUE, an extension of .$$$ will be appended, else only the file name
  161.  will be returned.}
  162.  
  163. {**********************************************************************}
  164.  
  165.  
  166. Implementation
  167. {------------}
  168.  
  169. var
  170.   Regs : Registers;
  171.   XY   : WindowCoordinates;
  172.  
  173. {**********************************************************}
  174.  
  175. function BetwS(Lower, Item, Upper  : LongInt) : boolean;
  176. {Performs a SIGNED test of the condition that Lower <= Item <= Upper,
  177.  returning TRUE if and only if the condition is met. Lower, Item, and
  178.  Upper can be any combination of 1, 2, and 4-byte entities.}
  179.   begin
  180.     BetwS := (Item >= Lower) and (Item <= Upper);
  181.     end;
  182.  
  183. {**********************************************************}
  184.  
  185. function BetwU(Lower, Item, Upper  : LongInt) : boolean;
  186. {Performs an UNSIGNED test of the condition that Lower <= Item <= Upper,
  187.  returning TRUE if and only if the condition is met. Lower, Item, and
  188.  Upper can be any combination of 1, 2, and 4-byte entities.}
  189.   const
  190.   {In the following table, columns represent hi-word states,
  191.    rows represent lo-word states.
  192.  
  193.       1. a < b, b < c     4. a = b, b < c     7. a > b, b < c
  194.       2.        b = c     5.        b = c     8.        b = c
  195.       3.        b > c     6.        b > c     9.        b > c }
  196.  
  197.     ST  : array[1..9,1..9] of boolean =
  198.       ((  true,  true, false,  true,  true, false, false, false, false),
  199.        (  true,  true, false,  true,  true, false, false, false, false),
  200.        (  true, false, false,  true, false, false, false, false, false),
  201.        (  true,  true, false,  true,  true, false, false, false, false),
  202.        (  true,  true, false,  true,  true, false, false, false, false),
  203.        (  true, false, false,  true, false, false, false, false, false),
  204.        (  true,  true, false, false, false, false, false, false, false),
  205.        (  true,  true, false, false, false, false, false, false, false),
  206.        (  true, false, false, false, false, false, false, false, false));
  207.  
  208.   type
  209.     WO  = ( HW, LW );
  210.     X   = record
  211.             case byte of
  212.               1 : (L : LongInt);
  213.               2 : (W : array[ WO ] of word);
  214.               end;
  215.     LT  = 1..3;
  216.   var
  217.     HiState,
  218.     LoState   : byte;
  219.   function LEG(A, B : word) : LT;
  220.   {Returns 1, 2, 3 as A is <, =, > B}
  221.     begin
  222.       if A < B then
  223.         LEG := 1
  224.       else if A = B then
  225.           LEG := 2
  226.         else
  227.           LEG := 3;
  228.       end;
  229.   begin
  230.     HiState := (3 * LEG(X(Lower).W[HW], X(Item).W[HW]) - 2) +
  231.                (LEG(X(Item).W[HW], X(Upper).W[HW]) - 1);
  232.     LoState := (3 * LEG(X(Lower).W[LW], X(Item).W[LW]) - 2) +
  233.                (LEG(X(Item).W[LW], X(Upper).W[LW]) - 1);
  234.     BetwU := ST[HiState, LoState];
  235.     end;
  236.  
  237. {**********************************************************}
  238.  
  239. Function StarString;
  240. {StarString is a Boolean function which returns True if a pattern
  241.  string possibly containing one or more '*' wild cards matches a
  242.  target. It works by repeatedly extracting maximum length sub-
  243.  strings not containing a * from Pattern, determining if that sub-
  244.  string exists in Target, and, if so, deleting from Target the first
  245.  character through the end of the partial pattern. A final test is
  246.  made on the residual portion of each to determine the final truth
  247.  value of the function. Character wild cards ('?') are handled by
  248.  substituting characters 1-for-1 from the target string into the
  249.  earliest possible match and proceeding as if they were non-existant.
  250.  The function will terminate as soon as the truth value can be
  251.  determined, so that no time is wasted in execution.}
  252.   var
  253.     Index   : Byte;
  254.     TrialB  : String;
  255.  
  256.   procedure ReplQ(var Pattern1 : String; Target1 : String);
  257.   {Replaces all occurrences of '?' in Pattern1 with the corresponding
  258.    character from Target1. If Target1[0] < Pattern1[0], any '?' occurring
  259.    in the tail will not be effected.}
  260.     var
  261.       T1 : Byte;
  262.     begin
  263.       T1 := Pos('?', Pattern1);
  264.       While (T1 <> 0) and (T1 <= Byte(Pattern1[0])) do begin
  265.         Pattern1[T1] := Target1[T1];
  266.         T1 := Pos('?', Pattern1);
  267.         end;
  268.       end; {ReplQ}
  269.  
  270.   procedure Split(Instr : String; Ch : Char; var Before, After : String;
  271.                   var Index : Byte);
  272.   {Splits Instr on the first occurrence of the character Ch. The products
  273.    of the split are returned in Before and After. Ch itself is discarded.
  274.    Index returns the character position in Instr at which the split
  275.    occurred. (0 means no split)}
  276.     begin
  277.      Index := Pos(Ch, Instr);
  278.      Before := Copy(Instr, 1, Index - 1);
  279.      Delete(Instr, 1, Index);
  280.      After := Instr;
  281.      end; {Split}
  282.  
  283.   procedure CountOccur(PatStr, InStr : String; var Count : Byte);
  284.   {Counts the number of occurrences of PatStr in Instr and returns the
  285.    count in Count}
  286.     var
  287.       T1  : Byte;
  288.     begin
  289.       Count := 0;
  290.       T1 := Pos(PatStr, InStr);
  291.       While T1 <> 0 do begin
  292.         Inc(Count);
  293.         Delete(Instr, 1, T1);
  294.         T1 := Pos(PatStr, Instr);
  295.         end;
  296.       end; {CountOccur}
  297.  
  298.   procedure BuildMatch(var Pattern1, Target1 : String; var Index1 : Byte);
  299.   {If possible, constructs the version of Pattern1 which matches the
  300.    earliest substring of Target1 by eliminating character wild cards.
  301.    The position is returned in Index1}
  302.     var
  303.       Pat1  : String;
  304.       T1,           {Pointer within Target1 to start of trial match }
  305.       T2,           {FOR loop index for character replacement       }
  306.       T3,           {Number of character wild cards in Pat1         }
  307.       T4    : Byte; {Position of the T3th character wild card       }
  308.     begin
  309.       If Pattern1 = '' then exit;
  310.       If Pos('?', Pattern1) = 0 then begin
  311.         Index1 := Pos(Pattern1, Target1);
  312.         exit;
  313.         end;
  314.       T1 := 0;
  315.       Pat1 := Pattern1;
  316.       CountOccur('?', Pat1, T3);
  317.       Index1 := Pos(Pat1, Target1);
  318.       While ((T1 + Byte(Pat1[0])) <= Byte(Target1[0])) and
  319.              (Index1 = 0) do begin
  320.         For T2 := 1 to T3 do begin
  321.           T4 := Pos('?',Pat1);
  322.           Pat1[T4] := Target1[T1+T4];
  323.           end; {For}
  324.         Index1 := Pos(Pat1, Target1);
  325.         If Index1 = 0 then
  326.           Pat1 := Pattern1
  327.         else
  328.           Pattern1 := Pat1;
  329.         Inc(T1);
  330.         end; {While}
  331.       end; {BuildMatch}
  332.  
  333.   begin {StarString}
  334.  
  335.     {First, take care of all the special cases}
  336.  
  337.     While Pos('**', Pattern) <> 0 do
  338.       Delete(Pattern, Pos('**', Pattern), 1);
  339.  
  340.     If (Byte(Pattern[0]) = 0) or           {No pattern string  }
  341.        (Byte( Target[0]) = 0) then begin   {or no target string}
  342.       StarString := False;
  343.       Exit;
  344.       end;
  345.  
  346.     If Pattern[1] = '?' then
  347.       Pattern[1] := Target[1];
  348.  
  349.     If Pos('*', Pattern) = 0 then begin    {No wild cards, so }
  350.       ReplQ(Pattern, Target);              {Quick result known}
  351.       StarString := (Pattern = Target);
  352.       Exit;
  353.       end;
  354.  
  355.     Split(Pattern, '*', TrialB, Pattern, Index);
  356.     BuildMatch(TrialB, Target, Index);
  357.     If Index <> 1 then begin               {No match possible }
  358.       StarString := False;
  359.       exit;
  360.       end;
  361.  
  362.     {End of special cases. Proceed with normal processing}
  363.  
  364.     Pattern := TrialB + '*' + Pattern;     {Possible match, so  }
  365.                                            {reconstruct Pattern }
  366.                                            {and proceed         }
  367.  
  368.     While (Pos('*', Pattern) <> 0) do begin  {Still more wild cards}
  369.       Split(Pattern, '*', TrialB, Pattern, Index);
  370.                                              {Disect the pattern   }
  371.  
  372.       {TrialB now contains that portion to the left of the wildcard,
  373.        and Pattern contains what was to the right. The wild card
  374.        itself has been discarded.}
  375.  
  376.       {From TrialB build the best possible match to Target, getting
  377.        rid of character wild cards. Put the expanded string back into
  378.        TrialB for further processing.}
  379.  
  380.       BuildMatch(TrialB, Target, Index);     {Try to find a match  }
  381.                                              { and set the Index   }
  382.  
  383.       If Index = 0 then begin                {No match is possible }
  384.         StarString := False;
  385.         exit;
  386.         end
  387.       else begin                              {Still possible match}
  388.         Delete(Target, 1, Index + Byte(TrialB[0]) - 1);
  389.         end;                                  {Strip off past the  }
  390.       end; {While}                            { last left pattern  }
  391.                                               { and try again      }
  392.       If Byte(Pattern[0]) = 0 then     {'*' as last character of Pattern}
  393.         StarString := True             { so we know there is a match.   }
  394.  
  395.       else begin        { Make sure we are looking at *last* occurrance }
  396.                         {                          of Pattern in Target }
  397.         Index := Pos(Pattern, Target);
  398.         TrialB := Target;                     { Save the current target }
  399.         While Index <> 0 do begin
  400.           Delete(Target, 1, Index + Byte(Pattern[0]) - 1);
  401.                                         { Delete through end of Pattern }
  402.           Index := Pos(Pattern, Target);
  403.           If Index <> 0 then TrialB := Target;    { Save the new target }
  404.           end;
  405.  
  406.         { TrialB now contains the maximum length substring of Target    }
  407.         { which contains the *last* occurrance of Pattern.              }
  408.  
  409.         BuildMatch(Pattern, TrialB, Index);
  410.         If Index = 0 then
  411.           StarString := False
  412.         else
  413.           StarString := ((Index + Byte(Pattern[0]) - 1) = Byte(TrialB[0]));
  414.         end;
  415.     end; {Function StarString}
  416.  
  417. {***************************************************************}
  418.  
  419. function WhoAmI;
  420. var
  421.   s, o  : integer;
  422.   c     : string;
  423. begin
  424.   s := memw[PrefixSeg:$2c];    {the segment address of the start of   }
  425.   o := 0;                      { the environment area at PrefixSeg:$2c}
  426.   while memw[s:o] <> 0 do      {search for end of environment         }
  427.     o := succ(o);              {  which is marked by two 0 bytes      }
  428.   o := o + 4;                  {skip across word count       }
  429.   c := '';
  430.   repeat
  431.     c := c + chr(mem[s:o]);    {transfer fully qualified path       }
  432.     o := succ(o);              {  as a legitimate TurboPASCAL string}
  433.     until mem[s:o] = 0;
  434.   WhoAmI := c;
  435.   end;
  436.  
  437. {**********************************************************************}
  438.  
  439. function searchenvironment;
  440.   var
  441.    x,y   : integer;
  442.    cs    : string;
  443.   begin
  444.    x := memw[prefixseg:$2C];
  445.    y := 0;
  446.    while memw[x:y] <> 0 do begin
  447.     if chr(mem[x:y]) = code[1] then begin
  448.      cs := '';
  449.      repeat                           {copy up to the '='}
  450.       cs := cs + chr(mem[x:y]);
  451.       y := y + 1
  452.       until chr(mem[x:y]) = '=';
  453.      if cs = code then begin          {got a match, so}
  454.       y := y + 1;                       {space across the '='}
  455.       cs := '';
  456.       repeat                            {and copy what's on the other side}
  457.        cs := cs + chr(mem[x:y]);
  458.        y := y + 1
  459.        until mem[x:y] = 0;
  460.       searchenvironment := cs;          {and that's the function value..}
  461.       exit                              {so set it and bail out}
  462.       end {if cs = code}
  463.      end {chr(mem[x:y]) = code[1]}
  464.     else                               {no match, so}
  465.      repeat                            {just find the end of the string}
  466.       y := y + 1
  467.       until mem[x:y] = 0;
  468.     y := y + 1;                      {space across string delimiter}
  469.     end; {while}
  470.     searchenvironment := '';
  471.    end; {of searchenvironment}
  472.  
  473. {**********************************************************}
  474.  
  475. Function LoWord;
  476.   type
  477.     XT = array[1..2] of Word;
  478.   var
  479.     X : XT absolute LI;
  480.   begin
  481.     LoWord := X[1];
  482.     end;
  483.  
  484. {**********************************************************************}
  485.  
  486. Function HiWord;
  487.   type
  488.     XT = array[1..2] of Word;
  489.   var
  490.     X : XT absolute LI;
  491.   begin
  492.     HiWord := X[2];
  493.     end;
  494.  
  495. {**********************************************************************}
  496.  
  497. Function LI;
  498. {Converts two Word vbls to a LongInt}
  499. type
  500.   LItype = record
  501.              case Integer of
  502.                1 : (IT : array[1..2] of Integer);
  503.                2 : (LIT: LongInt);
  504.              end;
  505. var
  506.   X : LItype;
  507. begin
  508.   X.IT[1] := Ilo;
  509.   X.IT[2] := Ihi;
  510.   LI := X.LIT;
  511.   end;
  512.  
  513. {**********************************************************************}
  514.  
  515. Function HEX;
  516.   Type
  517.     HexByte = record
  518.                 case Byte of
  519.                   1 : (LI : LongInt);
  520.                   2 : (BY : array[0..3] of Byte);
  521.                   3 : (Ts : array[0..1] of Word);
  522.                 end;
  523.   Const
  524.     B : Array[0..15] of Char =
  525.              ('0','1','2','3','4','5','6','7','8','9',
  526.               'A','B','C','D','E','F');
  527.   Var
  528.     S1 : String;
  529.     T1,
  530.     T2 : Byte;
  531.     HB : HexByte absolute A;
  532.   Begin
  533.     Case HB.Ts[1] of
  534.       0 :  begin
  535.              T2 := 1;           {At most 2 byte vbl}
  536.              Case HB.BY[1] of
  537.                0 : T2 := 0;     {It's a Byte}
  538.                end;
  539.              end;
  540.       else T2 := 3;
  541.       end;
  542.     S1 := '';
  543.     For T1 := T2 downto 0 do
  544.       S1 := S1 + B[HB.BY[T1] shr 4] + B[HB.BY[T1] and $0F];
  545.     HEX := S1;
  546.     end;
  547.  
  548. {**********************************************************************}
  549.  
  550. function Pmod;
  551. begin
  552.   Pmod := ((x mod modulus) + modulus) mod modulus;
  553.   end;
  554.  
  555. {**********************************************************}
  556.  
  557.   Procedure RepAll(S1, FS, SS : string; var S2 : string);
  558.   {In string S1 replace all occurrences of FS with SS}
  559.     var
  560.       T1 : Integer;
  561.       S3  : string;
  562.     begin
  563.       S2 := '';
  564.       while Pos(FS, S1) <> 0 do begin
  565.         T1 := Pos(FS, S1);
  566.         S2 := S2 + copy(S1, 1, pred(T1)) + SS;
  567.         delete(S1, 1, pred(T1) + Length(FS));
  568.         end; {while}
  569.       S2 := S2 + S1;
  570.       end; {RepAll}
  571.  
  572.   function RepAllF(S1, FS, SS : string) : string;
  573.     var
  574.       S2  : string;
  575.     begin
  576.       RepAll(S1, FS, SS, S2);
  577.       RepAllF := S2;
  578.       end; {RepAllF}
  579.  
  580. {**********************************************************}
  581.  
  582.   Procedure DelAll(S1, DS : string; var S2 : string);
  583.   {In string S1 delete all occurrences of DS}
  584.     begin
  585.       RepAll(S1, DS, '', S2);
  586.       end;
  587.  
  588.   function DelAllF(S1, DS : string) : string;
  589.     begin
  590.       DelAllF := RepAllF(S1, DS, '');
  591.       end; {DelAllF}
  592.  
  593. {**********************************************************}
  594.  
  595. function PosSet(A : CharSet; S : string) : byte;
  596.   var
  597.     T1  : byte;
  598.   begin
  599.     T1 := 1;
  600.     while (not (S[T1] in A)) and (T1 < Length(S)) do
  601.       inc(T1);
  602.     if S[T1] in A then
  603.       PosSet := T1
  604.     else
  605.       PosSet := 0;
  606.     end; {PosSet}
  607.  
  608.   function TrimLeadSet(S : string; CS : CharSet) : string;
  609.     var
  610.       L : byte;
  611.     begin
  612.       L := 1;
  613.       while (S[L] in CS) and (L <= byte(S[0])) do
  614.         inc(L);
  615.       if L = 0 then
  616.         TrimLeadSet := ''
  617.       else
  618.         TrimLeadSet := Copy(S, L, 255);
  619.       end; {TrimLeadSet}
  620.  
  621.   function TrimTrailSet(S : string; CS : CharSet) : string;
  622.     begin
  623.       while (S[byte(S[0])] in CS) and (byte(S[0]) > 0) do
  624.         dec(S[0]);
  625.       TrimTrailSet := S;
  626.       end; {TrimTrailSet}
  627.  
  628.   function TrimSet(S : string; CS : CharSet) : string;
  629.     begin
  630.       TrimSet := TrimTrailSet(TrimLeadSet(S, CS), CS);
  631.       end; {TrimSet}
  632.  
  633.   Procedure GetNext(var S1, S2 : String);
  634.   {Extracts the next space-delimited string from S1 and returns it
  635.   in S2. S1 is returned with the sub-string stripped off.
  636.   If S1 is empty on entry, both S1 and S2 will be empty on return.}
  637.  
  638.   var
  639.     T1 : Integer;
  640.   begin {GetNext}
  641.     If Length(S1) = 0 then begin
  642.       S2[0] := chr(0);
  643.       Exit
  644.       end;
  645.     S1 := TrimSet(S1, DelimSet);     {Strip leading and trailing blanks}
  646.     If Length(S1) = 0 then
  647.       S2[0] := chr(0)
  648.     else
  649.       If PosSet(DelimSet, S1) <> 0 then begin
  650.         T1 := PosSet(DelimSet, S1);
  651.         S2 := Copy(S1, 1, Pred(T1));
  652.         S1 := Copy(S1, T1, Length(S1) - Pred(T1));
  653.         end
  654.       else begin
  655.         S2 := S1;
  656.         S1 := '';
  657.         end;
  658.     end; {GetNext}
  659.  
  660.   function GetNextF(var S1 : string) : string;
  661.   var
  662.     S2 : string;
  663.   begin
  664.     GetNext(S1, S2);
  665.     GetNextF := S2;
  666.     end; {GetNextF}
  667.  
  668. {**********************************************************}
  669.  
  670.  
  671. function UniqueFileName(Path : string; AddExt : boolean) : string;
  672.   var
  673.     FN :  record
  674.             case integer of
  675.               1 : (LI : LongInt);
  676.               2 : (WD : array[1..2] of word);
  677.               end;
  678.     R  :  Registers;
  679.     S  :  string;
  680.  
  681.   begin
  682.     R.AH := $2C;
  683.     MsDos(R);
  684.     FN.WD[1] := R.CX;
  685.     FN.WD[2] := R.DX;
  686.     repeat
  687.       Inc(FN.LI);
  688.       S := Path + HexL(FN.LI);
  689.       if AddExt then S := S + '.$$$';
  690.       until not ExistFile(S);
  691.     UniqueFileName := S
  692.     end;
  693.  
  694.  
  695.  
  696.  
  697. {**********************************************************}
  698.  
  699. begin {Initialization section}
  700.   StartingMode := Mem[0:$449];
  701.   With Regs do begin
  702.     AH := 8;
  703.     Intr( $10, Regs );
  704.     StartingAttr := AH;
  705.     end;
  706.  
  707. end.
  708.  
  709.