📄 tclmacchan.c
字号:
chan = Tcl_CreateChannel(&fileChannelType, channelName, (ClientData) fileState, channelPermissions); if (chan == (Tcl_Channel) NULL) { *errorCodePtr = errno = EFAULT; Tcl_SetErrno(errno); FSClose(fileRef); ckfree((char *) fileState); return NULL; } fileState->fileChan = chan; fileState->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = fileState; fileState->volumeRef = fileSpec.vRefNum; fileState->fileRef = fileRef; fileState->pending = 0; fileState->watchMask = 0; if (mode & O_APPEND) { fileState->appendMode = true; } else { fileState->appendMode = false; } if ((mode & O_APPEND) || (mode & O_APPEND)) { if (Tcl_Seek(chan, 0, SEEK_END) < 0) { *errorCodePtr = errno = EFAULT; Tcl_SetErrno(errno); Tcl_Close(NULL, chan); FSClose(fileRef); ckfree((char *) fileState); return NULL; } } return chan;}/* *---------------------------------------------------------------------- * * Tcl_MakeFileChannel -- * * Makes a Tcl_Channel from an existing OS level file handle. * * Results: * The Tcl_Channel created around the preexisting OS level file handle. * * Side effects: * None. * *---------------------------------------------------------------------- */Tcl_ChannelTcl_MakeFileChannel(handle, mode) ClientData handle; /* OS level handle. */ int mode; /* ORed combination of TCL_READABLE and * TCL_WRITABLE to indicate file mode. */{ /* * Not implemented yet. */ return NULL;}/* *---------------------------------------------------------------------- * * FileBlockMode -- * * Set blocking or non-blocking mode on channel. Macintosh files * can never really be set to blocking or non-blocking modes. * However, we don't generate an error - we just return success. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */static intFileBlockMode( ClientData instanceData, /* Unused. */ int mode) /* The mode to set. */{ return 0;}/* *---------------------------------------------------------------------- * * FileClose -- * * Closes the IO channel. * * Results: * 0 if successful, the value of errno if failed. * * Side effects: * Closes the physical channel * *---------------------------------------------------------------------- */static intFileClose( ClientData instanceData, /* Unused. */ Tcl_Interp *interp) /* Unused. */{ FileState *fileState = (FileState *) instanceData; int errorCode = 0; OSErr err; err = FSClose(fileState->fileRef); FlushVol(NULL, fileState->volumeRef); if (err != noErr) { errorCode = errno = TclMacOSErrorToPosixError(err); panic("error during file close"); } ckfree((char *) fileState); Tcl_SetErrno(errorCode); return errorCode;}/* *---------------------------------------------------------------------- * * FileInput -- * * 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. * *---------------------------------------------------------------------- */intFileInput( ClientData instanceData, /* Unused. */ char *buffer, /* Where to store data read. */ int bufSize, /* How much space is available * in the buffer? */ int *errorCodePtr) /* Where to store error code. */{ FileState *fileState = (FileState *) instanceData; OSErr err; long length = bufSize; *errorCodePtr = 0; errno = 0; err = FSRead(fileState->fileRef, &length, buffer); if ((err == noErr) || (err == eofErr)) { return length; } else { switch (err) { case ioErr: *errorCodePtr = errno = EIO; case afpAccessDenied: *errorCodePtr = errno = EACCES; default: *errorCodePtr = errno = EINVAL; } return -1; } *errorCodePtr = errno; return -1;}/* *---------------------------------------------------------------------- * * FileOutput-- * * 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 intFileOutput( ClientData instanceData, /* Unused. */ CONST char *buffer, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCodePtr) /* Where to store error code. */{ FileState *fileState = (FileState *) instanceData; long length = toWrite; OSErr err; *errorCodePtr = 0; errno = 0; if (fileState->appendMode == true) { FileSeek(instanceData, 0, SEEK_END, errorCodePtr); *errorCodePtr = 0; } err = FSWrite(fileState->fileRef, &length, buffer); if (err == noErr) { err = FlushFile(fileState->fileRef); } else { *errorCodePtr = errno = TclMacOSErrorToPosixError(err); return -1; } return length;}/* *---------------------------------------------------------------------- * * FileSeek -- * * Seeks on an IO 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 intFileSeek( ClientData instanceData, /* Unused. */ long offset, /* Offset to seek to. */ int mode, /* Relative to where should we seek? */ int *errorCodePtr) /* To store error code. */{ FileState *fileState = (FileState *) instanceData; IOParam pb; OSErr err; *errorCodePtr = 0; pb.ioCompletion = NULL; pb.ioRefNum = fileState->fileRef; if (mode == SEEK_SET) { pb.ioPosMode = fsFromStart; } else if (mode == SEEK_END) { pb.ioPosMode = fsFromLEOF; } else if (mode == SEEK_CUR) { err = PBGetFPosSync((ParmBlkPtr) &pb); if (pb.ioResult == noErr) { if (offset == 0) { return pb.ioPosOffset; } offset += pb.ioPosOffset; } pb.ioPosMode = fsFromStart; } pb.ioPosOffset = offset; err = PBSetFPosSync((ParmBlkPtr) &pb); if (pb.ioResult == noErr){ return pb.ioPosOffset; } else if (pb.ioResult == eofErr) { long currentEOF, newEOF; long buffer, i, length; err = PBGetEOFSync((ParmBlkPtr) &pb); currentEOF = (long) pb.ioMisc; if (mode == SEEK_SET) { newEOF = offset; } else if (mode == SEEK_END) { newEOF = offset + currentEOF; } else if (mode == SEEK_CUR) { err = PBGetFPosSync((ParmBlkPtr) &pb); newEOF = offset + pb.ioPosOffset; } /* * Write 0's to the new EOF. */ pb.ioPosOffset = 0; pb.ioPosMode = fsFromLEOF; err = PBGetFPosSync((ParmBlkPtr) &pb); length = 1; buffer = 0; for (i = 0; i < (newEOF - currentEOF); i++) { err = FSWrite(fileState->fileRef, &length, &buffer); } err = PBGetFPosSync((ParmBlkPtr) &pb); if (pb.ioResult == noErr){ return pb.ioPosOffset; } } *errorCodePtr = errno = TclMacOSErrorToPosixError(err); return -1;}/* *---------------------------------------------------------------------- * * CommonWatch -- * * Initialize the notifier to watch handles from this channel. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */static voidCommonWatch( ClientData instanceData, /* The file state. */ int mask) /* Events of interest; an OR-ed * combination of TCL_READABLE, * TCL_WRITABLE and TCL_EXCEPTION. */{ FileState *infoPtr = (FileState *) instanceData; Tcl_Time blockTime = { 0, 0 }; infoPtr->watchMask = mask; if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); }}/* *---------------------------------------------------------------------- * * 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; FileState *infoPtr; FileState **nextPtrPtr; int removed = 0; if (chanPtr->typePtr != &fileChannelType) return; infoPtr = (FileState *) 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; FileState *infoPtr; if (chanPtr->typePtr != &fileChannelType) return; infoPtr = (FileState *) chanPtr->instanceData; infoPtr->nextPtr = tsdPtr->firstFilePtr; tsdPtr->firstFilePtr = infoPtr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -