Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2023-12

Procedures that work like WRITELN()

9 messages · 6 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

James Richters

I wanted to write what I thought should be a simple procedure, just instead of calling WRITELN() with some arguments,
call WRITELOG() with the same arguments that you would use to write to a file, but my WRITELOG() procedure would
write to the screen and the file.. but I can't figure out how to pass all the arguments to the two WRTIELNs.

So..

Procedure WriteLog(Filename:String, AllOtherAurguments:????);
Begin
    Writeln(Filename,AllOtherAurguments);
    Writeln(AllOtherAurguments);
End;

How can I make this work? Since WRITELN can take any number of many kinds of arguments,
how can I get them all and pass them along without knowing how many or what types they are?
How does WRITELN even work when you don't know this information?

I'm guessing there should be some way to do this, because WRITELN itself works, but how it could
possibly work is not within my experience.

The only way I could think of would be if there were versions of WRITELN with every combination
of possible arguments, but that seems completely unmanageable and ridiculous,
so there must be something more advanced going on, but maybe WRTELN is special and not something I can duplicate?

Any Ideas?

James

Reply by email

Michael Van Canneyt
to James Richters
James Richters wrote 31 lines
I wanted to write what I thought should be a simple procedure, just instead of calling WRITELN() with some arguments, call WRITELOG() with the same arguments that you would use to write to a file, but my WRITELOG() procedure would write to the screen and the file.. but I can't figure out how to pass all the arguments to the two WRTIELNs. So.. Procedure WriteLog(Filename:String, AllOtherAurguments:????); Begin Writeln(Filename,AllOtherAurguments); Writeln(AllOtherAurguments); End; How can I make this work? Since WRITELN can take any number of many kinds of arguments, how can I get them all and pass them along without knowing how many or what types they are? How does WRITELN even work when you don't know this information? I'm guessing there should be some way to do this, because WRITELN itself works, but how it could possibly work is not within my experience. The only way I could think of would be if there were versions of WRITELN with every combination of possible arguments, but that seems completely unmanageable and ridiculous, so there must be something more advanced going on, but maybe WRTELN is special and not something I can duplicate?

Writeln() is special. You cannot duplicate it.

What you can do is use WriteStr(), it has the same action as Writeln() but writes to a string instead of a file.

https://www.freepascal.org/docs-html/current/rtl/system/writestr.html

Michael.

Reply by email

Thomas Kurz
to Michael Van Canneyt

I think he wants to define his own procedure.

The nearest thing that comes into my mind is using ARRAY OF CONST, but the call requires square brackets, then:

procedure myproc (x: string; y: array of const);
begin ... end;
myproc ('Hello world', ['Number 1', 'Number 2', 3, 4.0]);
Earlier message 50 lines
----- Original Message ----- From: Michael Van Canneyt via fpc-pascal To: Sent: Wednesday, December 27, 2023, 12:40:24 Subject: [fpc-pascal] Procedures that work like WRITELN() On Wed, 27 Dec 2023, James Richters via fpc-pascal wrote: > I wanted to write what I thought should be a simple procedure, just instead > of calling WRITELN() with some arguments, > call WRITELOG() with the same arguments that you would use to write to a > file, but my WRITELOG() procedure would > write to the screen and the file.. but I can't figure out how to pass all > the arguments to the two WRTIELNs. > So.. > Procedure WriteLog(Filename:String, AllOtherAurguments:????); > Begin > Writeln(Filename,AllOtherAurguments); > Writeln(AllOtherAurguments); > End; > How can I make this work? Since WRITELN can take any number of many kinds > of arguments, > how can I get them all and pass them along without knowing how many or what > types they are? > How does WRITELN even work when you don't know this information? > I'm guessing there should be some way to do this, because WRITELN itself > works, but how it could > possibly work is not within my experience. > The only way I could think of would be if there were versions of WRITELN > with every combination > of possible arguments, but that seems completely unmanageable and > ridiculous, > so there must be something more advanced going on, but maybe WRTELN is > special and not something I can duplicate? Writeln() is special. You cannot duplicate it. What you can do is use WriteStr(), it has the same action as Writeln() but writes to a string instead of a file. https://www.freepascal.org/docs-html/current/rtl/system/writestr.html Michael.

Reply by email

James Richters
to Michael Van Canneyt: Writeln() is special. You cannot duplicate it. What you can do is use WriteStr(), it has…
Writeln() is special. You cannot duplicate it.

That's good to know, I can stop trying.

What you can do is use WriteStr(), it has the same action as Writeln() but

writes to a string instead of a file.

I was hoping to just replace all existing Writeln()s with my procedure with a global search and replace.
I think it's probably easiest to make my procedure:

Procedure WriteLog(Filename:String, WriteString:String);
Begin
    Writeln(Filename,WriteString);
    Writeln(WriteString);
End;

Then just fix the call to concatenate everything into a single string:

So if I end up with this:
WriteLog(Myfile,'some text ',MyInteger);
I'll have to change it to this:
WriteLog(Myfile,'some text '+InttoStr(MyInteger));

And if the arguments are really complicated I can just use WriteStr() to store it into a string and call my procedure with the resulting string.

It will be a little more effort than doing a global search and replace but at least I know that it's the only way.

Thanks for the help

James

Reply by email

DougC
to James Richters

It would be very useful if WriteStr() was a function that returned the resulting string instead of returning it via an output parameter. Then you could just wrap the Writeln parameters in WriteStr() and pass it to the new logging procedure. Unfortunately, the ISO extension did not end up doing that!

Doug C.

Reply by email

