home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / PASCAL / TBTREE16.ZIP / LRECLIST.PAS < prev    next >
Pascal/Delphi Source File  |  1989-07-15  |  29KB  |  740 lines

  1. (* TBTree16            Copyright (c)  1988,1989       Dean H. Farwell II    *)
  2.  
  3. unit LRecList;
  4.  
  5. (****************************************************************************)
  6. (*                                                                          *)
  7. (*                 L O G I C A L   L I S T   R O U T I N E S                *)
  8. (*                                                                          *)
  9. (****************************************************************************)
  10.  
  11. (* These routines handle logical record lists.  These lists are used to hold
  12.    a list of logical record numbers.  Once a list is created logical records
  13.    can be added to the list, the list can be traversed beginning to end or
  14.    back to front and the list can be destroyed.  Additionally, entries can be
  15.    deleted from the list. This list, in conjunction with retrieval routines in
  16.    the BTREE unit allows a list to be built that fulfills some user specified
  17.    criteria.  The list will exist until the user destroys it.  A routine is
  18.    provided for destroying a list and this should be done explicitly for
  19.    reasons which will become clear later.  A user can have many lists in
  20.    existence at once.  You can make a copy of a list.  Two list could be
  21.    combined (intersection or union) to create a third list if the user
  22.    desires.  Routines to combine lists in this way are provided in another
  23.    unit.  These lists give power that simply traversing the BTree does not.
  24.  
  25.    The implementation of these lists is not very straightforward.  I
  26.    first developed this unit by creating a giant linked list of
  27.    record numbers which would be kept on the heap.  It was extremely
  28.    straightforward but had the problem of being at the mercy of heap size.
  29.    In a large database these lists could easily overflow the heap.  I reworked
  30.    the problem and came up with this solution.  It stores the logical record
  31.    numbers in an array the size of a page in the page buffer.  If all the
  32.    record numbers will fit in one page then the list is kept in memory.  If
  33.    not then a temporary file is created and all but the current page is kept
  34.    in the page buffer (or out on disk if a page gets swapped out).  This is
  35.    all transparent to the user except that large lists will experience some
  36.    performance degredation.  The good news is that the logical record lists
  37.    can hold MAXLONGINT (over 2 billion) entries, one for every possible
  38.    logical record number.  (You would really run out of disk space sooner than
  39.    ever coming close to that limit).
  40.  
  41.    Since a temporary file may be created it is important that the user call
  42.    DestroyLrList when completed with the list.  Any file created will be
  43.    deleted.  Otherwise some strange files might show up on the disk.  All
  44.    files created will have an extension of 'LRF'.  You should avoid using LRF
  45.    as an extension in your applications, although everything will still work
  46.    properly if you do.
  47.  
  48.    note - Hopefully, I have given the user a rich set of routines which can
  49.    be used with the lists.  It is not in the user's best interest to access
  50.    fields in the lists directly.  Use the routines provided.  This will guard
  51.    against problems if the implementation section is ever changed.           *)
  52.  
  53. (*\*)
  54. (* Version Information
  55.  
  56.    Version 1.1 - Added DeleteFromLrList routine to delete entries from
  57.                  logical records list
  58.  
  59.                - Changed the routines so that if a cursor is invalid (does
  60.                  not point to a valid entry, a 0 is returned when a
  61.                  record number is requested.  This is true for the GetNextLr,
  62.                  GetPrevLr and GetCurrLr routines.  This shouldn't affect
  63.                  anything that you were previously doing.
  64.  
  65.    Version 1.2 - Added LRArraySize type
  66.  
  67.                - Added FindLargestLr routine
  68.  
  69.                - Added DesiredPosition routine
  70.  
  71.                - Added DesiredPage routine
  72.  
  73.                - Made a couple of minor changes internally (simplified code
  74.                  using DesiredPosition and DesiredPage)
  75.  
  76.    Version 1.3 - Added FindLrInList routine
  77.  
  78.    Version 1.4 - Changed way of assigning file names to a logical record list
  79.                  file.  This change removes any restrictions on the number of
  80.                  logical record lists that can be created.  For details on how
  81.                  this is handled, see the code within the implementation
  82.                  section.  However, you probably don't need to explore the
  83.                  details unless you are curious.
  84.  
  85.                - Made internal changes due to changes in the FILES unit.
  86.  
  87.                - Functionally, all routines provided still work the same
  88.  
  89.    Version 1.5 - Changed code internally to use Inc and Dec where practical
  90.  
  91.                - Added CopyLrList routine
  92.  
  93.    Version 1.6 - No Changes                                                  *)
  94.  
  95. (*\*)
  96. (*////////////////////////// I N T E R F A C E //////////////////////////////*)
  97.  
  98. interface
  99.  
  100. uses
  101.     FileDecs,
  102.     Files,
  103.     Numbers,
  104.     Page;
  105.  
  106. const
  107.     LRARRAYSIZE = 128;                (* This needs to be PAGESIZE / RNSIZE *)
  108.                                            (* it is presently 512 / 4 = 128 *)
  109.  
  110. type
  111.     LRArrayRange = 1 .. LRARRAYSIZE;
  112.  
  113.     LogicalRecordsArray = Array [LRArrayRange] of LrNumber;
  114.                                           (* this array must be same size (same
  115.                                              number of bytes) as a page in
  116.                                              the page buffer                 *)
  117.  
  118.     LrList = record            (* type which is used to hold a list of logical
  119.                                                               record numbers *)
  120.              fName    : FnString;            (* holds name of file if needed *)
  121.              currPage : PrNumber;                 (* current page in lrArray *)
  122.                                               (* first page used is always 1 *)
  123.              current  : LrNumber;                   (* current place in list *)
  124.              count    : LrNumber;       (* number of logical records in list *)
  125.              case Boolean of
  126.              TRUE  : (lrArray  : LogicalRecordsArray);
  127.              FALSE : (page : SinglePage);
  128.              end;
  129.  
  130.  
  131. (* This routine will create a logical record list.  It will accomplish this by
  132.    initializing the logical record page to all zeros and will set the count to
  133.    zero, the current (cursor) to zero and the current page to one.  To create
  134.    an empty list simply call this with a variable declared as type LrList.   *)
  135.  
  136. procedure CreateLrList(var lrLst : LrList);
  137.  
  138.  
  139. (* This routine will create a new logical record list (destLrLst) which is an
  140.    exact duplicate of the sourceLrLst.  You must use this routine to copy a
  141.    list.  Do not simply use a statement such as destLrLst := soureLrLst since
  142.    this will not work properly since part of a list may reside in a disk file
  143.    and not entirely in an lrLst variable.                                    *)
  144.  
  145. procedure CopyLrList(sourceLrLst : lrList;
  146.                      var destLrLst : LrList);
  147.  
  148. (*\*)
  149. (* This routine will add a logical record number to the end of a logical record
  150.    list.  It will update the cursor position to the newly added record.
  151.    It will increment the count by one.                                       *)
  152.  
  153. procedure AddToLrList(lrNum : LrNumber;
  154.                       var lrLst : LrList);
  155.  
  156.  
  157. (* This routine will delete an entry from a logical record list.  It is useful
  158.    when deleting records in the case where you do not want to have to recreate
  159.    a list after doing the delete.  It is important to realize two things when
  160.    using this routine.  The first is that it does nothing whatsoever to data
  161.    or index files.  It only affects the logical records list.  Secondly, it
  162.    is faster than recreating a list each time a delete is done, but for
  163.    large lists, it still takes time to perform the delete from the list.
  164.    If a large number of deletes are anticipated, it might be faster to do the
  165.    deletes on the data and index files and then do another retrieval thus
  166.    creating the new list only once.  This routine deletes the current entry
  167.    only ie entry at the cursor.
  168.  
  169.    One note before using this routine - You must be aware of what is
  170.    happening to the cursor.  When this routine deletes the current logical
  171.    record the cursor must be positioned somewhere.  The routine put the
  172.    cursor at the first entry past the deleted entry.  This is now the new
  173.    current entry.  To retrieve it use GetCurrLr not GetNextLr.  In other
  174.    words, when traversing a list from start to finish and deleting the
  175.    entries as you go, to get to the next entry use GetCurrLr.  Use GetPrevLr
  176.    if you are going from the end of the list to the front.                   *)
  177.  
  178. procedure DeleteFromLrList(var lrLst : LrList);
  179.  
  180.  
  181. (* This routine will destroy a logical record list.  It will delete the file
  182.    holding the logical record list if the file was ever created              *)
  183.  
  184. procedure DestroyLrList(var lrLst : LrList);
  185.  
  186.  
  187. (* This routine will return the first logical record in a logical record list
  188.    and set the cursor to the front of the list.  If the list is empty 0 will
  189.    be returned instead.                                                      *)
  190.  
  191. function GetFirstLr(var lrLst : LrList) : LrNumber;
  192.  
  193.  
  194. (* This routine will get the last logical record number in a logical record list
  195.    and set the cursor to the back of the list.  If the list is empty then
  196.    0 will be returned instead.  This routine should be used for traversing
  197.    the list in reverse order.                                                *)
  198.  
  199. function GetLastLr(var lrLst : LrList) : LrNumber;
  200.  
  201. (*\*)
  202. (* This routine is used to get the next logical record number in a logical list.
  203.    The cursor will be set to this record list cell as well.  This is used to
  204.    traverse the list in a forward manner.  The routine will return the logical
  205.    record number or 0 if the list is exhausted or the cursor position is
  206.    invalid.                                                                  *)
  207.  
  208. function GetNextLr(var lrLst : LrList) : LrNumber;
  209.  
  210.  
  211. (* This routine is used to get the previous logical record number in a logical
  212.    list.  The cursor will be updated to point to this entry.  This is used
  213.    to traverse the list in a backward manner.  The routine will return the
  214.    logical record number or 0 if the list is exhausted or the cursor position
  215.    is invalid.                                                               *)
  216.  
  217. function GetPrevLr(var lrLst : LrList) : LrNumber;
  218.  
  219.  
  220. (* This routine is used to get the current logical record in a logical list.
  221.    It will not update the cursor position.  It will return 0 if the cursor
  222.    position is not valid                                                     *)
  223.  
  224. function GetCurrLr(lrLst : LrList) : LrNumber;
  225.  
  226.  
  227. (* This routine returns the number of logical records currently in the logical
  228.    record list                                                               *)
  229.  
  230. function GetCountLr(lrLst : LrList) : LrNumber;
  231.  
  232. (*\*)
  233. (* This routine will return the correct physical record number (for the logical
  234.    record list) where the entry lrPos is found                               *)
  235.  
  236. function DesiredPage(lrPos : LrNumber) : PrNumber;
  237.  
  238.  
  239. (* This routine will return the position within a logical records array for
  240.    given lrPos                                                               *)
  241.  
  242. function DesiredPosition(lrPos : LrNumber) : LRArrayRange;
  243.  
  244.  
  245. (* This routine will return the largest logical record number within a logical
  246.    record list.                                                              *)
  247.  
  248. function FindLargestLr(lrLst : LrList) : LrNumber;
  249.  
  250.  
  251. (* This routine will look for a logical record number in a logical record list.
  252.    It will return TRUE if the record number is in the list and FALSE
  253.    otherwise.                                                                *)
  254.  
  255. function FindLrInList(lr : LrNumber;
  256.                       lrLst : LrList) : Boolean;
  257.  
  258. (*!*)
  259. (*\*)
  260. (*///////////////////// I M P L E M E N T A T I O N /////////////////////////*)
  261.  
  262. implementation
  263.  
  264. (* This routine will return a file name which is not being used.  It
  265.    accomplishes this by assigning a random file name ending with an extension
  266.    of LRF.  Then, a check is performed to see if that particular file exists.
  267.    If it does not exist, the file is available for use and the file name is
  268.    returned for use as the file name for a newly created logical record list
  269.    file.  If a file by that name exists, a new random file name is produced.
  270.    This process continues until an available file name is found.             *)
  271.  
  272. function GetUnusedFileName : FnString;
  273.  
  274. var
  275.     tempRandomFName : FnString;
  276.     tempString : String[5];
  277.     RandomPart : Word;
  278.     done : Boolean;
  279.  
  280.     begin
  281.     done := FALSE;
  282.     while not done do
  283.         begin
  284.         randomPart := Random(MAXWORD - 1) + 1;
  285.         Str(randomPart:5,tempString);
  286.         tempRandomFName := 'xxx' + tempString + '.LRF';
  287.         done := not FileExists(tempRandomFName);
  288.         end;
  289.     GetUnusedFileName := tempRandomFName;
  290.     end;                                 (* end of GetUnusedFileName routine *)
  291.  
  292. (*\*)
  293. (* This routine will create a logical record list.  It will accomplish this by
  294.    initializing the logical record page to all zeros and will set the count to
  295.    zero, the current (cursor) to zero and the current page to one.  To create
  296.    an empty list simply call this with a variable declared as type LrList.   *)
  297.  
  298. procedure CreateLrList(var lrLst : LrList);
  299.  
  300.     begin
  301.     lrLst.fName := '';        (* null file name since one does not yet exist *)
  302.     lrLst.currPage := 1;
  303.     lrLst.current := 0;
  304.     lrLst.count := 0;
  305.     FillChar(lrLst.page,PAGESIZE,0);
  306.     end;                                      (* end of CreateLrList routine *)
  307.  
  308. (* This routine will create a new logical record list (destLrLst) which is an
  309.    exact duplicate of the sourceLrLst.  You must use this routine to copy a
  310.    list.  Do not simply use a statement such as destLrLst := soureLrLst since
  311.    this will not work properly since part of a list may reside in a disk file
  312.    and not entirely in an lrLst variable.                                    *)
  313.  
  314. procedure CopyLrList(sourceLrLst : lrList;
  315.                      var destLrLst : LrList);
  316.  
  317. var
  318.     cnt : PrNumber;
  319.  
  320.     begin
  321.     destLrLst := sourceLrLst;
  322.     if destLrLst.count > LRARRAYSIZE then
  323.         begin
  324.         destLrLst.fName := GetUnusedFileName;
  325.         CreateGenericFile(destLrLst.fName);
  326.         for cnt := 1 to DesiredPage(sourceLrLst.count) do
  327.             begin
  328.             FetchPage(sourceLrLst.fName,cnt,destLrLst.page);
  329.             StorePage(destLrLst.fName,cnt,destLrLst.page);
  330.             end;
  331.         FetchPage(destLrLst.fName,destLrLst.currPage,destLrLst.page);
  332.         end;
  333.     end;                                        (* end of CopyLrList routine *)
  334.  
  335. (*\*)
  336. (* This routine will add a logical record number to the end of a logical record
  337.    list.  It will update the cursor position to the newly added record.
  338.    It will increment the count by one.                                       *)
  339.  
  340. procedure AddToLrList(lrNum : LrNumber;
  341.                       var lrLst : LrList);
  342.  
  343. var
  344.     tempPage : PrNumber;
  345.  
  346.     begin
  347.     if lrLst.count = 0 then
  348.         begin                                           (* list is now empty *)
  349.         lrLst.count := 1;
  350.         lrLst.lrArray[1] := lrNum;
  351.         lrLst.current := 1;
  352.         end
  353.     else
  354.         begin
  355.         lrLst.current := lrLst.count;                   (* put cursor at end *)
  356.         tempPage := DesiredPage(lrLst.current);
  357.         if lrLst.currPage <> tempPage then    (* make sure last page current *)
  358.             begin
  359.             lrLst.currPage := tempPage;
  360.             FetchPage(lrLst.fName,lrLst.currPage,lrLst.page);
  361.             end;
  362.         if lrLst.current Mod LRARRAYSIZE = 0 then           (* check if full *)
  363.             begin
  364.             if lrLst.currPage = 1 then
  365.                 begin        (* create the file for the logical records list *)
  366.                 lrLst.fName := GetUnusedFileName;
  367.                 CreateGenericFile(lrLst.fName);
  368.                 StorePage(lrLst.fName,1,lrLst.page);
  369.                 end;
  370.             Inc(lrLst.currPage);
  371.             FillChar(lrLst.page,PAGESIZE,0);
  372.             end;
  373.         Inc(lrLst.current);
  374.         Inc(lrLst.count);
  375.         lrLst.lrArray[DesiredPosition(lrLst.current)] := lrNum;
  376.         if lrLst.currPage > 1 then
  377.             begin
  378.             StorePage(lrLst.fName,lrLst.currPage,lrLst.page);
  379.             end;
  380.         end;
  381.     end;                                       (* end of AddToLrList routine *)
  382.  
  383. (*\*)
  384. (* This routine will delete an entry from a logical record list.  It is useful
  385.    when deleting records in the case where you do not want to have to recreate
  386.    a list after doing the delete.  It is important to realize two things when
  387.    using this routine.  The first is that it does nothing whatsoever to data
  388.    or index files.  It only affects the logical records list.  Secondly, it
  389.    is faster than recreating a list each time a delete is done, but for
  390.    large lists, it still takes time to perform the delete from the list.
  391.    If a large number of deletes are anticipated, it might be faster to do the
  392.    deletes on the data and index files and then do another retrieval thus
  393.    creating the new list only once.  This deletes the current entry only ie
  394.    entry at the cursor.                                                      *)
  395.  
  396. procedure DeleteFromLrList(var lrLst : LrList);
  397.  
  398. var
  399.     tempLrNum : LrNumber;
  400.     newLst,
  401.     tempLst : LrList;
  402.  
  403.     begin
  404.     CreateLrList(newLst);
  405.     tempLst := lrLst;
  406.     tempLrNum := GetFirstLr(tempLst);
  407.     while tempLrNum <> 0 do                                (* build new list *)
  408.         begin
  409.         if tempLst.current <> lrLst.current then
  410.             begin
  411.             AddToLrList(tempLrNum,newLst);
  412.             end;
  413.         tempLrNum := GetNextLr(tempLst);
  414.         end;
  415.     if lrLst.current = lrLst.count then     (* check to see if deleted entry
  416.                                                is at the end of the list     *)
  417.         begin                                   (* if so make cursor invalid *)
  418.         newLst.currPage := 1;
  419.         newLst.current := 0;
  420.         end
  421.     else
  422.         begin
  423.         newLst.currPage := lrLst.currPage;        (* get new cursor position *)
  424.         newLst.current := lrLst.current;
  425.         end;
  426.     DestroyLrList(lrLst);                             (* get rid of old list *)
  427.     lrLst := newLst;                                      (* return new list *)
  428.     end;                                  (* end of DeleteFromLrList routine *)
  429.  
  430. (*\*)
  431. (* This routine will destroy a logical record list.  It will delete the file
  432.    holding the logical record list if the file was ever created              *)
  433.  
  434. procedure DestroyLrList(var lrLst : LrList);
  435.  
  436.     begin
  437.     lrLst.currPage := 1;
  438.     lrLst.current := 0;
  439.     lrLst.count := 0;
  440.     FillChar(lrLst.page,PAGESIZE,0);
  441.     if lrLst.fName <> '' then
  442.         begin
  443.         DeleteGenericFile(lrLst.fName);
  444.         lrLst.fName := '';
  445.         end;
  446.     end;                                     (* end of DestroyLrList routine *)
  447.  
  448.  
  449. (* This routine will return the first logical record in a logical record list
  450.    and set the cursor to the front of the list.  If the list is empty 0 will
  451.    be returned instead.                                                      *)
  452.  
  453. function GetFirstLr(var lrLst : LrList) : LrNumber;
  454.  
  455.     begin
  456.     if lrLst.count = 0 then
  457.         begin
  458.         GetFirstLr := 0;
  459.         end
  460.     else
  461.         begin
  462.         lrLst.current := 1;
  463.         if lrLst.currPage <> 1 then
  464.             begin
  465.             FetchPage(lrLst.fName,1,lrLst.page);
  466.             lrLst.currPage := 1;
  467.             end;
  468.         GetFirstLr := lrLst.lrArray[1];
  469.         end;
  470.     end;                                        (* end of GetFirstLr routine *)
  471.  
  472. (*\*)
  473. (* This routine will get the last logical record number in a logical record list
  474.    and set the cursor to the back of the list.  If the list is empty then
  475.    0 will be returned instead.  This routine should be used for traversing
  476.    the list in reverse order.                                                *)
  477.  
  478. function GetLastLr(var lrLst : LrList) : LrNumber;
  479.  
  480. var
  481.     temp : PrNumber;
  482.  
  483.     begin
  484.     if lrLst.count = 0 then
  485.         begin
  486.         GetLastLr := 0;
  487.         end
  488.     else
  489.         begin
  490.         lrLst.current := lrLst.count;
  491.         temp := DesiredPage(lrLst.current);
  492.         if lrLst.currPage <> temp then
  493.             begin
  494.             lrLst.currPage := temp;
  495.             FetchPage(lrLst.fName,lrLst.currPage,lrLst.page);
  496.             end;
  497.         GetLastLr := lrLst.lrArray[DesiredPosition(lrLst.current)];
  498.         end;
  499.     end;                                         (* end of GetLastLr routine *)
  500.  
  501.  
  502. (* This routine is used to get the next logical record number in a logical list.
  503.    The cursor will be set to this record list cell as well.  This is used to
  504.    traverse the list in a forward manner.  The routine will return the logical
  505.    record number or 0 if the list is exhausted.                              *)
  506.  
  507. function GetNextLr(var lrLst : LrList) : LrNumber;
  508.  
  509.     begin
  510.     if (lrLst.current = lrLst.count) or
  511.        (lrLst.current = 0) then
  512.         begin
  513.         GetNextLr := 0;
  514.         end
  515.     else
  516.         begin
  517.         if lrLst.current Mod LRARRAYSIZE  = 0 then
  518.             begin
  519.             Inc(lrLst.currPage);
  520.             FetchPage(lrLst.fName,lrLst.currPage,lrLst.page);
  521.             end;
  522.         Inc(lrLst.current);
  523.         GetNextLr := lrLst.lrArray[DesiredPosition(lrLst.current)];
  524.         end;
  525.     end;                                         (* end of GetNextLr routine *)
  526.  
  527. (*\*)
  528. (* This routine is used to get the previous logical record number in a logical
  529.    list.  The cursor will be updated to point to this entry.  This is used
  530.    to traverse the list in a backward manner.  The routine will return the
  531.    logical record number or 0 if the list is exhausted or the cursor position
  532.    is invalid.                                                               *)
  533.  
  534. function GetPrevLr(var lrLst : LrList) : LrNumber;
  535.  
  536.     begin
  537. {    if lrLst.current in [0,1] then}
  538.      if (lrLst.current = 0) or (lrLst.current = 1) then
  539.         begin
  540.         GetPrevLr := 0;
  541.         end
  542.     else
  543.         begin
  544.         if (lrLst.current - 1) Mod LRARRAYSIZE  = 0 then
  545.             begin
  546.             Dec(lrLst.currPage);
  547.             FetchPage(lrLst.fName,lrLst.currPage,lrLst.page);
  548.             end;
  549.         Dec(lrLst.current);
  550.         GetPrevLr := lrLst.lrArray[DesiredPosition(lrLst.current)];
  551.         end;
  552.     end;                                         (* end of GetPrevLr routine *)
  553.  
  554.  
  555. (* This routine is used to get the current logical record in a logical list.
  556.    It will not update the cursor position.  It will return 0 if the cursor
  557.    position is not valid                                                     *)
  558.  
  559. function GetCurrLr(lrLst : LrList) : LrNumber;
  560.  
  561.     begin
  562.     if lrLst.current = 0 then
  563.         begin
  564.         GetCurrLr := 0;
  565.         end
  566.     else
  567.         begin
  568.         GetCurrLr := lrLst.lrArray[DesiredPosition(lrLst.current)];
  569.         end;
  570.     end;                                         (* end of GetCurrLr routine *)
  571.  
  572. (*\*)
  573. (* This routine returns the number of logical records currently in the logical
  574.    record list                                                               *)
  575.  
  576. function GetCountLr(lrLst : LrList) : LrNumber;
  577.  
  578.     begin
  579.     GetCountLr := lrLst.count;
  580.     end;                                        (* end of GetCountLr routine *)
  581.  
  582.  
  583. (* This routine will return the correct physical record number (for the logical
  584.    record list) where the entry lrPos is found                               *)
  585.  
  586. function DesiredPage(lrPos : LrNumber) : PrNumber;
  587.  
  588.     begin
  589.     DesiredPage := ((lrPos - 1) DIV LRARRAYSIZE) + 1;
  590.     end;                                       (* end of DesiredPage routine *)
  591.  
  592.  
  593. (* This routine will return the position within a logical records array for
  594.    given lrPos                                                               *)
  595.  
  596. function DesiredPosition(lrPos : LrNumber) : LRArrayRange;
  597.  
  598.     begin
  599.     DesiredPosition := ((lrPos - 1) MOD LRARRAYSIZE) + 1;
  600.     end;                                   (* end of DesiredPosition routine *)
  601.  
  602. (*\*)
  603. (* This routine will return the largest logical record number within a logical
  604.    record list.                                                              *)
  605.  
  606. function FindLargestLr(lrLst : LrList) : LrNumber;
  607.  
  608. var
  609.     tempMax,
  610.     max : LrNumber;
  611.     pageCnt,
  612.     lastPage : PrNumber;
  613.  
  614.     function FindMaxLrInPage(cnt : LRArrayRange) : LrNumber;
  615.  
  616.     var
  617.         max : LrNumber;
  618.         tempCnt : LRArrayRange;
  619.  
  620.     begin
  621.     max := 0;
  622.     for tempCnt := 1 to cnt do
  623.         begin
  624.         if lrLst.lrArray[tempCnt] > max then
  625.             begin
  626.             max := lrLst.lrArray[tempCnt];
  627.             end;
  628.         end;
  629.     FindMaxLrInPage := max;
  630.     end;                                   (* end of FindMaxLrInPage routine *)
  631.  
  632.     begin
  633.     max := 0;
  634.     if lrLst.count <> 0 then
  635.         begin
  636.         if lrLst.fName = '' then
  637.             begin
  638.             max := FindMaxLrInPage(lrLst.count);
  639.             end
  640.         else
  641.             begin
  642.             lastPage := DesiredPage(lrLst.count);
  643.             for pageCnt := 1 to lastPage do
  644.                 begin
  645.                 FetchPage(lrLst.fName,pageCnt,lrLst.page);
  646.                 if pageCnt < lastPage then
  647.                     begin
  648.                     tempMax := FindMaxLrInPage(LRARRAYSIZE);
  649.                     end
  650.                 else
  651.                     begin
  652.                     tempMax := FindMaxLrInPage(lrLst.count -
  653.                                                ((pageCnt - 1) * LRARRAYSIZE));
  654.                     end;
  655.                 if tempMax > max then
  656.                     begin
  657.                     max := tempMax;
  658.                     end;
  659.                 end;
  660.             if LrLst.currPage <> lastPage then
  661.                 begin
  662.                 FetchPage(lrLst.fName,lrLst.currPage,lrLst.page);
  663.                 end;
  664.             end;
  665.         end;
  666.     FindLargestLr := max;
  667.     end;                                             (* end of FindLargestLr *)
  668.  
  669. (*\*)
  670. (* This routine will look for a logical record number in a logical record list.
  671.    It will return TRUE if the record number is in the list and FALSE
  672.    otherwise.                                                                *)
  673.  
  674. function FindLrInList(lr : LrNumber;
  675.                       lrLst : LrList) : Boolean;
  676.  
  677. var
  678.     pageEntries : LRArrayRange;
  679.     pageCnt,
  680.     lastPage : PrNumber;
  681.  
  682.     function FindLrInPage(pageEntries : LRArrayRange) : Boolean;
  683.  
  684.     var
  685.         tempCnt : LRArrayRange;
  686.  
  687.     begin
  688.     for tempCnt := 1 to pageEntries do
  689.         begin
  690.         if lrLst.lrArray[tempCnt] = lr then
  691.             begin
  692.             FindLrInPage := TRUE;
  693.             Exit;
  694.             end;
  695.         end;
  696.     FindLrInPage := FALSE;
  697.     end;                                   (* end of FindMaxLrInPage routine *)
  698.  
  699.     begin
  700.     if lrLst.count <> 0 then
  701.         begin
  702.         if lrLst.fName = '' then
  703.             begin
  704.             if FindLrInPage(lrLst.count) then
  705.                 begin
  706.                 FindLrInList := TRUE;
  707.                 Exit;
  708.                 end;
  709.             end
  710.         else
  711.             begin
  712.             lastPage := DesiredPage(lrLst.count);
  713.             for pageCnt := 1 to lastPage do
  714.                 begin
  715.                 FetchPage(lrLst.fName,pageCnt,lrLst.page);
  716.                 if pageCnt < lastPage then
  717.                     begin
  718.                     pageEntries := LRARRAYSIZE;
  719.                     end
  720.                 else
  721.                     begin
  722.                     pageEntries := lrLst.count - ((pageCnt - 1) * LRARRAYSIZE);
  723.                     end;
  724.                 if FindLrInPage(pageEntries) then
  725.                     begin
  726.                     FindLrinList := TRUE;
  727.                     Exit;
  728.                     end;
  729.                 end;
  730.             FetchPage(lrLst.fName,lrLst.currPage,lrLst.page);
  731.             end;
  732.         end;
  733.     FindLrInList := FALSE;
  734.     end;                                              (* end of FindLrInList *)
  735.  
  736.  
  737. begin                                                 (* initialization code *)
  738. Randomize;
  739. end.                                                 (* end or LRecList unit *)
  740.