[Back to TEXTFILE SWAG index] [Back to Main SWAG index] [Original]

    {
    From: tfiske@delphi.com (Todd Fiske)

    I've got a huge unit that I've put together over the years that does this,
    but I'm not really ready to part with it. I'm happy to trade some tips
    though.

    The easiest way to start is with text files under 64K, for which you don't
    have to worry about lines crossing the buffer boundary. Get the size of the
    file, then allocate an array on the heap of that size and blockread the file
    into it. Then use a function that reads from the current position up to the
    next CR and/or LF and returns all of that as a string. Here's a simple
    example of this:

    {------------------------------------------------}
    {- bintext.pas - binary text file example       -}
    {- Todd Fiske (tfiske@delphi.com) - 09/28/1994  -}
    {------------------------------------------------}
    program bintext;

    uses
       dos;

    const
       CR = #13;
       LF = #10;

    {------------------------------------------------}
    {- input structure definition & base routines   -}
    {------------------------------------------------}
    type
       big_array = array[0..65519] of byte;
       big_ptr = ^big_array;
       input_buffer = record
          data : big_ptr;
          size : word;
          curr : word;
       end;
       input_ptr = ^input_buffer;

    procedure start_input(var i : input_ptr; size : word);
    begin
       if i = nil then begin
          new(i);                          { create structure }
          i^.size := size;
          GetMem(i^.data, i^.size);        { create array (could test MemAvail) }
          fillchar(i^.data^, i^.size, 0);  { initialize }
          i^.curr := 0;
       end;
    end;
    procedure stop_input(var i : input_ptr);
    begin
       if i <> nil then begin
          FreeMem(i^.data, i^.size);       { done with array }
          dispose(i);                      { done with structure }
          i := nil;
       end;
    end;
    procedure load_input(i : input_ptr; s : string);
    var
       f : file;
    begin
       assign(f, s);                       { set filename }
       reset(f, 1);                        { open with record length 1 }
       blockread(f, i^.data^, i^.size);    { read in file - should test IOResult }
       close(f);
    end;

    {------------------------------------------------}
    {- low level access routines                    -}
    {------------------------------------------------}
    function curr_char(i : input_ptr) : char;
    begin
       curr_char := char(i^.data^[i^.curr]);
    end;
    procedure next_char(i : input_ptr);
    begin
       inc(i^.curr);
    end;
    function curr_pos(i : input_ptr) : word;
    begin
       curr_pos := i^.curr;
    end;
    function end_of_input(i : input_ptr) : boolean;
    begin
       end_of_input := i^.curr >= i^.size;
    end;

    {------------------------------------------------}
    {- medium level access                          -}
    {------------------------------------------------}
    function get_line(i : input_ptr) : string;
    var
       w   : string;
       stt : word;
       len : byte;
    begin
       stt := curr_pos(i);
       while (not (curr_char(i) in [CR, LF])) and (not end_of_input(i)) do
          next_char(i);
       {- testing for both CR and LF here allows reading of Unix files -}

       len := curr_pos(i) - stt;           { determine length read }
       move(i^.data^[stt], w[1], len);     { copy into work string }
       w[0] := char(len);                  { set work string length }

       if curr_char(i) = CR then next_char(i);  { skip line-end chars }
       if curr_char(i) = LF then next_char(i);

       get_line := w;                      { return work string }
    end;

    {------------------------------------------------}
    {- main program                                 -}
    {------------------------------------------------}
    var
       sr   : SearchRec;
       i    : input_ptr;
       line : string;

    begin
       writeln;
       writeln('BinText - binary textfile example');

       if paramcount = 0 then begin        { check command line }
          writeln;
          writeln('usage: bintext <filename>');
          halt;
       end;

       FindFirst(paramstr(1), AnyFile, sr); { test input file }
       if DOSError <> 0 then begin
          writeln(paramstr(1), ' not found');
          halt;
       end;
       if sr.size > 65520 then begin
          writeln(sr.name, ' : ', sr.size, ' bytes - too big (65520 bytes max)');
          halt;
       end;

       i := nil;                           { load, read, and close }
       start_input(i, sr.size);
       load_input(i, sr.name);

       while not end_of_input(i) do begin
          line := get_line(i);
          writeln(line);
       end;

       stop_input(i);
    end.
    {------------------------------------------------}
    {- eof                                          -}
    {------------------------------------------------}

    {
    This array-of-char file handling can be very flexible. I've included routines
    in my own to do things like skip whitespace, skip while in a particular groups
    of characters, skip until in a group of characters, get-while and get-until
    routines, etc. Another thing you can do is save the byte start position of each
    line, and jump right to that line by setting i^.curr. What's more, the same
    basic methods work on binary files as well.
    }

[Back to TEXTFILE SWAG index] [Back to Main SWAG index] [Original]