📄 tclmacchan.c
字号:
/* * tclMacChan.c * * Channel drivers for Macintosh channels for the * console fds. * * Copyright (c) 1996-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. * * SCCS: @(#) tclMacChan.c 1.43 97/06/20 11:27:48 */#include "tclInt.h"#include "tclPort.h"#include "tclMacInt.h"#include <Aliases.h>#include <Errors.h>#include <Files.h>#include <Gestalt.h>#include <Processes.h>#include <Strings.h>#include <FSpCompat.h>#include <MoreFiles.h>#include <MoreFilesExtras.h>/* * The following variable is used to tell whether this module has been * initialized. */static int initialized = 0;/* * The following are flags returned by GetOpenMode. They * are or'd together to determine how opening and handling * a file should occur. */#define TCL_RDONLY (1<<0)#define TCL_WRONLY (1<<1)#define TCL_RDWR (1<<2)#define TCL_CREAT (1<<3)#define TCL_TRUNC (1<<4)#define TCL_APPEND (1<<5)#define TCL_ALWAYS_APPEND (1<<6)#define TCL_EXCL (1<<7)#define TCL_NOCTTY (1<<8)#define TCL_NONBLOCK (1<<9)#define TCL_RW_MODES (TCL_RDONLY|TCL_WRONLY|TCL_RDWR)/* * This structure describes per-instance state of a * macintosh file based channel. */typedef struct FileState { short fileRef; /* Macintosh file reference number. */ Tcl_Channel fileChan; /* Pointer to the channel for this file. */ int watchMask; /* OR'ed set of flags indicating which events * are being watched. */ int appendMode; /* Flag to tell if in O_APPEND mode or not. */ int volumeRef; /* Flag to tell if in O_APPEND mode or not. */ int pending; /* 1 if message is pending on queue. */ struct FileState *nextPtr; /* Pointer to next registered file. */} FileState;/* * The following pointer refers to the head of the list of files managed * that are being watched for file events. */static FileState *firstFilePtr;/* * The following structure is what is added to the Tcl event queue when * file events are generated. */typedef struct FileEvent { Tcl_Event header; /* Information that is standard for * all events. */ FileState *infoPtr; /* Pointer to file info structure. Note * that we still have to verify that the * file exists before dereferencing this * pointer. */} FileEvent;/* * Static routines for this file: */static int CommonGetHandle _ANSI_ARGS_((ClientData instanceData, int direction, ClientData *handlePtr));static void CommonWatch _ANSI_ARGS_((ClientData instanceData, int mask));static int FileBlockMode _ANSI_ARGS_((ClientData instanceData, int mode));static void FileChannelExitHandler _ANSI_ARGS_(( ClientData clientData));static void FileCheckProc _ANSI_ARGS_((ClientData clientData, int flags));static int FileClose _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static int FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr, int flags));static void FileInit _ANSI_ARGS_((void));static int FileInput _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode));static int FileOutput _ANSI_ARGS_((ClientData instanceData, char *buf, int toWrite, int *errorCode));static int FileSeek _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCode));static void FileSetupProc _ANSI_ARGS_((ClientData clientData, int flags));static int GetOpenMode _ANSI_ARGS_((Tcl_Interp *interp, char *string));static Tcl_Channel OpenFileChannel _ANSI_ARGS_((char *fileName, int mode, int permissions, int *errorCodePtr));static int StdIOBlockMode _ANSI_ARGS_((ClientData instanceData, int mode));static int StdIOClose _ANSI_ARGS_((ClientData instanceData, Tcl_Interp *interp));static int StdIOInput _ANSI_ARGS_((ClientData instanceData, char *buf, int toRead, int *errorCode));static int StdIOOutput _ANSI_ARGS_((ClientData instanceData, char *buf, int toWrite, int *errorCode));static int StdIOSeek _ANSI_ARGS_((ClientData instanceData, long offset, int mode, int *errorCode));static int StdReady _ANSI_ARGS_((ClientData instanceData, int mask));/* * This structure describes the channel type structure for file based IO: */static Tcl_ChannelType consoleChannelType = { "file", /* Type name. */ StdIOBlockMode, /* Set blocking/nonblocking mode.*/ StdIOClose, /* Close proc. */ StdIOInput, /* Input proc. */ StdIOOutput, /* Output proc. */ StdIOSeek, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ CommonWatch, /* Initialize notifier. */ CommonGetHandle /* Get OS handles out of channel. */};/* * This variable describes the channel type structure for file based IO. */static Tcl_ChannelType fileChannelType = { "file", /* Type name. */ FileBlockMode, /* Set blocking or * non-blocking mode.*/ FileClose, /* Close proc. */ FileInput, /* Input proc. */ FileOutput, /* Output proc. */ FileSeek, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ CommonWatch, /* Initialize notifier. */ CommonGetHandle /* Get OS handles out of channel. */};/* * Hack to allow Mac Tk to override the TclGetStdChannels function. */ typedef void (*TclGetStdChannelsProc) _ANSI_ARGS_((Tcl_Channel *stdinPtr, Tcl_Channel *stdoutPtr, Tcl_Channel *stderrPtr)); TclGetStdChannelsProc getStdChannelsProc = NULL;/* * Static variables to hold channels for stdin, stdout and stderr. */static Tcl_Channel stdinChannel = NULL;static Tcl_Channel stdoutChannel = NULL;static Tcl_Channel stderrChannel = NULL;/* *---------------------------------------------------------------------- * * FileInit -- * * This function initializes the file channel event source. * * Results: * None. * * Side effects: * Creates a new event source. * *---------------------------------------------------------------------- */static voidFileInit(){ initialized = 1; firstFilePtr = NULL; Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL); Tcl_CreateExitHandler(FileChannelExitHandler, NULL);}/* *---------------------------------------------------------------------- * * FileChannelExitHandler -- * * This function is called to cleanup the channel driver before * Tcl is unloaded. * * Results: * None. * * Side effects: * Destroys the communication window. * *---------------------------------------------------------------------- */static voidFileChannelExitHandler( ClientData clientData) /* Old window proc */{ Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL); initialized = 0;}/* *---------------------------------------------------------------------- * * FileSetupProc -- * * This procedure is invoked before Tcl_DoOneEvent blocks waiting * for an event. * * Results: * None. * * Side effects: * Adjusts the block time if needed. * *---------------------------------------------------------------------- */voidFileSetupProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */{ FileState *infoPtr; Tcl_Time blockTime = { 0, 0 }; if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Check to see if there is a ready file. If so, poll. */ for (infoPtr = firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask) { Tcl_SetMaxBlockTime(&blockTime); break; } }}/* *---------------------------------------------------------------------- * * FileCheckProc -- * * This procedure is called by Tcl_DoOneEvent to check the file * event source for events. * * Results: * None. * * Side effects: * May queue an event. * *---------------------------------------------------------------------- */static voidFileCheckProc( ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */{ FileEvent *evPtr; FileState *infoPtr; int sentMsg = 0; Tcl_Time blockTime = { 0, 0 }; if (!(flags & TCL_FILE_EVENTS)) { return; } /* * Queue events for any ready files that don't already have events * queued (caused by persistent states that won't generate WinSock * events). */ for (infoPtr = firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (infoPtr->watchMask && !infoPtr->pending) { infoPtr->pending = 1; evPtr = (FileEvent *) ckalloc(sizeof(FileEvent)); evPtr->header.proc = FileEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); } }}/*---------------------------------------------------------------------- * * FileEventProc -- * * This function is invoked by Tcl_ServiceEvent when a file event * reaches the front of the event queue. This procedure invokes * Tcl_NotifyChannel on the file. * * Results: * Returns 1 if the event was handled, meaning it should be removed * from the queue. Returns 0 if the event was not handled, meaning * it should stay on the queue. The only time the event isn't * handled is if the TCL_FILE_EVENTS flag bit isn't set. * * Side effects: * Whatever the notifier callback does. * *---------------------------------------------------------------------- */static intFileEventProc( Tcl_Event *evPtr, /* Event to service. */ int flags) /* Flags that indicate what events to * handle, such as TCL_FILE_EVENTS. */{ FileEvent *fileEvPtr = (FileEvent *)evPtr; FileState *infoPtr; if (!(flags & TCL_FILE_EVENTS)) { return 0; } /* * Search through the list of watched files for the one whose handle * matches the event. We do this rather than simply dereferencing * the handle in the event so that files can be deleted while the * event is in the queue. */ for (infoPtr = firstFilePtr; infoPtr != NULL; infoPtr = infoPtr->nextPtr) { if (fileEvPtr->infoPtr == infoPtr) { infoPtr->pending = 0; Tcl_NotifyChannel(infoPtr->fileChan, infoPtr->watchMask); break; } } return 1;}/* *---------------------------------------------------------------------- * * StdIOBlockMode -- * * Set blocking or non-blocking mode on channel. * * Results: * 0 if successful, errno when failed. * * Side effects: * Sets the device into blocking or non-blocking mode. * *---------------------------------------------------------------------- */static intStdIOBlockMode( ClientData instanceData, /* Unused. */ int mode) /* The mode to set. */{ /* * Do not allow putting stdin, stdout or stderr into nonblocking mode. */ if (mode == TCL_MODE_NONBLOCKING) { return EFAULT; } return 0;}/* *---------------------------------------------------------------------- * * StdIOClose -- * * Closes the IO channel. * * Results: * 0 if successful, the value of errno if failed. * * Side effects: * Closes the physical channel * *---------------------------------------------------------------------- */static intStdIOClose( ClientData instanceData, /* Unused. */ Tcl_Interp *interp) /* Unused. */{ int fd, errorCode = 0; /* * Invalidate the stdio cache if necessary. Note that we assume that * the stdio file and channel pointers will become invalid at the same * time. */ fd = (int) ((FileState*)instanceData)->fileRef; if (fd == 0) { fd = 0; stdinChannel = NULL; } else if (fd == 1) { stdoutChannel = NULL; } else if (fd == 2) { stderrChannel = NULL; } else { panic("recieved invalid std file"); } if (close(fd) < 0) { errorCode = errno; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -