diff options
Diffstat (limited to 'win/tclWinChan.c')
| -rw-r--r-- | win/tclWinChan.c | 696 |
1 files changed, 243 insertions, 453 deletions
diff --git a/win/tclWinChan.c b/win/tclWinChan.c index 9b018e4..a271919 100644 --- a/win/tclWinChan.c +++ b/win/tclWinChan.c @@ -4,7 +4,7 @@ * Channel drivers for Windows channels based on files, command pipes and * TCP sockets. * - * Copyright © 1995-1997 Sun Microsystems, Inc. + * Copyright (c) 1995-1997 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -25,8 +25,7 @@ #define FILE_TYPE_CONSOLE (FILE_TYPE_PIPE+2) /* - * The following structure contains per-instance data for a file based - * channel. + * The following structure contains per-instance data for a file based channel. */ typedef struct FileInfo { @@ -44,7 +43,7 @@ typedef struct FileInfo { * pending on the channel. */ } FileInfo; -typedef struct { +typedef struct ThreadSpecificData { /* * List of all file channels currently open. */ @@ -59,7 +58,7 @@ static Tcl_ThreadDataKey dataKey; * events are generated. */ -typedef struct { +typedef struct FileEvent { Tcl_Event header; /* Information that is standard for all * events. */ FileInfo *infoPtr; /* Pointer to file info structure. Note that @@ -72,110 +71,54 @@ typedef struct { * Static routines for this file: */ -static int FileBlockProc(void *instanceData, int mode); -static void FileChannelExitHandler(void *clientData); -static void FileCheckProc(void *clientData, int flags); -static int FileCloseProc(void *instanceData, - Tcl_Interp *interp, int flags); +static int FileBlockProc(ClientData instanceData, int mode); +static void FileChannelExitHandler(ClientData clientData); +static void FileCheckProc(ClientData clientData, int flags); +static int FileCloseProc(ClientData instanceData, + Tcl_Interp *interp); static int FileEventProc(Tcl_Event *evPtr, int flags); -static int FileGetHandleProc(void *instanceData, - int direction, void **handlePtr); -static int FileGetOptionProc(void *instanceData, - Tcl_Interp *interp, const char *optionName, - Tcl_DString *dsPtr); +static int FileGetHandleProc(ClientData instanceData, + int direction, ClientData *handlePtr); static ThreadSpecificData *FileInit(void); -static int FileInputProc(void *instanceData, char *buf, +static int FileInputProc(ClientData instanceData, char *buf, int toRead, int *errorCode); -static int FileOutputProc(void *instanceData, - const char *buf, int toWrite, int *errorCode); -#ifndef TCL_NO_DEPRECATED -static int FileSeekProc(void *instanceData, long offset, +static int FileOutputProc(ClientData instanceData, + CONST char *buf, int toWrite, int *errorCode); +static int FileSeekProc(ClientData instanceData, long offset, int mode, int *errorCode); -#endif -static long long FileWideSeekProc(void *instanceData, - long long offset, int mode, int *errorCode); -static void FileSetupProc(void *clientData, int flags); -static void FileWatchProc(void *instanceData, int mask); -static void FileThreadActionProc(void *instanceData, +static Tcl_WideInt FileWideSeekProc(ClientData instanceData, + Tcl_WideInt offset, int mode, int *errorCode); +static void FileSetupProc(ClientData clientData, int flags); +static void FileWatchProc(ClientData instanceData, int mask); +static void FileThreadActionProc(ClientData instanceData, int action); -static int FileTruncateProc(void *instanceData, - long long length); +static int FileTruncateProc(ClientData instanceData, + Tcl_WideInt length); static DWORD FileGetType(HANDLE handle); -static int NativeIsComPort(const WCHAR *nativeName); -static Tcl_Channel OpenFileChannel(HANDLE handle, char *channelName, - int permissions, int appendMode); - +static int NativeIsComPort(CONST TCHAR *nativeName); /* * This structure describes the channel type structure for file based IO. */ -static const Tcl_ChannelType fileChannelType = { +static Tcl_ChannelType fileChannelType = { "file", /* Type name. */ TCL_CHANNEL_VERSION_5, /* v5 channel */ - TCL_CLOSE2PROC, /* Close proc. */ + FileCloseProc, /* Close proc. */ FileInputProc, /* Input proc. */ FileOutputProc, /* Output proc. */ -#ifndef TCL_NO_DEPRECATED FileSeekProc, /* Seek proc. */ -#else - NULL, -#endif NULL, /* Set option proc. */ - FileGetOptionProc, /* Get option proc. */ + NULL, /* Get option proc. */ FileWatchProc, /* Set up the notifier to watch the channel. */ FileGetHandleProc, /* Get an OS handle from channel. */ - FileCloseProc, /* close2proc. */ + NULL, /* close2proc. */ FileBlockProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ FileWideSeekProc, /* Wide seek proc. */ FileThreadActionProc, /* Thread action proc. */ - FileTruncateProc /* Truncate proc. */ + FileTruncateProc, /* Truncate proc. */ }; - -/* - * General useful clarification macros. - */ - -#define SET_FLAG(var, flag) ((var) |= (flag)) -#define CLEAR_FLAG(var, flag) ((var) &= ~(flag)) -#define TEST_FLAG(value, flag) (((value) & (flag)) != 0) - -/* - * The number of 100-ns intervals between the Windows system epoch (1601-01-01 - * on the proleptic Gregorian calendar) and the Posix epoch (1970-01-01). - */ - -#define POSIX_EPOCH_AS_FILETIME \ - ((long long) 116444736 * (long long) 1000000000) - - -/* - *---------------------------------------------------------------------- - * - * TclWinGenerateChannelName -- - * - * This function generates names for channels. - * - * Results: - * None. - * - * Side effects: - * Creates a new window and creates an exit handler. - * - *---------------------------------------------------------------------- - */ -void -TclWinGenerateChannelName( - char channelName[], /* Buffer to accept the name. */ - const char *channelTypeName,/* Name of type of channel. */ - void *channelImpl) /* Pointer to channel implementation - * structure, used to generate a unique - * ID. */ -{ - snprintf(channelName, 16 + TCL_INTEGER_SPACE, "%s%" TCL_Z_MODIFIER "x", - channelTypeName, (size_t) channelImpl); -} /* *---------------------------------------------------------------------- @@ -197,7 +140,7 @@ static ThreadSpecificData * FileInit(void) { ThreadSpecificData *tsdPtr = - (ThreadSpecificData *) TclThreadDataKeyGet(&dataKey); + (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); if (tsdPtr == NULL) { tsdPtr = TCL_TSD_INIT(&dataKey); @@ -227,7 +170,7 @@ FileInit(void) static void FileChannelExitHandler( - TCL_UNUSED(void *)) + ClientData clientData) /* Old window proc */ { Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL); } @@ -251,14 +194,14 @@ FileChannelExitHandler( void FileSetupProc( - TCL_UNUSED(void *), + ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { FileInfo *infoPtr; Tcl_Time blockTime = { 0, 0 }; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (!TEST_FLAG(flags, TCL_FILE_EVENTS)) { + if (!(flags & TCL_FILE_EVENTS)) { return; } @@ -294,14 +237,14 @@ FileSetupProc( static void FileCheckProc( - TCL_UNUSED(void *), + ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { FileEvent *evPtr; FileInfo *infoPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (!TEST_FLAG(flags, TCL_FILE_EVENTS)) { + if (!(flags & TCL_FILE_EVENTS)) { return; } @@ -312,9 +255,9 @@ FileCheckProc( for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { - if (infoPtr->watchMask && !TEST_FLAG(infoPtr->flags, FILE_PENDING)) { - SET_FLAG(infoPtr->flags, FILE_PENDING); - evPtr = (FileEvent *)ckalloc(sizeof(FileEvent)); + if (infoPtr->watchMask && !(infoPtr->flags & FILE_PENDING)) { + infoPtr->flags |= FILE_PENDING; + evPtr = (FileEvent *) ckalloc(sizeof(FileEvent)); evPtr->header.proc = FileEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); @@ -353,7 +296,7 @@ FileEventProc( FileInfo *infoPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - if (!TEST_FLAG(flags, TCL_FILE_EVENTS)) { + if (!(flags & TCL_FILE_EVENTS)) { return 0; } @@ -367,7 +310,7 @@ FileEventProc( for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (fileEvPtr->infoPtr == infoPtr) { - CLEAR_FLAG(infoPtr->flags, FILE_PENDING); + infoPtr->flags &= ~(FILE_PENDING); Tcl_NotifyChannel(infoPtr->channel, infoPtr->watchMask); break; } @@ -393,11 +336,11 @@ FileEventProc( static int FileBlockProc( - void *instanceData, /* Instance data for channel. */ + ClientData instanceData, /* Instance data for channel. */ int mode) /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr = (FileInfo *) instanceData; /* * Files on Windows can not be switched between blocking and nonblocking, @@ -407,9 +350,9 @@ FileBlockProc( */ if (mode == TCL_MODE_NONBLOCKING) { - SET_FLAG(infoPtr->flags, FILE_ASYNC); + infoPtr->flags |= FILE_ASYNC; } else { - CLEAR_FLAG(infoPtr->flags, FILE_ASYNC); + infoPtr->flags &= ~(FILE_ASYNC); } return 0; } @@ -432,19 +375,14 @@ FileBlockProc( static int FileCloseProc( - void *instanceData, /* Pointer to FileInfo structure. */ - TCL_UNUSED(Tcl_Interp *), - int flags) + ClientData instanceData, /* Pointer to FileInfo structure. */ + Tcl_Interp *interp) /* Not used. */ { - FileInfo *fileInfoPtr = (FileInfo *)instanceData; + FileInfo *fileInfoPtr = (FileInfo *) instanceData; FileInfo *infoPtr; ThreadSpecificData *tsdPtr; int errorCode = 0; - if ((flags & (TCL_CLOSE_READ | TCL_CLOSE_WRITE)) != 0) { - return EINVAL; - } - /* * Remove the file from the watch list. */ @@ -462,7 +400,7 @@ FileCloseProc( && (GetStdHandle(STD_OUTPUT_HANDLE) != fileInfoPtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != fileInfoPtr->handle))) { if (CloseHandle(fileInfoPtr->handle) == FALSE) { - Tcl_WinConvertError(GetLastError()); + TclWinConvertError(GetLastError()); errorCode = errno; } } @@ -486,7 +424,7 @@ FileCloseProc( break; } } - ckfree(fileInfoPtr); + ckfree((char *)fileInfoPtr); return errorCode; } @@ -507,15 +445,15 @@ FileCloseProc( * *---------------------------------------------------------------------- */ -#ifndef TCL_NO_DEPRECATED + static int FileSeekProc( - void *instanceData, /* File state. */ + ClientData instanceData, /* File state. */ long offset, /* Offset to seek to. */ int mode, /* Relative to where should we seek? */ int *errorCodePtr) /* To store error code. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr = (FileInfo *) instanceData; LONG newPos, newPosHigh, oldPos, oldPosHigh; DWORD moveMethod; @@ -534,11 +472,11 @@ FileSeekProc( oldPosHigh = 0; oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT); - if (oldPos == (LONG) INVALID_SET_FILE_POINTER) { + if (oldPos == (LONG)INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); if (winError != NO_ERROR) { - Tcl_WinConvertError(winError); + TclWinConvertError(winError); *errorCodePtr = errno; return -1; } @@ -546,11 +484,11 @@ FileSeekProc( newPosHigh = (offset < 0 ? -1 : 0); newPos = SetFilePointer(infoPtr->handle, offset, &newPosHigh, moveMethod); - if (newPos == (LONG) INVALID_SET_FILE_POINTER) { + if (newPos == (LONG)INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); if (winError != NO_ERROR) { - Tcl_WinConvertError(winError); + TclWinConvertError(winError); *errorCodePtr = errno; return -1; } @@ -567,7 +505,6 @@ FileSeekProc( } return (int) newPos; } -#endif /* *---------------------------------------------------------------------- @@ -587,14 +524,14 @@ FileSeekProc( *---------------------------------------------------------------------- */ -static long long +static Tcl_WideInt FileWideSeekProc( - void *instanceData, /* File state. */ - long long offset, /* Offset to seek to. */ + ClientData instanceData, /* File state. */ + Tcl_WideInt offset, /* Offset to seek to. */ int mode, /* Relative to where should we seek? */ int *errorCodePtr) /* To store error code. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr = (FileInfo *) instanceData; DWORD moveMethod; LONG newPos, newPosHigh; @@ -607,20 +544,19 @@ FileWideSeekProc( moveMethod = FILE_END; } - newPosHigh = (LONG)(offset >> 32); - newPos = SetFilePointer(infoPtr->handle, (LONG)offset, + newPosHigh = Tcl_WideAsLong(offset >> 32); + newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(offset), &newPosHigh, moveMethod); - if (newPos == (LONG) INVALID_SET_FILE_POINTER) { + if (newPos == (LONG)INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); if (winError != NO_ERROR) { - Tcl_WinConvertError(winError); + TclWinConvertError(winError); *errorCodePtr = errno; return -1; } } - return (((long long)((unsigned)newPos)) - | ((long long)newPosHigh << 32)); + return (((Tcl_WideInt)((unsigned)newPos)) | (Tcl_LongAsWide(newPosHigh) << 32)); } /* @@ -641,10 +577,10 @@ FileWideSeekProc( static int FileTruncateProc( - void *instanceData, /* File state. */ - long long length) /* Length to truncate at. */ + ClientData instanceData, /* File state. */ + Tcl_WideInt length) /* Length to truncate at. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr = (FileInfo *) instanceData; LONG newPos, newPosHigh, oldPos, oldPosHigh; /* @@ -653,11 +589,10 @@ FileTruncateProc( oldPosHigh = 0; oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh, FILE_CURRENT); - if (oldPos == (LONG) INVALID_SET_FILE_POINTER) { + if (oldPos == (LONG)INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); - if (winError != NO_ERROR) { - Tcl_WinConvertError(winError); + TclWinConvertError(winError); return errno; } } @@ -666,14 +601,13 @@ FileTruncateProc( * Move to where we want to truncate */ - newPosHigh = (LONG)(length >> 32); - newPos = SetFilePointer(infoPtr->handle, (LONG)length, + newPosHigh = Tcl_WideAsLong(length >> 32); + newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(length), &newPosHigh, FILE_BEGIN); - if (newPos == (LONG) INVALID_SET_FILE_POINTER) { + if (newPos == (LONG)INVALID_SET_FILE_POINTER) { DWORD winError = GetLastError(); - if (winError != NO_ERROR) { - Tcl_WinConvertError(winError); + TclWinConvertError(winError); return errno; } } @@ -684,7 +618,7 @@ FileTruncateProc( */ if (!SetEndOfFile(infoPtr->handle)) { - Tcl_WinConvertError(GetLastError()); + TclWinConvertError(GetLastError()); return errno; } @@ -717,21 +651,18 @@ FileTruncateProc( static int FileInputProc( - void *instanceData, /* File state. */ + ClientData instanceData, /* File state. */ char *buf, /* Where to store data read. */ int bufSize, /* Num bytes available in buffer. */ int *errorCode) /* Where to store error code. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr; DWORD bytesRead; *errorCode = 0; + infoPtr = (FileInfo *) instanceData; /* - * TODO: This comment appears to be out of date. We *do* have a console - * driver, over in tclWinConsole.c. After some Windows developer confirms, - * this comment should be revised. - * * Note that we will block on reads from a console buffer until a full * line has been entered. The only way I know of to get around this is to * write a console driver. We should probably do this at some point, but @@ -741,10 +672,10 @@ FileInputProc( if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead, (LPOVERLAPPED) NULL) != FALSE) { - return (int)bytesRead; + return bytesRead; } - Tcl_WinConvertError(GetLastError()); + TclWinConvertError(GetLastError()); *errorCode = errno; if (errno == EPIPE) { return 0; @@ -772,12 +703,12 @@ FileInputProc( static int FileOutputProc( - void *instanceData, /* File state. */ - const char *buf, /* The data buffer. */ + ClientData instanceData, /* File state. */ + CONST char *buf, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCode) /* Where to store error code. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr = (FileInfo *) instanceData; DWORD bytesWritten; *errorCode = 0; @@ -787,18 +718,18 @@ FileOutputProc( * seek to the end of the file before writing the current buffer. */ - if (TEST_FLAG(infoPtr->flags, FILE_APPEND)) { + if (infoPtr->flags & FILE_APPEND) { SetFilePointer(infoPtr->handle, 0, NULL, FILE_END); } if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, (LPOVERLAPPED) NULL) == FALSE) { - Tcl_WinConvertError(GetLastError()); + TclWinConvertError(GetLastError()); *errorCode = errno; return -1; } infoPtr->dirty = 1; - return (int)bytesWritten; + return bytesWritten; } /* @@ -819,12 +750,12 @@ FileOutputProc( static void FileWatchProc( - void *instanceData, /* File state. */ + ClientData instanceData, /* File state. */ int mask) /* What events to watch for; OR-ed combination * of TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr = (FileInfo *) instanceData; Tcl_Time blockTime = { 0, 0 }; /* @@ -858,207 +789,18 @@ FileWatchProc( static int FileGetHandleProc( - void *instanceData, /* The file state. */ + ClientData instanceData, /* The file state. */ int direction, /* TCL_READABLE or TCL_WRITABLE */ - void **handlePtr) /* Where to store the handle. */ -{ - FileInfo *infoPtr = (FileInfo *)instanceData; - - if (!TEST_FLAG(direction, infoPtr->validMask)) { - return TCL_ERROR; - } - - *handlePtr = (void *)infoPtr->handle; - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * FileGetOptionProc -- - * - * Gets an option associated with an open file. 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. Sets error message if needed - * (by calling Tcl_BadChannelOption). - * - *---------------------------------------------------------------------- - */ - -static inline ULONGLONG -CombineDwords( - DWORD hi, - DWORD lo) -{ - ULARGE_INTEGER converter; - - converter.LowPart = lo; - converter.HighPart = hi; - return converter.QuadPart; -} - -static inline void -StoreElementInDict( - Tcl_Obj *dictObj, - const char *name, - Tcl_Obj *valueObj) -{ - /* - * We assume that the dict is being built fresh and that there's never any - * duplicate keys. - */ - - Tcl_Obj *nameObj = Tcl_NewStringObj(name, TCL_INDEX_NONE); - Tcl_DictObjPut(NULL, dictObj, nameObj, valueObj); -} - -static inline time_t -ToCTime( - FILETIME fileTime) /* UTC time */ -{ - LARGE_INTEGER convertedTime; - - convertedTime.LowPart = fileTime.dwLowDateTime; - convertedTime.HighPart = (LONG) fileTime.dwHighDateTime; - - return (time_t) ((convertedTime.QuadPart - - (long long) POSIX_EPOCH_AS_FILETIME) / (long long) 10000000); -} - -static Tcl_Obj * -StatOpenFile( - FileInfo *infoPtr) -{ - DWORD attr; - int dev, nlink = 1; - unsigned short mode; - unsigned long long size, inode; - long long atime, ctime, mtime; - BY_HANDLE_FILE_INFORMATION data; - Tcl_Obj *dictObj; - - if (GetFileInformationByHandle(infoPtr->handle, &data) != TRUE) { - Tcl_SetErrno(ENOENT); - return NULL; - } - - atime = ToCTime(data.ftLastAccessTime); - mtime = ToCTime(data.ftLastWriteTime); - ctime = ToCTime(data.ftCreationTime); - attr = data.dwFileAttributes; - size = CombineDwords(data.nFileSizeHigh, data.nFileSizeLow); - nlink = data.nNumberOfLinks; - - /* - * Unfortunately our stat definition's inode field (unsigned short) will - * throw away most of the precision we have here, which means we can't - * rely on inode as a unique identifier of a file. We'd really like to do - * something like how we handle 'st_size'. - */ - - inode = CombineDwords(data.nFileIndexHigh, data.nFileIndexLow); - - dev = data.dwVolumeSerialNumber; - - /* - * Note that this code has no idea whether the file can be executed. - */ - - mode = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR|S_IEXEC : S_IFREG; - mode |= (attr & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE; - mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 3; - mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 6; - - /* - * We don't construct a Tcl_StatBuf; we're using the info immediately. - */ - - TclNewObj(dictObj); -#define STORE_ELEM(name, value) StoreElementInDict(dictObj, name, value) - - STORE_ELEM("dev", Tcl_NewWideIntObj((long) dev)); - STORE_ELEM("ino", Tcl_NewWideIntObj((long long) inode)); - STORE_ELEM("nlink", Tcl_NewIntObj(nlink)); - STORE_ELEM("uid", Tcl_NewIntObj(0)); - STORE_ELEM("gid", Tcl_NewIntObj(0)); - STORE_ELEM("size", Tcl_NewWideIntObj((long long) size)); - STORE_ELEM("atime", Tcl_NewWideIntObj(atime)); - STORE_ELEM("mtime", Tcl_NewWideIntObj(mtime)); - STORE_ELEM("ctime", Tcl_NewWideIntObj(ctime)); - STORE_ELEM("mode", Tcl_NewWideIntObj(mode)); - - /* - * Windows only has files and directories, as far as we're concerned. - * Anything else and we definitely couldn't have got here anyway. - */ - if (attr & FILE_ATTRIBUTE_DIRECTORY) { - STORE_ELEM("type", Tcl_NewStringObj("directory", TCL_INDEX_NONE)); - } else { - STORE_ELEM("type", Tcl_NewStringObj("file", TCL_INDEX_NONE)); - } -#undef STORE_ELEM - - return dictObj; -} - -static int -FileGetOptionProc( - void *instanceData, /* The file state. */ - Tcl_Interp *interp, /* For error reporting. */ - const char *optionName, /* What option to read, or NULL for all. */ - Tcl_DString *dsPtr) /* Where to write the value read. */ + ClientData *handlePtr) /* Where to store the handle. */ { - FileInfo *infoPtr = (FileInfo *)instanceData; - int valid = 0; /* Flag if valid option parsed. */ - int len; - - if (optionName == NULL) { - len = 0; - valid = 1; - } else { - len = strlen(optionName); - } + FileInfo *infoPtr = (FileInfo *) instanceData; - /* - * Get option -stat - * Option is readonly and returned by [fconfigure chan -stat] but not - * returned by [fconfigure chan] without explicit option name. - */ - - if ((len > 1) && (strncmp(optionName, "-stat", len) == 0)) { - Tcl_Obj *dictObj = StatOpenFile(infoPtr); - const char *dictContents; - Tcl_Size dictLength; - - if (dictObj == NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't read file channel status: %s", - Tcl_PosixError(interp))); - return TCL_ERROR; - } - - /* - * Transfer dictionary to the DString. Note that we don't do this as - * an element as this is an option that can't be retrieved with a - * general probe. - */ - - dictContents = TclGetStringFromObj(dictObj, &dictLength); - Tcl_DStringAppend(dsPtr, dictContents, dictLength); - Tcl_DecrRefCount(dictObj); - return TCL_OK; - } - - if (valid) { + if (direction & infoPtr->validMask) { + *handlePtr = (ClientData) infoPtr->handle; return TCL_OK; + } else { + return TCL_ERROR; } - return Tcl_BadChannelOption(interp, optionName, - "stat"); } /* @@ -1091,17 +833,17 @@ TclpOpenFileChannel( Tcl_Channel channel = 0; int channelPermissions = 0; DWORD accessMode = 0, createMode, shareMode, flags; - const WCHAR *nativeName; + CONST TCHAR *nativeName; HANDLE handle; char channelName[16 + TCL_INTEGER_SPACE]; TclFile readFile = NULL, writeFile = NULL; - nativeName = (const WCHAR *)Tcl_FSGetNativePath(pathPtr); + nativeName = (TCHAR*) Tcl_FSGetNativePath(pathPtr); if (nativeName == NULL) { - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't open \"%s\": filename is invalid on this platform", - TclGetString(pathPtr))); + if (interp != (Tcl_Interp *) NULL) { + Tcl_AppendResult(interp, "couldn't open \"", + TclGetString(pathPtr), "\": filename is invalid on this platform", + NULL); } return NULL; } @@ -1149,46 +891,45 @@ TclpOpenFileChannel( } /* - * [2413550] Avoid double-open of serial ports on Windows. Special - * handling for Windows serial ports by a "name-hint" to directly open it - * with the OVERLAPPED flag set. + * [2413550] Avoid double-open of serial ports on Windows + * Special handling for Windows serial ports by a "name-hint" + * to directly open it with the OVERLAPPED flag set. */ - if (NativeIsComPort(nativeName)) { + if( NativeIsComPort(nativeName) ) { + handle = TclWinSerialOpen(INVALID_HANDLE_VALUE, nativeName, accessMode); if (handle == INVALID_HANDLE_VALUE) { - Tcl_WinConvertError(GetLastError()); - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't open serial \"%s\": %s", - TclGetString(pathPtr), Tcl_PosixError(interp))); + TclWinConvertError(GetLastError()); + if (interp != (Tcl_Interp *) NULL) { + Tcl_AppendResult(interp, "couldn't open serial \"", + TclGetString(pathPtr), "\": ", + Tcl_PosixError(interp), NULL); } return NULL; } /* - * For natively-named Windows serial ports we are done. - */ - + * For natively named Windows serial ports we are done. + */ channel = TclWinOpenSerialChannel(handle, channelName, channelPermissions); return channel; } - /* * If the file is being created, get the file attributes from the * permissions argument, else use the existing file attributes. */ - if (TEST_FLAG(mode, O_CREAT)) { - if (TEST_FLAG(permissions, S_IWRITE)) { + if (mode & O_CREAT) { + if (permissions & S_IWRITE) { flags = FILE_ATTRIBUTE_NORMAL; } else { flags = FILE_ATTRIBUTE_READONLY; } } else { - flags = GetFileAttributesW(nativeName); + flags = (*tclWinProcs->getFileAttributesProc)(nativeName); if (flags == 0xFFFFFFFF) { flags = 0; } @@ -1204,21 +945,19 @@ TclpOpenFileChannel( * Now we get to create the file. */ - handle = CreateFileW(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 = GetLastError(); - if ((err & 0xFFFFL) == ERROR_OPEN_FAILED) { - err = TEST_FLAG(mode, O_CREAT) ? ERROR_FILE_EXISTS - : ERROR_FILE_NOT_FOUND; + if ((err & 0xffffL) == ERROR_OPEN_FAILED) { + err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND; } - Tcl_WinConvertError(err); - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't open \"%s\": %s", - TclGetString(pathPtr), Tcl_PosixError(interp))); + TclWinConvertError(err); + if (interp != (Tcl_Interp *) NULL) { + Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr), + "\": ", Tcl_PosixError(interp), NULL); } return NULL; } @@ -1228,9 +967,9 @@ TclpOpenFileChannel( switch (FileGetType(handle)) { case FILE_TYPE_SERIAL: /* - * Natively named serial ports "com1-9", "\\\\.\\comXX" are already - * done with the code above. Here we handle all other serial port - * names. + * Natively named serial ports "com1-9", "\\\\.\\comXX" are + * already done with the code above. + * Here we handle all other serial port names. * * Reopen channel for OVERLAPPED operation. Normally this shouldn't * fail, because the channel exists. @@ -1238,11 +977,11 @@ TclpOpenFileChannel( handle = TclWinSerialOpen(handle, nativeName, accessMode); if (handle == INVALID_HANDLE_VALUE) { - Tcl_WinConvertError(GetLastError()); - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't reopen serial \"%s\": %s", - TclGetString(pathPtr), Tcl_PosixError(interp))); + TclWinConvertError(GetLastError()); + if (interp != (Tcl_Interp *) NULL) { + Tcl_AppendResult(interp, "couldn't reopen serial \"", + TclGetString(pathPtr), "\": ", + Tcl_PosixError(interp), NULL); } return NULL; } @@ -1254,10 +993,10 @@ TclpOpenFileChannel( channelPermissions); break; case FILE_TYPE_PIPE: - if (TEST_FLAG(channelPermissions, TCL_READABLE)) { + if (channelPermissions & TCL_READABLE) { readFile = TclWinMakeFile(handle); } - if (TEST_FLAG(channelPermissions, TCL_WRITABLE)) { + if (channelPermissions & TCL_WRITABLE) { writeFile = TclWinMakeFile(handle); } channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL); @@ -1265,9 +1004,8 @@ TclpOpenFileChannel( case FILE_TYPE_CHAR: case FILE_TYPE_DISK: case FILE_TYPE_UNKNOWN: - channel = OpenFileChannel(handle, channelName, - channelPermissions, - TEST_FLAG(mode, O_APPEND) ? FILE_APPEND : 0); + channel = TclWinOpenFileChannel(handle, channelName, + channelPermissions, (mode & O_APPEND) ? FILE_APPEND : 0); break; default: @@ -1277,11 +1015,8 @@ TclpOpenFileChannel( */ channel = NULL; - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "couldn't open \"%s\": bad file type", - TclGetString(pathPtr))); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "CHANNEL", "BAD_TYPE", - (char *)NULL); + Tcl_AppendResult(interp, "couldn't open \"", TclGetString(pathPtr), + "\": bad file type", NULL); break; } @@ -1306,11 +1041,11 @@ TclpOpenFileChannel( Tcl_Channel Tcl_MakeFileChannel( - void *rawHandle, /* OS level handle */ - int mode) /* OR'ed combination of TCL_READABLE and + ClientData rawHandle, /* OS level handle */ + int mode) /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */ { -#if defined(HAVE_NO_SEH) && !defined(_WIN64) && !defined(__clang__) +#if defined(HAVE_NO_SEH) && !defined(_WIN64) TCLEXCEPTION_REGISTRATION registration; #endif char channelName[16 + TCL_INTEGER_SPACE]; @@ -1320,7 +1055,7 @@ Tcl_MakeFileChannel( TclFile readFile = NULL, writeFile = NULL; BOOL result; - if ((mode & (TCL_READABLE|TCL_WRITABLE)) == 0) { + if (mode == 0) { return NULL; } @@ -1332,10 +1067,10 @@ Tcl_MakeFileChannel( channel = TclWinOpenConsoleChannel(handle, channelName, mode); break; case FILE_TYPE_PIPE: - if (TEST_FLAG(mode, TCL_READABLE)) { + if (mode & TCL_READABLE) { readFile = TclWinMakeFile(handle); } - if (TEST_FLAG(mode, TCL_WRITABLE)) { + if (mode & TCL_WRITABLE) { writeFile = TclWinMakeFile(handle); } channel = TclpCreateCommandChannel(readFile, writeFile, NULL, 0, NULL); @@ -1343,7 +1078,7 @@ Tcl_MakeFileChannel( case FILE_TYPE_DISK: case FILE_TYPE_CHAR: - channel = OpenFileChannel(handle, channelName, mode, 0); + channel = TclWinOpenFileChannel(handle, channelName, mode, 0); break; case FILE_TYPE_UNKNOWN: @@ -1363,7 +1098,7 @@ Tcl_MakeFileChannel( if (result == 0) { /* - * Unable to make a duplicate. It's definitely invalid at this + * Unable to make a duplicate. It's definately invalid at this * point. */ @@ -1376,7 +1111,7 @@ Tcl_MakeFileChannel( */ result = 0; -#if defined(HAVE_NO_SEH) && !defined(_WIN64) && !defined(__clang__) +#if defined(HAVE_NO_SEH) && !defined(_WIN64) /* * Don't have SEH available, do things the hard way. Note that this * needs to be one block of asm, to avoid stack imbalance; also, it is @@ -1402,7 +1137,7 @@ Tcl_MakeFileChannel( "leal 1f, %%eax" "\n\t" "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */ - "movl %%esp, 0xC(%%edx)" "\n\t" /* esp */ + "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */ "movl $0, 0x10(%%edx)" "\n\t" /* status */ /* @@ -1442,7 +1177,7 @@ Tcl_MakeFileChannel( */ "2:" "\t" - "movl 0xC(%%edx), %%esp" "\n\t" + "movl 0xc(%%edx), %%esp" "\n\t" "movl 0x8(%%edx), %%ebp" "\n\t" "movl 0x0(%%edx), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" @@ -1477,7 +1212,7 @@ Tcl_MakeFileChannel( * is valid to something. */ - channel = OpenFileChannel(handle, channelName, mode, 0); + channel = TclWinOpenFileChannel(handle, channelName, mode, 0); } return channel; @@ -1507,8 +1242,8 @@ TclpGetDefaultStdChannel( Tcl_Channel channel; HANDLE handle; int mode = -1; - const char *bufMode = NULL; - DWORD handleId = (DWORD) -1; + char *bufMode = NULL; + DWORD handleId = (DWORD)-1; /* Standard handle to retrieve. */ switch (type) { @@ -1555,7 +1290,7 @@ TclpGetDefaultStdChannel( */ if (Tcl_SetChannelOption(NULL,channel,"-translation","auto")!=TCL_OK || - Tcl_SetChannelOption(NULL,channel,"-eofchar","\x1A {}")!=TCL_OK || + Tcl_SetChannelOption(NULL,channel,"-eofchar","\032 {}")!=TCL_OK || Tcl_SetChannelOption(NULL,channel,"-buffering",bufMode)!=TCL_OK) { Tcl_Close(NULL, channel); return (Tcl_Channel) NULL; @@ -1566,7 +1301,7 @@ TclpGetDefaultStdChannel( /* *---------------------------------------------------------------------- * - * OpenFileChannel -- + * TclWinOpenFileChannel -- * * Constructs a File channel for the specified standard OS handle. This * is a helper function to break up the construction of channels into @@ -1583,7 +1318,7 @@ TclpGetDefaultStdChannel( */ Tcl_Channel -OpenFileChannel( +TclWinOpenFileChannel( HANDLE handle, /* Win32 HANDLE to swallow */ char *channelName, /* Buffer to receive channel name */ int permissions, /* OR'ed combination of TCL_READABLE, @@ -1603,12 +1338,11 @@ OpenFileChannel( for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->handle == (HANDLE) handle) { - return ((permissions & (TCL_READABLE|TCL_WRITABLE|TCL_EXCEPTION))==infoPtr->validMask) - ? infoPtr->channel : NULL; + return (permissions==infoPtr->validMask) ? infoPtr->channel : NULL; } } - infoPtr = (FileInfo *)ckalloc(sizeof(FileInfo)); + infoPtr = (FileInfo *) ckalloc((unsigned) sizeof(FileInfo)); /* * TIP #218. Removed the code inserting the new structure into the global @@ -1617,14 +1351,15 @@ OpenFileChannel( */ infoPtr->nextPtr = NULL; - infoPtr->validMask = permissions & (TCL_READABLE|TCL_WRITABLE|TCL_EXCEPTION); + infoPtr->validMask = permissions; infoPtr->watchMask = 0; infoPtr->flags = appendMode; infoPtr->handle = handle; infoPtr->dirty = 0; - TclWinGenerateChannelName(channelName, "file", infoPtr); + sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t)infoPtr); + infoPtr->channel = Tcl_CreateChannel(&fileChannelType, channelName, - infoPtr, permissions); + (ClientData) infoPtr, permissions); /* * Files have default translation of AUTO and ^Z eof char, which means @@ -1632,7 +1367,7 @@ OpenFileChannel( */ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); - Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\x1A {}"); + Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); return infoPtr->channel; } @@ -1694,11 +1429,11 @@ TclWinFlushDirtyChannels(void) static void FileThreadActionProc( - void *instanceData, + ClientData instanceData, int action) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - FileInfo *infoPtr = (FileInfo *)instanceData; + FileInfo *infoPtr = (FileInfo *) instanceData; if (action == TCL_CHANNEL_THREAD_INSERT) { infoPtr->nextPtr = tsdPtr->firstFilePtr; @@ -1782,13 +1517,13 @@ FileGetType( * * NativeIsComPort -- * - * Determines if a path refers to a Windows serial port. A simple and - * efficient solution is to use a "name hint" to detect COM ports by - * their filename instead of resorting to a syscall to detect serialness - * after the fact. - * + * Determines if a path refers to a Windows serial port. + * A simple and efficient solution is to use a "name hint" to detect + * COM ports by their filename instead of resorting to a syscall + * to detect serialness after the fact. * The following patterns cover common serial port names: - * COM[1-9] + * COM[1-9]:? + * //./COM[0-9]+ * \\.\COM[0-9]+ * * Results: @@ -1799,41 +1534,96 @@ FileGetType( static int NativeIsComPort( - const WCHAR *nativePath) /* Path of file to access, native encoding. */ + const TCHAR *nativePath) /* Path of file to access, native encoding. */ { - const WCHAR *p = (const WCHAR *) nativePath; - size_t i, len = wcslen(p); - /* - * 1. Look for com[1-9]:? + * Use wide-char or plain character case-insensitive comparison */ + if (tclWinProcs->useWide) { + const WCHAR *p = (const WCHAR *) nativePath; + int i, len = wcslen(p); - if ((len == 4) && (_wcsnicmp(p, L"com", 3) == 0)) { /* - * The 4th character must be a digit 1..9 + * 1. Look for com[1-9]:? */ - if ((p[3] < '1') || (p[3] > '9')) { - return 0; + if ( (len >= 4) && (len <= 5) + && (_wcsnicmp(p, L"com", 3) == 0) ) { + /* + * The 4th character must be a digit 1..9 optionally followed by a ":" + */ + + if ( (p[3] < L'1') || (p[3] > L'9') ) { + return 0; + } + if ( (len == 5) && (p[4] != L':') ) { + return 0; + } + return 1; } - return 1; - } - /* - * 2. Look for \\.\com[0-9]+ - */ + /* + * 2. Look for //./com[0-9]+ or \\.\com[0-9]+ + */ + + if ( (len >= 8) && ( + (_wcsnicmp(p, L"//./com", 7) == 0) + || (_wcsnicmp(p, L"\\\\.\\com", 7) == 0) ) ) + { + /* + * Charaters 8..end must be a digits 0..9 + */ + + for ( i=7; i<len; i++ ) { + if ( (p[i] < '0') || (p[i] > '9') ) { + return 0; + } + } + return 1; + } + + } else { + const char *p = (const char *) nativePath; + int i, len = strlen(p); - if ((len >= 8) && (_wcsnicmp(p, L"\\\\.\\com", 7) == 0)) { /* - * Charaters 8..end must be a digits 0..9 + * 1. Look for com[1-9]:? */ - for (i=7; i<len; i++) { - if ((p[i] < '0') || (p[i] > '9')) { + if ( (len >= 4) && (len <= 5) + && (strnicmp(p, "com", 3) == 0) ) { + /* + * The 4th character must be a digit 1..9 optionally followed by a ":" + */ + + if ( (p[3] < '1') || (p[3] > '9') ) { + return 0; + } + if ( (len == 5) && (p[4] != ':') ) { return 0; } + return 1; + } + + /* + * 2. Look for //./com[0-9]+ or \\.\com[0-9]+ + */ + + if ( (len >= 8) && ( + (strnicmp(p, "//./com", 7) == 0) + || (strnicmp(p, "\\\\.\\com", 7) == 0) ) ) + { + /* + * Charaters 8..end must be a digits 0..9 + */ + + for ( i=7; i<len; i++ ) { + if ( (p[i] < '0') || (p[i] > '9') ) { + return 0; + } + } + return 1; } - return 1; } return 0; } |
