Console Applications & StdIN

BlitzMax Forums/BlitzMax Programming/Console Applications & StdIN

Scaremonger(Posted 2013) [#1]
I have a console application that my client has asked me to extend. I've searched the forums investigating all sorts of avenues but the solution continues to evade me.

I have seen suggestions to use TCStandardIO and all sorts, but either I'm approaching it incorrectly or these options do not work.

The existing application does not have a window, it is a simple command line tool that takes various arguments and produces some results. Nothing special there.

What the client wants is the following command line support:
c:\app> app -c < control.txt
c:\app> type control.txt | app

I suggested an argument, but they are paying and thats what they want!

To test this I've got this outline code, but if I uncomment the readline() code it waits for CR. I know this is because of the way TextStream is implemented.
Print "STDIN"
Local stdIN:TStream = ReadStream(StandardIOStream)
If stdin Then 
	Print " EOF:  " + stdin.Eof() 
	Print " POS:  " + stdin.Pos()
	Print " SIZE: " + stdin.Size()
'	Print ReadLine(Stdin)
Else
	Print " Did not open"
End If

Print "TCSTANDARDIO"
Local stdIOStream:TCStandardIO = New TCStandardIO
If stdIOStream Then
	Print " EOF:   " + StdIOStream.Eof()
	Print " POS:   " + StdIOStream.pos()
	Print " SIZE:  " + StdIOStream.size()
'	Print ReadLine(StdIOStream)
Else
	Print " Did not open"
End If

Print "object.stdio"
Local StdIO:TStream = OpenStream("object.stdio") 'StdIoStream
If StdIO Then
	Print " EOF:  " + StdIO.Eof()
	Print " POS:  " + StdIO.pos()
	Print " SIZE: " + StdIO.size()
Else
	Print " Did not open"
End If


Is there a way to do this that is not blocking? or should I give up and use API calls?

Last edited 2013


Brucey(Posted 2013) [#2]
Command line tools are fun :-)

Non-blocking you can use something like select() to test if there is any new data available on a file descriptor, such as stdin.

I'm not sure if ReadByte (or whatever is the lowest-level call) will block or simply return 0 bytes if there is none available. You would need to try it.


Scaremonger(Posted 2013) [#3]
Readstdin(), Readbyte() and Reafile() all block too, so I went back to the API's.

Here is what I came up with, just in case anyone else needs it:
WIN32 ONLY
SuperStrict
'# ENSURE THIS IS NOT COMPILED IN GUI MODE

Extern "Win32"
	Function GetStdHandle:Int( nStdHandle:Int )
	Function PeekConsoleInputA( hConsoleInput:Int, lpBuffer:Byte Ptr, nLength:Int, lpNumberOfEventsRead:Int Ptr )
	Function ReadFile%( hFile:Int, lpBuffer:Byte Ptr, nNumberOfBytesToRead:Int, lpNumberOfBytesRead:Int Ptr, lpOverlapped:Byte Ptr=Null )
End Extern

If TSTDIN.Peek() Then
	Print TSTDIN.read()
Else
	Print "No stdin data"
End If

'############################################################
Type TSTDIN
Global stdIn%  = getStdHandle( -10 )
Global Buffer:Byte[16384]
	'------------------------------------------------------------
	Function Peek:Int()
		Local rd:Int
		Return Not peekconsoleinputA( stdIN, Varptr(buffer[0]), 1, Varptr(rd) )
	End Function
	'------------------------------------------------------------
	Function Read:String()
		Local rd:Int
		If ReadFile( stdin, Varptr(buffer[0]), buffer.length, Varptr(rd), Null ) Then
			Return String.FromCString( buffer )
		Else
			Return ""
		End If
	End Function
End Type



skidracer(Posted 2013) [#4]
For non blocking win32 console input I suggest you look at _kbhit() and _getch() documented here:

http://msdn.microsoft.com/en-us/library/58w7c94c(v=vs.80).aspx