Sign in Join

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

Mailing lists / fpc-pascal / 2010-10

TFileStream and stdin - how to make this work?

9 messages · 4 people ·

Reply by email Subscribe to this list Your subscription

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

Bernd Kreuss

Hi,

this might be a stupid question but I find myself again struggling with file IO and stdin/stdout. I am trying to do the following:

StdIn := TFileStream.Create('/dev/stdin', fmOpenRead);

and later on i want to poll whether there is something to read. I want to try reading binary data that will be piped to my application and i need to poll (non blocking!) and in case of incoming data read the first byte to determine the type of message that has arrived and then read the rest.

The Stream seems to be able to read when there is something to read on stdin but I cannot find any way to actually test whether the ReadByte() will block (nothing to read) or whether there is data available.

the properties size and position both are always $ffffffffffffffff and the stream has no eof property.

Can this be done at all? And is my way of opening the stream correct? What would be a more platform independent way of opening the stdin as a stream to read binary data or is there a different and better way to do this, maybe a stream is not the correct thing for this at all? How do I poll and read binary data from stdin?

Bernd

Reply by email

Honza
to Bernd Kreuss

2010/10/3 Bernd Kreuss :

Show quoted text 23 lines
this might be a stupid question but I find myself again struggling with file IO and stdin/stdout. I am trying to do the following: StdIn := TFileStream.Create('/dev/stdin', fmOpenRead); and later on i want to poll whether there is something to read. I want to try reading binary data that will be piped to my application and i need to poll (non blocking!) and in case of incoming data read the first byte to determine the type of message that has arrived and then read the rest. The Stream seems to be able to read when there is something to read on stdin but I cannot find any way to actually test whether the ReadByte() will block (nothing to read) or whether there is data available. the properties size and position both are always $ffffffffffffffff and the stream has no eof property. Can this be done at all? And is my way of opening the stream correct? What would be a more platform independent way of opening the stdin as a stream to read binary data or is there a different and better way to do this, maybe a stream is not the correct thing for this at all? How do I poll and read binary data from stdin?

I don't think it's possible to succeed in this using TFileStream. Additionally, the stdin thing on *nix is IMO designed to be normally used in a blocking manner.

OTOH, it's likely, that on *nix you can find some syscall/libc functionality, which will provide the "file descriptor is ready for reading" information. But you asked for platform independence and I don't know much about Windows. Neither if there is or is not something like that being cross platform somewhere in the RTL/FCL already.

bflm freepascal-bits.blogspot.com

Reply by email

Andreas Schneider
to Bernd Kreuss: this might be a stupid question but I find myself again struggling with file IO and…
Bernd Kreuss wrote 27 lines
Hi, this might be a stupid question but I find myself again struggling with file IO and stdin/stdout. I am trying to do the following: StdIn := TFileStream.Create('/dev/stdin', fmOpenRead); and later on i want to poll whether there is something to read. I want to try reading binary data that will be piped to my application and i need to poll (non blocking!) and in case of incoming data read the first byte to determine the type of message that has arrived and then read the rest. The Stream seems to be able to read when there is something to read on stdin but I cannot find any way to actually test whether the ReadByte() will block (nothing to read) or whether there is data available. the properties size and position both are always $ffffffffffffffff and the stream has no eof property. Can this be done at all? And is my way of opening the stream correct? What would be a more platform independent way of opening the stdin as a stream to read binary data or is there a different and better way to do this, maybe a stream is not the correct thing for this at all? How do I poll and read binary data from stdin? Bernd

You could use TIOStream from the unit iostream. AFAICS that should do exactly what you want - i.e. opening stdin/out/err as a TStream descendant.
I don't know however, if that fixes the problem you have with the stream blocking when nothing is to be read. If nothing else helps I guess you could use a thread to read the data from stdin, then it shouldn't matter if it blocks.

Best regards,
Andreas.

Reply by email

Bernd Kreuss
to Andreas Schneider
Andreas Schneider wrote 5 lines
You could use TIOStream from the unit iostream. AFAICS that should do exactly what you want - i.e. opening stdin/out/err as a TStream descendant. I don't know however, if that fixes the problem you have with the stream blocking when nothing is to be read.

TIOStream seems to work the same way on linux and windows (I tested only with wine but it worked) ...and it will block.

It seems I really have to do the receiving of the data in a separate thread.

(I wanted to avoid this because the things that must be done after reading the data must be done in the main thread (it's a GUI application) and now I have to fiddle around with synchronize & friends instead of a simple method call which is not nice because I also have to immediately answer the messages on stdout in a synchronous manner with information received from the GUI. Polling on idle from the GUI thread would have been so much more simple and elegant.)

Bernd

Reply by email

Honza
to Bernd Kreuss

2010/10/3 Bernd Kreuss :

Show quoted text 13 lines
TIOStream seems to work the same way on linux and windows (I tested only with wine but it worked) ...and it will block. It seems I really have to do the receiving of the data in a separate thread. (I wanted to avoid this because the things that must be done after reading the data must be done in the main thread (it's a GUI application) and now I have to fiddle around with synchronize & friends instead of a simple method call which is not nice because I also have to immediately answer the messages on stdout in a synchronous manner with information received from the GUI. Polling on idle from the GUI thread would have been so much more simple and elegant.)

See also sockets:

http://wiki.lazarus.freepascal.org/Sockets

and pipes:

http://www.freepascal.org/docs-html/fcl/pipes/tinputpipestream.html

The TInputPipeStream has a "property NumBytesAvailable: DWord; [r] Number of bytes available for reading.", which may enable the polling.

bflm freepascal-bits.blogspot.com

Reply by email

Seth Grover
to Seth Grover

See ./packages/fcl-base/examples/asiotest.pp in the FPC source. Also, google turned up: achenko.narod.ru/stdin2file.pas which seems to be something like what you're looking to do.

-SG

This email is fiction. Any resemblance to actual events or persons living or dead is purely coincidental. Seth Grover sethdgrover[at]gmail[dot]com

Reply by email

Bernd Kreuss
to Honza: 2010/10/3 Bernd Kreuss : See also sockets: http://wiki.lazarus.freepascal.org/Sockets and…
Honza wrote 10 lines
See also sockets: http://wiki.lazarus.freepascal.org/Sockets and pipes: http://www.freepascal.org/docs-html/fcl/pipes/tinputpipestream.html The TInputPipeStream has a "property NumBytesAvailable: DWord; [r] Number of bytes available for reading.", which may enable the polling.

I'm currently evaluating what is the easiest (least complicated) way of communicating with a separate executable that is only used to display some GUI forms to display some data and a few GUI elements to give input to the main application. It is some kind of frontend to a process that cannot have its own GUI (the other half of my code resides in a DLL and i haven't found any *reliable* and robust way of creating a LCL GUI directly from within this library because I have no control over the application's main thread, all I have are function calls from the main application on certain events that all come from different threads).

I have a (buggy) prototype that tries to create its own GUI thread in the DLL and an ugly mess of QueueAsyncCall() to communicate with it and a homemade event loop but it will still randomly crash ---> no idea why, not reliable.

And I have another (already working) prototype which uses tSimpleIPCServer and Client to communicate with a separately started executable, this works quite nice but i thought i could make it even easier and more compact.

Now I have a third prototype almost complete that uses TProcess to start the exe from the dll and this is why I needed the stdio stuff. I have now made a separate thread to listen on stdio and the synchronize() stuff seems not so complicated as I initially thought. Overall I currently like the TProcess/stdio method the most.

Bernd

Reply by email

Bernd Kreuss
to Seth Grover: Could you use THandleStream (http://www.freepascal.org/docs-html/rtl/classes/thandlestream…
Seth Grover wrote
Could you use THandleStream (http://www.freepascal.org/docs-html/rtl/classes/thandlestream.html)? myInputStream := THandleStream.Create(StdInputHandle);

Yea, this looks like what TIOStream internally seems to do. I have now worked around the blocking issue by simply reading from the stream in a separate thread.

I almost found the above myself (found something similar with google) but I couldn't remember the name of the StdInputHandle constant i only found a windows only example with something like STD_INPUT_HANDLE while I was sitting on my Linux laptop at that moment.

(the final application will run on windows but i was doing some initial experiments with TProcess and stdio while sitting at my linux machine)

Bernd

Reply by email