Recent

Author Topic: Where is the implementation of WriteLn()  (Read 18798 times)

adem0x

  • New Member
  • *
  • Posts: 17
Where is the implementation of WriteLn()
« on: January 15, 2018, 08:03:47 pm »
When I check with the Wiki, it says it says that the declaration for WriteLn is in system.fpd line 65.

[ https://www.freepascal.org/docs-html/rtl/system/writeln.html ]

Indeed, it is.


But, where is it actually implemented?

I would like to borrow the implementation sources to fork it so that it becomes an ordinary function returning a string.

IOW, I want it to be something like

function Writeln(Args: Arguments): String;

This would make life a lot easier to port console app to GUI (or anything else that you would use with TStream or to simply display some text in a Memo or Editbox).

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12704
  • FPC developer.
Re: Where is the implementation of WriteLn()
« Reply #1 on: January 15, 2018, 08:26:48 pm »
All .fpd declarations are fake for documentation purposes.

Usually that means that the corresponding functions don't really exist, but are translated into a series of calls with corresponding types by the compiler.

But while you can't hack the procedure, you can often redirect the results (e.g. to a memo) Create a stream derivative and use streamex.assignstream to handle it.

rvk

  • Hero Member
  • *****
  • Posts: 6948
Re: Where is the implementation of WriteLn()
« Reply #2 on: January 15, 2018, 08:32:03 pm »
I don't think there is a "single" function for writeln. If you trace it through the source you'll get jumps all over the place. This is also probably due to the cross-platform it needs to support.

But there is a function WriteStr() which does what you describe for writeln with output-string.

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

It's also possible to create a different standard output so the writeln() goes to your source. (like marco mentions)

But I think it would be much easier to port a program by rewriting the writeln() and make a own version which only accepts one parameter.

It kinda depends on the source you want to port.

mas steindorff

  • Hero Member
  • *****
  • Posts: 563
Re: Where is the implementation of WriteLn()
« Reply #3 on: January 15, 2018, 08:40:41 pm »
Sounds like you're trying to recreate the' "format" command it all you want is the string
windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

adem0x

  • New Member
  • *
  • Posts: 17
Re: Where is the implementation of WriteLn()
« Reply #4 on: January 15, 2018, 08:42:33 pm »
But, surely, it must exist somewhere in the compiler sources.

And, I really don't want to use redirection and pipes and what not. It makes debugging much harder.

Regarding WriteStr(). It sure is a better alternative but it too seems to be buried in the compiler.

The drawback is that there's, AFAIK, no counterpart of it in Delphi world.

I am porting HeadConv and I'd like it to be Delphi compatible too.

adem0x

  • New Member
  • *
  • Posts: 17
Re: Where is the implementation of WriteLn()
« Reply #5 on: January 15, 2018, 08:44:25 pm »
Can Format() do everything WriteLn() or WriteStr() do?

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12704
  • FPC developer.
Re: Where is the implementation of WriteLn()
« Reply #6 on: January 15, 2018, 08:54:54 pm »
Well, delphi has no writeln() that you can intercept either, so why do you need it with fpc ?

adem0x

  • New Member
  • *
  • Posts: 17
Re: Where is the implementation of WriteLn()
« Reply #7 on: January 15, 2018, 09:32:27 pm »
There's unit by Peter Below (TeamB) that lets you map to Text to TStream.

https://groups.google.com/forum/#!msg/borland.public.delphi.objectpascal/TAFRAr22r7c/xAp2pbWogtYJ

I am sure it could be modified to use with FPC. But, what I want is a more direct solution (one that does not involve Text or redirection).

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12704
  • FPC developer.
Re: Where is the implementation of WriteLn()
« Reply #8 on: January 15, 2018, 09:35:29 pm »
There's unit by Peter Below (TeamB) that lets you map to Text to TStream.

https://groups.google.com/forum/#!msg/borland.public.delphi.objectpascal/TAFRAr22r7c/xAp2pbWogtYJ

I am sure it could be modified to use with FPC. But, what I want is a more direct solution (one that does not involve Text or redirection).

No need, since a similar unit is already included and maintained as "streamex", as said in my first reply. Even the function name "assignstream" is the same, so should be blind drop in.

adem0x

  • New Member
  • *
  • Posts: 17
Re: Where is the implementation of WriteLn()
« Reply #9 on: January 15, 2018, 10:21:08 pm »
Trouble with SystemIO (and other redirection methods) is that it is a very roundabout way of doing what is otherwise a very simple operation, that is 'call a function with parameters/arguments to return a string'.

I find it hard to understand why WriteLn/WriteStr are buried in compiler code.

I am prepared to put a bounty on it to bring all the relevant code into one single separate unit.

How do I put a bounty on such a thing?

Does anyone know?

rvk

  • Hero Member
  • *****
  • Posts: 6948
Re: Where is the implementation of WriteLn()
« Reply #10 on: January 15, 2018, 10:38:32 pm »
The problem is that writeln() does some "magic" with it's parameters. You can, for instance, give it multiple (undefined) number of parameters with different types. That's why the code is not as simple (and it does some extra things during compilation which is not possible for "normal" functions). So creating a similar function isn't that easy (if at all possible).

You say you don't want to "capture" the writeln() output? What DO you want?? Because what you suggested, does just that.

Another option would be to create your own writeln(). But it can have only defined (in number and type) parameters. So you create
Code: Pascal  [Select][+][-]
  1. procedure writeln(S: String); // this function can do something else with S the output it to screen.
Then you need to rewrite the source which uses it to use one parameter. You'll get errors where there is more than one parameter so it's quite easy to translate all writeln().
Code: Pascal  [Select][+][-]
  1. writeln('hello', ' ', 'world', 2018);
will become
Code: Pascal  [Select][+][-]
  1. writeln('hello' + ' ' + 'world' + inttostr(2018));

Another way:
Code: Pascal  [Select][+][-]
  1. writestr(S, 'hello', ' ', 'world', 2018);
  2. // now do something with S
Yeah, no Delphi compatibility.
But it's the only way to properly get the writeln() (with it's magical implementation) out of the original source-code.

