📄 tclwinchan.c
字号:
channel = NULL; switch (type) { case FILE_TYPE_SERIAL: /* * Reopen channel for OVERLAPPED operation * Normally this shouldn't fail, because the channel exists */ handle = TclWinSerialReopen(handle, nativeName, accessMode); if (handle == INVALID_HANDLE_VALUE) { TclWinConvertError(GetLastError()); if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "couldn't reopen serial \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } 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: case FILE_TYPE_DISK: case FILE_TYPE_UNKNOWN: channel = TclWinOpenFileChannel(handle, channelName, channelPermissions, (mode & O_APPEND) ? FILE_APPEND : 0); break; default: /* * The handle is of an unknown type, probably /dev/nul equivalent * or possibly a closed handle. */ channel = NULL; Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), "\": ", "bad file type", (char *) NULL); break; } return channel;}/* *---------------------------------------------------------------------- * * Tcl_MakeFileChannel -- * * Creates a Tcl_Channel from an existing platform specific file * handle. * * Results: * The Tcl_Channel created around the preexisting file. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_MakeFileChannel(rawHandle, mode) ClientData rawHandle; /* OS level handle */ int mode; /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */{ char channelName[16 + TCL_INTEGER_SPACE]; Tcl_Channel channel = NULL; HANDLE handle = (HANDLE) rawHandle; HANDLE dupedHandle; DCB dcb; DWORD consoleParams, type; TclFile readFile = NULL; TclFile writeFile = NULL; BOOL result; if (mode == 0) { return NULL; } /* * GetFileType() returns FILE_TYPE_UNKNOWN for invalid handles. */ type = GetFileType(handle); /* * 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. */ 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; } } } 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_DISK: case FILE_TYPE_CHAR: channel = TclWinOpenFileChannel(handle, channelName, mode, 0); break; case FILE_TYPE_UNKNOWN: default: /* * The handle is of an unknown type. Test the validity of this OS * handle by duplicating it, then closing the dupe. The Win32 API * doesn't provide an IsValidHandle() function, so we have to emulate * it here. This test will not work on a console handle reliably, * which is why we can't test every handle that comes into this * function in this way. */ result = DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), &dupedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); if (result != 0) { /* * Unable to make a duplicate. It's definately invalid at this * point. */ return NULL; } /* * Use structured exception handling (Win32 SEH) to protect the close * of this duped handle which might throw EXCEPTION_INVALID_HANDLE. */#ifdef HAVE_NO_SEH __asm__ __volatile__ ( "movl %esp, _ESP" "\n\t" "movl %ebp, _EBP"); __asm__ __volatile__ ( "pushl $__except_makefilechannel_handler" "\n\t" "pushl %fs:0" "\n\t" "mov %esp, %fs:0"); result = 0;#else __try {#endif /* HAVE_NO_SEH */ CloseHandle(dupedHandle);#ifdef HAVE_NO_SEH __asm__ __volatile__ ( "jmp makefilechannel_pop" "\n" "makefilechannel_reentry:" "\n\t" "movl _ESP, %esp" "\n\t" "movl _EBP, %ebp"); result = 1; /* True when exception was raised */ __asm__ __volatile__ ( "makefilechannel_pop:" "\n\t" "mov (%esp), %eax" "\n\t" "mov %eax, %fs:0" "\n\t" "add $8, %esp"); if (result) return NULL;#else } __except (EXCEPTION_EXECUTE_HANDLER) { /* * Definately an invalid handle. So, therefore, the original * is invalid also. */ return NULL; }#endif /* HAVE_NO_SEH */ /* Fall through, the handle is valid. */ /* * Create the undefined channel, anyways, because we know the handle * is valid to something. */ channel = TclWinOpenFileChannel(handle, channelName, mode, 0); } return channel;}#ifdef HAVE_NO_SEHstatic__attribute__ ((cdecl)) __attribute__ ((used))EXCEPTION_DISPOSITION_except_makefilechannel_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void *EstablisherFrame, struct _CONTEXT *ContextRecord, void *DispatcherContext){ __asm__ __volatile__ ( "jmp makefilechannel_reentry"); return 0; /* Function does not return */}#endif/* *---------------------------------------------------------------------- * * TclpGetDefaultStdChannel -- * * Constructs a channel for the specified standard OS handle. * * Results: * Returns the specified default standard channel, or NULL. * * Side effects: * May cause the creation of a standard channel and the underlying * file. * *---------------------------------------------------------------------- */Tcl_ChannelTclpGetDefaultStdChannel(type) int type; /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */{ Tcl_Channel channel; HANDLE handle; int mode; char *bufMode; DWORD handleId; /* Standard handle to retrieve. */ switch (type) { case TCL_STDIN: handleId = STD_INPUT_HANDLE; mode = TCL_READABLE; bufMode = "line"; break; case TCL_STDOUT: handleId = STD_OUTPUT_HANDLE; mode = TCL_WRITABLE; bufMode = "line"; break; case TCL_STDERR: handleId = STD_ERROR_HANDLE; mode = TCL_WRITABLE; bufMode = "none"; break; default: panic("TclGetDefaultStdChannel: Unexpected channel type"); break; } handle = GetStdHandle(handleId); /* * Note that we need to check for 0 because Windows may return 0 if this * is not a console mode application, even though this is not a valid * handle. */ if ((handle == INVALID_HANDLE_VALUE) || (handle == 0)) { return (Tcl_Channel) NULL; } channel = Tcl_MakeFileChannel(handle, mode); if (channel == NULL) { return (Tcl_Channel) NULL; } /* * Set up the normal channel options for stdio handles. */ if ((Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-translation", "auto") == TCL_ERROR) || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-eofchar", "\032 {}") == TCL_ERROR) || (Tcl_SetChannelOption((Tcl_Interp *) NULL, channel, "-buffering", bufMode) == TCL_ERROR)) { Tcl_Close((Tcl_Interp *) NULL, channel); return (Tcl_Channel) NULL; } 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_ChannelTclWinOpenFileChannel(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; infoPtr->dirty = 0; 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;}/* *---------------------------------------------------------------------- * * TclWinFlushDirtyChannels -- * * Flush all dirty channels to disk, so that requesting the * size of any file returns the correct value. * * Results: * None. * * Side effects: * Information is actually written to disk now, rather than * later. Don't call this too often, or there will be a * performance hit (i.e. only call when we need to ask for * the size of a file). * *---------------------------------------------------------------------- */voidTclWinFlushDirtyChannels (){ FileInfo *infoPtr; ThreadSpecificData *tsdPtr; tsdPtr = FileInit(); /* * Flush all channels which are dirty, i.e. may have data pending * in the OS */ for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->dirty) { FlushFileBuffers(infoPtr->handle); infoPtr->dirty = 0; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -