diff options
Diffstat (limited to 'mac/tclMacChan.c')
| -rw-r--r-- | mac/tclMacChan.c | 1394 | 
1 files changed, 0 insertions, 1394 deletions
| diff --git a/mac/tclMacChan.c b/mac/tclMacChan.c deleted file mode 100644 index 2fbac8f..0000000 --- a/mac/tclMacChan.c +++ /dev/null @@ -1,1394 +0,0 @@ -/*  - * 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. - * - * RCS: @(#) $Id: tclMacChan.c,v 1.6 1999/04/16 00:47:19 stanton Exp $ - */ - -#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 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; - -typedef struct ThreadSpecificData { -    int initialized;		/* True after the thread initializes */ -    FileState *firstFilePtr;	/* the head of the list of files managed -				 * that are being watched for file events. */ -    Tcl_Channel stdinChannel; -    Tcl_Channel stdoutChannel;	/* Note - these seem unused */ -    Tcl_Channel stderrChannel; -} ThreadSpecificData; - -static Tcl_ThreadDataKey dataKey; - -/* - * 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 ThreadSpecificData *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, -        		    CONST char *string)); -static Tcl_Channel	OpenFileChannel _ANSI_ARGS_((CONST 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; - - -/* - *---------------------------------------------------------------------- - * - * FileInit -- - * - *	This function initializes the file channel event source. - * - * Results: - *	None. - * - * Side effects: - *	Creates a new event source. - * - *---------------------------------------------------------------------- - */ - -static ThreadSpecificData * -FileInit() -{ -    ThreadSpecificData *tsdPtr = -	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey); -    if (tsdPtr == NULL) { -	tsdPtr = TCL_TSD_INIT(&dataKey); -	tsdPtr->firstFilePtr = NULL; -	Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL); -	Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL); -    } -    return tsdPtr; -} - -/* - *---------------------------------------------------------------------- - * - * FileChannelExitHandler -- - * - *	This function is called to cleanup the channel driver before - *	Tcl is unloaded. - * - * Results: - *	None. - * - * Side effects: - *	Destroys the communication window. - * - *---------------------------------------------------------------------- - */ - -static void -FileChannelExitHandler( -    ClientData clientData)	/* Old window proc */ -{ -    Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL); -} - -/* - *---------------------------------------------------------------------- - * - * FileSetupProc -- - * - *	This procedure is invoked before Tcl_DoOneEvent blocks waiting - *	for an event. - * - * Results: - *	None. - * - * Side effects: - *	Adjusts the block time if needed. - * - *---------------------------------------------------------------------- - */ - -void -FileSetupProc( -    ClientData data,		/* Not used. */ -    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */ -{ -    FileState *infoPtr; -    Tcl_Time blockTime = { 0, 0 }; -    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - -    if (!(flags & TCL_FILE_EVENTS)) { -	return; -    } -     -    /* -     * Check to see if there is a ready file.  If so, poll. -     */ - -    for (infoPtr = tsdPtr->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 void -FileCheckProc( -    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 }; -    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - -    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 = tsdPtr->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 int -FileEventProc( -    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; -    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - -    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 = tsdPtr->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 int -StdIOBlockMode( -    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 int -StdIOClose( -    ClientData instanceData,	/* Unused. */ -    Tcl_Interp *interp)		/* Unused. */ -{ -    int fd, errorCode = 0; -    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - -    /* -     * Invalidate the stdio cache if necessary.  Note that we assume that -     * the stdio file and channel pointers will become invalid at the same -     * time. -     * Do not close standard channels while in thread-exit. -     */ - -    fd = (int) ((FileState*)instanceData)->fileRef; -    if (!TclInExit()) { -	if (fd == 0) { -	    tsdPtr->stdinChannel = NULL; -	} else if (fd == 1) { -	    tsdPtr->stdoutChannel = NULL; -	} else if (fd == 2) { -	    tsdPtr->stderrChannel = NULL; -	} else { -	    panic("recieved invalid std file"); -	} -     -	if (close(fd) < 0) { -	    errorCode = errno; -	} -    } -    return errorCode; -} - -/* - *---------------------------------------------------------------------- - * - * CommonGetHandle -- - * - *	Called from Tcl_GetChannelHandle to retrieve OS handles from inside - *	a file based channel. - * - * Results: - *	The appropriate handle or NULL if not present.  - * - * Side effects: - *	None. - * - *---------------------------------------------------------------------- - */ - -static int -CommonGetHandle( -    ClientData instanceData,		/* The file state. */ -    int direction,			/* Which handle to retrieve? */ -    ClientData *handlePtr) -{ -    if ((direction == TCL_READABLE) || (direction == TCL_WRITABLE)) { -	*handlePtr = (ClientData) ((FileState*)instanceData)->fileRef; -	return TCL_OK; -    } -    return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * StdIOInput -- - * - *	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. - * - *---------------------------------------------------------------------- - */ - -int -StdIOInput( -    ClientData instanceData,		/* Unused. */ -    char *buf,				/* Where to store data read. */ -    int bufSize,			/* How much space is available -                                         * in the buffer? */ -    int *errorCode)			/* Where to store error code. */ -{ -    int fd; -    int bytesRead;			/* How many bytes were read? */ - -    *errorCode = 0; -    errno = 0; -    fd = (int) ((FileState*)instanceData)->fileRef; -    bytesRead = read(fd, buf, (size_t) bufSize); -    if (bytesRead > -1) { -        return bytesRead; -    } -    *errorCode = errno; -    return -1; -} - -/* - *---------------------------------------------------------------------- - * - * StdIOOutput-- - * - *	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 int -StdIOOutput( -    ClientData instanceData,		/* Unused. */ -    char *buf,				/* The data buffer. */ -    int toWrite,			/* How many bytes to write? */ -    int *errorCode)			/* Where to store error code. */ -{ -    int written; -    int fd; - -    *errorCode = 0; -    errno = 0; -    fd = (int) ((FileState*)instanceData)->fileRef; -    written = write(fd, buf, (size_t) toWrite); -    if (written > -1) { -        return written; -    } -    *errorCode = errno; -    return -1; -} - -/* - *---------------------------------------------------------------------- - * - * StdIOSeek -- - * - *	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 int -StdIOSeek( -    ClientData instanceData,			/* Unused. */ -    long offset,				/* Offset to seek to. */ -    int mode,					/* Relative to where -                                                 * should we seek? */ -    int *errorCodePtr)				/* To store error code. */ -{ -    int newLoc; -    int fd; - -    *errorCodePtr = 0; -    fd = (int) ((FileState*)instanceData)->fileRef; -    newLoc = lseek(fd, offset, mode); -    if (newLoc > -1) { -        return newLoc; -    } -    *errorCodePtr = errno; -    return -1; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_PidObjCmd -- - * - *      This procedure is invoked to process the "pid" Tcl command. - *      See the user documentation for details on what it does. - * - * Results: - *      A standard Tcl result. - * - * Side effects: - *      See the user documentation. - * - *---------------------------------------------------------------------- - */ - -        /* ARGSUSED */ -int -Tcl_PidObjCmd(dummy, interp, objc, objv) -    ClientData dummy;           /* Not used. */ -    Tcl_Interp *interp;         /* Current interpreter. */ -    int objc;                   /* Number of arguments. */ -    Tcl_Obj *CONST *objv;       /* Argument strings. */ -{ -    ProcessSerialNumber psn; -    char buf[20];  -    Tcl_Channel chan; -    Tcl_Obj *resultPtr; - -    if (objc > 2) { -        Tcl_WrongNumArgs(interp, 1, objv, "?channelId?"); -        return TCL_ERROR; -    } -    if (objc == 1) { -        resultPtr = Tcl_GetObjResult(interp); -	GetCurrentProcess(&psn); -	sprintf(buf, "0x%08x%08x", psn.highLongOfPSN, psn.lowLongOfPSN); -        Tcl_SetStringObj(resultPtr, buf, -1); -    } else { -        chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), -                NULL); -        if (chan == (Tcl_Channel) NULL) { -            return TCL_ERROR; -        }  -	/* -	 * We can't create pipelines on the Mac so -	 * this will always return an empty list. -	 */ -    } -     -    return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * 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_Channel -TclpGetDefaultStdChannel( -    int type)			/* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */ -{ -    Tcl_Channel channel = NULL; -    int fd = 0;			/* Initializations needed to prevent */ -    int mode = 0;		/* compiler warning (used before set). */ -    char *bufMode = NULL; -    char channelName[16 + TCL_INTEGER_SPACE]; -    int channelPermissions; -    FileState *fileState; - -    /* -     * If the channels were not created yet, create them now and -     * store them in the static variables. -     */ - -    switch (type) { -	case TCL_STDIN: -	    fd = 0; -	    channelPermissions = TCL_READABLE; -	    bufMode = "line"; -	    break; -	case TCL_STDOUT: -	    fd = 1; -	    channelPermissions = TCL_WRITABLE; -	    bufMode = "line"; -	    break; -	case TCL_STDERR: -	    fd = 2; -	    channelPermissions = TCL_WRITABLE; -	    bufMode = "none"; -	    break; -	default: -	    panic("TclGetDefaultStdChannel: Unexpected channel type"); -	    break; -    } - -    sprintf(channelName, "console%d", (int) fd); -    fileState = (FileState *) ckalloc((unsigned) sizeof(FileState)); -    channel = Tcl_CreateChannel(&consoleChannelType, channelName, -	    (ClientData) fileState, channelPermissions); -    fileState->fileChan = channel; -    fileState->fileRef = fd; - -    /* -     * Set up the normal channel options for stdio handles. -     */ - -    Tcl_SetChannelOption(NULL, channel, "-translation", "cr"); -    Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode); -     -    return channel; -} - -/* - *---------------------------------------------------------------------- - * - * 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_Channel -TclpOpenFileChannel( -    Tcl_Interp *interp,			/* Interpreter for error reporting; -                                         * can be NULL. */ -    char *fileName,			/* Name of file to open. */ -    char *modeString,			/* A list of POSIX open modes or -                                         * a string such as "rw". */ -    int permissions)			/* If the open involves creating a -                                         * file, with what modes to create -                                         * it? */ -{ -    Tcl_Channel chan; -    int mode; -    char *native; -    Tcl_DString ds, buffer; -    int errorCode; -     -    mode = GetOpenMode(interp, modeString); -    if (mode == -1) { -	return NULL; -    } - -    if (Tcl_TranslateFileName(interp, fileName, &buffer) == NULL) { -	return NULL; -    } -    native = Tcl_UtfToExternalDString(NULL, Tcl_DStringValue(&buffer),  -    	    Tcl_DStringLength(&buffer), &ds); -    chan = OpenFileChannel(native, mode, permissions, &errorCode); -    Tcl_DStringFree(&ds); -    Tcl_DStringFree(&buffer); - -    if (chan == NULL) { -	Tcl_SetErrno(errorCode); -	if (interp != (Tcl_Interp *) NULL) { -            Tcl_AppendResult(interp, "couldn't open \"", fileName, "\": ", -                    Tcl_PosixError(interp), (char *) NULL); -        } -	return NULL; -    } -     -    return chan; -} - -/* - *---------------------------------------------------------------------- - * - * OpenFileChannel-- - * - *	Opens a Macintosh file and creates a Tcl channel to control it. - * - * Results: - *	A Tcl channel. - * - * Side effects: - *	Will open a Macintosh file. - * - *---------------------------------------------------------------------- - */ - -static Tcl_Channel -OpenFileChannel( -    CONST char *fileName,		/* Name of file to open (native). */ -    int mode,				/* Mode for opening file. */ -    int permissions,			/* If the open involves creating a -                                         * file, with what modes to create -                                         * it? */ -    int *errorCodePtr)			/* Where to store error code. */ -{ -    int channelPermissions; -    Tcl_Channel chan; -    char macPermision; -    FSSpec fileSpec; -    OSErr err; -    short fileRef; -    FileState *fileState; -    char channelName[16 + TCL_INTEGER_SPACE]; -     -    /* -     * Note we use fsRdWrShPerm instead of fsRdWrPerm which allows shared -     * writes on a file.  This isn't common on a mac but is common with  -     * Windows and UNIX and the feature is used by Tcl. -     */ - -    switch (mode & (TCL_RDONLY | TCL_WRONLY | TCL_RDWR)) { -	case TCL_RDWR: -	    channelPermissions = (TCL_READABLE | TCL_WRITABLE); -	    macPermision = fsRdWrShPerm; -	    break; -	case TCL_WRONLY: -	    /* -	     * Mac's fsRdPerm permission actually defaults to fsRdWrPerm because -	     * the Mac OS doesn't realy support write only access.  We explicitly -	     * set the permission fsRdWrShPerm so that we can have shared write -	     * access. -	     */ -	    channelPermissions = TCL_WRITABLE; -	    macPermision = fsRdWrShPerm; -	    break; -	case TCL_RDONLY: -	default: -	    channelPermissions = TCL_READABLE; -	    macPermision = fsRdPerm; -	    break; -    } -      -    err = FSpLocationFromPath(strlen(fileName), fileName, &fileSpec); -    if ((err != noErr) && (err != fnfErr)) { -	*errorCodePtr = errno = TclMacOSErrorToPosixError(err); -	Tcl_SetErrno(errno); -	return NULL; -    } - -    if ((err == fnfErr) && (mode & TCL_CREAT)) { -	err = HCreate(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, 'MPW ', 'TEXT'); -	if (err != noErr) { -	    *errorCodePtr = errno = TclMacOSErrorToPosixError(err); -	    Tcl_SetErrno(errno); -	    return NULL; -	} -    } else if ((mode & TCL_CREAT) && (mode & TCL_EXCL)) { -        *errorCodePtr = errno = EEXIST; -	Tcl_SetErrno(errno); -        return NULL; -    } - -    err = HOpenDF(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, macPermision, &fileRef); -    if (err != noErr) { -	*errorCodePtr = errno = TclMacOSErrorToPosixError(err); -	Tcl_SetErrno(errno); -	return NULL; -    } - -    if (mode & TCL_TRUNC) { -	SetEOF(fileRef, 0); -    } -     -    sprintf(channelName, "file%d", (int) fileRef); -    fileState = (FileState *) ckalloc((unsigned) sizeof(FileState)); -    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->volumeRef = fileSpec.vRefNum; -    fileState->fileRef = fileRef; -    fileState->pending = 0; -    fileState->watchMask = 0; -    if (mode & TCL_ALWAYS_APPEND) { -	fileState->appendMode = true; -    } else { -	fileState->appendMode = false; -    } -         -    if ((mode & TCL_ALWAYS_APPEND) || (mode & TCL_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_Channel -Tcl_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 int -FileBlockMode( -    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 int -FileClose( -    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. - * - *---------------------------------------------------------------------- - */ - -int -FileInput( -    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 int -FileOutput( -    ClientData instanceData,		/* Unused. */ -    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 int -FileSeek( -    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 void -CommonWatch( -    ClientData instanceData,		/* The file state. */ -    int mask)				/* Events of interest; an OR-ed -                                         * combination of TCL_READABLE, -                                         * TCL_WRITABLE and TCL_EXCEPTION. */ -{ -    FileState **nextPtrPtr, *ptr; -    FileState *infoPtr = (FileState *) instanceData; -    int oldMask = infoPtr->watchMask; -    ThreadSpecificData *tsdPtr; - -    tsdPtr = FileInit(); - -    infoPtr->watchMask = mask; -    if (infoPtr->watchMask) { -	if (!oldMask) { -	    infoPtr->nextPtr = tsdPtr->firstFilePtr; -	    tsdPtr->firstFilePtr = infoPtr; -	} -    } else { -	if (oldMask) { -	    /* -	     * Remove the file from the list of watched files. -	     */ - -	    for (nextPtrPtr = &(tsdPtr->firstFilePtr), ptr = *nextPtrPtr; -		 ptr != NULL; -		 nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) { -		if (infoPtr == ptr) { -		    *nextPtrPtr = ptr->nextPtr; -		    break; -		} -	    } -	} -    } -} - -/* - *---------------------------------------------------------------------- - * - * GetOpenMode -- - * - * Description: - *	Computes a POSIX mode mask from a given string and also sets - *	a flag to indicate whether the caller should seek to EOF during - *	opening of the file. - * - * Results: - *	On success, returns mode to pass to "open". If an error occurs, the - *	returns -1 and if interp is not NULL, sets the interp's result to an - *	error message. - * - * Side effects: - *	Sets the integer referenced by seekFlagPtr to 1 if the caller - *	should seek to EOF during opening the file. - * - * Special note: - *	This code is based on a prototype implementation contributed - *	by Mark Diekhans. - * - *---------------------------------------------------------------------- - */ - -static int -GetOpenMode( -    Tcl_Interp *interp,			/* Interpreter to use for error -					 * reporting - may be NULL. */ -    CONST char *string)			/* Mode string, e.g. "r+" or -					 * "RDONLY CREAT". */ -{ -    int mode, modeArgc, c, i, gotRW; -    char **modeArgv, *flag; - -    /* -     * Check for the simpler fopen-like access modes (e.g. "r").  They -     * are distinguished from the POSIX access modes by the presence -     * of a lower-case first letter. -     */ - -    mode = 0; -    /* -     * Guard against international characters before using byte oriented -     * routines. -     */ - -    if (!(string[0] & 0x80) -	    && islower(UCHAR(string[0]))) { /* INTL: ISO only. */ -	switch (string[0]) { -	    case 'r': -		mode = TCL_RDONLY; -		break; -	    case 'w': -		mode = TCL_WRONLY|TCL_CREAT|TCL_TRUNC; -		break; -	    case 'a': -		mode = TCL_WRONLY|TCL_CREAT|TCL_APPEND; -		break; -	    default: -		error: -                if (interp != (Tcl_Interp *) NULL) { -                    Tcl_AppendResult(interp, -                            "illegal access mode \"", string, "\"", -                            (char *) NULL); -                } -		return -1; -	} -	if (string[1] == '+') { -	    mode &= ~(TCL_RDONLY|TCL_WRONLY); -	    mode |= TCL_RDWR; -	    if (string[2] != 0) { -		goto error; -	    } -	} else if (string[1] != 0) { -	    goto error; -	} -        return mode; -    } - -    /* -     * The access modes are specified using a list of POSIX modes -     * such as TCL_CREAT. -     */ - -    if (Tcl_SplitList(interp, string, &modeArgc, &modeArgv) != TCL_OK) { -        if (interp != (Tcl_Interp *) NULL) { -            Tcl_AddErrorInfo(interp, -                    "\n    while processing open access modes \""); -            Tcl_AddErrorInfo(interp, string); -            Tcl_AddErrorInfo(interp, "\""); -        } -        return -1; -    } -     -    gotRW = 0; -    for (i = 0; i < modeArgc; i++) { -	flag = modeArgv[i]; -	c = flag[0]; -	if ((c == 'R') && (strcmp(flag, "RDONLY") == 0)) { -	    mode = (mode & ~TCL_RW_MODES) | TCL_RDONLY; -	    gotRW = 1; -	} else if ((c == 'W') && (strcmp(flag, "WRONLY") == 0)) { -	    mode = (mode & ~TCL_RW_MODES) | TCL_WRONLY; -	    gotRW = 1; -	} else if ((c == 'R') && (strcmp(flag, "RDWR") == 0)) { -	    mode = (mode & ~TCL_RW_MODES) | TCL_RDWR; -	    gotRW = 1; -	} else if ((c == 'A') && (strcmp(flag, "APPEND") == 0)) { -	    mode |= TCL_ALWAYS_APPEND; -	} else if ((c == 'C') && (strcmp(flag, "CREAT") == 0)) { -	    mode |= TCL_CREAT; -	} else if ((c == 'E') && (strcmp(flag, "EXCL") == 0)) { -	    mode |= TCL_EXCL; -	} else if ((c == 'N') && (strcmp(flag, "NOCTTY") == 0)) { -	    mode |= TCL_NOCTTY; -	} else if ((c == 'N') && (strcmp(flag, "NONBLOCK") == 0)) { -	    mode |= TCL_NONBLOCK; -	} else if ((c == 'T') && (strcmp(flag, "TRUNC") == 0)) { -	    mode |= TCL_TRUNC; -	} else { -            if (interp != (Tcl_Interp *) NULL) { -                Tcl_AppendResult(interp, "invalid access mode \"", flag, -                        "\": must be RDONLY, WRONLY, RDWR, APPEND, CREAT", -                        " EXCL, NOCTTY, NONBLOCK, or TRUNC", (char *) NULL); -            } -	    ckfree((char *) modeArgv); -	    return -1; -	} -    } -    ckfree((char *) modeArgv); -    if (!gotRW) { -        if (interp != (Tcl_Interp *) NULL) { -            Tcl_AppendResult(interp, "access mode must include either", -                    " RDONLY, WRONLY, or RDWR", (char *) NULL); -        } -	return -1; -    } -    return mode; -} | 
