summaryrefslogtreecommitdiffstats
path: root/win/tclWinChan.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinChan.c')
-rw-r--r--win/tclWinChan.c696
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;
}