Tcl Source Code

Check-in [d937aa574e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fixed console code to properly deal with pasting of uneven lines by reading entire lines from the console at once instead of reading one byte, then the rest of the line.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | core-8-1-branch-old
Files: files | file ages | folders
SHA1: d937aa574ed55572d8e35c05e32d3fe931c8ec7e
User & Date: redman 1999-04-01 00:56:12.000
Context
1999-04-01
21:52
Applied Jan's patch, fixed TCL_MEM_DEBUG. check-in: 8c0c86be64 user: redman tags: core-8-1-branch-old
00:56
Fixed console code to properly deal with pasting of uneven lines by reading entire lines from the co... check-in: d937aa574e user: redman tags: core-8-1-branch-old
00:38
Added new bitmap for 8.1b3 and modified text in Finished panel. check-in: 8c3361f3a6 user: redman tags: core-8-1-branch-old
Changes
Unified Diff Ignore Whitespace Patch
Changes to ChangeLog.






1
2
3
4
5
6
7






1999-03-30    <[email protected]>

	* unix/Makefile.in: Removed trailing backslash that broke the
	"depend" target.

	* unix/tclUnixInit.c (TclpSetInitialEncodings): Changed to avoid
	calling setlocale().  We now look directly at env(LANG) and
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
1999-03-31    <[email protected]>

	* win/tclWinConsole.c: WinNT has a bug when reading a single
	character from the console.  Rewrote the code for the console to
	read an entire line at a time using the reader thread.

1999-03-30    <[email protected]>

	* unix/Makefile.in: Removed trailing backslash that broke the
	"depend" target.

	* unix/tclUnixInit.c (TclpSetInitialEncodings): Changed to avoid
	calling setlocale().  We now look directly at env(LANG) and
Changes to win/tclWinConsole.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinConsole.c --
 *
 *	This file implements the Windows-specific console functions,
 *	and the "console" channel driver.
 *
 * Copyright (c) 1999 by Scriptics Corp.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinConsole.c,v 1.1.2.5 1999/03/27 00:39:31 redman Exp $
 */

#include "tclWinInt.h"

#include <dos.h>
#include <fcntl.h>
#include <io.h>











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinConsole.c --
 *
 *	This file implements the Windows-specific console functions,
 *	and the "console" channel driver.
 *
 * Copyright (c) 1999 by Scriptics Corp.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinConsole.c,v 1.1.2.6 1999/04/01 00:56:12 redman Exp $
 */

#include "tclWinInt.h"

#include <dos.h>
#include <fcntl.h>
#include <io.h>
36
37
38
39
40
41
42
43
44


45
46
47
48
49
50
51
#define CONSOLE_ASYNC	(1<<1)	/* Channel is non-blocking. */

/*
 * Bit masks used in the sharedFlags field of the ConsoleInfo structure below.
 */

#define CONSOLE_EOF	  (1<<2)  /* Console has reached EOF. */
#define CONSOLE_EXTRABYTE (1<<3)  /* extra byte consumed while waiting for read
				     access */


/*
 * This structure describes per-instance data for a console based channel.
 */

typedef struct ConsoleInfo {
    HANDLE handle;
    int type;







|
|
>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#define CONSOLE_ASYNC	(1<<1)	/* Channel is non-blocking. */

/*
 * Bit masks used in the sharedFlags field of the ConsoleInfo structure below.
 */

#define CONSOLE_EOF	  (1<<2)  /* Console has reached EOF. */
#define CONSOLE_BUFFERED  (1<<3)  /* data was read into a buffer by the reader
				     thread */

#define CONSOLE_BUFFER_SIZE (8*1024)
/*
 * This structure describes per-instance data for a console based channel.
 */

typedef struct ConsoleInfo {
    HANDLE handle;
    int type;
88
89
90
91
92
93
94
95


96
97
98
99
100
101
102
103
				 * synchronized with the writable
				 * object. */
    int toWrite;		/* Current amount to be written.  Access is
				 * synchronized with the writable object. */
    int readFlags;		/* Flags that are shared with the reader
				 * thread.  Access is synchronized with the
				 * readable object.  */
    char extraByte;             /* Buffer for extra character consumed by reade


				   thread. */
} ConsoleInfo;

typedef struct ThreadSpecificData {
    /*
     * The following pointer refers to the head of the list of consoles
     * that are being watched for file events.
     */







|
>
>
|







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
				 * synchronized with the writable
				 * object. */
    int toWrite;		/* Current amount to be written.  Access is
				 * synchronized with the writable object. */
    int readFlags;		/* Flags that are shared with the reader
				 * thread.  Access is synchronized with the
				 * readable object.  */
    int bytesRead;              /* number of bytes in the buffer */
    int offset;                 /* number of bytes read out of the buffer */
    char buffer[CONSOLE_BUFFER_SIZE];
                                /* Data consumed by reader thread. */
} ConsoleInfo;

typedef struct ThreadSpecificData {
    /*
     * The following pointer refers to the head of the list of consoles
     * that are being watched for file events.
     */
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600


601
602
603
604

605
606



607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
     */
    
    if (result == -1) {
	*errorCode = errno;
	return -1;
    }

    if (infoPtr->readFlags & CONSOLE_EXTRABYTE) {
	/*
	 * The reader thread consumed 1 byte.
	 */

	*buf = infoPtr->extraByte;
	infoPtr->readFlags &= ~CONSOLE_EXTRABYTE;
	buf++;
	bufSize--;


	bytesRead = 1;

	/*
	 * If further read attempts would block, return what we have.

	 */




	if (result == 0) {
	    return bytesRead;
	}
    }
    
    /*
     * Attempt to read bufSize bytes.  The read will return immediately
     * if there is any data available.  Otherwise it will block until
     * at least one byte is available or an EOF occurs.
     */

    if (ReadConsole(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &count,
		    (LPOVERLAPPED) NULL) == TRUE) {
	return bytesRead + count;
    } else if (bytesRead) {
	/*
	 * Ignore errors if we have data to return.
	 */
	
	return bytesRead;
    }

    return -1;
}

/*
 *----------------------------------------------------------------------







|

|


|
|
|
|
>
>
|

|
<
>
|
|
>
>
>
|
|
<










<
<
<
<
<
|
|







589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609

610
611
612
613
614
615
616
617

618
619
620
621
622
623
624
625
626
627





628
629
630
631
632
633
634
635
636
     */
    
    if (result == -1) {
	*errorCode = errno;
	return -1;
    }

    if (infoPtr->readFlags & CONSOLE_BUFFERED) {
	/*
	 * Data is stored in the buffer.
	 */

	if (bufSize < (infoPtr->bytesRead - infoPtr->offset)) {
	    memcpy(buf, &infoPtr->buffer[infoPtr->offset], bufSize);
	    bytesRead = bufSize;
	    infoPtr->offset += bufSize;
	} else {
	    memcpy(buf, &infoPtr->buffer[infoPtr->offset], bufSize);
	    bytesRead = infoPtr->bytesRead - infoPtr->offset;

	    /*

	     * Reset the buffer
	     */
	    
	    infoPtr->readFlags &= ~CONSOLE_BUFFERED;
	    infoPtr->offset = 0;
	}

	return bytesRead;

    }
    
    /*
     * Attempt to read bufSize bytes.  The read will return immediately
     * if there is any data available.  Otherwise it will block until
     * at least one byte is available or an EOF occurs.
     */

    if (ReadConsole(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &count,
		    (LPOVERLAPPED) NULL) == TRUE) {





	buf[count] = '\0';
	return count;
    }

    return -1;
}

/*
 *----------------------------------------------------------------------
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
		return 1;
	    }

	    /*
	     * Ignore errors if there is data in the buffer.
	     */
	    
	    if (infoPtr->readFlags & CONSOLE_EXTRABYTE) {
		return 0;
	    } else {
		return -1;
	    }
	}

	/*
	 * If there is data in the buffer, the console must be
	 * readable (since it is a line-oriented device).
	 */

	if (infoPtr->readFlags & CONSOLE_EXTRABYTE) {
	    return 1;
	}

	
	/*
	 * There wasn't any data available, so reset the thread and
	 * try again.







|











|







978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
		return 1;
	    }

	    /*
	     * Ignore errors if there is data in the buffer.
	     */
	    
	    if (infoPtr->readFlags & CONSOLE_BUFFERED) {
		return 0;
	    } else {
		return -1;
	    }
	}

	/*
	 * If there is data in the buffer, the console must be
	 * readable (since it is a line-oriented device).
	 */

	if (infoPtr->readFlags & CONSOLE_BUFFERED) {
	    return 1;
	}

	
	/*
	 * There wasn't any data available, so reset the thread and
	 * try again.
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Signals the main thread when input become available.  May
 *	cause the main thread to wake up by posting a message.  May
 *	consume one byte from the console for each wait operation.
 *
 *----------------------------------------------------------------------
 */

