diff options
Diffstat (limited to 'win/tclWinChan.c')
-rw-r--r-- | win/tclWinChan.c | 610 |
1 files changed, 249 insertions, 361 deletions
diff --git a/win/tclWinChan.c b/win/tclWinChan.c index c2ba568..e2126fb 100644 --- a/win/tclWinChan.c +++ b/win/tclWinChan.c @@ -9,26 +9,12 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinChan.c,v 1.5 1999/03/10 05:52:53 stanton Exp $ + * RCS: @(#) $Id: tclWinChan.c,v 1.6 1999/04/16 00:48:07 stanton Exp $ */ #include "tclWinInt.h" /* - * This is the size of the channel name for File based channels - */ - -#define CHANNEL_NAME_SIZE 64 -static char channelName[CHANNEL_NAME_SIZE+1]; - -/* - * The following variable is used to tell whether this module has been - * initialized. - */ - -static int initialized = 0; - -/* * State flags used in the info structures below. */ @@ -36,6 +22,9 @@ static int initialized = 0; #define FILE_ASYNC (1<<1) /* Channel is non-blocking. */ #define FILE_APPEND (1<<2) /* File is in append mode. */ +#define FILE_TYPE_SERIAL (FILE_TYPE_PIPE+1) +#define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2) + /* * The following structure contains per-instance data for a file based channel. */ @@ -53,11 +42,15 @@ typedef struct FileInfo { struct FileInfo *nextPtr; /* Pointer to next registered file. */ } FileInfo; -/* - * List of all file channels currently open. - */ +typedef struct ThreadSpecificData { + /* + * List of all file channels currently open. + */ + + FileInfo *firstFilePtr; +} ThreadSpecificData; -static FileInfo *firstFilePtr; +static Tcl_ThreadDataKey dataKey; /* * The following structure is what is added to the Tcl event queue when @@ -77,14 +70,6 @@ typedef struct FileEvent { * Static routines for this file: */ -static int ComGetOptionProc _ANSI_ARGS_((ClientData instanceData, - Tcl_Interp *interp, char *optionName, - Tcl_DString *dsPtr)); -static int ComInputProc _ANSI_ARGS_((ClientData instanceData, - char *buf, int toRead, int *errorCode)); -static int ComSetOptionProc _ANSI_ARGS_((ClientData instanceData, - Tcl_Interp *interp, char *optionName, - char *value)); static int FileBlockProc _ANSI_ARGS_((ClientData instanceData, int mode)); static void FileChannelExitHandler _ANSI_ARGS_(( @@ -97,7 +82,7 @@ static int FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags)); static int FileGetHandleProc _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr)); -static void FileInit _ANSI_ARGS_((void)); +static ThreadSpecificData *FileInit _ANSI_ARGS_((void)); static int FileInputProc _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode)); static int FileOutputProc _ANSI_ARGS_((ClientData instanceData, @@ -127,18 +112,6 @@ static Tcl_ChannelType fileChannelType = { FileGetHandleProc, /* Get an OS handle from channel. */ }; -static Tcl_ChannelType comChannelType = { - "com", /* Type name. */ - FileBlockProc, /* Set blocking or non-blocking mode.*/ - FileCloseProc, /* Close proc. */ - ComInputProc, /* Input proc. */ - FileOutputProc, /* Output proc. */ - NULL, /* Seek proc. */ - ComSetOptionProc, /* Set option proc. */ - ComGetOptionProc, /* Get option proc. */ - FileWatchProc, /* Set up notifier to watch the channel. */ - FileGetHandleProc /* Get an OS handle from channel. */ -}; /* *---------------------------------------------------------------------- @@ -156,13 +129,18 @@ static Tcl_ChannelType comChannelType = { *---------------------------------------------------------------------- */ -static void +static ThreadSpecificData * FileInit() { - initialized = 1; - firstFilePtr = NULL; - Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL); - Tcl_CreateExitHandler(FileChannelExitHandler, NULL); + ThreadSpecificData *tsdPtr = + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); + if (tsdPtr == NULL) { + tsdPtr = TCL_TSD_INIT(&dataKey); + tsdPtr->firstFilePtr = NULL; + Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL); + Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL); + } + return tsdPtr; } /* @@ -187,7 +165,6 @@ FileChannelExitHandler(clientData) ClientData clientData; /* Old window proc */ { Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL); - initialized = 0; } /* @@ -214,6 +191,7 @@ FileSetupProc(data, flags) { FileInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; @@ -223,7 +201,8 @@ FileSetupProc(data, flags) * Check to see if there is a ready file. If so, poll. */ - for (infoPtr = firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { + for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); break; @@ -255,6 +234,7 @@ FileCheckProc(data, flags) { FileEvent *evPtr; FileInfo *infoPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return; @@ -266,7 +246,8 @@ FileCheckProc(data, flags) * events). */ - for (infoPtr = firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { + for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) { infoPtr->flags |= FILE_PENDING; evPtr = (FileEvent *) ckalloc(sizeof(FileEvent)); @@ -305,6 +286,7 @@ FileEventProc(evPtr, flags) { FileEvent *fileEvPtr = (FileEvent *)evPtr; FileInfo *infoPtr; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); if (!(flags & TCL_FILE_EVENTS)) { return 0; @@ -317,7 +299,8 @@ FileEventProc(evPtr, flags) * event is in the queue. */ - for (infoPtr = firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { + for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { if (fileEvPtr->infoPtr == infoPtr) { infoPtr->flags &= ~(FILE_PENDING); Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask); @@ -390,6 +373,7 @@ FileCloseProc(instanceData, interp) FileInfo *fileInfoPtr = (FileInfo *) instanceData; FileInfo **nextPtrPtr; int errorCode = 0; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); /* * Remove the file from the watch list. @@ -397,11 +381,22 @@ FileCloseProc(instanceData, interp) FileWatchProc(instanceData, 0); - if (CloseHandle(fileInfoPtr->handle) == FALSE) { - TclWinConvertError(GetLastError()); - errorCode = errno; + /* + * Don't close the Win32 handle if the handle is a standard channel + * during the exit process. Otherwise, one thread may kill the stdio + * of another. + */ + + if (!TclInExit() + || ((GetStdHandle(STD_INPUT_HANDLE) != fileInfoPtr->handle) + && (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle) + && (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) { + if (CloseHandle(fileInfoPtr->handle) == FALSE) { + TclWinConvertError(GetLastError()); + errorCode = errno; + } } - for (nextPtrPtr = &firstFilePtr; (*nextPtrPtr) != NULL; + for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == fileInfoPtr) { (*nextPtrPtr) = fileInfoPtr->nextPtr; @@ -455,7 +450,7 @@ FileSeekProc(instanceData, offset, mode, errorCodePtr) if (newPos == 0xFFFFFFFF) { TclWinConvertError(GetLastError()); *errorCodePtr = errno; - return -1; + return -1; } return newPos; } @@ -605,7 +600,7 @@ FileWatchProc(instanceData, mask) * * FileGetHandleProc -- * - * Called from Tcl_GetChannelFile to retrieve OS handles from + * Called from Tcl_GetChannelHandle to retrieve OS handles from * a file based channel. * * Results: @@ -633,196 +628,7 @@ FileGetHandleProc(instanceData, direction, handlePtr) return TCL_ERROR; } } - -/* - *---------------------------------------------------------------------- - * - * ComInputProc -- - * - * Reads input from the IO channel into the buffer given. Returns - * count of how many bytes were actually read, and an error indication. - * - * Results: - * A count of how many bytes were read is returned and an error - * indication is returned in an output argument. - * - * Side effects: - * Reads input from the actual channel. - * - *---------------------------------------------------------------------- - */ - -static int -ComInputProc(instanceData, buf, bufSize, errorCode) - ClientData instanceData; /* File state. */ - char *buf; /* Where to store data read. */ - int bufSize; /* How much space is available - * in the buffer? */ - int *errorCode; /* Where to store error code. */ -{ - FileInfo *infoPtr; - DWORD bytesRead; - DWORD dw; - COMSTAT cs; - - *errorCode = 0; - infoPtr = (FileInfo *) instanceData; - - if (ClearCommError(infoPtr->handle, &dw, &cs)) { - if (dw != 0) { - *errorCode = EIO; - return -1; - } - if (cs.cbInQue != 0) { - if ((DWORD) bufSize > cs.cbInQue) { - bufSize = cs.cbInQue; - } - } else { - if (infoPtr->flags & FILE_ASYNC) { - errno = *errorCode = EAGAIN; - return -1; - } else { - bufSize = 1; - } - } - } - - if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead, - (LPOVERLAPPED) NULL) == FALSE) { - TclWinConvertError(GetLastError()); - *errorCode = errno; - return -1; - } - - return bytesRead; -} - -/* - *---------------------------------------------------------------------- - * - * ComSetOptionProc -- - * - * Sets an option on a channel. - * - * Results: - * A standard Tcl result. Also sets interp->result on error if - * interp is not NULL. - * - * Side effects: - * May modify an option on a device. - * - *---------------------------------------------------------------------- - */ - -static int -ComSetOptionProc(instanceData, interp, optionName, value) - ClientData instanceData; /* File state. */ - Tcl_Interp *interp; /* For error reporting - can be NULL. */ - char *optionName; /* Which option to set? */ - char *value; /* New value for option. */ -{ - FileInfo *infoPtr; - DCB dcb; - int len; - infoPtr = (FileInfo *) instanceData; - - len = strlen(optionName); - if ((len > 1) && (strncmp(optionName, "-mode", len) == 0)) { - if (GetCommState(infoPtr->handle, &dcb)) { - if ((BuildCommDCB(value, &dcb) == FALSE) || - (SetCommState(infoPtr->handle, &dcb) == FALSE)) { - /* - * one should separate the 2 errors... - */ - if (interp) { - Tcl_AppendResult(interp, "bad value for -mode: should be ", - "baud,parity,data,stop", NULL); - } - return TCL_ERROR; - } else { - return TCL_OK; - } - } else { - if (interp) { - Tcl_AppendResult(interp, "can't get comm state", NULL); - } - return TCL_ERROR; - } - } else { - return Tcl_BadChannelOption(interp, optionName, "mode"); - } -} - -/* - *---------------------------------------------------------------------- - * - * ComGetOptionProc -- - * - * Gets a mode associated with an IO channel. If the optionName arg - * is non NULL, retrieves the value of that option. If the optionName - * arg is NULL, retrieves a list of alternating option names and - * values for the given channel. - * - * Results: - * A standard Tcl result. Also sets the supplied DString to the - * string value of the option(s) returned. - * - * Side effects: - * The string returned by this function is in static storage and - * may be reused at any time subsequent to the call. - * - *---------------------------------------------------------------------- - */ - -static int -ComGetOptionProc(instanceData, interp, optionName, dsPtr) - ClientData instanceData; /* File state. */ - Tcl_Interp *interp; /* For error reporting - can be NULL. */ - char *optionName; /* Option to get. */ - Tcl_DString *dsPtr; /* Where to store value(s). */ -{ - FileInfo *infoPtr; - DCB dcb; - int len; - - infoPtr = (FileInfo *) instanceData; - - if (optionName == NULL) { - Tcl_DStringAppendElement(dsPtr, "-mode"); - len = 0; - } else { - len = strlen(optionName); - } - if ((len == 0) || - ((len > 1) && (strncmp(optionName, "-mode", len) == 0))) { - if (GetCommState(infoPtr->handle, &dcb) == 0) { - /* - * shouldn't we flag an error instead ? - */ - Tcl_DStringAppendElement(dsPtr, ""); - } else { - char parity; - char *stop; - char buf[32]; - - parity = 'n'; - if (dcb.Parity < 4) { - parity = "noems"[dcb.Parity]; - } - - stop = (dcb.StopBits == ONESTOPBIT) ? "1" : - (dcb.StopBits == ONE5STOPBITS) ? "1.5" : "2"; - - wsprintf(buf, "%d,%c,%d,%s", dcb.BaudRate, parity, dcb.ByteSize, - stop); - Tcl_DStringAppendElement(dsPtr, buf); - } - return TCL_OK; - } else { - return Tcl_BadChannelOption(interp, optionName, "mode"); - } -} /* *---------------------------------------------------------------------- @@ -853,28 +659,27 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) * file, with what modes to create * it? */ { - FileInfo *infoPtr; + Tcl_Channel channel = 0; int seekFlag, mode, channelPermissions; - DWORD accessMode, createMode, shareMode, flags; - char *nativeName; - Tcl_DString buffer; + DWORD accessMode, createMode, shareMode, flags, consoleParams, type; + TCHAR *nativeName; + Tcl_DString ds, buffer; DCB dcb; - Tcl_ChannelType *channelTypePtr; HANDLE handle; - - if (!initialized) { - FileInit(); - } + char channelName[16 + TCL_INTEGER_SPACE]; + TclFile readFile = NULL; + TclFile writeFile = NULL; mode = TclGetOpenMode(interp, modeString, &seekFlag); if (mode == -1) { return NULL; } - nativeName = Tcl_TranslateFileName(interp, fileName, &buffer); - if (nativeName == NULL) { + if (Tcl_TranslateFileName(interp, fileName, &ds) == NULL) { return NULL; } + nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds), &buffer); switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: @@ -930,7 +735,7 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) flags = FILE_ATTRIBUTE_READONLY; } } else { - flags = GetFileAttributes(nativeName); + flags = (*tclWinProcs->getFileAttributesProc)(nativeName); if (flags == 0xFFFFFFFF) { flags = 0; } @@ -946,13 +751,11 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) * Now we get to create the file. */ - handle = CreateFile(nativeName, accessMode, shareMode, NULL, createMode, - flags, (HANDLE) NULL); + handle = (*tclWinProcs->createFileProc)(nativeName, accessMode, + shareMode, NULL, createMode, flags, (HANDLE) NULL); if (handle == INVALID_HANDLE_VALUE) { DWORD err; - - openerr: err = GetLastError(); if ((err & 0xffffL) == ERROR_OPEN_FAILED) { err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND; @@ -960,87 +763,82 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) TclWinConvertError(err); if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "couldn't open \"", fileName, "\": ", - Tcl_PosixError(interp), (char *) NULL); + Tcl_PosixError(interp), (char *) NULL); } Tcl_DStringFree(&buffer); return NULL; } + + type = GetFileType(handle); - if (GetFileType(handle) == FILE_TYPE_CHAR) { - dcb.DCBlength = sizeof( DCB ) ; - if (GetCommState(handle, &dcb)) { - /* - * This is a com port. Reopen it with the correct modes. - */ - - COMMTIMEOUTS cto; - - CloseHandle(handle); - handle = CreateFile(nativeName, accessMode, 0, NULL, OPEN_EXISTING, - flags, NULL); - if (handle == INVALID_HANDLE_VALUE) { - goto openerr; - } + /* + * If the file is a character device, we need to try to figure out + * whether it is a serial port, a console, or something else. We + * test for the console case first because this is more common. + */ - /* - * FileInit the com port. - */ - - SetCommMask(handle, EV_RXCHAR); - SetupComm(handle, 4096, 4096); - PurgeComm(handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR - | PURGE_RXCLEAR); - cto.ReadIntervalTimeout = MAXDWORD; - cto.ReadTotalTimeoutMultiplier = 0; - cto.ReadTotalTimeoutConstant = 0; - cto.WriteTotalTimeoutMultiplier = 0; - cto.WriteTotalTimeoutConstant = 0; - SetCommTimeouts(handle, &cto); - - GetCommState(handle, &dcb); - SetCommState(handle, &dcb); - channelTypePtr = &comChannelType; + if (type == FILE_TYPE_CHAR) { + if (GetConsoleMode(handle, &consoleParams)) { + type = FILE_TYPE_CONSOLE; } else { - channelTypePtr = &fileChannelType; + dcb.DCBlength = sizeof( DCB ) ; + if (GetCommState(handle, &dcb)) { + type = FILE_TYPE_SERIAL; + } } - } else { - channelTypePtr = &fileChannelType; } - Tcl_DStringFree(&buffer); - infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo)); - infoPtr->nextPtr = firstFilePtr; - firstFilePtr = infoPtr; - infoPtr->validMask = channelPermissions; - infoPtr->watchMask = 0; - infoPtr->flags = (mode & O_APPEND) ? FILE_APPEND : 0; - infoPtr->handle = handle; - - sprintf(channelName, "file%d", (int) handle); - - infoPtr->channel = Tcl_CreateChannel(channelTypePtr, channelName, - (ClientData) infoPtr, channelPermissions); - - if (seekFlag) { - if (Tcl_Seek(infoPtr->channel, 0, SEEK_END) < 0) { - if (interp != (Tcl_Interp *) NULL) { - Tcl_AppendResult(interp, "could not seek to end of file on \"", - channelName, "\": ", Tcl_PosixError(interp), - (char *) NULL); - } - Tcl_Close(NULL, infoPtr->channel); - return NULL; - } + channel = NULL; + + switch (type) + { + case FILE_TYPE_SERIAL: + channel = TclWinOpenSerialChannel(handle, channelName, + channelPermissions); + break; + case FILE_TYPE_CONSOLE: + channel = TclWinOpenConsoleChannel(handle, channelName, + channelPermissions); + break; + case FILE_TYPE_PIPE: + if (channelPermissions & TCL_READABLE) + { + readFile = TclWinMakeFile(handle); + } + if (channelPermissions & TCL_WRITABLE) + { + writeFile = TclWinMakeFile(handle); + } + channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL); + break; + case FILE_TYPE_CHAR: + default: + channel = TclWinOpenFileChannel(handle, channelName, + channelPermissions, + (mode & O_APPEND) ? FILE_APPEND : 0); + break; + } - /* - * Files have default translation of AUTO and ^Z eof char, which - * means that a ^Z will be appended to them at close. - */ - - Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); - Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); - return infoPtr->channel; + Tcl_DStringFree(&buffer); + Tcl_DStringFree(&ds); + + if (channel != NULL) + { + if (seekFlag) { + if (Tcl_Seek(channel, 0, SEEK_END) < 0) { + if (interp != (Tcl_Interp *) NULL) { + Tcl_AppendResult(interp, + "could not seek to end of file on \"", + channelName, "\": ", Tcl_PosixError(interp), + (char *) NULL); + } + Tcl_Close(NULL, channel); + return NULL; + } + } + } + return channel; } /* @@ -1061,57 +859,78 @@ TclpOpenFileChannel(interp, fileName, modeString, permissions) */ Tcl_Channel -Tcl_MakeFileChannel(handle, mode) - ClientData handle; /* OS level handle */ +Tcl_MakeFileChannel(rawHandle, mode) + ClientData rawHandle; /* OS level handle */ int mode; /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { - char channelName[20]; - FileInfo *infoPtr; - - if (!initialized) { - FileInit(); - } + char channelName[16 + TCL_INTEGER_SPACE]; + Tcl_Channel channel = NULL; + HANDLE handle = (HANDLE) rawHandle; + DCB dcb; + DWORD consoleParams; + DWORD type; + TclFile readFile = NULL; + TclFile writeFile = NULL; if (mode == 0) { return NULL; } - sprintf(channelName, "file%d", (int) handle); + type = GetFileType(handle); /* - * See if a channel with this handle already exists. + * If the file is a character device, we need to try to figure out + * whether it is a serial port, a console, or something else. We + * test for the console case first because this is more common. */ - - for (infoPtr = firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { - if (infoPtr->handle == (HANDLE) handle) { - return (mode == infoPtr->validMask) ? infoPtr->channel : NULL; + + if (type == FILE_TYPE_CHAR) { + if (GetConsoleMode(handle, &consoleParams)) { + type = FILE_TYPE_CONSOLE; + } else { + dcb.DCBlength = sizeof( DCB ) ; + if (GetCommState(handle, &dcb)) { + type = FILE_TYPE_SERIAL; + } } } - infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo)); - infoPtr->nextPtr = firstFilePtr; - firstFilePtr = infoPtr; - infoPtr->validMask = mode; - infoPtr->watchMask = 0; - infoPtr->flags = 0; - infoPtr->handle = (HANDLE) handle; - infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName, - (ClientData) infoPtr, mode); + switch (type) + { + case FILE_TYPE_SERIAL: + channel = TclWinOpenSerialChannel(handle, channelName, mode); + break; + case FILE_TYPE_CONSOLE: + channel = TclWinOpenConsoleChannel(handle, channelName, mode); + break; + case FILE_TYPE_PIPE: + if (mode & TCL_READABLE) + { + readFile = TclWinMakeFile(handle); + } + if (mode & TCL_WRITABLE) + { + writeFile = TclWinMakeFile(handle); + } + channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL); + break; + case FILE_TYPE_UNKNOWN: + break; + case FILE_TYPE_CHAR: + default: + channel = TclWinOpenFileChannel(handle, channelName, mode, 0); + break; - /* - * Windows files have AUTO translation mode and ^Z eof char on input. - */ - - Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); - Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); - return infoPtr->channel; + } + + return channel; } /* *---------------------------------------------------------------------- * - * TclGetDefaultStdChannel -- + * TclpGetDefaultStdChannel -- * * Constructs a channel for the specified standard OS handle. * @@ -1126,7 +945,7 @@ Tcl_MakeFileChannel(handle, mode) */ Tcl_Channel -TclGetDefaultStdChannel(type) +TclpGetDefaultStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ { Tcl_Channel channel; @@ -1187,3 +1006,72 @@ TclGetDefaultStdChannel(type) } return channel; } + + + +/* + *---------------------------------------------------------------------- + * + * TclWinOpenFileChannel -- + * + * Constructs a File channel for the specified standard OS handle. + * This is a helper function to break up the construction of + * channels into File, Console, or Serial. + * + * Results: + * Returns the new channel, or NULL. + * + * Side effects: + * May open the channel and may cause creation of a file on the + * file system. + * + *---------------------------------------------------------------------- + */ + +Tcl_Channel +TclWinOpenFileChannel(handle, channelName, permissions, appendMode) + HANDLE handle; + char *channelName; + int permissions; + int appendMode; +{ + FileInfo *infoPtr; + ThreadSpecificData *tsdPtr; + + tsdPtr = FileInit(); + + /* + * See if a channel with this handle already exists. + */ + + for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; + infoPtr = infoPtr->nextPtr) { + if (infoPtr->handle == (HANDLE) handle) { + return (permissions == infoPtr->validMask) ? infoPtr->channel : NULL; + } + } + + infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo)); + infoPtr->nextPtr = tsdPtr->firstFilePtr; + tsdPtr->firstFilePtr = infoPtr; + infoPtr->validMask = permissions; + infoPtr->watchMask = 0; + infoPtr->flags = appendMode; + infoPtr->handle = handle; + + wsprintfA(channelName, "file%lx", (int) infoPtr); + + infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName, + (ClientData) infoPtr, permissions); + + /* + * Files have default translation of AUTO and ^Z eof char, which + * means that a ^Z will be accepted as EOF when reading. + */ + + Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); + Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); + + return infoPtr->channel; +} + |