home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TBTREE.ZIP / LOGICAL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-07-31  |  13.1 KB  |  324 lines

  1. (* TBTree13             Copyright (c)  1988            Dean H. Farwell II    *)
  2.  
  3. unit Logical;
  4.  
  5. (*****************************************************************************)
  6. (*                                                                           *)
  7. (*              L O G I C A L  R E C O R D  R O U T I N E S                  *)
  8. (*                                                                           *)
  9. (*****************************************************************************)
  10.  
  11.  
  12. (* This unit is used to manipulate logical records.  A logical record is made
  13.    some number of bytes.  The minimum logical record size is one byte.  The
  14.    maximum size is MAXDATASIZE (MAXWORD = 65535).  Depending on the size of
  15.    logical and physical records, many logical records could reside in a single
  16.    physical record or a logical record could use many physical records.  In the
  17.    later case contiguous physical records are used.  Since fixed logical and
  18.    physical record sizes are used the physical records used for a logical
  19.    record can easily be calculated.                                          *)
  20.  
  21.  
  22. (* Version Information
  23.  
  24.    Version 1.1 - Added GetValidLogicalRecords routine
  25.  
  26.    Version 1.2 - Removed several types which were not used
  27.  
  28.                - Removed CalculateRecordSize routine
  29.                  This routine was not used and was for future enhancements
  30.  
  31.    Version 1.3 - Changed MAXDATASIZE to 65520 which is the maximum
  32.                  number of bytes for a structued type in Turbo Pascal 4.0
  33.  
  34.                - Added StoreNewLogicalRecord routine                         *)
  35.  
  36. (*\*)
  37. (*////////////////////////// I N T E R F A C E //////////////////////////////*)
  38.  
  39. interface
  40.  
  41. uses
  42.     Compare,
  43.     FileDecs,
  44.     Files,
  45.     LRecList,
  46.     Numbers,
  47.     Page;
  48.  
  49. const
  50.     MAXDATASIZE = 65520;       (* max number of bytes for a logical record   *)
  51.  
  52. type
  53.     DataSizeRange = 1 .. MAXDATASIZE;     (* range for size of a field
  54.                                             (attribute.  Also maximum number of
  55.                                              bytes in a logical record       *)
  56.  
  57. (*\*)
  58. (* This routine will get a logical record from a given data file and will put
  59.    the record into a memory location.  The location will be destination.  Size
  60.    is used to pass the number of bytes contained in the logical record.  The
  61.    BITMAP will be checked to ensure that the record is in use (that it exists).
  62.    If it is in use then it is fetched.  Otherwise, nothing will be returned in
  63.    destination.  Before calling this routine, you can check to see if the
  64.    logical record exists.  If it was retrieved from an index then it exists
  65.    (unless the record was deleted and it wasn't deleted from the index.  You
  66.    can use RecordUsed(fName,lrNum) to check for the existence of the record
  67.    before calling this if there is a possibility thet the record doesn't
  68.    exist.                                                                    *)
  69.  
  70. procedure GetALogicalRecord(fName : FnString;
  71.                             lrNum : LrNumber;
  72.                             var destination;
  73.                             size : DataSizeRange);
  74.  
  75.  
  76. (* This routine will store a logical record for a given DATA file.  The routine
  77.    will set the logical record to used and will create the appropriate physical
  78.    record(s) if required (StorePage will do this automatically).  The logical
  79.    record size is size and the data must reside in source.  This routine is
  80.    only used if the logical record number is known.  If a new record is to be
  81.    stored use StoreNewLogicalRecord rather than this routine                 *)
  82.  
  83. procedure StoreALogicalRecord(fName : FnString;
  84.                               lrNum : LrNumber;
  85.                               var source;
  86.                               size : DataSizeRange);
  87.  
  88.  
  89. (* This routine will store a new logical record for a given DATA file.  The
  90.    routine will set the logical record to used and will create the appropriate physical
  91.    record(s) if required (StorePage will do this automatically).  The logical
  92.    record size is size and the data must reside in source.  Normally, when
  93.    inserting new records, you will not know the next unused logical record
  94.    number.  This routine will assign the appropriate logical record number so
  95.    that you won't have to worry about it.  The routine will return the logical
  96.    record number which will be associated with this record upon return.  You
  97.    will need this returned logical record number if there are any indexes
  98.    associated with this DATA file.                                           *)
  99.  
  100. function StoreNewLogicalRecord(fName : FnString;
  101.                                 var source;
  102.                                 size : DataSizeRange) : LrNumber;
  103.  
  104.  
  105. (* This routine will return a list of logical records which are currently in
  106.    use (contain valid data) for a given data file.  This routine is necessary
  107.    to be able to process all records which have not been deleted without
  108.    using an index.                                                           *)
  109.  
  110. procedure GetValidLogicalRecords(fName : FnString;
  111.                                  var lrLst : LrList);
  112.  
  113. (*\*)
  114. (*///////////////////// I M P L E M E N T A T I O N /////////////////////////*)
  115.  
  116. implementation
  117.  
  118.  
  119. (* This routine will calculate the physical record number and the byte location
  120.    within the physical record for a given logical record.  The logical record
  121.    and the logical record sizes are passed as parameters.                    *)
  122.  
  123. procedure ConvertLogicalToPhysical(lrNum : LrNumber;
  124.                                    lrSize : DataSizeRange;
  125.                                    var prNum : PrNumber;
  126.                                    var firstByte : PageRange);
  127.  
  128. var
  129.     bf : DataSizeRange;                                  (* blocking factor *)
  130.  
  131.     begin
  132.     if lrSize < PAGESIZE then
  133.         begin
  134.         bf := Trunc(PAGESIZE / lrSize);
  135.         prNum := Trunc((lrNum - 1) / bf) + 1;
  136.         firstByte := ((lrNum - ((bf * (prNum - 1)) + 1)) * lrSize) + 1;
  137.         end
  138.     else
  139.         begin
  140.         bf := Trunc((lrSize - 1) / PAGESIZE) + 1;
  141.         prNum := ((lrNum - 1) * bf) + 1;
  142.         firstByte := 1;
  143.         end;
  144.     end;                          (* end of ConvertLogicalToPhysical routine *)
  145.  
  146. (*\*)
  147. (* This routine will get a logical record from a given data file and will put
  148.    the record into a memory location.  The location will be destination.  Size
  149.    is used to pass the number of bytes contained in the logical record.  The
  150.    BITMAP will be checked to ensure that the record is in use (that it exists).
  151.    If it is in use then it is fetched.  Otherwise, nothing will be returned in
  152.    destination.  Before calling this routine, you can check to see if the
  153.    logical record exists.  If it was retrieved from an index then it exists
  154.    (unless the record was deleted and it wasn't deleted from the index.  You
  155.    can use RecordUsed(fName,lrNum) to check for the existence of the record
  156.    before calling this if there is a possibility thet the record doesn't
  157.    exist.                                                                    *)
  158.  
  159. procedure GetALogicalRecord(fName : FnString;
  160.                             lrNum : LrNumber;
  161.                             var destination;
  162.                             size : DataSizeRange);
  163.  
  164. type
  165.     MemoryArray = array [DataSizeRange] of byte;
  166.  
  167. var
  168.     prNum : PrNumber;
  169.     firstByte : PageRange;
  170.     page : SinglePage;
  171.     byteCnt : DataSizeRange;
  172.     memory : MemoryArray absolute destination;
  173.     done : Boolean;
  174.  
  175.     begin
  176.     if RecordUsed(fName,lrNum) then
  177.         begin
  178.         ConvertLogicalToPhysical(lrNum,size,prNum,firstByte);
  179.         if size <= PAGESIZE then
  180.             begin
  181.             FetchPage(fName,prNum,page);
  182.             Move(page[firstByte],destination,size);
  183.             end
  184.         else
  185.             begin
  186.             byteCnt := 1;
  187.             done := FALSE;
  188.             while not done do
  189.                 begin
  190.                 FetchPage(fName,prNum,page);
  191.                 if size > PAGESIZE then
  192.                     begin
  193.                     Move(page[firstByte],memory[byteCnt],PAGESIZE);
  194.                     byteCnt := byteCnt + PAGESIZE;
  195.                     size := size - PAGESIZE;
  196.                     end
  197.                 else
  198.                     begin                             (* last time thru loop *)
  199.                     Move(page[firstByte],memory[byteCnt],size);
  200.                     done := TRUE;
  201.                     end;
  202.                 end;
  203.             end;
  204.         end;
  205.     end;                                 (* end of GetALogicalRecord routine *)
  206.  
  207. (*\*)
  208. (* This routine will store a logical record for a given DATA file.  The routine
  209.    will set the logical record to used and will create the appropriate physical
  210.    record(s) if required (StorePage will do this automatically).  The logical
  211.    record size is size and the data must reside in source.  This routine is
  212.    only used if the logical record number is known.  If a new record is to be
  213.    stored use StoreNewLogicalRecord rather than this routine                 *)
  214.  
  215. procedure StoreALogicalRecord(fName : FnString;
  216.                               lrNum : LrNumber;
  217.                               var source;
  218.                               size : DataSizeRange);
  219.  
  220. type
  221.     MemoryArray = array [DataSizeRange] of byte;
  222.  
  223. var
  224.     prNum : PrNumber;
  225.     firstByte : PageRange;
  226.     page : SinglePage;
  227.     byteCnt : DataSizeRange;
  228.     memory : MemoryArray absolute source;
  229.     done : Boolean;
  230.  
  231.     begin
  232.     ConvertLogicalToPhysical(lrNum,size,prNum,firstByte);
  233.     SetRecordUsed(fName,lrNum);       (* it may be already be marked as used.
  234.                                          This doesn't matter and its faster not
  235.                                          to check.                           *)
  236.     if size <= PAGESIZE then
  237.         begin
  238.         if PageExists(fName,prNum) then               (* if it exists get it *)
  239.             begin
  240.             FetchPage(fName,prNum,page);
  241.             end
  242.         else                           (* if it doesn't exist make a new one *)
  243.             begin
  244.             FillChar(page,PAGESIZE,0);
  245.             end;
  246.         Move(source,page[firstByte],size);
  247.         StorePage(fName,prNum,page);
  248.         end
  249.     else
  250.         begin
  251.         byteCnt := 1;
  252.         done := FALSE;
  253.         while not done do
  254.             begin
  255.             if size > PAGESIZE then
  256.                 begin
  257.                 Move(memory[byteCnt],page[firstByte],PAGESIZE);
  258.                 StorePage(fName,prNum,page);
  259.                 prNum := prNum + 1;
  260.                 byteCnt := byteCnt + PAGESIZE;
  261.                 size := size - PAGESIZE;
  262.                 end
  263.             else
  264.                 begin                                 (* last time thru loop *)
  265.                 FillChar(page,PAGESIZE,0);
  266.                 Move(memory[byteCnt],page[firstByte],size);
  267.                 StorePage(fName,prNum,page);
  268.                 done := TRUE;
  269.                 end;
  270.             end;
  271.         end;
  272.     end;                               (* end of StoreALogicalRecord routine *)
  273.  
  274. (*\*)
  275. (* This routine will store a new logical record for a given DATA file.  The
  276.    routine will set the logical record to used and will create the appropriate physical
  277.    record(s) if required (StorePage will do this automatically).  The logical
  278.    record size is size and the data must reside in source.  Normally, when
  279.    inserting new records, you will not know the next unused logical record
  280.    number.  This routine will assign the appropriate logical record number so
  281.    that you won't have to worry about it.  The routine will return the logical
  282.    record number which will be associated with this record upon return.  You
  283.    will need this returned logical record number if there are any indexes
  284.    associated with this DATA file.                                           *)
  285.  
  286. function StoreNewLogicalRecord(fName : FnString;
  287.                                 var source;
  288.                                 size : DataSizeRange) : LrNumber;
  289.  
  290. var
  291.     lrNum : LrNumber;
  292.  
  293.     begin
  294.     lrNum := FirstUnUsedRecord(fName);
  295.     StoreALogicalRecord(fName,lrNum,source,size);
  296.     StoreNewLogicalRecord := lrNum;
  297.     end;                             (* end of StoreNewLogicalRecord routine *)
  298.  
  299. (*\*)
  300. (* This routine will return a list of logical records which are currently in
  301.    use (contain valid data) for a given data file.  This routine is necessary
  302.    to be able to process all records which have not been deleted without
  303.    using an index.                                                           *)
  304.  
  305. procedure GetValidLogicalRecords(fName : FnString;
  306.                                  var lrLst : LrList);
  307.  
  308. var
  309.     lrNum : LrNumber;
  310.  
  311.     begin
  312.     CreateLrList(lrLst);
  313.     for lrNum := 1 to LastUsedRecord(fName) do
  314.         begin
  315.         if RecordUsed(fName,lrNum) then
  316.             begin
  317.             AddToLrList(lrNum,lrLst);
  318.             end;
  319.         end;
  320.     end;                            (* end of GetValidLogicalRecords routine *)
  321.  
  322.  
  323. end.                                                  (* end of Logical unit *)
  324.