Discussion:
[Lazarus] Cloning standard output to text file
Carlos E. R. via Lazarus
2018-05-04 10:51:38 UTC
Permalink
Hi,

I know I did this decades ago with Turbo Pascal, but I can't remember
how, and my google foo fails me.

I want to do a series of "writeln(...)" and have the output go
simultaneously to the console and to a text file of my choice. I have
the vague idea that this was done writing a text file handler :-?

I can of course do two writeln calls for each current call, but it is a
nuisance.

I can not use a mywriteln wrapper that would do the two calls, because I
do not know how to create a procedure that takes a variant number of
parameters, as "writeln()" does...

Ideas?

If you know of a google search string to locate these ideas, just tell
me ;-)
--
Cheers / Saludos,

Carlos E. R.
(from 42.3 x86_64 "Malachite" at Telcontar)
Mattias Gaertner via Lazarus
2018-05-04 10:58:00 UTC
Permalink
On Fri, 4 May 2018 12:51:38 +0200
Post by Carlos E. R. via Lazarus
[...]
I want to do a series of "writeln(...)" and have the output go
simultaneously to the console and to a text file of my choice. I have
the vague idea that this was done writing a text file handler :-?
[...]
If you know of a google search string to locate these ideas, just tell
me ;-)
fpc redirect stdout

Mattias
--
Carlos E. R. via Lazarus
2018-05-04 11:31:50 UTC
Permalink
Post by Mattias Gaertner via Lazarus
On Fri, 4 May 2018 12:51:38 +0200
Post by Carlos E. R. via Lazarus
[...]
I want to do a series of "writeln(...)" and have the output go
simultaneously to the console and to a text file of my choice. I have
the vague idea that this was done writing a text file handler :-?
[...]
If you know of a google search string to locate these ideas, just tell
me ;-)
fpc redirect stdout
Thank you! :-)

Found it. At least for redirection, the output is sent to a file.

<http://lists.freepascal.org/fpc-pascal/2010-July/026163.html>

Now I have to figure out how to write both to file and screen :-)

More ideas to investigate here:

<http://fpc-devel.freepascal.narkive.com/KZnUZaMJ/stdout-capture-for-fpc-rtl>
--
Cheers / Saludos,

Carlos E. R.
(from 42.3 x86_64 "Malachite" at Telcontar)
Marco van de Voort via Lazarus
2018-05-04 17:30:56 UTC
Permalink
Post by Carlos E. R. via Lazarus
Now I have to figure out how to write both to file and screen :-)
fpc streamio
--
Carlos E. R. via Lazarus
2018-05-04 18:15:56 UTC
Permalink
Post by Marco van de Voort via Lazarus
Post by Carlos E. R. via Lazarus
Now I have to figure out how to write both to file and screen :-)
fpc streamio
Results in church related links, LOL.


Better "freepascal streamio".

<https://www.freepascal.org/docs-html/fcl/streamio/index.html>

«The StreamIO unit implements a call to reroute the input or output of a
text file to a descendents of TStream.»


Sorry, I fail to see how I can use this with writeln to write to *both*
output and file at the same time. Maybe I miss something :-?
--
Cheers / Saludos,

Carlos E. R.
(from 42.3 x86_64 "Malachite" at Telcontar)
leledumbo via Lazarus
2018-05-06 21:39:02 UTC
Permalink
Post by Carlos E. R. via Lazarus
Sorry, I fail to see how I can use this with writeln to write to *both*
output and file at the same time. Maybe I miss something :-?
{$mode objfpc}{$H+}

uses
Classes,SysUtils,StreamIO;

type
TDoubleStream = class(TFileStream)
private
FStdOut: TextFile;
public
constructor Create(const AFileName: string; Mode: Word);
destructor Destroy; override;
function Write(const Buffer; Count: longint): longint; override;
end;

constructor TDoubleStream.Create(const AFileName: string; Mode: Word);
begin
inherited Create(AFileName,Mode);
AssignFile(FStdOut,''); // empty string = stdout
Rewrite(FStdOut);
end;

destructor TDoubleStream.Destroy;
begin
CloseFile(FStdOut);
inherited Destroy;
end;

function TDoubleStream.Write(const Buffer; Count: longint): longint;
var
p: PChar;
begin
Result := inherited Write(Buffer, Count);
p := PChar(@Buffer); // safe assumption for standard output, I guess?
while Count > 0 do begin
System.Write(FStdOut,p^);
Inc(p);
Dec(Count);
end;
end;

var
ds: TStream;
begin
ds := TDoubleStream.Create('log.txt', fmCreate or fmOpenWrite);
try
AssignStream(Output,ds);
Rewrite(Output);
WriteLn('Hello!');
finally
ds.Free;
end;
end.



