home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MKEY.ZIP / MKEYB.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-06-05  |  14.9 KB  |  436 lines

  1. UNIT MkeyB;
  2.  
  3. INTERFACE
  4.  
  5. USES Crt, TPAsciiZ, Btrieve;
  6.  
  7.   {$I-}
  8. CONST
  9.   MaxKeys = 5;
  10.   MaxFields = 25;
  11.   MaxKeyLen = 80;
  12.   MaxDatarecSize = 1024;
  13.   { --------------------- Btrieve Operation Codes ----------------------- }
  14.  
  15.   { Operation codes sent to Btrieve          }
  16.   { ---------------------------------------- }
  17.   AbortTransactionOp = 21;
  18.   BeginTransactionOp = 19;
  19.   ClearOwnerOp = 30;
  20.   CloseOp = 1;
  21.   CreateOp = 14;
  22.   DeleteOp = 4;
  23.   EndTransactionOp = 20;
  24.   ExtendOp = 16;
  25.   GetDirectOp = 23;
  26.   GetEqualOp = 5;
  27.   GetGreaterOp = 8;
  28.   GetGreaterOrEqualOp = 9;
  29.   GetHighestOp = 13;
  30.   GetKeyOp = 50;
  31.   GetLessThanOp = 10;
  32.   GetLessThanOrEqualOp = 11; { Retireves a record with a key value less }
  33.   GetLowestOp = 12;
  34.   GetNextOp = 6;
  35.   GetPositionOp = 22;
  36.   GetPreviousOp = 7;
  37.   InsertOp = 2;
  38.   OpenOp = 0;
  39.   ResetOp = 28;
  40.   SetOwnerOp = 29;
  41.   StatOp = 15;
  42.   StepDirectOp = 24;
  43.   UnlockOp = 27;
  44.   UpdateOp = 3;
  45.   VersionOp = 26;
  46.  
  47.   { -------------------- Extended Key Types Constants ------------------- }
  48.  
  49.   ArrayCharKey = 0; { Array of character     1-255 bytes       }
  50.   SignedIntKey = 1; { Signed whole number    Even # of bytes   }
  51.   FloatKey = 2; { IEEE floating point    4 or 8            }
  52.   DateKey = 3; { Date                   4 bytes           }
  53.   TimeKey = 4; { Time                   4 bytes           }
  54.   DecimalKey = 5; { semi-BCD               1-?? (variable)   }
  55.   MoneyKey = 6; { same as Decimal        1-?? (variable)   }
  56.   LogicalKey = 7; { Logical key            1 or 2 bytes      }
  57.   NumericKey = 8; { Numeric                1-255 variable    }
  58.   BFloatKey = 9; { Old Microsoft float    4 or 8 bytes      }
  59.   lStringKey = 10; { Pascal string          1-254 (255) bytes }
  60.   NullStringKey = 11; { Null terminated string 1-255 bytes       }
  61.   UnsignedIntKey = 14; { Unsigned whole number  Even # of bytes   }
  62.  
  63. TYPE
  64.   KEY_TYPE = (KEY_INTEGER, KEY_CHAR, KEY_STRING, KEY_REAL);
  65.   Field_Type = (Valid_Date_Field, Date_Field, Integer_Field,
  66.                 Real_Field, String_Field, Non_Blank, Memo_Field);
  67.  
  68.   {***** All Date Fields must be a STRING of at LEAST
  69.                        Length 10. Memo fields must be LongInts. All
  70.                        other fields are STRINGS of appropriate lengths *****}
  71.  
  72.  
  73.   ColSeqType = RECORD
  74.                  ColSeqSign : BYTE; { The signature byte }
  75.                  ColSeqName : ARRAY[1..10] OF CHAR;
  76.                  ColSeq : ARRAY[1..10] OF CHAR;
  77.                END; {colseqtype}
  78.   KeyDescrip = RECORD
  79.                  Offset : INTEGER;
  80.                  KEYLENGTH : WORD;
  81.                  Flags : WORD;
  82.                  KEYTYPE : KEY_TYPE;
  83.                  EXTENSION : STRING[3];
  84.                  UNIQUE : BOOLEAN;
  85.                  UPSHIFT : BOOLEAN;
  86.                  INDEX_FILE : FILE;
  87.                END;
  88.   DBField = RECORD
  89.               XCoord : INTEGER;
  90.               YCoord : INTEGER;
  91.               FieldData : ^STRING;
  92.               FieldType : Field_Type;
  93.               FieldLength : INTEGER;
  94.               LegalChars : STRING[80];
  95.               ScreenPrompt : STRING[80];
  96.               HelpPrompt : STRING[80];
  97.             END;
  98.  
  99.   FileSpecType = RECORD
  100.                    CASE BYTE OF
  101.                      0 : (RecSize : WORD; { Record length in bytes }
  102.                           PageSize : WORD; { Page size to use       }
  103.                           Number_of_keys : WORD; { # of keys NOT segments }
  104.                           NumRecs : LONGINT; { # of records in file }
  105.                           FileFlags : WORD; { Bit flags for file     }
  106.                           ReservedWord : WORD; { Fill with $0000        }
  107.                           Allocation : WORD; { # pages to preallocate }
  108.                           {Key : ARRAY[0..MaxKeys] OF KeySpecType;}
  109.                           AltColSeq : ColSeqType); { Alternate col seq }
  110.                      1 : (MinSize : ARRAY[1..128] OF BYTE);
  111.                  END; {FileSpecType}
  112.   File_Type = RECORD
  113.                 Name : STRING[60];
  114.                 PositionBlock : ARRAY[1..128] OF BYTE;
  115.                 IOERROR : BOOLEAN;
  116.                 REC_REF : LONGINT;
  117.                 DATA_FILE : FILE;
  118.                 LastKeyUsed : WORD;
  119.                 Key : ARRAY[0..MaxKeys] OF KeyDescrip;
  120.                 PromptAttribute : INTEGER;
  121.                 GetAttribute : INTEGER;
  122.                 DisplayAttribute : INTEGER;
  123.                 HelpAttribute : INTEGER;
  124.                 NumOfFields : INTEGER;
  125.                 Field : ARRAY[1..MaxFields] OF DBField;
  126.                 FileSpec : FileSpecType;
  127.               END;
  128.  
  129. VAR
  130.   BtError : WORD;
  131.  
  132. FUNCTION KEYOFFSET(VAR R; VAR F) : WORD;
  133. PROCEDURE DebugBt(FileDesc : File_Type; Bt_Error : WORD);
  134. PROCEDURE CLOSE_FILE(VAR F : File_Type; VAR R);
  135. PROCEDURE OPEN_FILE(VAR F : File_Type);
  136. PROCEDURE DELETE_RECORD(VAR F : File_Type; VAR R);
  137. PROCEDURE READ_RECORD(VAR F : File_Type; K : INTEGER; VAR R);
  138. PROCEDURE NEXT_RECORD(VAR F : File_Type; K : INTEGER; VAR R);
  139. PROCEDURE PREVIOUS_RECORD(VAR F : File_Type; K : INTEGER; VAR R);
  140. PROCEDURE ADD_RECORD(VAR F : File_Type; VAR R);
  141. PROCEDURE UPDATE_RECORD(VAR F : File_Type; VAR R);
  142.  
  143.  
  144. IMPLEMENTATION
  145.  
  146.   {$I-}
  147.   {=========================================================================}
  148.   {These are the MULKEY Routines themselves}
  149.   {=========================================================================}
  150.  
  151.   PROCEDURE DebugBt(FileDesc : File_Type; Bt_Error : WORD);
  152.   VAR
  153.     I : WORD;
  154.     Ch : CHAR;
  155.   BEGIN
  156.     IF (Bt_Error <> 0) OR (Bt_Error = 0) THEN
  157.       BEGIN
  158.         WITH FileDesc DO
  159.           BEGIN
  160.             WITH FileSpec DO
  161.               BEGIN
  162.                 WRITELN('RecSize := ', RecSize);
  163.                 WRITELN('PageSize := ', PageSize);
  164.                 WRITELN('Number_of_keys := ', Number_of_keys);
  165.                 WRITELN('LastKeyUsed := ', LastKeyUsed);
  166.                 WRITELN('FileFlags := ', FileFlags);
  167.                 WRITELN('ReservedWord := ', ReservedWord);
  168.                 WRITELN('Allocation := ', Allocation);
  169.                 FOR I := 0 TO Number_of_keys DO
  170.                   BEGIN
  171.                     WITH Key[I] DO
  172.                       BEGIN
  173.                         WRITELN('Key #', I, ' Offset := ', Offset);
  174.                         WRITELN('Key #', I, ' KeyLength := ', KEYLENGTH);
  175.                         WRITELN('Key #', I, ' Flags := ', Flags);
  176.                       END;
  177.                   END; {With Key}
  178.                 WRITELN('Num_Of_Fields := ', NumOfFields);
  179.               END; {with FileSpec}
  180.           END; {with FileDesc}
  181.         WRITELN('Btrieve Error #', Bt_Error);
  182.         Ch := readkey;
  183.       END;      {If Bt_Error}
  184.   END;
  185.  
  186.   FUNCTION KEYOFFSET(VAR R; VAR F) : WORD;
  187.   BEGIN
  188.     {Use to compute the OFFSET parameter of a key}
  189.     KEYOFFSET := (OFS(F) + $8000) - (OFS(R) + $8000);
  190.   END;
  191.  
  192.   PROCEDURE OPEN_FILE(VAR F : File_Type);
  193.     {Opens a multi- key database and all index files, re- builds missing index
  194.     file(s) and database freespace chain}
  195.   TYPE
  196.     BKeySpecType = RECORD
  197.                      Offset : WORD;
  198.                      KEYLENGTH : WORD;
  199.                      Flags : WORD;
  200.                      NotUsed : ARRAY[1..4] OF BYTE;
  201.                      KEYTYPE : BYTE;
  202.                      Reserved : ARRAY[1..5] OF BYTE;
  203.                    END;
  204.     BFileSpecType = RECORD
  205.                       CASE BYTE OF
  206.                         0 : (RecSize : WORD; { Record length in bytes }
  207.                              PageSize : WORD; { Page size to use       }
  208.                              Number_of_keys : WORD; { # of keys NOT segments }
  209.                              NumRecs : LONGINT; { # of records in file }
  210.                              FileFlags : WORD; { Bit flags for file     }
  211.                              ReservedWord : WORD; { Fill with $0000        }
  212.                              Allocation : WORD; { # pages to preallocate }
  213.                              BKey : ARRAY[0..MaxKeys] OF BKeySpecType;
  214.                              AltColSeq : ColSeqType); { Alternate col seq }
  215.                         1 : (MinSize : ARRAY[1..128] OF BYTE);
  216.                     END; {FileSpecType}
  217.  
  218.   VAR
  219.     R : ARRAY[0..MaxDatarecSize] OF BYTE;
  220.     I : INTEGER;
  221.     Bt_Error : WORD ABSOLUTE BtError;
  222.     FileBufSize : WORD;
  223.     Key_Len : WORD;
  224.     FyleName : Asciiz;
  225.     F2 : BFileSpecType;
  226.     J : INTEGER;
  227.  
  228.   BEGIN
  229.     Str2Asc(F.Name, FyleName);
  230.     FILLCHAR(F2, SIZEOF(F2), 0);
  231.     FOR I := 1 TO F.FileSpec.Number_Of_Keys DO
  232.       BEGIN
  233.         F2.BKey[I-1].Offset := F.Key[I].Offset + 1;
  234.         F2.BKey[I-1].KEYLENGTH := F.Key[I].KEYLENGTH;
  235.         F2.BKey[I-1].Flags := F.Key[I].Flags;
  236.         F2.BKey[I-1].KEYTYPE := 10;
  237.       END;
  238.     F2.RecSize := F.FileSpec.RecSize;
  239.     F2.PageSize := F.FileSpec.PageSize;
  240.     F2.Number_of_keys := F.FileSpec.Number_of_keys;
  241.     F2.NumRecs := F.FileSpec.NumRecs;
  242.     F2.FileFlags := F.FileSpec.FileFlags;
  243.     F2.ReservedWord := F.FileSpec.ReservedWord;
  244.     F2.Allocation := F.FileSpec.Allocation;
  245.     I := 0;
  246.     FileBufSize := SIZEOF(F2);
  247.     WITH F DO
  248.       BEGIN
  249.         LastKeyUsed := 0;
  250.         Key_Len := F2.BKey[LastKeyUsed].KEYLENGTH;
  251.         Bt_Error := BTRV(OpenOp, PositionBlock, R, F2.RecSize,
  252.                          FyleName, I, Key_Len);
  253.         IF Bt_Error <> 0 THEN
  254.           BEGIN
  255.             Bt_Error := BTRV(CreateOp, PositionBlock, F2, FileBufSize,
  256.                              FyleName, I, Key_Len);
  257.  
  258.             Bt_Error := BTRV(OpenOp, PositionBlock, R, F2.RecSize,
  259.                              FyleName, I, Key_Len);
  260.             IF Bt_Error <> 0 THEN
  261.               BEGIN
  262.                 HALT(1);
  263.               END;
  264.           END;
  265.         LastKeyUsed := 0;
  266.       END;
  267.   END;
  268.  
  269.   PROCEDURE CLOSE_FILE(VAR F : File_Type; VAR R);
  270.     {Close database and all index files}
  271.   VAR
  272.     Bt_Error : WORD ABSOLUTE BtError;
  273.     FileBufSize : WORD;
  274.     Key_Buf : STRING;
  275.     Key_Len : WORD;
  276.   BEGIN
  277.     FileBufSize := SIZEOF(F);
  278.     WITH F DO
  279.       BEGIN
  280.         Key_Len := Key[LastKeyUsed].KEYLENGTH;
  281.         Bt_Error := BTRV(CloseOp,
  282.                          PositionBlock,
  283.                          FileSpec,
  284.                          FileBufSize,
  285.                          Key_Buf,
  286.                          LastKeyUsed,
  287.                          Key_Len);
  288.         IOERROR := Bt_Error <> 0;
  289.       END;
  290.   END;
  291.  
  292.   PROCEDURE DELETE_RECORD(VAR F : File_Type; VAR R);
  293.     {Delete the last record retrieved from the database and all its keys.
  294.     IOERROR indicates no valid last record retrieved.}
  295.   VAR
  296.     Bt_Error : WORD ABSOLUTE BtError;
  297.     Key_Len, RecSiz : WORD;
  298.   BEGIN
  299.     WITH F DO
  300.       BEGIN
  301.         Key_Len := Key[LastKeyUsed].KEYLENGTH;
  302.         RecSiz := FileSpec.RecSize;
  303.         Bt_Error := BTRV(GetEqualOp, PositionBlock, R, RecSiz,
  304.                          PTR(SEG(R), OFS(R) +
  305.                              Key[LastKeyUsed].Offset)^,
  306.                          LastKeyUsed -1,
  307.                          Key_Len);
  308.         Bt_Error := BTRV(DeleteOp, PositionBlock, R, RecSiz,
  309.                          PTR(SEG(R), OFS(R) +
  310.                              Key[LastKeyUsed].Offset)^,
  311.                          LastKeyUsed-1,
  312.                          Key_Len);
  313.         IOERROR := Bt_Error <> 0;
  314.       END;
  315.   END;
  316.  
  317.   PROCEDURE READ_RECORD(VAR F : File_Type; K : INTEGER; VAR R);
  318.     {Read a record from the database with a key equal to or higher than that
  319.     indicated by key field K in record R. IOERROR indicates search key was
  320.     higher than any in the index.}
  321.   VAR
  322.     Bt_Error : WORD ABSOLUTE BtError;
  323.     Key_Len : WORD;
  324.     I : word;
  325.     S_Ptr : ^STRING;
  326.     WorkBuffer, HoldBuffer, Blanks : STRING;
  327.   BEGIN
  328.     WITH F DO
  329.       BEGIN
  330.         LastKeyUsed := K;
  331.         Key_Len := Key[LastKeyUsed].KEYLENGTH;
  332.         S_Ptr := PTR(SEG(R), OFS(R) + Key[LastKeyUsed].Offset);
  333.         HoldBuffer := S_Ptr^ ;
  334.         WorkBuffer := '';
  335.         Bt_Error := BTRV(GetLowestOp, PositionBlock, R,
  336.                          FileSpec.RecSize,
  337.                          WorkBuffer,
  338.                          K - 1, Key_Len);
  339.         Bt_Error := BTRV(GetGreaterOrEqualOp, PositionBlock,
  340.                          R, FileSpec.RecSize,
  341.                          HoldBuffer,
  342.                          K - 1, Key_Len);
  343.         IOERROR := Bt_Error <> 0;
  344.       END;
  345.   END;
  346.  
  347.   PROCEDURE NEXT_RECORD(VAR F : File_Type; K : INTEGER; VAR R);
  348.     {Read the next record by key K from the database. IOERROR indicates end of
  349.     file by key K.}
  350.   VAR
  351.     Bt_Error : WORD ABSOLUTE BtError;
  352.     Key_Len : WORD;
  353.   BEGIN
  354.     WITH F DO
  355.       BEGIN
  356.         Key_Len := Key[LastKeyUsed].KEYLENGTH;
  357.         Bt_Error := BTRV(GetNextOp, PositionBlock, R,
  358.                          FileSpec.RecSize,
  359.                          PTR(SEG(R), OFS(R)
  360.                              + Key[LastKeyUsed].Offset)^,
  361.                          LastKeyUsed-1, Key_Len);
  362.         IOERROR := Bt_Error <> 0;
  363.       END;
  364.   END;
  365.  
  366.   PROCEDURE PREVIOUS_RECORD(VAR F : File_Type; K : INTEGER; VAR R);
  367.     {Read the previous record by key K from the database. IOERROR indicates start
  368.     of file by key K.}
  369.   VAR
  370.     Bt_Error : WORD ABSOLUTE BtError;
  371.     Key_Len : WORD;
  372.   BEGIN
  373.     WITH F DO
  374.       BEGIN
  375.         Key_Len := Key[LastKeyUsed].KEYLENGTH;
  376.         Bt_Error := BTRV(GetPreviousOp, PositionBlock, R,
  377.                          FileSpec.RecSize,
  378.                          PTR(SEG(R), OFS(R)
  379.                              + Key[LastKeyUsed].Offset)^,
  380.                          LastKeyUsed-1, Key_Len);
  381.         IOERROR := Bt_Error <> 0;
  382.       END;
  383.   END;
  384.  
  385.  
  386.   PROCEDURE ADD_RECORD(VAR F : File_Type; VAR R);
  387.     {
  388.     Add record R to the database and update all index files. IOERROR usually
  389.     indicates a duplicate key in a unique key index.
  390.     }
  391.   VAR
  392.     Bt_Error : WORD ABSOLUTE BtError;
  393.     Key_Len, Posit : WORD;
  394.     P : ^String;
  395.     WorkBuffer : String;
  396.   BEGIN
  397.     WITH F DO
  398.       BEGIN
  399.         Posit := Key[1].Offset;
  400.         P := PTR(SEG(R), OFS(R) + (Posit));
  401.         WorkBuffer := P^;
  402.         Key_Len := Key[1].KEYLENGTH;
  403.         Bt_Error := BTRV(InsertOp, PositionBlock, R,
  404.                          FileSpec.RecSize,
  405.                          WorkBuffer,
  406.                          0, Key_Len);
  407.         IOERROR := Bt_Error <> 0;
  408.       END;
  409.   END;
  410.  
  411.   PROCEDURE UPDATE_RECORD(VAR F : File_Type; VAR R);
  412.     {
  413.     Update the last retrieved record with data from record R and update any
  414.     index files whose keys were changed. IOERROR usually indicates a duplicate
  415.     key in a unique key index.
  416.     }
  417.   VAR
  418.     Bt_Error : WORD ABSOLUTE BtError;
  419.     Key_Len : WORD;
  420.   BEGIN
  421.     WITH F DO
  422.       BEGIN
  423.         Key_Len := Key[LastKeyUsed].KEYLENGTH;
  424.         Bt_Error := BTRV(UpdateOp, PositionBlock, R,
  425.                          FileSpec.RecSize,
  426.                          PTR(SEG(R), OFS(R)
  427.                              + Key[LastKeyUsed].Offset)^,
  428.                          LastKeyUsed-1, Key_Len);
  429.         IOERROR := Bt_Error <> 0;
  430.       END;
  431.   END;
  432.  
  433.  
  434.   {End of MULTIKEY routines}
  435. END.
  436.