📄 tclwinchan.c
字号:
*/static intFileSeekProc(instanceData, offset, mode, errorCodePtr) 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; DWORD moveMethod; DWORD newPos, newPosHigh; DWORD oldPos, oldPosHigh; *errorCodePtr = 0; if (mode == SEEK_SET) { moveMethod = FILE_BEGIN; } else if (mode == SEEK_CUR) { moveMethod = FILE_CURRENT; } else { moveMethod = FILE_END; } /* * Save our current place in case we need to roll-back the seek. */ oldPosHigh = (DWORD)0; oldPos = SetFilePointer(infoPtr->handle, (LONG)0, &oldPosHigh, FILE_CURRENT); if (oldPos == INVALID_SET_FILE_POINTER) { int winError = GetLastError(); if (winError != NO_ERROR) { TclWinConvertError(winError); *errorCodePtr = errno; return -1; } } newPosHigh = (DWORD)(offset < 0 ? -1 : 0); newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh, moveMethod); if (newPos == INVALID_SET_FILE_POINTER) { int winError = GetLastError(); if (winError != NO_ERROR) { TclWinConvertError(winError); *errorCodePtr = errno; return -1; } } /* * Check for expressability in our return type, and roll-back otherwise. */ if (newPosHigh != 0) { *errorCodePtr = EOVERFLOW; SetFilePointer(infoPtr->handle, (LONG)oldPos, &oldPosHigh, FILE_BEGIN); return -1; } return (int) newPos;}/* *---------------------------------------------------------------------- * * FileWideSeekProc -- * * Seeks on a file-based channel. Returns the new position. * * Results: * -1 if failed, the new position if successful. If failed, it * also sets *errorCodePtr to the error code. * * Side effects: * Moves the location at which the channel will be accessed in * future operations. * *---------------------------------------------------------------------- */static Tcl_WideIntFileWideSeekProc(instanceData, offset, mode, errorCodePtr) 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; DWORD moveMethod; DWORD newPos, newPosHigh; *errorCodePtr = 0; if (mode == SEEK_SET) { moveMethod = FILE_BEGIN; } else if (mode == SEEK_CUR) { moveMethod = FILE_CURRENT; } else { moveMethod = FILE_END; } newPosHigh = (DWORD)(offset >> 32); newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh, moveMethod); if (newPos == INVALID_SET_FILE_POINTER) { int winError = GetLastError(); if (winError != NO_ERROR) { TclWinConvertError(winError); *errorCodePtr = errno; return -1; } } return ((Tcl_WideInt) newPos) | (((Tcl_WideInt) newPosHigh) << 32);}/* *---------------------------------------------------------------------- * * FileInputProc -- * * Reads input from the IO channel into the buffer given. Returns * count of how many bytes were actually read, and an error indication. * * Results: * A count of how many bytes were read is returned and an error * indication is returned in an output argument. * * Side effects: * Reads input from the actual channel. * *---------------------------------------------------------------------- */static intFileInputProc(instanceData, buf, bufSize, errorCode) ClientData instanceData; /* File state. */ char *buf; /* Where to store data read. */ int bufSize; /* How much space is available * in the buffer? */ int *errorCode; /* Where to store error code. */{ FileInfo *infoPtr; DWORD bytesRead; *errorCode = 0; infoPtr = (FileInfo *) instanceData; /* * 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 for now, we just block. The same * problem exists for files being read over the network. */ if (ReadFile(infoPtr->handle, (LPVOID) buf, (DWORD) bufSize, &bytesRead, (LPOVERLAPPED) NULL) != FALSE) { return bytesRead; } TclWinConvertError(GetLastError()); *errorCode = errno; if (errno == EPIPE) { return 0; } return -1;}/* *---------------------------------------------------------------------- * * FileOutputProc -- * * Writes the given output on the IO channel. Returns count of how * many characters were actually written, and an error indication. * * Results: * A count of how many characters were written is returned and an * error indication is returned in an output argument. * * Side effects: * Writes output on the actual channel. * *---------------------------------------------------------------------- */static intFileOutputProc(instanceData, buf, toWrite, errorCode) 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; DWORD bytesWritten; *errorCode = 0; /* * If we are writing to a file that was opened with O_APPEND, we need to * seek to the end of the file before writing the current buffer. */ if (infoPtr->flags & FILE_APPEND) { SetFilePointer(infoPtr->handle, 0, NULL, FILE_END); } if (WriteFile(infoPtr->handle, (LPVOID) buf, (DWORD) toWrite, &bytesWritten, (LPOVERLAPPED) NULL) == FALSE) { TclWinConvertError(GetLastError()); *errorCode = errno; return -1; } infoPtr->dirty = 1; return bytesWritten;}/* *---------------------------------------------------------------------- * * FileWatchProc -- * * Called by the notifier to set up to watch for events on this * channel. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */static voidFileWatchProc(instanceData, mask) 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; Tcl_Time blockTime = { 0, 0 }; /* * Since the file is always ready for events, we set the block time * to zero so we will poll. */ infoPtr->watchMask = mask & infoPtr->validMask; if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); }}/* *---------------------------------------------------------------------- * * FileGetHandleProc -- * * Called from Tcl_GetChannelHandle to retrieve OS handles from * a file based channel. * * Results: * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if * there is no handle for the specified direction. * * Side effects: * None. * *---------------------------------------------------------------------- */static intFileGetHandleProc(instanceData, direction, handlePtr) ClientData instanceData; /* The file state. */ int direction; /* TCL_READABLE or TCL_WRITABLE */ ClientData *handlePtr; /* Where to store the handle. */{ FileInfo *infoPtr = (FileInfo *) instanceData; if (direction & infoPtr->validMask) { *handlePtr = (ClientData) infoPtr->handle; return TCL_OK; } else { return TCL_ERROR; }}/* *---------------------------------------------------------------------- * * TclpOpenFileChannel -- * * Open an File based channel on Unix systems. * * Results: * The new channel or NULL. If NULL, the output argument * errorCodePtr is set to a POSIX error. * * Side effects: * May open the channel and may cause creation of a file on the * file system. * *---------------------------------------------------------------------- */Tcl_ChannelTclpOpenFileChannel(interp, pathPtr, mode, permissions) Tcl_Interp *interp; /* Interpreter for error reporting; * can be NULL. */ Tcl_Obj *pathPtr; /* Name of file to open. */ int mode; /* POSIX mode. */ int permissions; /* If the open involves creating a * file, with what modes to create * it? */{ Tcl_Channel channel = 0; int channelPermissions; DWORD accessMode, createMode, shareMode, flags, consoleParams, type; CONST TCHAR *nativeName; DCB dcb; HANDLE handle; char channelName[16 + TCL_INTEGER_SPACE]; TclFile readFile = NULL; TclFile writeFile = NULL; nativeName = (TCHAR*) Tcl_FSGetNativePath(pathPtr); if (nativeName == NULL) { return NULL; } switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) { case O_RDONLY: accessMode = GENERIC_READ; channelPermissions = TCL_READABLE; break; case O_WRONLY: accessMode = GENERIC_WRITE; channelPermissions = TCL_WRITABLE; break; case O_RDWR: accessMode = (GENERIC_READ | GENERIC_WRITE); channelPermissions = (TCL_READABLE | TCL_WRITABLE); break; default: panic("TclpOpenFileChannel: invalid mode value"); break; } /* * Map the creation flags to the NT create mode. */ switch (mode & (O_CREAT | O_EXCL | O_TRUNC)) { case (O_CREAT | O_EXCL): case (O_CREAT | O_EXCL | O_TRUNC): createMode = CREATE_NEW; break; case (O_CREAT | O_TRUNC): createMode = CREATE_ALWAYS; break; case O_CREAT: createMode = OPEN_ALWAYS; break; case O_TRUNC: case (O_TRUNC | O_EXCL): createMode = TRUNCATE_EXISTING; break; default: createMode = OPEN_EXISTING; break; } /* * If the file is being created, get the file attributes from the * permissions argument, else use the existing file attributes. */ if (mode & O_CREAT) { if (permissions & S_IWRITE) { flags = FILE_ATTRIBUTE_NORMAL; } else { flags = FILE_ATTRIBUTE_READONLY; } } else { flags = (*tclWinProcs->getFileAttributesProc)(nativeName); if (flags == 0xFFFFFFFF) { flags = 0; } } /* * Set up the file sharing mode. We want to allow simultaneous access. */ shareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; /* * Now we get to create the file. */ handle = (*tclWinProcs->createFileProc)(nativeName, accessMode, shareMode, NULL, createMode, flags, (HANDLE) NULL); if (handle == INVALID_HANDLE_VALUE) { DWORD err; err = GetLastError(); if ((err & 0xffffL) == ERROR_OPEN_FAILED) { err = (mode & O_CREAT) ? ERROR_FILE_EXISTS : ERROR_FILE_NOT_FOUND; } TclWinConvertError(err); if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "couldn't open \"", Tcl_GetString(pathPtr), "\": ", Tcl_PosixError(interp), (char *) NULL); } return NULL; } 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; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -