On Wed, Apr 11, 2018 at 5:33 PM, Sven Van Caekenberghe <[email protected]> wrote: > I think we have to reset this whole discussion. > > FileStream stdin > > and > > Stdio stdin > > are completely different !
Could you explain the difference because I'm dead tired and got confused :) > > We'll have to check that first, before talking about the issues raised in > this thread. > > And BTW these terminal streams are a real pain to test ;-) > >> On 11 Apr 2018, at 17:20, Sven Van Caekenberghe <[email protected]> wrote: >> >> >> >>> On 11 Apr 2018, at 17:16, Denis Kudriashov <[email protected]> wrote: >>> >>> >>> 2018-04-11 17:02 GMT+02:00 Sven Van Caekenberghe <[email protected]>: >>> >>> >>>> On 11 Apr 2018, at 16:36, Sven Van Caekenberghe <[email protected]> wrote: >>>> >>>> I can make your example, using the Zn variants, work with the following >>>> change: >>>> >>>> StdioStream>>#atEnd >>>> ^ peekBuffer isNil or: [ (peekBuffer := self next) isNil ] >>> >>> Argh, make that >>> >>> atEnd >>> ^ peekBuffer isNil and: [ (peekBuffer := self next) isNil ] >>> >>> But discussion exactly about "self next isNil": how to avoid it. >> >> I know, but like this it could/might become an implementation detail. >> >> The more things that I try, the more that I feel that stdin is so special >> that it does not fit in the rest of the stream zoo. >> >>> but I am still testing, this is probably not the final answer/solution. >>> >>>> Which is a literal implementation of your statement that you can only know >>>> that you are atEnd by reading (and thus waiting/blocking) and checking for >>>> nil, which seems logical to me, given the fact that you *are* waiting for >>>> user input. >>>> >>>> BTW, at least on macOS you have to enter ctrl-D (^D) on a separate line, I >>>> am not sure how relevant that is, but that is probably another argument >>>> that stdin is special (being line-buffered by the OS, EOF needing to be on >>>> a separate line). >>>> >>>> And FWIW, I have been writing networking code in Pharo for years, and I >>>> have never had issues with unclear semantics of these primitives (#atEnd, >>>> #next, #peek) on network streams, either the classic SocketStream or the >>>> Zdc* streams (TLS or not). That is why I think we have to be careful. >>>> >>>> That being said, it is important to continue this discussion, I find it >>>> very interesting. I am trying to write some test code using stdin myself, >>>> to better understand the topic. >>>> >>>>> On 11 Apr 2018, at 16:06, Alistair Grant <[email protected]> wrote: >>>>> >>>>> On 11 April 2018 at 15:11, Sven Van Caekenberghe <[email protected]> wrote: >>>>>> >>>>>> >>>>>>> On 11 Apr 2018, at 11:12, Sven Van Caekenberghe <[email protected]> wrote: >>>>>>> >>>>>>> How does one modify #atEnd to block ? I suppose you are talking about >>>>>>> StdioStream>>#atEnd ? >>>>>>> >>>>>>> ^ self peek isNil >>>>>>> >>>>>>> ? >>>>>> >>>>>> Still the same question, how do you implement a blocking #atEnd for >>>>>> stdin ? >>>>>> >>>>>> I have seen your stdio.cs which is indeed needed as the current >>>>>> StdioStream>>#atEnd is bogus for sure. >>>>>> >>>>>> But that is still a non-blocking one, right ? >>>>>> >>>>>> Since there is a peekBuffer in StdioStream, why can't that be used ? >>>>> >>>>> I think you've created a chicken-and-egg problem with this question, >>>>> but ignoring that for now: >>>>> >>>>> >>>>> StdioStream>>peek >>>>> "Answer what would be returned if the message next were sent to the >>>>> receiver. If the receiver is at the end, answer nil. " >>>>> >>>>> self atEnd ifTrue: [^ nil ]. >>>>> >>>>> peekBuffer ifNotNil: [ ^ peekBuffer ]. >>>>> >>>>> ^ peekBuffer := self next. >>>>> >>>>> >>>>> >>>>> So when we first start the program, i.e. the user hasn't entered any >>>>> input yet, and #peek is called: >>>>> >>>>> 1. #atEnd returns false because Ctrl-D (or similar) hasn't been >>>>> entered (assuming it is non-blocking). >>>>> 2. peekBuffer is nil because we haven't previously called #peek. >>>>> 3. The system now blocks on "self next". >>>>> >>>>> >>>>> Just a reminder: for terminal input the end-of-file isn't reached >>>>> until the user explicitly enters the end of file key (Ctrl-D). >>>>> >>>>> So, if there is no buffered input (either none has been entered yet, >>>>> or all input has been consumed) >>>>> >>>>> #atEnd (after the patch) calls #primAtEnd:. >>>>> >>>>> At the moment, #primAtEnd: ends up calling the libc function feof(), >>>>> which is non-blocking and answers the end-of-file flag for the FILE*. >>>>> Since the user hasn't entered Ctrl-D, that's false. >>>>> >>>>> If we want to control iteration over the stream and ensure that we >>>>> don't need to do a "stream next == nil" check, then #primAtEnd: is >>>>> going to have to peek for the next character, and that means waiting >>>>> for the user to enter that character. >>>>> >>>>> In c that is typically done using: >>>>> >>>>> atEnd = ungetc(fgetc(fp), fp); >>>>> >>>>> and fgetc() will block until the user enters something. >>>>> >>>>>> I have run your example testAtEnd.st now, and it works/fails as >>>>>> advertised. >>>>> >>>>> :-) >>>>> >>>>> >>>>> Cheers, >>>>> Alistair > >
