tclwinchan.c
来自「tcl是工具命令语言」· C语言 代码 · 共 1,431 行 · 第 1/3 页
C
1,431 行
* 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# ifdef TCL_MEM_DEBUG __asm__ __volatile__ ( "movl %%esp, %0" "\n\t" "movl %%ebp, %1" "\n\t" "movl %%fs:0, %2" "\n\t" : "=m"(INITIAL_ESP), "=m"(INITIAL_EBP), "=r"(INITIAL_HANDLER) );# endif /* TCL_MEM_DEBUG */ result = 0; __asm__ __volatile__ ( "pushl %ebp" "\n\t" "pushl $__except_makefilechannel_handler" "\n\t" "pushl %fs:0" "\n\t" "movl %esp, %fs:0");#else __try {#endif /* HAVE_NO_SEH */ CloseHandle(dupedHandle);#ifdef HAVE_NO_SEH __asm__ __volatile__ ( "jmp makefilechannel_pop" "\n" "makefilechannel_reentry:" "\n\t" "movl %%fs:0, %%eax" "\n\t" "movl 0x8(%%eax), %%esp" "\n\t" "movl 0x8(%%esp), %%ebp" "\n" "movl $1, %0" "\n" "makefilechannel_pop:" "\n\t" "movl (%%esp), %%eax" "\n\t" "movl %%eax, %%fs:0" "\n\t" "add $12, %%esp" "\n\t" : "=m"(result) : : "%eax");# ifdef TCL_MEM_DEBUG __asm__ __volatile__ ( "movl %%esp, %0" "\n\t" "movl %%ebp, %1" "\n\t" "movl %%fs:0, %2" "\n\t" : "=m"(RESTORED_ESP), "=m"(RESTORED_EBP), "=r"(RESTORED_HANDLER) ); if (INITIAL_ESP != RESTORED_ESP) panic("ESP restored incorrectly"); if (INITIAL_EBP != RESTORED_EBP) panic("EBP restored incorrectly"); if (INITIAL_HANDLER != RESTORED_HANDLER) panic("HANDLER restored incorrectly");# endif /* TCL_MEM_DEBUG */ 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))EXCEPTION_DISPOSITION_except_makefilechannel_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void *EstablisherFrame, struct _CONTEXT *ContextRecord, void *DispatcherContext){ __asm__ __volatile__ ( "jmp makefilechannel_reentry"); /* Nuke compiler warning about unused static function */ _except_makefilechannel_handler(NULL, NULL, NULL, NULL); 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; } }}/* *---------------------------------------------------------------------- * * TclpCutFileChannel -- * * Remove any thread local refs to this channel. See * Tcl_CutChannel for more info. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */voidTclpCutFileChannel(chan) Tcl_Channel chan; /* The channel being removed. Must * not be referenced in any * interpreter. */{ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Channel *chanPtr = (Channel *) chan; FileInfo *infoPtr; FileInfo **nextPtrPtr; int removed = 0; if (chanPtr->typePtr != &fileChannelType) return; infoPtr = (FileInfo *) chanPtr->instanceData; for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL; nextPtrPtr = &((*nextPtrPtr)->nextPtr)) { if ((*nextPtrPtr) == infoPtr) { (*nextPtrPtr) = infoPtr->nextPtr; removed = 1; break; } } /* * This could happen if the channel was created in one thread * and then moved to another without updating the thread * local data in each thread. */ if (!removed) panic("file info ptr not on thread channel list");}/* *---------------------------------------------------------------------- * * TclpSpliceFileChannel -- * * Insert thread local ref for this channel. * Tcl_SpliceChannel for more info. * * Results: * None. * * Side effects: * Changes thread local list of valid channels. * *---------------------------------------------------------------------- */voidTclpSpliceFileChannel(chan) Tcl_Channel chan; /* The channel being removed. Must * not be referenced in any * interpreter. */{ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); Channel *chanPtr = (Channel *) chan; FileInfo *infoPtr; if (chanPtr->typePtr != &fileChannelType) return; infoPtr = (FileInfo *) chanPtr->instanceData; infoPtr->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = infoPtr;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?