home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / DBT.ZIP / MKEY4.ARC / MULKEY4.PAS next >
Encoding:
Pascal/Delphi Source File  |  1987-12-31  |  20.7 KB  |  592 lines

  1. Unit Mulkey4;
  2.  
  3. {This is the MULKEY shell routines written by Edwin Floyd, rewritten
  4.  by James C Walker <Cap'n> 72255,1616. Please refer to the original
  5.  for programming instructions}
  6.  
  7. Interface
  8.  
  9. Uses TPCrt, taccess;
  10.  
  11.   {$I-}
  12. Const
  13.   MaxKeys = 5;
  14.   MaxFields = 25;
  15. Type
  16.   KEY_TYPE = (KEY_INTEGER, KEY_CHAR, KEY_STRING, KEY_REAL);
  17.   Field_Type = (Valid_Date_Field, Date_Field, Integer_Field,
  18.                 Real_Field, String_Field, Non_Blank);
  19.   File_Type = Record
  20.                 Name : String[60];
  21.                 RecSize : Integer;
  22.                 IOERROR : Boolean;
  23.                 REC_REF : LongInt;
  24.                 DATA_FILE : DataFile;
  25.                 NUMBER_OF_KEYS : Byte;
  26.                 Key : Array[1..MaxKeys] Of Record
  27.                                              Offset : Integer;
  28.                                              KEYLENGTH : Word;
  29.                                              EXTENSION : String[3];
  30.                                              UNIQUE : Boolean;
  31.                                              UPSHIFT : Boolean;
  32.                                              KEYTYPE : KEY_TYPE;
  33.                                              INDEX_FILE : IndexFile;
  34.                                            End;
  35.                 PromptAttribute : Integer;
  36.                 GetAttribute : Integer;
  37.                 DisplayAttribute : Integer;
  38.                 HelpAttribute : Integer;
  39.                 NumOfFields : Integer;
  40.                 Field : Array[1..MaxFields] Of Record
  41.                                                  XCoord : Integer;
  42.                                                  YCoord : Integer;
  43.                                                  FieldData : ^String;
  44.                                                  FieldType : Field_Type;
  45.                                                  FieldLength : Integer;
  46.                                                  LegalChars : String[80];
  47.                                                  ScreenPrompt : String[80];
  48.                                                  HelpPrompt : String[80];
  49.                                                End;
  50.               End;
  51.   Word2 = String[254];
  52.  
  53. Var
  54.   WORK_KEY : TaKeyStr;
  55.   WORK_REC : Array[0..MaxDataRecSize] Of Char;
  56.  
  57. Function WildMatch(FirstStr, SecondStr : Word2) : Boolean;
  58. Function KEYOFFSET(Var R; Var F) : Integer;
  59. Procedure KEY_TO_STRING(Var Key; Len : Byte; TYP : KEY_TYPE; UP : Boolean);
  60. Procedure CLOSE_FILE(Var F : File_Type);
  61. Procedure OPEN_FILE(Var F : File_Type);
  62. Procedure DELETE_RECORD(Var F : File_Type);
  63. Procedure READ_RECORD(Var F : File_Type; K : Integer; Var R);
  64. Procedure NEXT_RECORD(Var F : File_Type; K : Integer; Var R);
  65. Procedure PREVIOUS_RECORD(Var F : File_Type; K : Integer; Var R);
  66. Procedure Search_Partial(Var F : File_Type; K : Integer; Templat : Word2;
  67.                          Var R);
  68. Procedure ADD_RECORD(Var F : File_Type; Var R);
  69. Procedure UPDATE_RECORD(Var F : File_Type; Var R);
  70.  
  71.  
  72. Implementation
  73.  
  74.   {$I-}
  75.   {=========================================================================}
  76.   {These are the MULKEY Routines themselves}
  77.   {=========================================================================}
  78.  
  79.   Function WildMatch {(FirstStr, SecondStr : Word2) : Boolean} ;
  80.     {- search forward to find a given variable or scope}
  81.     {- return true if something was found}
  82.   Const
  83.     maxwrdchr2 = 255;
  84.     any = '* ';
  85.     one = '?';
  86.     termchar = '$$';
  87.     termchar1 = '$';
  88.     Procedure simptemp(Var t : Word2);
  89.       {- simplify the template by removing adjacent * 's}
  90.     Var
  91.       I, J : Integer;
  92.     Begin
  93.       I := 1; J := 1;
  94.       While t[I] <> termchar1 Do
  95.         Begin
  96.           If ((t[I] = any) And (t[Succ(I)] = any)) Then
  97.             For J := Succ(I) To Pred(maxwrdchr2) Do t[J] := t[Succ(J)]
  98.           Else
  99.             I := Succ(I);
  100.         End;
  101.     End;                     {simptemp}
  102.     Function Match(S, t : Word2) : Boolean;
  103.       {- return true if this is a match}
  104.       {- s is the test string, t is the match template}
  105.     Label 1;
  106.     Var
  107.       tp, tpon, spsav, sp : Integer;
  108.       On : Boolean;
  109.     Begin
  110.       sp := 1; tp := 1;
  111.       On := False;
  112.       Match := False;
  113.       While ((S[sp] <> termchar1) Or (t[tp] <> termchar1)) Do
  114.         Begin
  115.           While t[tp] = one Do
  116.             Begin {pass over '?' keeping t and s sync'ed}
  117.               If S[sp] = termchar1 Then GoTo 1; {ran out of string needing a ? match}
  118.               sp := Succ(sp);
  119.               tp := Succ(tp);
  120.             End;
  121.           If t[tp] = any Then
  122.             Begin      {'* ' was found}
  123.               On := True;
  124.               tpon := Succ(tp); {save the next template position beyond *}
  125.               spsav := sp; {save string position}
  126.               tp := Succ(tp); {move to next template check}
  127.               If t[tp] = termchar1 Then
  128.                 Begin {last template character was '* '}
  129.                   Match := True; {any more string chars must match}
  130.                   GoTo 1;
  131.                 End;
  132.             End;
  133.           If t[tp] = S[sp] Then
  134.             Begin {if match found proceed to next comparison}
  135.               sp := Succ(sp);
  136.               tp := Succ(tp);
  137.             End
  138.           Else
  139.             Begin       {otherwise....}
  140.               If (Not On) Then GoTo 1 {fatal mismatch - no backup from *}
  141.               Else
  142.                 Begin {non- fatal mismatch}
  143.                   spsav := Succ(spsav); {account for mismatched char with the *}
  144.                   If S[spsav] = termchar1
  145.                   Then GoTo 1; {end of string without fitting template}
  146.                   sp := spsav;
  147.                   tp := tpon; {try the template constraint just
  148.                               following the * again}
  149.                 End;
  150.             End;
  151.         End;  {of both strings reached}
  152.       Match := True;
  153. 1:
  154.     End;                        {match}
  155.   Begin
  156.     WildMatch := False;
  157.     FirstStr := FirstStr + '$';
  158.     SecondStr := SecondStr + '$';
  159.     simptemp(SecondStr);
  160.     If Match(FirstStr, SecondStr) Then
  161.       WildMatch := True
  162.     Else
  163.       WildMatch := False;
  164.   End;
  165.   Function KEYOFFSET {(VAR R; VAR F) : Integer} ;
  166.   Begin
  167.     {Use to compute the OFFSET parameter of a key}
  168.     KEYOFFSET := (Ofs(F) + $8000) - (Ofs(R) + $8000);
  169.   End;
  170.   Procedure KEY_TO_STRING {(VAR Key; LEN : Byte; TYP : KEY_TYPE; UP : Boolean)} ;
  171.     {Converts a key of the designated type to a string in WORK_KEY for Turbo
  172.     Index storage}
  173.   Var
  174.     INTEGER_KEY : Integer Absolute Key;
  175.     CHAR_KEY : Array[1..MaxKeyLen] Of Char Absolute Key;
  176.     STRING_KEY : String[MaxKeyLen] Absolute Key;
  177.     REAL_KEY : Real Absolute Key;
  178.     I : Integer;
  179.   Begin
  180.     Case TYP Of
  181.       KEY_INTEGER :
  182.         Begin
  183.           I := INTEGER_KEY + $8000;
  184.           WORK_KEY := Chr(hi(I)) + Chr(lo(I));
  185.         End;
  186.       KEY_CHAR :
  187.         Begin
  188.           If Len > MaxKeyLen Then Len := MaxKeyLen;
  189.           WORK_KEY[0] := Chr(Len);
  190.           If Len > 0 Then Move(Key, WORK_KEY[1], Len);
  191.         End;
  192.       KEY_STRING : WORK_KEY := STRING_KEY;
  193.       KEY_REAL : Str(REAL_KEY:16, WORK_KEY);
  194.     End;
  195.     If UP And ((TYP = KEY_CHAR) Or (TYP = KEY_STRING)) Then
  196.       For I := 1 To Length(WORK_KEY) Do
  197.         WORK_KEY[I] := Upcase(WORK_KEY[I]);
  198.   End;
  199.   Procedure CLOSE_FILE {(VAR F : File_Type)} ;
  200.     {Close database and all index files}
  201.   Var
  202.     I : Integer;
  203.   Begin
  204.     With F Do
  205.       Begin
  206.         CloseFile(DATA_FILE);
  207.         For I := 1 To NUMBER_OF_KEYS Do
  208.           Begin
  209.             With Key[I] Do CloseIndex(INDEX_FILE);
  210.           End;
  211.       End;
  212.   End;
  213.   Procedure OPEN_FILE {(VAR F : File_Type)} ;
  214.     {Opens a multi- key database and all index files, re- builds missing index
  215.     file(s) and database freespace chain}
  216.   Var
  217.     I, Dup : Integer;
  218.     FLAG : Integer Absolute WORK_REC;
  219.     KEY_FILE_OK : Array[1..MaxKeys] Of Boolean;
  220.     ALL_KEYS_OK : Boolean;
  221.   Begin
  222.     With F Do
  223.       Begin
  224.         If (NUMBER_OF_KEYS < 1) Or (NUMBER_OF_KEYS > MaxKeys) Then
  225.           Begin
  226.             WriteLn('In file ', Name, ', ', NUMBER_OF_KEYS,
  227.                     ' keys specified, 1.. ', MaxKeys, ' keys allowed');
  228.             Halt;
  229.           End;
  230.         ALL_KEYS_OK := True;
  231.         IOERROR := False;
  232.         OpenFile(DATA_FILE, Name + '.DAT', RecSize);
  233.         If Not OK Then
  234.           Begin
  235.             MakeFile(DATA_FILE, Name + '.DAT', RecSize);
  236.             For I := 1 To NUMBER_OF_KEYS Do
  237.               Begin
  238.                 With Key[I] Do
  239.                   Begin
  240.                     If UNIQUE Then Dup := 0 Else Dup := 1;
  241.                     MakeIndex(INDEX_FILE, Name + '.' + EXTENSION, KEYLENGTH, Dup);
  242.                     ClearKey(INDEX_FILE);
  243.                   End;
  244.               End;
  245.           End
  246.         Else
  247.           Begin
  248.             For I := 1 To NUMBER_OF_KEYS Do
  249.               Begin
  250.                 With Key[I] Do
  251.                   Begin
  252.                     If Offset < 2 Then
  253.                       Begin
  254.                         WriteLn('Key Offset for key ', I, ' is ', Offset,
  255.                                 ', Minimum is 2 for file ', Name);
  256.                         Halt;
  257.                       End;
  258.                     If (KEYTYPE = KEY_CHAR)
  259.                     And ((KEYLENGTH < 1) Or (KEYLENGTH > MaxKeyLen)) Then
  260.                       Begin
  261.                         WriteLn('KeyLength for key ', I, ' is ', KEYLENGTH,
  262.                                 ', it must be between 1 and ', MaxKeyLen, ' in file ',
  263.                                 Name);
  264.                         Halt;
  265.                       End;
  266.                     If UNIQUE Then Dup := 0 Else Dup := 1;
  267.                     OpenIndex(INDEX_FILE, Name + '.' + EXTENSION, KEYLENGTH, Dup);
  268.                     If Not OK Then
  269.                       Begin
  270.                         MakeIndex(INDEX_FILE, Name + '.' + EXTENSION, KEYLENGTH,
  271.                                   Dup);
  272.                         ALL_KEYS_OK := False;
  273.                         KEY_FILE_OK[I] := False;
  274.                       End
  275.                     Else
  276.                       KEY_FILE_OK[I] := True;
  277.                     ClearKey(INDEX_FILE);
  278.                   End;
  279.               End;
  280.           End;
  281.         If Not ALL_KEYS_OK Then
  282.           Begin
  283.             GoToXY(1, 1);
  284.             WriteLn('Please wait, rebuilding index file(s) in ', Name, ' for ',
  285.                     FileLen(DATA_FILE), ' records');
  286.             REC_REF := 1;
  287.             With DATA_FILE Do
  288.               Begin
  289.                 FirstFree := - 1;
  290.                 NumberFree := 0;
  291.               End;
  292.             While REC_REF < FileLen(DATA_FILE) Do
  293.               Begin
  294.                 GetRec(DATA_FILE, REC_REF, WORK_REC);
  295.                 If FLAG = 0 Then
  296.                   Begin
  297.                     For I := 1 To NUMBER_OF_KEYS Do
  298.                       If Not KEY_FILE_OK[I] Then With Key[I] Do
  299.                         Begin
  300.                           KEY_TO_STRING(WORK_REC[Offset], KEYLENGTH, KEYTYPE,
  301.                                         UPSHIFT);
  302.                           AddKey(INDEX_FILE, REC_REF, WORK_KEY);
  303.                           If Not OK Then IOERROR := True;
  304.                         End;
  305.                   End
  306.                 Else
  307.                   Begin
  308.                     With DATA_FILE Do
  309.                       Begin
  310.                         If FLAG <> FirstFree Then
  311.                           Begin
  312.                             FLAG := FirstFree;
  313.                             PutRec(DATA_FILE, REC_REF, WORK_REC);
  314.                             FirstFree := REC_REF;
  315.                           End;
  316.                         NumberFree := Succ(NumberFree);
  317.                       End;
  318.                   End;
  319.                 REC_REF := Succ(REC_REF);
  320.               End;
  321.           End;
  322.         REC_REF := 0;
  323.       End;
  324.     GoToXY(1, 1); ClrEol;
  325.   End;
  326.   Procedure DELETE_RECORD {(VAR F : File_Type)} ;
  327.     {Delete the last record retrieved from the database and all its keys.
  328.     IOERROR indicates no valid last record retrieved.}
  329.   Var
  330.     K : Integer;
  331.   Begin
  332.     With F Do If REC_REF <> 0 Then
  333.       Begin
  334.         GetRec(DATA_FILE, REC_REF, WORK_REC);
  335.         DeleteRec(DATA_FILE, REC_REF);
  336.         For K := 1 To NUMBER_OF_KEYS Do With Key[K] Do
  337.           Begin
  338.             KEY_TO_STRING(WORK_REC[Offset], KEYLENGTH, KEYTYPE, UPSHIFT);
  339.             DeleteKey(INDEX_FILE, REC_REF, WORK_KEY);
  340.           End;
  341.         IOERROR := False;
  342.         REC_REF := 0;
  343.       End
  344.       Else
  345.         IOERROR := True;
  346.   End;
  347.   Procedure READ_RECORD {(VAR F : File_Type; K : Integer; VAR R)} ;
  348.     {Read a record from the database with a key equal to or higher than that
  349.     indicated by key field K in record R. IOERROR indicates search key was
  350.     higher than any in the index.}
  351.   Var
  352.     REC : Array[0..MaxDataRecSize] Of Char Absolute R;
  353.     REF : LongInt;
  354.   Begin
  355.     With F Do
  356.       Begin
  357.         If (K > NUMBER_OF_KEYS) Or (K < 1) Then
  358.           Begin
  359.             WriteLn('Key ', K, ' Referenced, Keys 1.. ', NUMBER_OF_KEYS,
  360.                     ' Defined in file ', Name);
  361.             Halt;
  362.           End;
  363.         With Key[K] Do
  364.           Begin
  365.             KEY_TO_STRING(REC[Offset], KEYLENGTH, KEYTYPE, UPSHIFT);
  366.             SearchKey(INDEX_FILE, REF, WORK_KEY);
  367.             If OK Then GetRec(DATA_FILE, REF, REC);
  368.             If OK Then REC_REF := REF;
  369.             IOERROR := Not OK;
  370.           End;
  371.       End;
  372.   End;
  373.   Procedure NEXT_RECORD {(VAR F : File_Type; K : Integer; VAR R)} ;
  374.     {Read the next record by key K from the database. IOERROR indicates end of
  375.     file by key K.}
  376.   Var
  377.     REC : Array[0..MaxDataRecSize] Of Char Absolute R;
  378.     REF : LongInt;
  379.   Begin
  380.     With F Do
  381.       Begin
  382.         If (K > NUMBER_OF_KEYS) Or (K < 1) Then
  383.           Begin
  384.             WriteLn('Key ', K, ' Referenced, Keys 1.. ', NUMBER_OF_KEYS,
  385.                     ' Defined in file ', Name);
  386.             Halt;
  387.           End;
  388.         With Key[K] Do
  389.           Begin
  390.             NextKey(INDEX_FILE, REF, WORK_KEY);
  391.             If OK Then GetRec(DATA_FILE, REF, REC);
  392.             If OK Then REC_REF := REF;
  393.             IOERROR := Not OK;
  394.             If Not OK Then
  395.               Begin
  396.                 NextKey(INDEX_FILE, REF, WORK_KEY);
  397.                 If OK Then GetRec(DATA_FILE, REF, REC);
  398.                 If OK Then REC_REF := REF;
  399.               End;
  400.           End;
  401.       End;
  402.   End;
  403.   Procedure PREVIOUS_RECORD {(VAR F : File_Type; K : Integer; VAR R)} ;
  404.     {Read the previous record by key K from the database. IOERROR indicates start
  405.     of file by key K.}
  406.   Var
  407.     REC : Array[0..MaxDataRecSize] Of Char Absolute R;
  408.     REF : LongInt;
  409.   Begin
  410.     With F Do
  411.       Begin
  412.         If (K > NUMBER_OF_KEYS) Or (K < 1) Then
  413.           Begin
  414.             WriteLn('Key ', K, ' Referenced, Keys 1.. ', NUMBER_OF_KEYS,
  415.                     ' Defined in file', Name);
  416.             Halt;
  417.           End;
  418.         With Key[K] Do
  419.           Begin
  420.             PrevKey(INDEX_FILE, REF, WORK_KEY);
  421.             If OK Then GetRec(DATA_FILE, REF, REC);
  422.             If OK Then REC_REF := REF;
  423.             IOERROR := Not OK;
  424.             If Not OK Then
  425.               Begin
  426.                 PrevKey(INDEX_FILE, REF, WORK_KEY);
  427.                 If OK Then GetRec(DATA_FILE, REF, REC);
  428.                 If OK Then REC_REF := REF;
  429.               End;
  430.           End;
  431.       End;
  432.   End;
  433.   Procedure Search_Partial {(VAR F : File_Type; K : Integer; Templat : Word2;
  434.                            VAR R)} ;
  435.     {-- This procedure is to allow a wildcard match of an index field.
  436.     Acceptable wildcards are * and ?. Templat must be a string, no
  437.     greater than 254 characters. Careful attention must be paid that
  438.     the search starts from the Work_Key you specify. To start the search
  439.     from the beginning set the Work_Key to blank, to pick up the
  440.     search from the last point, return Work_Key to the value it had
  441.     after this procedure}
  442.   Var
  443.     REC : Array[0..MaxDataRecSize] Of Char Absolute R;
  444.     REF : LongInt;
  445.     Foundit : Boolean;
  446.   Begin
  447.     With F Do
  448.       Begin
  449.         If (K > NUMBER_OF_KEYS) Or (K < 1) Then
  450.           Begin
  451.             WriteLn('Key ', K, ' Referenced, Keys 1.. ', NUMBER_OF_KEYS,
  452.                     ' Defined in file ', Name);
  453.             Halt;
  454.           End;
  455.         With Key[K] Do
  456.           Begin
  457.             REF := REC_REF;
  458.             SearchKey(INDEX_FILE, REF, WORK_KEY);
  459.             NextKey(INDEX_FILE, REF, WORK_KEY);
  460.             If Not OK Then
  461.               Begin
  462.                 ClearKey(INDEX_FILE);
  463.                 NextKey(INDEX_FILE, REF, WORK_KEY);
  464.               End;
  465.             While OK And Not WildMatch(WORK_KEY, Templat) Do
  466.               Begin
  467.                 NextKey(INDEX_FILE, REF, WORK_KEY);
  468.               End;              {while}
  469.             REC_REF := REF;
  470.             GetRec(DATA_FILE, REC_REF, REC);
  471.             IOERROR := Not OK;
  472.           End;                 {With K}
  473.       End;                     {With F}
  474.   End;                         {Search}
  475.   Procedure ADD_RECORD {(VAR F : File_Type; VAR R)} ;
  476.     {
  477.     Add record R to the database and update all index files. IOERROR usually
  478.     indicates a duplicate key in a unique key index.
  479.     }
  480.   Var
  481.     REC : Array[0..MaxDataRecSize] Of Char Absolute R;
  482.     FLAG : Integer Absolute R;
  483.     REF : LongInt;
  484.     K : Integer;
  485.   Begin
  486.     With F Do
  487.       Begin
  488.         IOERROR := False;
  489.         FLAG := 0;
  490.         AddRec(DATA_FILE, REF, REC);
  491.         FlushFile(DATA_FILE);
  492.         K := 1;
  493.         While (K <= NUMBER_OF_KEYS) And Not IOERROR Do
  494.           Begin
  495.             With Key[K] Do
  496.               Begin
  497.                 KEY_TO_STRING(REC[Offset], KEYLENGTH, KEYTYPE, UPSHIFT);
  498.                 AddKey(INDEX_FILE, REF, WORK_KEY);
  499.                 FlushIndex(INDEX_FILE);
  500.                 IOERROR := Not OK;
  501.               End;
  502.             K := Succ(K);
  503.           End;
  504.         If IOERROR Then
  505.           Begin
  506.             K := Pred(Pred(K));
  507.             While K > 0 Do
  508.               Begin
  509.                 With Key[K] Do
  510.                   Begin
  511.                     KEY_TO_STRING(REC[Offset], KEYLENGTH, KEYTYPE, UPSHIFT);
  512.                     DeleteKey(INDEX_FILE, REF, WORK_KEY);
  513.                   End;
  514.                 K := Pred(K);
  515.               End;
  516.             DeleteRec(DATA_FILE, REF);
  517.           End
  518.         Else
  519.           REC_REF := REF;
  520.       End;
  521.   End;
  522.   Procedure UPDATE_RECORD {(VAR F : File_Type; VAR R)} ;
  523.     {
  524.     Update the last retrieved record with data from record R and update any
  525.     index files whose keys were changed. IOERROR usually indicates a duplicate
  526.     key in a unique key index.
  527.     }
  528.   Var
  529.     REC : Array[0..MaxDataRecSize] Of Char Absolute R;
  530.     FLAG : Integer Absolute R;
  531.     S : String[MaxKeyLen];
  532.     K : Integer;
  533.   Begin
  534.     With F Do
  535.       Begin
  536.         IOERROR := False;
  537.         If REC_REF <> 0 Then
  538.           Begin
  539.             FLAG := 0;
  540.             GetRec(DATA_FILE, REC_REF, WORK_REC);
  541.             K := 1;
  542.             While (K <= NUMBER_OF_KEYS) And Not IOERROR Do
  543.               Begin
  544.                 With Key[K] Do
  545.                   Begin
  546.                     KEY_TO_STRING(WORK_REC[Offset], KEYLENGTH, KEYTYPE, UPSHIFT);
  547.                     S := WORK_KEY;
  548.                     KEY_TO_STRING(REC[Offset], KEYLENGTH, KEYTYPE, UPSHIFT);
  549.                     If S <> WORK_KEY Then
  550.                       Begin
  551.                         DeleteKey(INDEX_FILE, REC_REF, S);
  552.                         AddKey(INDEX_FILE, REC_REF, WORK_KEY);
  553.                         FlushIndex(INDEX_FILE);
  554.                         IOERROR := Not OK;
  555.                         If IOERROR Then AddKey(INDEX_FILE, REC_REF, S);
  556.                       End;
  557.                     K := Succ(K);
  558.                   End;
  559.               End;
  560.             If IOERROR Then
  561.               Begin
  562.                 K := Pred(Pred(K));
  563.                 While K > 0 Do
  564.                   Begin
  565.                     With Key[K] Do
  566.                       Begin
  567.                         KEY_TO_STRING(WORK_REC[Offset], KEYLENGTH, KEYTYPE,
  568.                                       UPSHIFT);
  569.                         S := WORK_KEY;
  570.                         KEY_TO_STRING(REC[Offset], KEYLENGTH, KEYTYPE, UPSHIFT);
  571.                         If S <> WORK_KEY Then
  572.                           Begin
  573.                             DeleteKey(INDEX_FILE, REC_REF, WORK_KEY);
  574.                             AddKey(INDEX_FILE, REC_REF, S);
  575.                           End;
  576.                       End;
  577.                     K := Pred(K);
  578.                   End;
  579.               End
  580.             Else
  581.               Begin
  582.                 PutRec(DATA_FILE, REC_REF, REC);
  583.                 FlushFile(DATA_FILE);
  584.               End;
  585.           End
  586.         Else
  587.           IOERROR := True;
  588.       End;
  589.   End;
  590.   {End of MULTIKEY routines}
  591. End.
  592.