Re: [fpc-pascal] Read Field names from VMT
Thank you!On Dec 27, 2023 7:46 AM, Sven Barth via fpc-pascal wrote: Am 26.12.2023 um 21:29 schrieb Amir--- via fpc-pascal: On 12/26/23 01:14, Sven Barth via fpc-pascal wrote: Amir--- via fpc-pascalschrieb am Di., 26. Dez. 2023, 07:03: Hi, I want to retrieve the name of the fields in a record/class, at run time. It looks like "TVmt.vFieldTable" is what I need. But I cannot find any documentation about how to explore the content of this table. I appreciate any pointer. This only works for published fields and only fields of type class or interface can be published. That would work for me. How can I enumerate over those fields? You can use the PVmtFieldTable and PVmtFieldEntry types from the TypInfo unit: === code begin === program tfield; {$mode objfpc}{$H+} uses TypInfo; type {$M+} TSub = class end; TTest = class published fTest: TSub; end; var vft: PVmtFieldTable; vfe: PVmtFieldEntry; i: SizeInt; begin vft := PVmtFieldTable(PVMT(TTest)^.vFieldTable); Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); end; end. === code end === === output begin === PS C:\fpc\git> .\testoutput\tfield.exe 1 field(s) with 1 type(s) 0 -> fTest @ 8 of type TSub === output end === Side note: contrary to what I had originally written only classes, but not interfaces are allowed for published fields and they need to have $M enabled. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
On Wed, Dec 27, 2023 at 3:42 PM Wayne Sherman wrote: > 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); ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
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. On Wed, Dec 27, 2023 at 3:25 AM 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? > > > > > > Any Ideas? > > > > James > > ___ > fpc-pascal maillist - fpc-pascal@lists.freepascal.org > https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
Am 27.12.2023 um 12:25 schrieb James Richters via fpc-pascal: 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___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
Am 26.12.2023 um 21:29 schrieb Amir--- via fpc-pascal: On 12/26/23 01:14, Sven Barth via fpc-pascal wrote: Amir--- via fpc-pascal schrieb am Di., 26. Dez. 2023, 07:03: Hi, I want to retrieve the name of the fields in a record/class, at run time. It looks like "TVmt.vFieldTable" is what I need. But I cannot find any documentation about how to explore the content of this table. I appreciate any pointer. This only works for published fields and only fields of type class or interface can be published. That would work for me. How can I enumerate over those fields? You can use the PVmtFieldTable and PVmtFieldEntry types from the TypInfo unit: === code begin === program tfield; {$mode objfpc}{$H+} uses TypInfo; type {$M+} TSub = class end; TTest = class published fTest: TSub; end; var vft: PVmtFieldTable; vfe: PVmtFieldEntry; i: SizeInt; begin vft := PVmtFieldTable(PVMT(TTest)^.vFieldTable); Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); end; end. === code end === === output begin === PS C:\fpc\git> .\testoutput\tfield.exe 1 field(s) with 1 type(s) 0 -> fTest @ 8 of type TSub === output end === Side note: contrary to what I had originally written only classes, but not interfaces are allowed for published fields and they need to have $M enabled. Regards, Sven___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
On Wed, Dec 27, 2023 at 3:25 AM James Richters 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. 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 ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
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.___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
>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 ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Procedures that work like WRITELN()
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]); - Original Message - From: Michael Van Canneyt via fpc-pascal To: ja...@productionautomation.net 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. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Daily snapshots?
Hello, as it seems to take longer for the next major release, I'd appreciate if automated snapshots could be provided either daily or weekly. In the documentation, I found a link to ftp://ftp.freepascal.org/pub/fpc/snapshot/trunk/ but I cannot login. I tried with user=anynous and password=my-email-address. I don't mind the long time for the next release, but it'd help enormously to have the option to download an up-to-date nightly build :) Kind regards, Thomas ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [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. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
[fpc-pascal] Procedures that work like WRITELN()
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 - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal