Menu

#1285 Tcl_SetChannelOption (-buffering line) working incorrectly

final: 8.0.5
closed-invalid
8
2001-07-19
2000-10-26
Anonymous
No

OriginalBugID: 1923 Bug
Version: 8.0.5
SubmitDate: '1999-04-22'
LastModified: '1999-11-07'
Severity: MED
Status: UnAssn
Submitter: pat
ChangedBy: hobbs
OS: Windows NT
OSVersion: 4.00.1381
Machine: X86
FixedDate: '2000-10-25'
ClosedDate: '2000-10-25'

Name:Kenneth Atwell

Comments:
As you can see, the line buffer option that is selected to not
functioning correctly.

I believe this is related to "\n" (Unix) versus "\r\n" (DOS) line
returns. The buffer sent to MyChannelOutputProc() does not contain the
full buffer when the output is mulitple lines long. It appears that
buffers with more EOLs are truncated before buffers with less EOLs.

ReproducibleScript:
Compile and link the following C program (I used MS Visual C++ v5). Run
the program. Sorry about the length, but I had to include some (unused)
boilerplate to create the channel.

----

#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "tcl.h"

int MyChannelCloseProc ( ClientData instanceData, Tcl_Interp *interp )
{
return 0;
}

int MyChannelInputProc ( ClientData instanceData, char *buf, int
bufSize, int *errorCodePtr )
{
*errorCodePtr = ENODEV;
return -1;
}

int MyChannelOutputProc ( ClientData instanceData, char *buf, int
toWrite, int *errorCodePtr )
{
/*
* BUG: "buf" does not always end with a '\n', despite the fact that
we
* selected line buffering. This bug can be caught by uncommenting
the
* assert() macro below.
*/

/* assert ( '\n' == buf [ toWrite - 1 ] ); */

char *pszTmp = ( char * ) malloc ( toWrite + 1 );
assert ( pszTmp );
strncpy ( pszTmp, buf, toWrite );
pszTmp [ toWrite ] = '\0';

printf ( "***BEGIN***\n" );
printf ( pszTmp );
printf ( "***END***\n" );

free ( pszTmp );
return toWrite;
}

void MyChannelWatchProc ( ClientData instanceData, int mask )
{
}

int MyChannelGetHandleProc ( ClientData instanceData, int direction,
ClientData *handlePtr )
{
return TCL_ERROR;
}

static Tcl_ChannelType g_CommandWindowChannelType =
{
"my_channel_type", /* name */
NULL, /* block mode proc */
MyChannelCloseProc, /* close proc */
MyChannelInputProc, /* input proc */
MyChannelOutputProc, /* output proc */
NULL, /* seek proc */
NULL, /* set option proc */
NULL, /* get option proc */
MyChannelWatchProc, /* watch proc */
MyChannelGetHandleProc /* get handle proc */
};

static Tcl_Channel g_CommandWindowChannel;

void main ()
{
int result;

Tcl_Interp *interp = Tcl_CreateInterp ();
assert ( interp );

/* Create a new type of I/O channel. */

g_CommandWindowChannel = Tcl_CreateChannel (
&g_CommandWindowChannelType,
"my_channel",
(ClientData) 0,
TCL_WRITABLE );

/* Set STDIN, STDOUT, and STDERR to use this channel. */

Tcl_SetStdChannel ( g_CommandWindowChannel, TCL_STDOUT );

/* Set the channel buffering. Ouput will occur at EOLs. */

result = Tcl_SetChannelOption ( interp, g_CommandWindowChannel,
"-buffering", "line" );
assert ( TCL_OK == result );

/* Test the new channel with a simple puts*/

result = Tcl_Eval ( interp, "puts \"This line prints correctly.\"" );
assert ( TCL_OK == result );

/* This next command results in an error */

result = Tcl_Eval ( interp, "foo" );
assert ( TCL_ERROR == result );

/* Now try to print out $errorInfo */

result = Tcl_Eval ( interp, "puts $errorInfo" );
assert ( TCL_OK == result );
}

ObservedBehavior:
The output of the program is:

***BEGIN***
This line prints correctly.
***END***
***BEGIN***
invalid command name "foo"
while executing
"fo***END***
***BEGIN***
o"
***END***

DesiredBehavior:
Correct output would be:

***BEGIN***
This line prints correctly.
***END***
***BEGIN***
invalid command name "foo"
while executing
"foo"
***END***

Discussion

  • Donal K. Fellows

    • labels: 104247 --> 25. Channel System
     
  • Don Porter

    Don Porter - 2001-02-08

    Is this a duplicate of #119300 ?

     
  • Andreas Kupries

    Andreas Kupries - 2001-07-17
    • priority: 5 --> 8
    • assigned_to: nobody --> andreas_kupries
     
  • Andreas Kupries

    Andreas Kupries - 2001-07-19

    Logged In: YES
    user_id=75003

    #119300 does not exist (anymore). I believe this is now
    #219300, no ?

     
  • Don Porter

    Don Porter - 2001-07-19

    Logged In: YES
    user_id=80530

    I believe that is correct.

     
  • Andreas Kupries

    Andreas Kupries - 2001-07-19
    • summary: Tcl_SetChannelOption (-buffing, line) not working correctly --> Tcl_SetChannelOption (-buffering line) working incorrectly
     
  • Andreas Kupries

    Andreas Kupries - 2001-07-19
    • status: open --> closed-invalid
     
  • Andreas Kupries

    Andreas Kupries - 2001-07-19

    Logged In: YES
    user_id=75003

    I have to declare this item as invalid. Here comes the
    explanation.

    puts <some-data> translates into a call
    to "Tcl_PutsObjCmd", which in turn calls "Tcl_WriteObj",
    which in turn calls "WriteChars" (in "tclIO.c"). The last
    procedure now does several things: EOL translation and
    conversion of the internal UTF-8 to the external encoding.

    For the first action (EOL-translation) the system goes over
    the input, translates and stores the result in a staging
    buffer. Whenever the staging buffer is full the result is
    handed to the UTF-8 conversion. This stages appends the
    result of the conversion to the current buffer in the out
    queue, or allocates a new one if the queue was empty.

    All of the above can result in breaking apart the data to
    write into several chunks, each in its own buffer. So it is
    possible for the first buffer to contain some full lines of
    the data to write and a partial line, without a closing \n.
    Still, the buffer does _contain full lines_ and thus has to
    be flushed according to the set buffering policy.

    So it is possible that a buffer is written which is not
    closed with a \n, even if policy "line" is set. It just has
    to contain at least one full line. That a partial line
    follows does not detract from the requirement to flush this
    buffer. The assumption you assert upon (end of buffer ==
    \n) is simply not true.