ActiveState Powered by ActiveState

ActiveState Community


Trying to intercept stdout and stdin while a script is running

Posted by apiscitello on 2008-01-14 11:00
OS: Windows

I am creating an application in C that is designed to run various Tcl scripts, but I need to intercept the output to the console as it is running. I also need to automatically fill any requests for input automatically (depending on options) or have the user enter input from the console window. I began to develop my application testing with Tcl 8.4.16, but have run into problems when using Tcl 8.5.0. I am not sure if I am using the appropriate methods to do this, but I have not been able to find many examples on this type of application.

Is there anything I am doing wrong or should be doing differently below?

I have simplified my application to the following (this works fine in Tcl 8.4.16):

Tcl_DriverInputProc * inProc;
Tcl_DriverOutputProc * outProc;

int OutputProc(ClientData instanceData, const char * buf, int toWrite, int * errorCodePtr)
{
	//do something here
	return outProc(instanceData, buf, toWrite, errorCodePtr);
}

int InputProc(ClientData instanceData, char *buf, int bufSize, int *errorCodePtr)
{
	//do something here
	return inProc(instanceData, buf, bufSize, errorCodePtr);
}

int _tmain(int argc, char* argv[])
{

	Tcl_FindExecutable(argv[0]);
	Tcl_Interp * interp = Tcl_CreateInterp();

	//get stdin channel
	Tcl_Channel stdinChan = Tcl_GetStdChannel(TCL_STDIN);
	Tcl_ChannelType * chanType = Tcl_GetChannelType(stdinChan);
	//save the old input procedure so I can use it later
	inProc = chanType->inputProc;
	//assign my input procedure to it
	chanType->inputProc = &InputProc;

	//get stdout channel
	Tcl_Channel stdoutChan = Tcl_GetStdChannel(TCL_STDOUT);
	Tcl_ChannelType * stdoutType = Tcl_GetChannelType(stdoutChan);
	//save the old output procedure so I can use it later
	outProc = stdoutType->outputProc;
	//assign my output procedure to it
	stdoutType->outputProc = &OutputProc;

	//evaluate a script
	int result = Tcl_Eval(interp, "gets stdin x");

	//get the variable out
	const char * x  = Tcl_GetVar(interp, "x", 0);

	//output to console
	result = Tcl_Eval(interp, "puts $x");

	return 0;
}

This code by itself works fine in both versions of Tcl. However, there is a slightly different behavior when I'm using 8.4.16 vs. 8.5.0. If I set a breakpoint and look at the buf variable in the OutputProc, I get the following differences when I enter "abc" from the console:

8.4.16: buf = 61 62 63 0d 0a ("abc\r\n")
8.5.0: buf = 61 00 62 00 63 00 0d 00 0a 00

Does anyone know what these extra characters are?

Similarly, when I examine the contents of buf on the InputProc after getting values, I notice the same things.

I'm open to suggestions.

jeffh | Mon, 2008-01-14 13:06

It looks like you 8.5.0 output is Tcl_UniChar-sized data or somehow output as UCS-2 (unicode). You are getting your regular ASCII data in short (2-byte) sized output.

-->