Also note that the original HeadConv is really old and should have a GUI version already. There is also a newer version in JEDI of it. And there are also a few other GUI C header conversion utilities. But that's besides the point.
« Last Edit: January 15, 2018, 10:42:29 pm by rvk »

mas steindorff

  • Hero Member
  • *****
  • Posts: 563
Re: Where is the implementation of WriteLn()
« Reply #11 on: January 15, 2018, 10:42:24 pm »
Can Format() do everything WriteLn() or WriteStr() do?
I can't say, I do not use writeLn or WriteStr any more except when I'm working with files. Even then, I'm either working with binarys or CSV so their are better options.  here's some info on the format().
http://wiki.freepascal.org/Format_function
In my view, format is to writeX as sprintf is to printf but with the new Tstringhelper, I may need to update my string handling.




windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

adem0x

  • New Member
  • *
  • Posts: 17
Re: Where is the implementation of WriteLn()
« Reply #12 on: January 15, 2018, 11:41:32 pm »
That's why the code is not as simple (and it does some extra things during compilation which is not possible for "normal" functions). So creating a similar function isn't that easy (if at all possible).

Trouble is, as things are at the moment, there's no way (for a mere mortal such as I) to even attempt to study what is possible let alone emulate it.

This bothers me in more ways than one. We have an open source compiler; yet, some /code/ is not available because it's obscured out of human eyes.

Quote
You say you don't want to "capture" the writeln() output? What DO you want?? Because what you suggested, does just that.

Say, we had a function with all (or as much/many as possible) features and frills of WriteLn() but one that returned a string. Lets call it WriteLnAsString().

I could use it in countless places. I could directly output stuff to TStream, EditBox, Memo etc. etc.

A very simple assignment.

With redirection, I have to go through unnecessary hoops.

Quote
Another option would be to create your own writeln(). But it can have only defined (in number and type) parameters.

I did consider that. But, it is very laborious and error-prone process. You have to go through the source you're porting and catch every single variation and provide for them.

Add to that the fact that there's no documentation (that I could find) about every feature of WriteLn, you're in complete dark. 'Source is the documentation' falls flat here since there is no single source for WriteLn.

Actually, this is not the first time I needed 'WriteLnAsString()'. A couple years ago I met the same wall, and I gave up (it was a more complex code).

Incidentally, emulating WriteLn using string concatenation is not that easy. WriteLn does a lot more than that (internally formatting numbers, adding tabs, etc.).

Quote
Code: Pascal  [Select][+][-]
  1. writestr(S, 'hello', ' ', 'world', 2018);
  2. // now do something with S
Yeah, no Delphi compatibility.

I suppose I could create a DLL using FPC and use it with Delphi. Horror.

Just because there's no standalone function.

I could, if I had the temerity to put myself through that torture, do something like WriteLn(output, [arguments]) and then read it right after..

Definitely not an elegant solution.

Quote
Also note that the original HeadConv is really old and should have a GUI version already. There is also a newer version in JEDI of it.

I have started with the Jedi version. But, it didn't compile with anything later than D7.

