home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / arrays / larry / larry.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1990-07-15  |  17.1 KB  |  573 lines

  1. (* The compilersetting with the word OFF or ON after should be
  2.    left in that state *)
  3.  
  4. {$D+} { Debug information }
  5. {$L+} { Local symbols }
  6.  
  7. {$A+} { Word align in this module for speed }
  8. {$B-} { ShortCurcit boolean evaluation ON (- state) }
  9. {$F-} { Far call OFF }
  10. {$I-} { I/O Checking OFF }
  11. {$O-} { Overlay OFF }
  12.  
  13. {$R-} { RangeCheck }
  14. {$S-} { StackCheck }
  15. {$V+} { Varcheck }
  16.  
  17. (* There is NO floating point in this module so leave the following OFF *)
  18. {$E-} { Coprocessor emulation OFF }
  19. {$N-} { Software floatingpoint OFF}
  20.  
  21. Unit Larry;
  22.  
  23. Interface
  24.  
  25. Const NoHandle=-1;
  26.       DefaultBuckets=16;
  27.  
  28. Type IndexType=LongInt;
  29.      ArrayHandle=Integer;
  30.      WhenClose=(Purge,NoPurge);
  31.      WhenOpen=(Reuse,Create);
  32.      Modes=(ReadWrite,NoRead,NoWrite);
  33.  
  34. Function OpenArray(FName:String;
  35.                    EntrySize:Word;
  36.                    NumEntries:IndexType;
  37.                    NumBuckets:Integer;
  38.                    PurgeFlag:WhenClose;
  39.                    ReuseFlag:WhenOpen;
  40.                    Mode:Modes):ArrayHandle;
  41.  
  42. Function Larray(EntrySize:Word;NumEntries:Indextype):ArrayHandle;
  43.  
  44. Function Darray(FName:String;EntrySize:Word;NumEntries:Indextype):ArrayHandle;
  45.  
  46. (* OpenArray generates the internal structures and prepares the file for
  47.    access and Larray and Darray is a simpler interface to OpenArray
  48.    generating filename and selecting stacksize and other defaults *)
  49.  
  50. Procedure CloseArray(Handle:ArrayHandle);
  51.  
  52. (* Closearray deletes the internal structs and removes the
  53.    arr from mem/disk*)
  54.  
  55.  
  56. Procedure UnFreeze(Handle:ArrayHandle;Entry:IndexType);
  57.  
  58. (* Removes a lock *)
  59.  
  60. Procedure FlushArray(Handle:ArrayHandle);
  61.  
  62. (* Flushes all data for an array to disk and frees the stack entries *)
  63.  
  64. Procedure FlushAllArrays;
  65.  
  66. (* Flushes all open arrays *)
  67.  
  68. Function GetPointer(Handle:ArrayHandle;Entry:IndexType):Pointer;
  69.  
  70. (* GetPointer does all the nitty_gritty for this package, reading/writing
  71.    data updating buckets et.c. *)
  72.  
  73. Function Freeze(Handle:ArrayHandle;Entry:IndexType):Pointer;
  74.  
  75. (* Locks an entry in ram, same as getpointer *)
  76.  
  77. Procedure WriteMode(Handle:ArrayHandle;Flag:Modes);
  78. (* Flags that we are initializing the array and that it shall assume
  79.    all entries accessed as NEW *)
  80.  
  81. Implementation
  82.  
  83. Uses DOS;
  84.  
  85. Const MaxArraysOpen=7; (* Max number of arrays open at one time *)
  86.  
  87. Type EntryType=Record
  88.                  Locked:Boolean;      (* Flag frozen entry *)
  89.                  ItemInBuf:IndexType; (* Item in this buffer *)
  90.                  Data:Pointer         (* Pointer to the buffer *)
  91.                end;
  92.  
  93. Const BucketMax=(32768 Div SizeOf(EntryType));
  94.  
  95. Type  Stack=Array [0..BucketMax] Of EntryType;
  96.  
  97.      ArrayHeader=Record
  98.                    Allocated:Boolean; (* Flag entry in use *)
  99.                    DiskFile:File;     (* Disk file used *)
  100.                    FileOpen:Boolean;  (* Flag file Open/Closed *)
  101.                    RecordSize:Word;   (* Size of item in bytes *)
  102.                    StackSize:Integer; (* Number of buckets in array *)
  103.                    DataStack:^Stack;  (* Pointer to the bucket struct *)
  104.                    AccessMode:Modes;  (* Operation of array *)
  105.                    TotalEntries:IndexType; (* Max entries in array *)
  106.                    PurgeWhenClosed:WhenClose; (* What to do when closed *)
  107.                  end;
  108.  
  109. Var
  110.      Headers:Array [0..MaxArraysOpen] Of ArrayHeader;
  111.      Ind:Integer;
  112.      OldExit:Pointer;
  113.  
  114. Procedure IoAbort;
  115. (* Check for pending I/O errors and aborts if any *)
  116. Var Temp:Integer;
  117. Begin
  118.   Temp:=IoResult;
  119.   If Temp=0 Then Exit;
  120.   WriteLN('LARRY: Critical I/O error #',Temp,'.');
  121.   HALT
  122. end;
  123.  
  124. Function OpenArray;
  125. (* Opens/Create the array*)
  126.  
  127. (* Get the first free handle *)
  128. Function GetHandle:ArrayHandle;
  129. Var H:ArrayHandle;
  130. Begin
  131.   H:=0;
  132.   (* Scan for a free entry *)
  133.   While (H<=MaxArraysOpen) AND (Headers[H].Allocated=TRUE) Do H:=Succ(H);
  134.   If H>MaxArraysOpen Then GetHandle:=NoHandle (* none left *)
  135.                      Else GetHandle:=H
  136. end;
  137.  
  138. Var NewHandle:ArrayHandle;
  139.     FileSizeRequired:LongInt;
  140.     DriveForData:Integer;
  141.     DumBuf:Array [0..1] Of Char;
  142.     Result:Word;
  143.     Temp:Integer;
  144. Begin
  145.   (* Rangecheck the bucketsize *)
  146.   If NumBuckets-1>BucketMax Then
  147.   Begin
  148.     WriteLN('LARRY: Too many buckets');
  149.     HALT
  150.   end;
  151.   NewHandle:=GetHandle; (* Get the handle *)
  152.   If NewHandle=NoHandle Then
  153.   Begin  (* All handles in use *)
  154.     WriteLN('LARRY: No available handle');
  155.     HALT
  156.   end;
  157.   (* Calculate the size of the file *)
  158.   FileSizeRequired:=LongInt(EntrySize)*NumEntries;
  159.   (* Check if enuf space on the target drive *)
  160.   If FName[2]=':' Then
  161.     DriveForData:=Ord(UpCase(FName[1]))-Ord('A')+1
  162.   Else DriveForData:=0;
  163.   If DiskFree(DriveForData)<FileSizeRequired Then
  164.   Begin
  165.     WriteLN('LARRY: not enough disk space');
  166.     Halt
  167.   end;
  168.   With Headers[NewHandle] Do
  169.   Begin
  170.     Assign(DiskFile,FName);
  171.     If ReuseFlag=Reuse Then (* See if we are opening old file *)
  172.     Begin
  173.       Reset(DiskFile,EntrySize);
  174.       If IoResult<>0 Then (* Trap the absent file error *)
  175.       Begin
  176.         If Mode=NoWrite Then (* If readonly array we cant create it *)
  177.         Begin
  178.           WriteLN('LARRY: Can''t create file for READ ONLY array');
  179.           HALT
  180.         end;
  181.         Rewrite(DiskFile,EntrySize);
  182.         If IOResult<>0 Then (* Test for build failure *)
  183.         Begin
  184.           WriteLN('LARRY: Can''t create disk file');
  185.           HALT
  186.         end;
  187.         (* Force the file to full size by writing to the last record *)
  188.         Seek(DiskFile,NumEntries-1);
  189.         IoAbort; (* Check error *)
  190.         BlockWrite(DiskFile,DumBuf,1); (* Write a dummy block *)
  191.         If IoResult<>0 Then
  192.         Begin
  193.           WriteLN('LARRY: I/O Error creating file');
  194.           HALT
  195.         end
  196.       end
  197.     end
  198.     else
  199.     Begin (* Generate a NEW array regardless of old status *)
  200.       If Mode=NoWrite Then
  201.       Begin
  202.         WriteLN('LARRY: Mode for NEW array can''t be READ ONLY');
  203.         HALT
  204.       end;
  205.       Rewrite(DiskFile,EntrySize); (* Create NEW file deleteing old *)
  206.       If IoResult<>0 Then
  207.       Begin
  208.         WriteLN('LARRY: Can''t create disk file');
  209.         HALT
  210.       end
  211.     end;
  212.     If ReuseFlag=Create Then
  213.     Begin (* Force file to FULL SIZE *)
  214.       seek(DiskFile,NumEntries-1);
  215.       If IoResult<>0 Then; (* Dummy to get rid of possible I/O err *)
  216.       BlockWrite(DiskFile,DumBuf,1,Result);
  217.       If IoResult<>0 Then
  218.       Begin
  219.         WriteLN('LARRY: I/O Error creating file');
  220.         Halt
  221.       end;
  222.     end; (* If Not ReuseFlag *)
  223.     Close(DiskFile); (* Dont need file open yet *)
  224.     (* Start allocating memory for the structures and testing if there
  225.        is enuf with free heapspace *)
  226.     If MaxAvail<NumBuckets*SizeOf(EntryType) Then
  227.     Begin
  228.       WriteLN('LARRY: Not enough memory for datastructs');
  229.       HALT
  230.     end;
  231.     (* Allocate control structure *)
  232.     GetMem(DataStack,NumBuckets*SizeOf(EntryType));
  233.     (* Start allocating the databuckets *)
  234.     For Temp:=0 To NumBuckets-1 Do
  235.       With DataStack^[Temp] Do
  236.       Begin
  237.         If MaxAvail<EntrySize Then (* Check mem *)
  238.         Begin
  239.           WriteLN('LARRY: Not enough memory for datastructs');
  240.           HALT
  241.         end;
  242.         GetMem(Data,EntrySize); (* Allocate *)
  243.         ItemInBuf:=-1; (* Mark entry as free *)
  244.         Locked:=False  (* Mark as unlocked *)
  245.       end;
  246.     (* Update the control structure with its values *)
  247.     RecordSize:=EntrySize; (* Size of entry *)
  248.     TotalEntries:=NumEntries; (* Number of entries *)
  249.     PurgeWhenClosed:=PurgeFlag; (* What to do when closing the array *)
  250.     StackSize:=NumBuckets; (* Number of buckets in ram *)
  251.     FileOpen:=False; (* File is still closed *)
  252.     Allocated:=True; (* Structure built *)
  253.     AccessMode:=Mode; (* Default mode for array *)
  254.   end; (* With Headers... *)
  255.   OpenArray:=NewHandle (* Return the new handle for the array *)
  256. end;
  257.  
  258. Function Larray;
  259. (* This is a simple interface into the OpenArray function generating an
  260.    R/W array with a new datafile that will be purged upon closure *)
  261. Type NamStr=String[12];
  262. Var NewName:NamStr;
  263. Function GenName:NamStr;
  264. Var N:NamStr;
  265.     ChkCount:Integer;
  266.     F:File;
  267. Begin
  268.   (* Generate a unique name for the array in the format
  269.       'LARRYxxx.ARR' where xxx is 000 to 999 *)
  270.   For ChkCount:=1 To 999 Do
  271.   Begin
  272.     Str(ChkCount,N);
  273.     While Length(N)<3 Do N:='0'+N; (* Pad with zeroes *)
  274.     N:='LARRY'+N+'.ARR';
  275.     Assign(F,N); (* Check if already there *)
  276.     Reset(F);
  277.     If IoResult=2 Then (* If not *)
  278.     Begin
  279.       GenName:=N; (* Use this name *)
  280.       Exit
  281.     end;
  282.     Close(F)
  283.   end;
  284.   (* After testing all 1000 combinations ... *)
  285.   WriteLN('LARRY: Unable to generate name for array');
  286.   HALT
  287. end;
  288.  
  289. Begin
  290.   (* Do a call to OpenArray with defaultvaules *)
  291.   Larray:=OpenArray(GenName,EntrySize,NumEntries,DefaultBuckets,
  292.                     Purge,Create,ReadWrite)
  293. end;
  294.  
  295. Function DArray;
  296. (* Simplified interface for ON-DISK arrays. Supplied is filename
  297.    Opens file for array-access in REUSE and KEEP mode *)
  298.  
  299. Begin
  300.   DArray:=OpenArray(FName,EntrySize,NumEntries,DefaultBuckets,
  301.                     NoPurge,Reuse,ReadWrite)
  302. end;
  303.  
  304. Function Freeze;
  305. (* Locks an entry in ram *)
  306. Begin
  307.   (* We must be allowed to READ the array to use this *)
  308.   If Headers[Handle].AccessMode=NoRead Then
  309.   Begin
  310.     WriteLN('LARRY: Attempt FREEZE on WRITE ONLY array');
  311.     HALT
  312.   end;
  313.   (* Get the item to ensure it is in memory *)
  314.   (* it will endup in the first stackentry *)
  315.   Freeze:=GetPointer(Handle,Entry);
  316.   Headers[Handle].DataStack^[0].Locked:=True; (* Flag it resident *)
  317. end;
  318.  
  319. Procedure UnFreeze;
  320. (* Releases an entry allowing it to dissapear from memory
  321. NOTE: trying to release a nonlocked entry is actually an error but
  322.       since it will not couse ANY trouble to release an entry that
  323.       is not locked no such check will be done. *)
  324. Var Dummy:Pointer;
  325. Begin
  326.   Dummy:=GetPointer(Handle,Entry); (* Ensure it is in mem and bucket 0 *)
  327.   Headers[Handle].DataStack^[0].Locked:=False; (* Free it *)
  328. end;
  329.  
  330. Procedure FlushArray;
  331. (* Writes the content of an array out to disk emptying all buckets and
  332.    releasing all locks *)
  333. Var Ind:Integer;
  334. Begin
  335.   With Headers[Handle] Do
  336.   Begin
  337.     If Not Allocated Then Exit; (* Check if allocated *)
  338.     If Not FileOpen Then (* Open the file if it is closed *)
  339.     Begin
  340.       Reset(DiskFile,RecordSize);
  341.       IoAbort; (* Fail program if cant be done *)
  342.       FileOpen:=True;
  343.     end;
  344.     For Ind:=0 To StackSize-1 Do (* Search the entire stack *)
  345.     With DataStack^[Ind] Do
  346.       Begin
  347.         If ItemInBuf<>-1 Then (* Check if entry in bucket *)
  348.         Begin (* If so flush it out to disk *)
  349.           seek(DiskFile,ItemInBuf); (* Position filePtr *)
  350.           IoAbort;
  351.           BlockWrite(DiskFile,Data^,1); (* Write Data *)
  352.           IoAbort;
  353.           ItemInBuf:=-1; (* Free entry *)
  354.           Locked:=False; (* Release a locked entry (If any) *)
  355.         end
  356.       end;
  357.     Close(DiskFile); (* Close the file *)
  358.     FileOpen:=False; (* And flag it closed *)
  359.   end
  360. end;
  361.  
  362. Procedure FlushAllArrays;
  363. (* Do the above procedure for ALL arrays *)
  364. Var H:ArrayHandle;
  365. Begin
  366.   For H:=0 To MaxArraysOpen Do FlushArray(H)
  367. end;
  368.  
  369. Procedure CloseArray;
  370. (* Closes down the usage for an array *)
  371. Var Temp:Integer;
  372. Begin
  373.   (* Standard validity check *)
  374.   With Headers[Handle] Do
  375.   Begin
  376.     If Not Allocated Then Exit;
  377.     If PurgeWhenClosed=Purge Then (* Check for removal of file *)
  378.     Begin
  379.       (* If the file is to be removed we don't bother to flush the mem
  380.          buckets to disk, just simply deallocate it *)
  381.       If FileOpen Then Close(DiskFile); (* Close if open *)
  382.       FileOpen:=FALSE;
  383.       Erase(DiskFile); (* Murder disk file *)
  384.       If IoResult<>0 Then (* Check if OK *)
  385.       Begin
  386.         WriteLN('LARRY: Can''t scratch file');
  387.         HALT
  388.       end
  389.     end Else FlushArray(Handle); (* Else flush the buckets *)
  390.     (* Return all memory to the heap *)
  391.     For Temp:=0 To StackSize-1 Do
  392.       FreeMem(DataStack^[Temp].Data,RecordSize);
  393.     FreeMem(DataStack,StackSize*SizeOf(EntryType));
  394.     Allocated:=False; (* Say no longer allocated *)
  395.   end;
  396. end;
  397.  
  398.  
  399. (* **************************************************
  400.    Here is the most important function of this package!
  401.    It is used to shuffle data to and from memory, locating
  402.    the desired entry and returning a pointer to the data-
  403.    bucket. If you need to speed up the scheme it is in this
  404.    function you should start tampering... *)
  405.  
  406. Function GetPointer;
  407. Var Temp:Integer;
  408.  
  409. Procedure MoveLast(Entry:Integer);
  410. (* Used for moving a bucket into highpriority position (Bucket 0)
  411.    each time it is used *)
  412.  
  413. Var Hold:EntryType;
  414. Begin
  415.   If Entry=0 Then Exit; (* Dont try this with entry 0 *)
  416.   Hold:=Headers[Handle].DataStack^[Entry]; (* Copy the free entry *)
  417.   (* Move up first entries *)
  418.   Move(Headers[Handle].DataStack^[0],Headers[Handle].DataStack^[1],
  419.        SizeOf(EntryType)*Entry);
  420.   Headers[Handle].DataStack^[0]:=Hold (* Store entry at prio pos. *)
  421. end;
  422.  
  423. Procedure MoveUpStack;
  424. (* Move up the first entry taking care of entries falling out on the
  425.    other end, by writing them down into the file, the file is assumed
  426.    to be open *)
  427. Var LastFound:Integer;
  428.  
  429. Begin
  430.   With Headers[Handle] Do
  431.   Begin
  432.     If DataStack^[0].ItemInBuf=-1 Then Exit; (* First entry is free *)
  433.     If DataStack^[StackSize-1].ItemInBuf=-1 Then
  434.     Begin (* Last entry is free *)
  435.       MoveLast(StackSize-1);
  436.       Exit
  437.     end;
  438.     (* This is kinkier, the last entry needs to be written out unless it is
  439.        locket in ram where is should be ignored *)
  440.     LastFound:=StackSize-1; (* Scan for first nonlocked entry *)
  441.     While (LastFound<>-1) And (DataStack^[LastFound].Locked=True) Do
  442.       Dec(LastFound);
  443.     (* Now LastFound points to a safe entry or ... *)
  444.     If LastFound=-1 Then
  445.     Begin
  446.       WriteLN('LARRY: All entries LOCKED in stack');
  447.       HALT
  448.     end;
  449.     With DataStack^[LastFound] Do
  450.     Begin
  451.       If AccessMode<>NoWrite Then (* If ReadOnly dont write *)
  452.       Begin
  453.         seek(DiskFile,ItemInBuf);
  454.         IoAbort;
  455.         BlockWrite(DiskFile,Data^,1);
  456.         IoAbort
  457.       end;
  458.       ItemInBuf:=-1; (* Say bucket is empty *)
  459.     end;
  460.     MoveLast(LastFound); (* Move it to poleposition *)
  461.   end
  462. end;
  463.  
  464. Function FindEntry:Integer;
  465. (* Locate an entry in the stack return -1 if not found *)
  466. Var Temp:Integer;
  467. Begin
  468.   (* Scan the stack for the entry *)
  469.   With Headers[Handle] Do
  470.   For Temp:=0 To StackSize-1 Do
  471.   With DataStack^[Temp] Do
  472.   Begin
  473.     If ItemInBuf=Entry Then
  474.     Begin (* Found *)
  475.       FindEntry:=Temp;   (* To caller *)
  476.       Exit
  477.     end
  478.   end;
  479.   FindEntry:=-1;
  480. end;
  481.  
  482. Begin
  483.   If (Handle<0) Or (Handle>MaxArraysOpen) Then
  484.   Begin
  485.     WriteLN('LARRY: Invalid array handle');
  486.     HALT
  487.   end;
  488.   With Headers[Handle] Do
  489.   Begin
  490.     (* Do some validation *)
  491.     If Not Allocated Then
  492.     Begin
  493.       WriteLN('LARRY: Invalid array handle');
  494.       HALT
  495.     end;
  496.     (* Search the stack first *)
  497.     Temp:=FindEntry;
  498.     If Temp<>-1 Then With DataStack^[Temp] Do
  499.     Begin (* Found *)
  500.       GetPointer:=Data; (* Return pointer to data *)
  501.       MoveLast(Temp);   (* To pole position *)
  502.       Exit
  503.     end;
  504.     (* Not in stack, get from file *)
  505.     If Not FileOpen Then
  506.     Begin (* Open the file if closed *)
  507.       Reset(DiskFile,RecordSize);
  508.       IoAbort;
  509.       FileOpen:=True
  510.     end;
  511.     MoveUpStack; (* Move stack to form a new entry at position zero *)
  512.     With DataStack^[0] Do
  513.     Begin
  514.       If AccessMode<>NoRead Then (* Check for write only *)
  515.       Begin
  516.         seek(DiskFile,Entry); (* Position file ptr *)
  517.         IoAbort;
  518.         BlockRead(DiskFile,Data^,1); (* Read the entry to ram *)
  519.         IoAbort
  520.       end;
  521.       ItemInBuf:=Entry; (* Say in use by this item *)
  522.       Locked:=False;    (* and movable *)
  523.       GetPointer:=Data  (* Return of the pointer *)
  524.     end
  525.   end
  526. end;
  527.  
  528. Procedure WriteMode;
  529. (* Change the mode for an open array, this is used to switch mode
  530.    for example when initializing a large array *)
  531. Begin
  532.   With Headers[Handle] Do
  533.   Begin
  534.     If Not Allocated Then Exit;
  535.     AccessMode:=Flag
  536.   end
  537. end;
  538.  
  539. (*$F+*)
  540. (* This is a new exitprocedure installed to cleanup any arrays not
  541.    properly closed before program termination *)
  542.  
  543. Procedure ExitProcedure;
  544. Var H:ArrayHandle;
  545. Begin
  546.   ExitProc:=OldExit; (* Restore old exitprocedure *)
  547.   If (InOutRes<>0) And (ErrorAddr<>NIL) Then
  548.     (* Abort due to I/O error *)
  549.     Exit; (* Don't do anything *)
  550.   FlushAllArrays; (* Flush all arrays to disk *)
  551.   For H:=0 To MaxArraysOpen Do
  552.     If Headers[H].Allocated Then
  553.       CloseArray(H);
  554. end;
  555. (*$F-*)
  556.  
  557. Begin (* AutoInit part *)
  558.   For Ind:=0 To MaxArraysOpen Do (* Clear all assignments *)
  559.     With Headers[Ind] Do
  560.     Begin
  561.       Allocated:=False;
  562.       FileOpen:=False;
  563.       RecordSize:=0;
  564.       TotalEntries:=0;
  565.       DataStack:=NIL;
  566.       StackSize:=0;
  567.       PurgeWhenClosed:=NoPurge;
  568.       AccessMode:=ReadWrite;
  569.     end;
  570.   OldExit:=ExitProc; (* Copy old exitprocedure *)
  571.   ExitProc:=@ExitProcedure; (* Our exitcloser *)
  572. end.
  573.