home *** CD-ROM | disk | FTP | other *** search
/ RBBS in a Box Volume 1 #3.1 / RBBSIABOX31.cdr / typd / txtsek.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1990-09-29  |  7.5 KB  |  249 lines

  1. (*[72457,2131]
  2. TXTSEK.PAS                06-Oct-85 7075               184
  3.  
  4.     Keywords: MSDOS PCDOS TEXT INDEX RANDOM ACCESS FILES
  5.  
  6.     This program demonstrates a technique to index a sequential text file.
  7.     After indexing, any line of the text file can be accessed randomly by line
  8.     number. This may be useful for text sort programs, text-based databases,
  9.     large file editors or anywhere that disk paging of text files is required.
  10.     Written with PCDOS TP 3.01A, should run on MSDOS as is, CP/M with minor
  11.     modifications. Capacity as it stands is for files of up to 9000 lines and
  12.     2.3 Mbytes.
  13. *)
  14.  
  15. PROGRAM textseek;
  16.  
  17.     {
  18.     Demonstrate a technique for making a normal text file into a fully indexed
  19.     file, where any line can be read randomly by line number. Each line must
  20.     be terminated by at least a <LF>.
  21.  
  22.     Useful for text sort programs, large file editors, text databases, etc.
  23.  
  24.     Should run on any PCDOS or MSDOS Turbo 3.0 (developed on IBM).
  25.  
  26.     Written 10/5/85, Kim Kokkonen, TurboPower Software.
  27.     408-378-3672, CompuServe 72457,2131.
  28.  
  29.     Released to the public domain.
  30.     }
  31.  
  32.   CONST
  33.     {maxlines*maxlength gives the maximum filesize, here about 2.3 megabytes}
  34.     MaxLines = 9000;          {limited by 7*maxlines<=65536}
  35.     MaxLength = 255;          {max length of a given line, limited to 255}
  36.     BufSize = 4096;           {number of bytes per blockread}
  37.  
  38.   TYPE
  39.     TextString = STRING[MaxLength];
  40.     PathName = STRING[64];
  41.     FilePointer = RECORD
  42.                     SeekTo : Real;
  43.                     LenToRead : Byte;
  44.                   END;
  45.     FileIndexArray = ARRAY[1..MaxLines] OF FilePointer;
  46.     FileIndexPtr = ^FileIndexArray;
  47.     TextBuffer = ARRAY[1..BufSize] OF Char;
  48.     TextBufferPtr = ^TextBuffer;
  49.  
  50.     {following record carries all information about the indexed text file}
  51.     {requires 97 bytes in the segment where its var is located}
  52.     {requires 7*maxlines+bufsize on the heap}
  53.     IndexedFile =
  54.     RECORD
  55.       fil : FILE;             {untyped file is critical for this application}
  56.       EndOfFile : Boolean;    {true when all of file read}
  57.       LineNum : Integer;      {last line read in}
  58.       FilePosition : Real;    {current byte position in file during readin}
  59.       Buffer : TextBufferPtr; {pointer to buffer for this file}
  60.       BufPos : Integer;       {position in current buffer}
  61.       BytesRead : Integer;    {number read in last blockread}
  62.       index : FileIndexPtr;   {pointer to file index}
  63.     END;
  64.  
  65.   VAR
  66.     fname : PathName;
  67.     F : IndexedFile;
  68.     L : TextString;
  69.     LineToSeek : Integer;
  70.     Success : Boolean;
  71.  
  72.   FUNCTION Cardinal(i : Integer) : Real;
  73.       {-return positive real 0<=r<=65535}
  74.     VAR
  75.       r : Real;
  76.     BEGIN
  77.       r := i;
  78.       IF r < 0 THEN r := r+65536.0;
  79.       Cardinal := r;
  80.     END;                      {cardinal}
  81.  
  82.   PROCEDURE OpenFile(fname : PathName;
  83.                      VAR F : IndexedFile;
  84.                      VAR Success : Boolean);
  85.       {-open an indexed textfile, return true if successful}
  86.     BEGIN
  87.       WITH F DO BEGIN
  88.  
  89.         {open the physical file}
  90.         Assign(fil, fname);
  91.         {$I-} Reset(fil, 1) {$I+} ;
  92.         Success := (IOResult = 0);
  93.         IF NOT(Success) THEN Exit;
  94.         EndOfFile := False;
  95.  
  96.         {allocate the file buffer}
  97.         Success := 16.0*Cardinal(MaxAvail) > Cardinal(SizeOf(TextBuffer));
  98.         IF NOT(Success) THEN BEGIN
  99.           Close(fil);
  100.           Exit;
  101.         END;
  102.         New(Buffer);
  103.         BytesRead := 0;
  104.         BufPos := 1;          {force blockread the first time}
  105.  
  106.         {allocate the lines array}
  107.         Success := 16.0*Cardinal(MaxAvail) > Cardinal(SizeOf(FileIndexArray));
  108.         IF NOT(Success) THEN BEGIN
  109.           Close(fil);
  110.           Exit;
  111.         END;
  112.         New(index);
  113.         LineNum := 0;
  114.         FilePosition := 0.0;
  115.  
  116.       END;
  117.     END;                      {openfile}
  118.  
  119.   PROCEDURE CloseFile(VAR F : IndexedFile);
  120.       {-free up dynamic space and close physical file}
  121.     BEGIN
  122.       WITH F DO BEGIN
  123.         Close(fil);
  124.         Dispose(index);
  125.         Dispose(Buffer);
  126.       END;
  127.     END;                      {closefile}
  128.  
  129.   PROCEDURE ReadNewLine(VAR F : IndexedFile; VAR L : TextString);
  130.       {-read a text line and store information for later random access}
  131.     VAR
  132.       EndOfLine : Boolean;
  133.       lpos, terminators : Integer;
  134.       ch : Char;
  135.     BEGIN
  136.       WITH F DO BEGIN
  137.         EndOfLine := False;
  138.         lpos := 0;
  139.         terminators := 1;
  140.  
  141.         {look at characters until end of line found}
  142.         REPEAT
  143.  
  144.           IF BufPos > BytesRead THEN BEGIN
  145.             {get another buffer full}
  146.             BlockRead(fil, Buffer^, BufSize, BytesRead);
  147.             BufPos := 1;
  148.           END;
  149.  
  150.           IF BytesRead = 0 THEN
  151.             ch := ^Z
  152.           ELSE BEGIN
  153.             ch := Buffer^[BufPos];
  154.             BufPos := Succ(BufPos);
  155.           END;
  156.  
  157.           CASE ch OF
  158.             ^M : terminators := Succ(terminators);
  159.             ^J : EndOfLine := True;
  160.             ^Z : BEGIN
  161.                    EndOfLine := True;
  162.                    EndOfFile := True;
  163.                  END;
  164.           ELSE
  165.             IF lpos < MaxLength THEN BEGIN
  166.               lpos := Succ(lpos);
  167.               L[lpos] := ch;
  168.             END;
  169.           END;
  170.  
  171.         UNTIL EndOfLine;
  172.  
  173.         {finish up line}
  174.         L[0] := Chr(lpos);
  175.  
  176.         {store info for later random access}
  177.         IF LineNum < MaxLines THEN BEGIN
  178.           LineNum := Succ(LineNum);
  179.           WITH index^[LineNum] DO BEGIN
  180.             SeekTo := FilePosition;
  181.             LenToRead := lpos;
  182.           END;
  183.           FilePosition := FilePosition+lpos+terminators;
  184.         END;
  185.  
  186.       END;
  187.     END;                      {readnewline}
  188.  
  189.   PROCEDURE ReadIndexedLine(VAR F : IndexedFile;
  190.                             VAR Num : Integer;
  191.                             VAR L : TextString);
  192.       {-get an indexed line from f}
  193.       {increment num for quasi-sequential access}
  194.     BEGIN
  195.       WITH F DO BEGIN
  196.         IF (Num > 0) AND (Num < LineNum) THEN BEGIN
  197.           WITH index^[Num] DO BEGIN
  198.             LongSeek(fil, SeekTo);
  199.             BlockRead(fil, L[1], LenToRead);
  200.             L[0] := Chr(LenToRead);
  201.           END;
  202.           Num := Succ(Num);
  203.         END ELSE BEGIN
  204.           L := '';
  205.           Num := 0;
  206.         END;
  207.       END;
  208.     END;                      {readindexedline}
  209.  
  210.   PROCEDURE BuildFileIndex(fname : PathName;
  211.                            VAR F : IndexedFile;
  212.                            VAR Success : Boolean);
  213.       {-read a text file and define index pointers for random access}
  214.     VAR
  215.       L : TextString;
  216.     BEGIN
  217.       OpenFile(fname, F, Success);
  218.       IF NOT(Success) THEN Exit;
  219.       {read it all to get the filepointers}
  220.       {ignore the returned string l in this case}
  221.       WHILE NOT(F.EndOfFile) DO ReadNewLine(F, L);
  222.     END;                      {buildfilepointers}
  223.  
  224.   BEGIN
  225.  
  226.     {get a file to read, and read it in}
  227.     Write('Enter text file name to read: ');
  228.     ReadLn(fname);
  229.     WriteLn('Reading');
  230.     BuildFileIndex(fname, F, Success);
  231.     IF NOT(Success) THEN BEGIN
  232.       WriteLn('could not build index...');
  233.       Halt;
  234.     END;
  235.  
  236.     {demonstrate random access}
  237.     REPEAT
  238.       Write('Enter any linenumber (0 to quit, max ', F.LineNum, '): ');
  239.       ReadLn(LineToSeek);
  240.       IF LineToSeek > 0 THEN BEGIN
  241.         ReadIndexedLine(F, LineToSeek, L);
  242.         WriteLn(L);
  243.       END;
  244.     UNTIL LineToSeek = 0;
  245.  
  246.     CloseFile(F);
  247.  
  248.   END.
  249.