tim11g wrote:
> I have some old code filled with Writeln's that I want to use in a GUI
> application. I would like to redirect STDOUT to a Tmemo, so the
> writeln's would be logged into the Memo.
> 
> Modeling on the code for CRT32, I have written a a replacement for
> TextOut that writes to the Tmemo. I have made a version of AssignCRT
> called AssignMemo, but I don't know where to call it from, or what
> variable to use for the file handle, F.
> 
> If I attempt to run what I have so far, I get "I/O Error 105" on the
> line   ReWrite(Output); during the initialization.
> 
> Here is the code I have so far:

You have sort of the right idea. I've written a unit based on Peter 
Below's StreamIO unit (which is very similar to what ianhinson provided 
in his reply). It's provided below. Call AssignStrings to associate a 
TStrings object (such as TMemo.Lines) with a TextFile variable. Then 
call the normal I/O functions and pass that TextFile variable as the 
first parameter, just as if you were writing to a real file.

If you're still set on using your old WriteLn commands unchanged, then 
let me know and I'll take another look. But if you want to write to 
something other than stdout, a text-file driver with a custom Assign 
command is really the right way to do it.

-- 
Rob

unit StringsIO;

// By Rob Kennedy, 29 December 2006
// See http://www.cs.wisc.edu/~rkennedy/license

// Based on StreamIO by Peter Below
// Subject: Re: Text Files and Streams
// Message-ID: <[EMAIL PROTECTED]>
// borland.public.delphi.objectpascal
// Thu, 04 Jan 2001 17:20:29 +0100
// 
http://groups.google.com/group/borland.public.delphi.objectpascal/msg/d682a8b5a5760ac4

interface

uses Classes;

// Attach a TStrings S to a TextFile F to allow I/O via WriteLn/ReadLn
// S must not be nil
// The TStrings object is not freed when the textfile is closed via
// CloseFile. It has to stay in existence and must not be modified
// through other means as long as the textfile is open.
procedure AssignStrings(var F: TextFile; S: TStrings);

implementation

uses SysUtils, Math;

type
   PInternalData = ^TInternalData;
   TInternalData = record
     Strings: TStrings;
     Text: string;
     Char: Integer;
   end;

// Get the internal data stored in the textrec userdata area
function GetDeviceData(var F: TTextRec): PInternalData;
begin
   Result := PInternalData(@F.UserData);
end;

// Called by Read, ReadLn etc. to fill the textfiles buffer from the
// TStrings object.
function DevIn(var F: TTextRec): Integer;
var
   Data: PInternalData;
begin
   Result := 0;
   Data := GetDeviceData(F);
   if Data.Char <= Length(Data.Text) then begin
     F.BufEnd := Min(F.BufSize, Length(Data.Text) - Pred(Data.Char));
     Move(Data.Text[Data.Char], F.BufPtr^, F.BufEnd);
     Inc(Data.Char, F.BufEnd);
   end else
     F.BufEnd := 0;
   F.BufPos := 0;
end;

// A dummy method, flush on input does nothing.
function DevFlushIn(var F: TTextRec): Integer;
begin
   Result := 0;
end;

// Write the textfile buffers content to the TStrings. Called by Write,
// WriteLn when the buffer becomes full. Also called by Flush.
function DevOut(var F: TTextRec): Integer;
var
   Data: PInternalData;
   s: string;
begin
   Result := 0;
   if F.BufPos <= 0 then
     exit;
   Data := GetDeviceData(F);
   SetString(s, F.BufPtr, F.BufPos);
   Data.Strings.Text := Data.Strings.Text + s;
   F.BufPos := 0;
end;

// Called by CloseFile. Clears the internal record
function DevClose(var F: TTextRec): Integer;
var
   Data: PInternalData;
begin
   Data := GetDeviceData(F);
   Finalize(Data^);
   Result := 0;
end;

// Called by Reset, Rewrite, or Append to prepare the textfile for I/O
function DevOpen(var F: TTextRec): Integer;
var
   Data: PInternalData;
begin
   Result := 0;
   Data := GetDeviceData(F);
   case F.Mode of
     fmInput: begin // Reset
       F.InOutFunc := @DevIn;
       F.FlushFunc := @DevFlushIn;
       F.BufPos := 0;
       F.BufEnd := 0;
       Data.Char := 1;
       Data.Text := Data.Strings.Text;
     end;
     fmOutput: begin // Rewrite
       F.InOutFunc := @DevOut;
       F.FlushFunc := @DevOut;
       F.BufPos := 0;
       F.BufEnd := 0;
       Data.Char := 0;
       Data.Strings.Clear;
     end;
     fmInOut: begin // Append
       F.Mode := fmOutput;
       F.InOutFunc := @DevOut;
       F.FlushFunc := @DevOut;
       F.BufPos := 0;
       F.BufEnd := 0;
       Data.Char := 0;
     end;
   end;
end;

procedure AssignStrings(var F: TextFile; S: TStrings);
var
   Data: PInternalData;
begin
   Assert(Assigned(S));
   TTextRec(F).Mode := fmClosed;
   TTextRec(F).BufSize := SizeOf(TTextRec(F).Buffer);
   TTextRec(F).BufPtr := TTextRec(F).Buffer;
   TTextRec(F).OpenFunc := @DevOpen;
   TTextRec(F).CloseFunc := @DevClose;
   TTextRec(F).Name[0] := #0;
   TTextRec(F).Flags := tfCRLF;
   // Store strings reference into Userdata area
   Data := GetDeviceData(TTextRec(F));
   Initialize(Data^);
   Data.Strings := S;
end;

end.

Reply via email to