--
Sent from: http://free-pascal-lazarus.989080.n3.nabble.com/
--

Bart via Lazarus
2018-05-04 11:30:10 UTC
Permalink
On Fri, May 4, 2018 at 12:51 PM, Carlos E. R. via Lazarus
Post by Carlos E. R. via Lazarus
I want to do a series of "writeln(...)" and have the output go
simultaneously to the console and to a text file of my choice. I have
the vague idea that this was done writing a text file handler :-?
I once wrote a simple utility (myutil) that read from stdin, echoed to
stdout and echoed to a logfile.
I then used a pipe from the commandline to achieve what I wanted.
E.g.:

myprog | mytuil path/to/log

Or something similar to that.

Bart
--
Carlos E. R. via Lazarus
2018-05-04 11:34:54 UTC
Permalink
Post by Bart via Lazarus
On Fri, May 4, 2018 at 12:51 PM, Carlos E. R. via Lazarus
Post by Carlos E. R. via Lazarus
I want to do a series of "writeln(...)" and have the output go
simultaneously to the console and to a text file of my choice. I have
the vague idea that this was done writing a text file handler :-?
I once wrote a simple utility (myutil) that read from stdin, echoed to
stdout and echoed to a logfile.
I then used a pipe from the commandline to achieve what I wanted.
myprog | mytuil path/to/log
Or something similar to that.
Yes, of course, that's what I'm doing now, but I wanted to do it
internally, control the file name, perhaps rotate it, etc :-)


Actually:

myprog | tee mytuil path/to/log



It has the effect that text to screen is written in chunks, may stop at
the middle of a line. So at the end each cycle, I issue a "flush(output);"
--
Cheers / Saludos,

Carlos E. R.
(from 42.3 x86_64 "Malachite" at Telcontar)
Reimar Grabowski via Lazarus
2018-05-04 16:46:43 UTC
Permalink
On Fri, 4 May 2018 13:34:54 +0200
Post by Carlos E. R. via Lazarus
Yes, of course, that's what I'm doing now, but I wanted to do it
internally, control the file name, perhaps rotate it, etc :-)
Perhaps you should use a logger.
There are surely some FPC ones out there that can do all this for you.
A fast google search brings up http://wiki.freepascal.org/Log4Delphi which is based on Log4J (which does all that).

hih
R.
--
Carlos E. R. via Lazarus
2018-05-04 18:09:00 UTC
Permalink
Post by Reimar Grabowski via Lazarus
On Fri, 4 May 2018 13:34:54 +0200
Post by Carlos E. R. via Lazarus
Yes, of course, that's what I'm doing now, but I wanted to do it
internally, control the file name, perhaps rotate it, etc :-)
Perhaps you should use a logger.
There are surely some FPC ones out there that can do all this for you.
A fast google search brings up http://wiki.freepascal.org/Log4Delphi which is based on Log4J (which does all that).
Well, I send to syslog the important things :-)

In this phase I use many writeln as debug help, and using a pipe and a
tee does the job fine.

The idea here:
<http://lists.freepascal.org/fpc-pascal/2010-July/026163.html> redirects
all stdout to a file, but I'm thinking that it is basically the same as
replacing all writeln found with writeln(F, ...), achieving the same
thing perhaps simpler. Well, except that commenting out a the call to
"redirect" disables it.

The basic trick it does is:

var
f : TextFile;
s: TDebugStream;

and a procedure to redirect the output:


procedure redirect;
begin
s := TDebugStream.Create();
AssignStream(f, s);
Rewrite(f);
output := f;
end;


wich replaces stdout (output) with f. The role of tTDebugStream I don't
get. It is created thus:



Type
TDebugStream = class(TStream)
function Write(const Buffer; Count : Longint) : Longint; override;
end;

implementation

function TDebugStream.Write(const Buffer; Count : Longint) : Longint;
var
msg : ansistring;

begin
result := count;
SetLength(msg, count);
move(buffer, PChar(msg)[0], count);
OutputDebugString(PChar(TrimRight(msg)));
end;



I also miss where the file name is assigned.


But anyway, what I wanted is to write both to the screen and to a file,
so this is not sufficient.


Further in the thread they say that this would do - this is the classic
method I had forgotten:


var
oldoutput, f: TextFile;
begin
AssignFile(f, 'somefile');
Rewrite(f);
oldoutput := Output;
Output := f;
Writeln('Hello World'); // this is send to Output
Output := oldoutput;
CloseFile(f);
end.

At the start of the thread there is a suggestion to "implementing your
own textfile driver", but the link is dead.
--
Cheers / Saludos,

Carlos E. R.
(from 42.3 x86_64 "Malachite" at Telcontar)
Loading...