home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / btree / tree / files.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-07-13  |  23.1 KB  |  586 lines

  1. (* TBTree16             Copyright (c)  1988,1989       Dean H. Farwell II    *)
  2.  
  3. unit Files;
  4.  
  5. (*****************************************************************************)
  6. (*                                                                           *)
  7. (*                 F I L E  H A N D L I N G  R O U T I N E S                 *)
  8. (*                                                                           *)
  9. (*****************************************************************************)
  10.  
  11. (* This unit is used to create, delete and check the existence of files. There
  12.    are currently three types of files: DATA, INDEX and LLIST.  The data files
  13.    are used to hold user data.  The INDEX files can be used to hold an index
  14.    for a given DATA file.  The LLIST files are for holding logical record
  15.    lists which take up more than one disk page and must be stored on disk (or
  16.    in the page buffer).
  17.  
  18.    This unit also serves another purpose.  It has routines for handling the
  19.    bitmap records for files requiring them.  DATA files and INDEX files both
  20.    require bitmaps which serve to mark records as being either used or unused.
  21.    The bitmap records are always the last records in the file and are moved
  22.    down to make space as new records are added to the file.  This is all
  23.    accomplished automatically without user intervention.  You should never
  24.    need to access bitmap records explicitly.
  25.  
  26.    Most of the routines provided are for internal use only and should not be
  27.    used within applications.  There are several exceptions however.  The first
  28.    exception to this is the FileExists routine which is handy and can be used
  29.    freely without problems.  The other exceptions are the FetchUserDataArray,
  30.    SaveUserDataArray and FetchFileVersion routines.                          *)
  31.  
  32. (*\*)
  33. (* Version Information
  34.  
  35.    Version 1.1 - No Changes
  36.  
  37.    Version 1.2 - No Changes
  38.  
  39.    Version 1.3 - No Changes
  40.  
  41.    Version 1.4 - Added FileExists routine
  42.  
  43.                - Totally redefined the role of the unit.  The purpose of the
  44.                  unit is as stated above.  Most routines have been removed or
  45.                  replaced.  Fully read and understand the comments provided
  46.                  with the unit
  47.  
  48.    Version 1.5 - Changed code internally to use Inc and Dec where practical
  49.  
  50.                - Changed code internally to use newly added FastMove unit
  51.  
  52.    Version 1.6 - Changed CreateGenericFile such that it will delete the file
  53.                  (if it exists) before creating it.  If the file is being
  54.                  recreated, the buffer will be purged of any lingering pages
  55.                  from the old file
  56.  
  57.                - Moved the parameter record routines from the LOGICAL unit and
  58.                  BTREE unit to this unit.  This will slightly reduce
  59.                  redundancy and the overall code for an application.  This is
  60.                  completely transparent to the user.
  61.  
  62.                - Fixed an error to MoveRecords (used only internally) which
  63.                  would cause catestrophic problems with large files.  Also
  64.                  made routine more generic.  This routine is not normally used
  65.                  except internally.
  66.  
  67.                - Added FetchFileType routine                                 *)
  68.  
  69. (*\*)
  70. (*////////////////////////// I N T E R F A C E //////////////////////////////*)
  71.  
  72. interface
  73.  
  74. uses
  75.     Dos,
  76.     FastMove,
  77.     FileBuff,
  78.     FileDecs,
  79.     Math,
  80.     Numbers,
  81.     Page;
  82.  
  83.  
  84. (* This creates a file.  This routine should NEVER be used (except
  85.    internally by TBTREE).  There are specific routines available designed to
  86.    create DATA, VLRDATA and INDEX files.  Do not use this routine!!!!        *)
  87.  
  88. procedure CreateGenericFile(var fName : FnString);
  89.  
  90.  
  91. (* This routine will delete a file.  This routine should NEVER be used (except
  92.    internally by TBTREE).  There are specific routines available designed to
  93.    delete DATA, VLRDATA and INDEX files.  Do not use this routine!!!!        *)
  94.  
  95. procedure DeleteGenericFile(fName : FnString);
  96.  
  97.  
  98. (* This routine will check to see if a given file exists.  It is safe to use
  99.    this routine for checking the existence of any file.  The routine is handy
  100.    for an application which must work whther the file has already been created
  101.    on not.  Two examples of use follow:
  102.  
  103.             if not FileExists(myDataFile) then
  104.                 begin
  105.                 CreateDataFile(myDataFile,SizeOf(myDataRecord));
  106.                 end;
  107.  
  108.  
  109.             if not FileExists(myIndexFile) then
  110.                 begin
  111.                 CreateIndexFile(myIndexFile,SizeOf(Byte),BYTEVALUE);
  112.                 end;
  113.  
  114.     Notice the difference in usage for a DATA file and an INDEX file         *)
  115.  
  116. function FileExists(fName : FnString) : Boolean;
  117.  
  118. (*\*)
  119. (* This routine will fetch and return the user data array from the given DATA,
  120.    VLRDATA or INDEX file.  The array will be returned via the userData
  121.    parameter passed in.                                                      *)
  122.  
  123. procedure FetchUserDataArray(fName : FnString;
  124.                              var userData : UserDataArray);
  125.  
  126.  
  127. (* This routine will store the user data array into the parameter record of
  128.    the given DATA, VLRDATA or INDEX file.                                    *)
  129.  
  130. procedure SaveUserDataArray(fName : FnString;
  131.                              userData : UserDataArray);
  132.  
  133.  
  134. (* This routine will return a string which tells which version of TBTREE was
  135.    used to create the DATA or INDEX.  It should only be used for a file of
  136.    type DATA, VLRDATA or INDEX.                                              *)
  137.  
  138. procedure FetchFileVersion(fName : FnString;
  139.                            var verString : VersionString);
  140.  
  141.  
  142. (* This routine will return the file type for the given file.  The returned
  143.    value is of type FileTypes.                                               *)
  144.  
  145. function FetchFileType(fName : FnString) : FileTypes;
  146.  
  147.  
  148. (* **********      **********       **********        **********     *********
  149.    All of the following routines are for internal use only!!!!!  Do not use
  150.    these routines!!!!!!!!!
  151.    **********      **********       **********        **********     *********)
  152.  
  153. (* This procedure will read the zeroth physical record from the given file and
  154.    return the number of bytes requested in the variable pRec.                *)
  155.  
  156. procedure FetchFileParameters(var dFName : FnString;   (* var for speed only *)
  157.                               var pRec;
  158.                               size : PageRange);
  159.  
  160.  
  161. (* This procedure will copy the contents of pRec and save it to the zeroth
  162.    physical record in the data file.                                         *)
  163.  
  164. procedure SaveFileParameters(var dFName : FnString;    (* var for speed only *)
  165.                              var pRec;
  166.                              size : PageRange);
  167.  
  168. (*\*)
  169. (* This routine will calculate the physical record number corresponding to the
  170.    given record number (rNum).  firstBMRec is needed as the starting
  171.    location.                                                                 *)
  172.  
  173. function CalculateBitmapRecord(firstBMRec : PrNumber;
  174.                                rNum : RecordNumber) : PrNumber;
  175.  
  176.  
  177. (* This routine will perform two important functions.  First, it will set the
  178.    bit corresponding to rNum to show that the record is used.  Second, it will
  179.    find the next available record number and will return that record number.
  180.    It may require the addition of one bitmap record to do that.  If this is
  181.    required, it will be performed automatically.                             *)
  182.  
  183. function FindNextAvailInBitmap(fName : FnString;
  184.                                firstBMRec : PrNumber;
  185.                                var lastBMRec : PrNumber;
  186.                                rNum : RecordNumber) : RecordNumber;
  187.  
  188.  
  189. (* This routine will move records for the given file down n records.  This
  190.    will free up n physical records for use.  The first record to be moved is
  191.    passed in firstRec and the last record to move is lastRec.  lastRec must be
  192.    the last physical record in the file.  firstRec and lastRec will be
  193.    returned with values updated to reflect where the records now reside.     *)
  194.  
  195. procedure MoveRecords(fName : FnString;
  196.                       var firstRec : PrNumber;
  197.                       var lastRec : PrNumber;
  198.                       n : PrNumber);
  199.  
  200.  
  201. (* This routine will set the bit associated with rNum in the file fName to
  202.    the desired value. It will calculate the correct bitmap record and read it
  203.    in, set the bit to the value specified by bit (the parameter of type
  204.    BitValue passed in) and store the bitmap record.                          *)
  205.  
  206. procedure SetBitInBitmap(fName : FnString;
  207.                          firstBMRec : PrNumber;
  208.                          rNum : RecordNumber;
  209.                          bit : BitValue);
  210.  
  211.  
  212. (* This routine will check to see if the bit associated with rNum in the file
  213.    fName is set or not.  The routine will return TRUE if the bit is set.     *)
  214.  
  215. function CheckBitInBitmap(fName : FnString;
  216.                           firstBMRec : PrNumber;
  217.                           rNum : RecordNumber) : Boolean;
  218.  
  219. (*!*)
  220. (*\*)
  221. (*///////////////////// I M P L E M E N T A T I O N /////////////////////////*)
  222.  
  223. implementation
  224.  
  225. const
  226.     FILETYPELOC = 276;
  227.  
  228. (* This creates a file.  This routine should NEVER be used (except
  229.    internally by TBTREE).  There are specific routines available designed to
  230.    create DATA, VLRDATA and INDEX files.  Do not use this routine!!!!        *)
  231.  
  232. procedure CreateGenericFile(var fName : FnString);
  233.  
  234. var
  235.     tempFile : File;
  236.  
  237.     begin
  238.     DeleteGenericFile(fName);   (* This will delete the file and clear any
  239.                                    pages for this file out of the buffer.
  240.                                    This will only happen if the file exists  *)
  241.     RewriteUntypedFile(fName,tempFile,PAGESIZE);  (* force creation of new
  242.                                                      file
  243.                                                      - will rewrite old file
  244.                                                      if it exists            *)
  245.     end;                                 (* end of CreateGenericFile routine *)
  246.  
  247.  
  248. (* This routine will delete a file.  This routine should NEVER be used (except
  249.    internally by TBTREE).  There are specific routines available designed to
  250.    delete DATA, VLRDATA and INDEX files.  Do not use this routine!!!!        *)
  251.  
  252. procedure DeleteGenericFile(fName : FnString);
  253.  
  254. var
  255.     tempFile : File;
  256.  
  257.     begin
  258.     if FileExists(fName) then
  259.         begin
  260.         ReleaseAllPages(fName);                (* release all pages for this
  261.                                                         file from the buffer *)
  262.         OpenUntypedFile(fName,tempFile,PAGESIZE);  (* needed to get the file
  263.                                                         id (tempFile)        *)
  264.         CloseFile(fName);
  265.         Erase(tempFile);
  266.         end;
  267.     end;                                        (* end of DeleteFile routine *)
  268.  
  269. (*\*)
  270. (* This routine will check to see if a given file exists.  It is safe to use
  271.    this routine for checking the existence of any file.  The routine is handy
  272.    for an application which must work whether the file has already been
  273.    created on not.  Two examples of use follow:
  274.  
  275.             if not FileExists(myDataFile) then
  276.                 begin
  277.                 CreateDataFile(myDataFile,SizeOf(myDataRecord));
  278.                 end;
  279.  
  280.             if not FileExists(myIndexFile) then
  281.                 begin
  282.                 CreateIndexFile(myIndexFile,SizeOf(Byte),BYTEVALUE);
  283.                 end;
  284.  
  285.     Notice the difference in usage for a DATA file and an INDEX file         *)
  286.  
  287. function FileExists(fName : FnString) : Boolean;
  288.  
  289. var
  290.     dummy : SearchRec;                   (* SearchRec is defined in DOS unit *)
  291.  
  292.     begin
  293.     FindFirst(fName,ANYFILE,dummy);
  294.     if DosError = 0 then
  295.         begin
  296.         FileExists := TRUE;
  297.         end
  298.     else
  299.         begin
  300.         FileExists := FALSE;
  301.         end;
  302.     end;                                        (* end of FileExists routine *)
  303.  
  304. (*\*)
  305. (* This routine will fetch and return the user data array from the given DATA,
  306.    VLRDATA or INDEX file.  The array will be returned via the userData
  307.    parameter passed in.                                                      *)
  308.  
  309. procedure FetchUserDataArray(fName : FnString;
  310.                              var userData : UserDataArray);
  311.  
  312. var
  313.     page : SinglePage;
  314.  
  315.     begin
  316.     FetchPage(fName,0,page);
  317.     FastMover(page,userData,SizeOf(userData));
  318.     end;                                (* end of FetchUserDataArray routine *)
  319.  
  320.  
  321. (* This routine will store the user data array into the parameter record of
  322.    the given DATA, VLRDATA or INDEX file.                                    *)
  323.  
  324. procedure SaveUserDataArray(fName : FnString;
  325.                              userData : UserDataArray);
  326.  
  327. var
  328.     page : SinglePage;
  329.  
  330.     begin
  331.     FetchPage(fName,0,page);
  332.     FastMover(userData,page,SizeOf(userData));
  333.     StorePage(fName,0,page);
  334.     end;                                 (* end of SaveUserDataArray routine *)
  335.  
  336. (*\*)
  337. (* This routine will return a string which tells which version of TBTREE was
  338.    used to create the DATA or INDEX.  It should only be used for a file of
  339.    type DATA, VLRDATA or INDEX.                                              *)
  340.  
  341. procedure FetchFileVersion(fName : FnString;
  342.                            var verString : VersionString);
  343.  
  344. var
  345.     page : SinglePage;
  346.  
  347.     begin
  348.     FetchPage(fName,0,page);
  349.     FastMover(page[SizeOf(UserDataArray) + 1],verString,SizeOf(verString));
  350.     end;                                (* end of FetchVersionFile procedure *)
  351.  
  352.  
  353. (* This routine will return the file type for the given file.  The returned
  354.    value is of type FileTypes.                                               *)
  355.  
  356. function FetchFileType(fName : FnString) : FileTypes;
  357.  
  358. var
  359.     page : SinglePage;
  360.  
  361.     begin
  362.     FetchPage(fName,0,page);
  363.     FetchFileType := FileTypes(page[FILETYPELOC]);
  364.     end;                                     (* end of FetchFileType routine *)
  365.  
  366. (*\*)
  367. (* This routine will move records for the given file down n records.  This
  368.    will free up n physical records for use.  The first record to be moved is
  369.    passed in firstRec and the last record to move is lastRec.  lastRec must be
  370.    the last physical record in the file.  firstRec and lastRec will be
  371.    returned with values updated to reflect where the records now reside.     *)
  372.  
  373. procedure MoveRecords(fName : FnString;
  374.                       var firstRec : PrNumber;
  375.                       var lastRec : PrNumber;
  376.                       n : PrNumber);
  377.  
  378. var
  379.     zeroPage,
  380.     page : SinglePage;
  381.     cnt : PrNumber;
  382.  
  383.     begin
  384.     FillChar(zeroPage,PAGESIZE,0);                      (* zero out old page *)
  385.     for cnt := lastRec downto firstRec do
  386.         begin
  387.         FetchPage(fName,cnt,page);
  388.         StorePage(fName,cnt + n,page);
  389.         StorePage(fName,cnt,zeroPage);      (* store empty page in old place *)
  390.         end;
  391.     Inc(firstRec,n);
  392.     Inc(lastRec,n);
  393.     end;                                       (* end of MoveRecords routine *)
  394.  
  395.  
  396. (* This routine will calculate the bit location for the given record
  397.    number (rNum).  firstBMRec is needed as the starting location.  The
  398.    location is returned in prNum, byteNum and bitNum.  The routine does not
  399.    affect the bitmaps themselves.                                            *)
  400.  
  401. procedure CalculateBitmapBitLocation(firstBMRec : PrNumber;
  402.                                      rNum : RecordNumber;
  403.                                      var prNum : PrNumber;
  404.                                      var byteNum : PageRange;
  405.                                      var bitNum : BytePosition);
  406.  
  407.     begin
  408.     prNum := ((rNum - 1) Div (8 * PAGESIZE)) + firstBMRec;
  409.     byteNum := (((rNum - 1) Mod (8 * PAGESIZE)) Div 8) + 1;
  410.     bitNum := (rNum - 1) Mod 8;
  411.     bitNum := (bitNum Xor 7) And 7;    (* this will yield the correct bit
  412.                                           position within the byte. This is
  413.                                           necessary because bit 7 (most
  414.                                           significant) in the byte is the
  415.                                           existence bit for the first record
  416.                                           not the eighth *)
  417.     end;                        (* end of CalculateBitmapBitLocation routine *)
  418.  
  419. (*\*)
  420. (* This procedure will read the zeroth physical record from the given file and
  421.    return the number of bytes requested in the variable pRec.                *)
  422.  
  423. procedure FetchFileParameters(var dFName : FnString;   (* var for speed only *)
  424.                               var pRec;
  425.                               size : PageRange);
  426.  
  427. var
  428.     page : SinglePage;
  429.  
  430.     begin
  431.     FetchPage(dFName,0,page);
  432.     FastMover(page,pRec,size);
  433.     end;                            (* end of FetchFileParameters procedure *)
  434.  
  435.  
  436. (* This procedure will copy the contents of pRec and save it to the zeroth
  437.    physical record in the data file.                                         *)
  438.  
  439. procedure SaveFileParameters(var dFName : FnString;    (* var for speed only *)
  440.                              var pRec;
  441.                              size : PageRange);
  442.  
  443. var
  444.     page : SinglePage;
  445.  
  446.     begin
  447.     FetchPage(dFName,0,page);
  448.     FastMover(pRec,page,size);
  449.     StorePage(dFName,0,page);
  450.     end;                              (* end of SaveFileParameters procedure *)
  451.  
  452.  
  453. (* This routine will calculate the physical record number corresponding to the
  454.    given record number (rNum).  firstBMRec is needed as the starting
  455.    location.                                                                 *)
  456.  
  457. function CalculateBitmapRecord(firstBMRec : PrNumber;
  458.                                rNum : RecordNumber) : PrNumber;
  459.  
  460.     begin
  461.     CalculateBitmapRecord := ((rNum - 1) Div (8 * PAGESIZE)) + firstBMRec;
  462.     end;                          (* end of CalculateBitmapBitRecord routine *)
  463.  
  464. (*\*)
  465. (* This routine will perform two important functions.  First, it will set the
  466.    bit corresponding to rNum to show that the record is used.  Second, it will
  467.    find the next available record number and will return that record number.
  468.    It may require the addition of one bitmap record to do that.  If this is
  469.    required, it will be performed automatically.                             *)
  470.  
  471. function FindNextAvailInBitmap(fName : FnString;
  472.                                firstBMRec : PrNumber;
  473.                                var lastBMRec : PrNumber;
  474.                                rNum : RecordNumber) : RecordNumber;
  475.  
  476. var
  477.     page : SinglePage;                             (* copy of page in buffer *)
  478.     prNum : PrNumber;
  479.     byteNum : PageRange;                        (* byte position within page *)
  480.     bitNum : BytePosition;                       (* bit position within byte *)
  481.     done : Boolean;                                             (* byte loop *)
  482.  
  483.     begin
  484.     CalculateBitmapBitLocation(firstBMRec,rNum,prNum,byteNum,bitNum);
  485.     FetchPage(fName,prNum,page);
  486.     SetBit(page[byteNum],bitNum,1);
  487.     StorePage(fName,prNum,page);
  488.     while TRUE do                                      (* BITMAP record loop *)
  489.         begin
  490.         done := FALSE;
  491.         while not done do                                       (* byte loop *)
  492.             begin
  493.             if page[byteNum] <> MAXBYTE then
  494.                               (* the check against MAXBYTE is for efficiency
  495.                                since it will preclude checking individual
  496.                                bits for a byte in which all bits are set
  497.                                to one                                        *)
  498.                 begin
  499.                 bitNum := 7;
  500.                 while TRUE do
  501.                     begin                                        (* bit loop *)
  502.                     if not BitOn(page[byteNum],bitNum) then
  503.                         begin
  504.                         FindNextAvailInBitmap := ((prNum - firstBMRec) *
  505.                                                   PAGESIZE * 8) +
  506.                                                  ((byteNum - 1) * 8) +
  507.                                                  (8 - bitNum);
  508.                         Exit;                     (* only way out of routine *)
  509.                         end
  510.                     else
  511.                         begin
  512.                         Dec(bitNum);
  513.                         end;
  514.                     end;
  515.                 end;
  516.             if byteNum = PAGESIZE then
  517.                 begin
  518.                 done := TRUE;
  519.                 end
  520.             else
  521.                 begin
  522.                 Inc(byteNum);
  523.                 end;
  524.             end;
  525.         Inc(prNum);
  526.         byteNum := 1;
  527.         if PageExists(fName,prNum) then           (* if not past last record *)
  528.             begin
  529.             FetchPage(fName,prNum,page);              (* get next b m record *)
  530.             end
  531.         else
  532.             begin
  533.             FillChar(page,PAGESIZE,0);              (* create new record page
  534.                                                      for this bit map record *)
  535.             StorePage(fName,prNum,page);              (* store the new page *)
  536.             lastBMRec := prNum;                (* update value of lastBMRec *)
  537.             end;
  538.         end;
  539.     end;                             (* end of FindNextAvailInBitmap routine *)
  540.  
  541. (*\*)
  542. (* This routine will set the bit associated with rNum in the file fName to
  543.    the desired value. It will calculate the correct bitmap record and read it
  544.    in, set the bit to the value specified by bit (the parameter of type
  545.    BitValue passed in) and store the bitmap record.                          *)
  546.  
  547. procedure SetBitInBitmap(fName : FnString;
  548.                          firstBMRec : PrNumber;
  549.                          rNum : RecordNumber;
  550.                          bit : BitValue);
  551.  
  552. var
  553.     page : SinglePage;
  554.     prNum : PrNumber;
  555.     byteNum : PageRange;
  556.     bitNum : BytePosition;
  557.  
  558.     begin
  559.     CalculateBitmapBitLocation(firstBMRec,rNum,prNum,byteNum,bitNum);
  560.     FetchPage(fName,prNum,page);
  561.     SetBit(page[byteNum],bitNum,bit);
  562.     StorePage(fName,prNum,page);
  563.     end;                                    (* end of SetBitInBitmap routine *)
  564.  
  565. (*\*)
  566. (* This routine will check to see if the bit associated with rNum in the file
  567.    fName is set or not.  The routine will return TRUE if the bit is set.     *)
  568.  
  569. function CheckBitInBitmap(fName : FnString;
  570.                           firstBMRec : PrNumber;
  571.                           rNum : RecordNumber) : Boolean;
  572.  
  573. var
  574.     page : SinglePage;
  575.     prNum : PrNumber;
  576.     byteNum : PageRange;
  577.     bitNum : BytePosition;
  578.  
  579.     begin
  580.     CalculateBitmapBitLocation(firstBMRec,rNum,prNum,byteNum,bitNum);
  581.     FetchPage(fName,prNum,page);
  582.     CheckBitInBitmap := BitOn(page[byteNum],bitNum);
  583.     end;                                    (* end of SetBitInBitmap routine *)
  584.  
  585. end.                                                    (* end of Files unit *)
  586.