While its code is hard enough already, the fact that it uses countless local functions/procedures and dozens of global variables doesn't make it any easier to follow.

I have turned it into a class with all those local functions/procedures and global variables moved into member of private section.

IOW, I have spent sometime on it and it works.

The only remaining issue is to get rid of all those System.Text stuff. Doing that will make it easier to understand and then improve.

Yet, WriteLn is blocking me --or, bothering me-- as the current proposals will only add further complexity to the code.

I have to say, I have come to hate WriteLn with an immesurable passion...

I have never used it. But the danm thing comes up in legacy code.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8835
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Where is the implementation of WriteLn()
« Reply #13 on: January 15, 2018, 11:52:19 pm »
I find it hard to understand why WriteLn/WriteStr are buried in compiler code.

I am prepared to put a bounty on it to bring all the relevant code into one single separate unit.

How do I put a bounty on such a thing?

Does anyone know?
You can't, as rvk has explained and I've ever answered before. This "burial" allows implementation of something not possible through user level procedure definition. For instance, original and standard Pascal has no notion of procedure overloading (disabled in TP mode, but no idea why enabled in ISO mode, looks like a bug), but Ord(), Succ(), Pred() and many other built-in functions must work for any ordinal type including user defined ones. By making them a command for the compiler instead of true procedure call, this can be done without allowing overloading.

The source is not that dark, just `grep -ir fpc_write_ *` in the source directory, there they are.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Where is the implementation of WriteLn()
« Reply #14 on: January 15, 2018, 11:55:58 pm »
Trouble is, as things are at the moment, there's no way (for a mere mortal such as I) to even attempt to study what is possible let alone emulate it.

This bothers me in more ways than one. We have an open source compiler; yet, some /code/ is not available because it's obscured out of human eyes.

There is no code. Writeln is dynamically generated by the compiler its not template or generics based function each parameter is analyzed and replaced with appropriate calls most of the time multiple functions are used.
There is nothing hiden from you if you want to see the generator code for the writeln then ask in the fpc mailing list.

Quote
You say you don't want to "capture" the writeln() output? What DO you want?? Because what you suggested, does just that.

Say, we had a function with all (or as much/many as possible) features and frills of WriteLn() but one that returned a string. Lets call it WriteLnAsString().

I could use it in countless places. I could directly output stuff to TStream, EditBox, Memo etc. etc.
You have one it is calle writestr and exports everything to a string that you can do what ever you want with it.

A very simple assignment.

With redirection, I have to go through unnecessary hoops.

Quote
Another option would be to create your own writeln(). But it can have only defined (in number and type) parameters.

I did consider that. But, it is very laborious and error-prone process. You have to go through the source you're porting and catch every single variation and provide for them.

Add to that the fact that there's no documentation (that I could find) about every feature of WriteLn, you're in complete dark. 'Source is the documentation' falls flat here since there is no single source for WriteLn.

Actually, this is not the first time I needed 'WriteLnAsString()'. A couple years ago I met the same wall, and I gave up (it was a more complex code).

Incidentally, emulating WriteLn using string concatenation is not that easy. WriteLn does a lot more than that (internally formatting numbers, adding tabs, etc.).

Quote
Code: Pascal  [Select][+][-]
  1. writestr(S, 'hello', ' ', 'world', 2018);
  2. // now do something with S
Yeah, no Delphi compatibility.

I suppose I could create a DLL using FPC and use it with Delphi. Horror.
you can't there is no function to link against. Your generated function will be limited to what ever you define during the compile.


Just because there's no standalone function.

I could, if I had the temerity to put myself through that torture, do something like WriteLn(output, [arguments]) and then read it right after..

Definitely not an elegant solution.

Quote
Also note that the original HeadConv is really old and should have a GUI version already. There is also a newer version in JEDI of it.

I have started with the Jedi version. But, it didn't compile with anything later than D7.

While its code is hard enough already, the fact that it uses countless local functions/procedures and dozens of global variables doesn't make it any easier to follow.

I have turned it into a class with all those local functions/procedures and global variables moved into member of private section.

IOW, I have spent sometime on it and it works.

The only remaining issue is to get rid of all those System.Text stuff. Doing that will make it easier to understand and then improve.

Yet, WriteLn is blocking me --or, bothering me-- as the current proposals will only add further complexity to the code.

I have to say, I have come to hate WriteLn with an immesurable passion...

I have never used it. But the danm thing comes up in legacy code.
use the stream solution you have found to redirect writeln to a stream make sure that it works both in lazarus and delphi and use a tstringstream to redirect the result to that is the simplest solution in your case.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

 

TinyPortal © 2005-2018