static DWORD WINAPI
ConsoleReaderThread(LPVOID arg)
{







|







1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Signals the main thread when input become available.  May
 *	cause the main thread to wake up by posting a message.  May
 *	one line from the console for each wait operation.
 *
 *----------------------------------------------------------------------
 */

static DWORD WINAPI
ConsoleReaderThread(LPVOID arg)
{
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062

	count = 0;

	/* 
	 * Look for data on the console, but first ignore any events
	 * that are not KEY_EVENTs 
	 */
	if (ReadConsole(handle, &(infoPtr->extraByte), 1, &count, NULL)
		!= FALSE) {
	    /*
	     * One byte was consumed as a side effect of waiting for the
	     * console to become readable.
	     */
	    
	    infoPtr->readFlags |= CONSOLE_EXTRABYTE;
	} else {
	    DWORD err;
	    err = GetLastError();
	    
	    if (err == EOF) {
		infoPtr->readFlags = CONSOLE_EOF;
	    }







|
|

|
<


|







1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054

1055
1056
1057
1058
1059
1060
1061
1062
1063
1064

	count = 0;

	/* 
	 * Look for data on the console, but first ignore any events
	 * that are not KEY_EVENTs 
	 */
	if (ReadConsole(handle, infoPtr->buffer, CONSOLE_BUFFER_SIZE,
		&infoPtr->bytesRead, NULL) != FALSE) {
	    /*
	     * Data was stored in the buffer.

	     */
	    
	    infoPtr->readFlags |= CONSOLE_BUFFERED;
	} else {
	    DWORD err;
	    err = GetLastError();
	    
	    if (err == EOF) {
		infoPtr->readFlags = CONSOLE_EOF;
	    }