Sven Barth
to James Richters: I wanted to write what I thought should be a simple procedure, just instead of calling…
James Richters wrote 44 lines
I wanted to write what I thought should be a simple procedure, just instead of calling WRITELN() with some arguments, call WRITELOG() with the same arguments that you would use to write to a file, but my WRITELOG() procedure would write to the screen and the file.. but I can’t figure out how to pass all the arguments to the two WRTIELNs. So…. Procedure WriteLog(Filename:String, AllOtherAurguments:????); Begin Writeln(Filename,AllOtherAurguments); Writeln(AllOtherAurguments); End; How can I make this work?Since WRITELN can take any number of many kinds of arguments, how can I get them all and pass them along without knowing how many or what types they are? How does WRITELN even work when you don’t know this information? I’m guessing there should be some way to do this, because WRITELN itself works, but how it could possibly work is not within my experience. The only way I could think of would be if there were versions of WRITELN with every combination of possible arguments, but that seems completely unmanageable and ridiculous, so there must be something more advanced going on, but maybe WRTELN is special and not something I can duplicate?

Write(Ln) is a compiler intrinsic and thus can behave in ways that are not possible for ordinary functions.

Your only ways are either to use "array of const" like "Format" does or write a text file driver as is done in the StreamIO unit which allows to assign a Stream to a TextFile that can in turn be used as the file parameter of Write(Ln). You can implement any other output through this.

Regards,
Sven

Reply by email

Wayne Sherman
to James Richters: I wanted to write what I thought should be a simple procedure, just instead of calling…
Show quoted text 5 lines
I wanted to write what I thought should be a simple procedure, just instead of calling WRITELN() with some arguments, call WRITELOG() with the same arguments that you would use to write to a file, but my WRITELOG() procedure would write to the screen and the file.. but I can’t figure out how to pass all the arguments to the two WRTIELNs.

Essentially you want to emulate what the "tee" command does but internal to your program. You can intercept data written to STDOUT and copy the data to your desired destination(s) (i.e. to console and file).

See message thread "redirecting stdout" here:
https://lists.freepascal.org/pipermail/fpc-pascal/2010-July/thread.html#26149

Also redirecting stdout to a Stream / TMemo:
https://forum.lazarus.freepascal.org/index.php/topic,34621.0.html

Reply by email

Wayne Sherman
to James Richters: I wanted to write what I thought should be a simple procedure, just instead of calling…

Example using a TFileStream descendant and StreamIO AssignStream:

program TeeStdOut;
{$mode objfpc}
uses
  Classes, SysUtils, StreamIO;
type
  TTeeStream = class(TFileStream)
  Private
    FOriginalStdOut: Text;
    FNewStdOut: Text;
  public
    constructor Create(const AFileName: string; Mode: Word);
    destructor Destroy; override;
    function Write(const Buffer; Count : Longint) : Longint; override;
  end;
constructor TTeeStream.Create(const AFileName: string; Mode: Word);
begin
  inherited Create(AFileName, Mode);
  FOriginalStdOut := Output; // save original stdout
  AssignStream(FNewStdOut, Self);
  Rewrite(FNewStdOut);
  // The following code causes stdout to be redirected
  //   to FNewStdOut (and our TTeeStream)
  Output := FNewStdOut;
end;
destructor TTeeStream.Destroy;
begin
  Output := FOriginalStdOut;
  Close(FNewStdOut);
  inherited Destroy;
end;
function TTeeStream.Write(const Buffer; Count: Longint): Longint;
begin
  Result := inherited Write(Buffer, Count);
//  FileWrite(System.StdOutPutHandle, Buffer, Count); //this also works
  FileWrite(TextRec(Output).Handle, Buffer, Count);
end;
var
  TeeStream: TTeeStream;
begin
  WriteLn('WriteLn to stdout before TTeeStream redirect');
  TeeStream := TTeeStream.Create('test.txt', fmCreate);
  try
    WriteLn('Hello, World! after creating TTeeStream');
    WriteLn('(WriteLn to stdout redirected to console and to file)');
  finally
    TeeStream.Free;
  end;
  WriteLn('WriteLn to stdout after destroying TTeeStream');
end.
Show quoted text 58 lines
I wanted to write what I thought should be a simple procedure, just instead of calling WRITELN() with some arguments, call WRITELOG() with the same arguments that you would use to write to a file, but my WRITELOG() procedure would write to the screen and the file.. but I can’t figure out how to pass all the arguments to the two WRTIELNs. So…. Procedure WriteLog(Filename:String, AllOtherAurguments:????); Begin Writeln(Filename,AllOtherAurguments); Writeln(AllOtherAurguments); End; How can I make this work? Since WRITELN can take any number of many kinds of arguments, how can I get them all and pass them along without knowing how many or what types they are? How does WRITELN even work when you don’t know this information? I’m guessing there should be some way to do this, because WRITELN itself works, but how it could possibly work is not within my experience. The only way I could think of would be if there were versions of WRITELN with every combination of possible arguments, but that seems completely unmanageable and ridiculous, so there must be something more advanced going on, but maybe WRTELN is special and not something I can duplicate? Any Ideas? James _______________________________________________ fpc-pascal maillist - https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email

Wayne Sherman
to Wayne Sherman
Example using a TFileStream descendant and StreamIO AssignStream: ...(line 42 follows) FileWrite(TextRec(Output).Handle, Buffer, Count);
Although that worked (I don't know why) I intended line 42 to be:
FileWrite(TextRec(FOriginalStdOut).Handle, Buffer, Count);

Reply by email