os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacChan.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacChan.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1275 @@
     1.4 +/* 
     1.5 + * tclMacChan.c
     1.6 + *
     1.7 + *	Channel drivers for Macintosh channels for the
     1.8 + *	console fds.
     1.9 + *
    1.10 + * Copyright (c) 1996-1997 Sun Microsystems, Inc.
    1.11 + *
    1.12 + * See the file "license.terms" for information on usage and redistribution
    1.13 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    1.14 + *
    1.15 + * RCS: @(#) $Id: tclMacChan.c,v 1.21.2.1 2005/01/27 22:53:34 andreas_kupries Exp $
    1.16 + */
    1.17 +
    1.18 +#include "tclInt.h"
    1.19 +#include "tclPort.h"
    1.20 +#include "tclMacInt.h"
    1.21 +#include <Aliases.h>
    1.22 +#include <Errors.h>
    1.23 +#include <Files.h>
    1.24 +#include <Gestalt.h>
    1.25 +#include <Processes.h>
    1.26 +#include <Strings.h>
    1.27 +#include <FSpCompat.h>
    1.28 +#include <MoreFiles.h>
    1.29 +#include <MoreFilesExtras.h>
    1.30 +#include "tclIO.h"
    1.31 +
    1.32 +#ifdef __MSL__
    1.33 +#include <unix.mac.h>
    1.34 +#define TCL_FILE_CREATOR (__getcreator(0))
    1.35 +#else
    1.36 +#define TCL_FILE_CREATOR 'MPW '
    1.37 +#endif
    1.38 +
    1.39 +/*
    1.40 + * This structure describes per-instance state of a 
    1.41 + * macintosh file based channel.
    1.42 + */
    1.43 +
    1.44 +typedef struct FileState {
    1.45 +    short fileRef;		/* Macintosh file reference number. */
    1.46 +    Tcl_Channel fileChan;	/* Pointer to the channel for this file. */
    1.47 +    int watchMask;		/* OR'ed set of flags indicating which events
    1.48 +    				 * are being watched. */
    1.49 +    int appendMode;		/* Flag to tell if in O_APPEND mode or not. */
    1.50 +    int volumeRef;		/* Flag to tell if in O_APPEND mode or not. */
    1.51 +    int pending;		/* 1 if message is pending on queue. */
    1.52 +    struct FileState *nextPtr;	/* Pointer to next registered file. */
    1.53 +} FileState;
    1.54 +
    1.55 +typedef struct ThreadSpecificData {
    1.56 +    int initialized;		/* True after the thread initializes */
    1.57 +    FileState *firstFilePtr;	/* the head of the list of files managed
    1.58 +				 * that are being watched for file events. */
    1.59 +    Tcl_Channel stdinChannel;
    1.60 +    Tcl_Channel stdoutChannel;	/* Note - these seem unused */
    1.61 +    Tcl_Channel stderrChannel;
    1.62 +} ThreadSpecificData;
    1.63 +
    1.64 +static Tcl_ThreadDataKey dataKey;
    1.65 +
    1.66 +/*
    1.67 + * The following structure is what is added to the Tcl event queue when
    1.68 + * file events are generated.
    1.69 + */
    1.70 +
    1.71 +typedef struct FileEvent {
    1.72 +    Tcl_Event header;		/* Information that is standard for
    1.73 +				 * all events. */
    1.74 +    FileState *infoPtr;		/* Pointer to file info structure.  Note
    1.75 +				 * that we still have to verify that the
    1.76 +				 * file exists before dereferencing this
    1.77 +				 * pointer. */
    1.78 +} FileEvent;
    1.79 +
    1.80 +
    1.81 +/*
    1.82 + * Static routines for this file:
    1.83 + */
    1.84 +
    1.85 +static int		CommonGetHandle _ANSI_ARGS_((ClientData instanceData,
    1.86 +		            int direction, ClientData *handlePtr));
    1.87 +static void		CommonWatch _ANSI_ARGS_((ClientData instanceData,
    1.88 +		            int mask));
    1.89 +static int		FileBlockMode _ANSI_ARGS_((ClientData instanceData,
    1.90 +			    int mode));
    1.91 +static void		FileChannelExitHandler _ANSI_ARGS_((
    1.92 +		            ClientData clientData));
    1.93 +static void		FileCheckProc _ANSI_ARGS_((ClientData clientData,
    1.94 +			    int flags));
    1.95 +static int		FileClose _ANSI_ARGS_((ClientData instanceData,
    1.96 +			    Tcl_Interp *interp));
    1.97 +static int		FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
    1.98 +			    int flags));
    1.99 +static ThreadSpecificData *FileInit _ANSI_ARGS_((void));
   1.100 +static int		FileInput _ANSI_ARGS_((ClientData instanceData,
   1.101 +			    char *buf, int toRead, int *errorCode));
   1.102 +static int		FileOutput _ANSI_ARGS_((ClientData instanceData,
   1.103 +			    CONST char *buf, int toWrite, int *errorCode));
   1.104 +static int		FileSeek _ANSI_ARGS_((ClientData instanceData,
   1.105 +			    long offset, int mode, int *errorCode));
   1.106 +static void		FileSetupProc _ANSI_ARGS_((ClientData clientData,
   1.107 +			    int flags));
   1.108 +static void             FileThreadActionProc _ANSI_ARGS_ ((
   1.109 +			   ClientData instanceData, int action));
   1.110 +static Tcl_Channel	OpenFileChannel _ANSI_ARGS_((CONST char *fileName, 
   1.111 +			    int mode, int permissions, int *errorCodePtr));
   1.112 +static int		StdIOBlockMode _ANSI_ARGS_((ClientData instanceData,
   1.113 +			    int mode));
   1.114 +static int		StdIOClose _ANSI_ARGS_((ClientData instanceData,
   1.115 +			    Tcl_Interp *interp));
   1.116 +static int		StdIOInput _ANSI_ARGS_((ClientData instanceData,
   1.117 +			    char *buf, int toRead, int *errorCode));
   1.118 +static int		StdIOOutput _ANSI_ARGS_((ClientData instanceData,
   1.119 +			    CONST char *buf, int toWrite, int *errorCode));
   1.120 +static int		StdIOSeek _ANSI_ARGS_((ClientData instanceData,
   1.121 +			    long offset, int mode, int *errorCode));
   1.122 +static int		StdReady _ANSI_ARGS_((ClientData instanceData,
   1.123 +		            int mask));
   1.124 +
   1.125 +/*
   1.126 + * This structure describes the channel type structure for file based IO:
   1.127 + */
   1.128 +
   1.129 +static Tcl_ChannelType consoleChannelType = {
   1.130 +    "file",			/* Type name. */
   1.131 +    TCL_CHANNEL_VERSION_4,	/* v4 channel */
   1.132 +    StdIOClose,			/* Close proc. */
   1.133 +    StdIOInput,			/* Input proc. */
   1.134 +    StdIOOutput,		/* Output proc. */
   1.135 +    StdIOSeek,			/* Seek proc. */
   1.136 +    NULL,			/* Set option proc. */
   1.137 +    NULL,			/* Get option proc. */
   1.138 +    CommonWatch,		/* Initialize notifier. */
   1.139 +    CommonGetHandle		/* Get OS handles out of channel. */
   1.140 +    NULL,			/* close2proc. */
   1.141 +    StdIOBlockMode,		/* Set blocking/nonblocking mode.*/
   1.142 +    NULL,			/* flush proc. */
   1.143 +    NULL,			/* handler proc. */
   1.144 +    NULL,			/* wide seek proc. */
   1.145 +    NULL,		        /* thread actions */
   1.146 +};
   1.147 +
   1.148 +/*
   1.149 + * This variable describes the channel type structure for file based IO.
   1.150 + */
   1.151 +
   1.152 +static Tcl_ChannelType fileChannelType = {
   1.153 +    "file",			/* Type name. */
   1.154 +    TCL_CHANNEL_VERSION_4,	/* v4 channel */
   1.155 +    FileClose,			/* Close proc. */
   1.156 +    FileInput,			/* Input proc. */
   1.157 +    FileOutput,			/* Output proc. */
   1.158 +    FileSeek,			/* Seek proc. */
   1.159 +    NULL,			/* Set option proc. */
   1.160 +    NULL,			/* Get option proc. */
   1.161 +    CommonWatch,		/* Initialize notifier. */
   1.162 +    CommonGetHandle		/* Get OS handles out of channel. */
   1.163 +    NULL,			/* close2proc. */
   1.164 +    FileBlockMode,		/* Set blocking/nonblocking mode.*/
   1.165 +    NULL,			/* flush proc. */
   1.166 +    NULL,			/* handler proc. */
   1.167 +    NULL,			/* wide seek proc. */
   1.168 +    FileThreadActionProc,       /* thread actions */
   1.169 +};
   1.170 +
   1.171 +
   1.172 +/*
   1.173 + * Hack to allow Mac Tk to override the TclGetStdChannels function.
   1.174 + */
   1.175 + 
   1.176 +typedef void (*TclGetStdChannelsProc) _ANSI_ARGS_((Tcl_Channel *stdinPtr,
   1.177 +	Tcl_Channel *stdoutPtr, Tcl_Channel *stderrPtr));
   1.178 +	
   1.179 +TclGetStdChannelsProc getStdChannelsProc = NULL;
   1.180 +
   1.181 +
   1.182 +/*
   1.183 + *----------------------------------------------------------------------
   1.184 + *
   1.185 + * FileInit --
   1.186 + *
   1.187 + *	This function initializes the file channel event source.
   1.188 + *
   1.189 + * Results:
   1.190 + *	None.
   1.191 + *
   1.192 + * Side effects:
   1.193 + *	Creates a new event source.
   1.194 + *
   1.195 + *----------------------------------------------------------------------
   1.196 + */
   1.197 +
   1.198 +static ThreadSpecificData *
   1.199 +FileInit()
   1.200 +{
   1.201 +    ThreadSpecificData *tsdPtr =
   1.202 +	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
   1.203 +    if (tsdPtr == NULL) {
   1.204 +	tsdPtr = TCL_TSD_INIT(&dataKey);
   1.205 +	tsdPtr->firstFilePtr = NULL;
   1.206 +	Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL);
   1.207 +	Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL);
   1.208 +    }
   1.209 +    return tsdPtr;
   1.210 +}
   1.211 +
   1.212 +/*
   1.213 + *----------------------------------------------------------------------
   1.214 + *
   1.215 + * FileChannelExitHandler --
   1.216 + *
   1.217 + *	This function is called to cleanup the channel driver before
   1.218 + *	Tcl is unloaded.
   1.219 + *
   1.220 + * Results:
   1.221 + *	None.
   1.222 + *
   1.223 + * Side effects:
   1.224 + *	Destroys the communication window.
   1.225 + *
   1.226 + *----------------------------------------------------------------------
   1.227 + */
   1.228 +
   1.229 +static void
   1.230 +FileChannelExitHandler(
   1.231 +    ClientData clientData)	/* Old window proc */
   1.232 +{
   1.233 +    Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);
   1.234 +}
   1.235 +
   1.236 +/*
   1.237 + *----------------------------------------------------------------------
   1.238 + *
   1.239 + * FileSetupProc --
   1.240 + *
   1.241 + *	This procedure is invoked before Tcl_DoOneEvent blocks waiting
   1.242 + *	for an event.
   1.243 + *
   1.244 + * Results:
   1.245 + *	None.
   1.246 + *
   1.247 + * Side effects:
   1.248 + *	Adjusts the block time if needed.
   1.249 + *
   1.250 + *----------------------------------------------------------------------
   1.251 + */
   1.252 +
   1.253 +void
   1.254 +FileSetupProc(
   1.255 +    ClientData data,		/* Not used. */
   1.256 +    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
   1.257 +{
   1.258 +    FileState *infoPtr;
   1.259 +    Tcl_Time blockTime = { 0, 0 };
   1.260 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.261 +
   1.262 +    if (!(flags & TCL_FILE_EVENTS)) {
   1.263 +	return;
   1.264 +    }
   1.265 +    
   1.266 +    /*
   1.267 +     * Check to see if there is a ready file.  If so, poll.
   1.268 +     */
   1.269 +
   1.270 +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; 
   1.271 +	    infoPtr = infoPtr->nextPtr) {
   1.272 +	if (infoPtr->watchMask) {
   1.273 +	    Tcl_SetMaxBlockTime(&blockTime);
   1.274 +	    break;
   1.275 +	}
   1.276 +    }
   1.277 +}
   1.278 +
   1.279 +/*
   1.280 + *----------------------------------------------------------------------
   1.281 + *
   1.282 + * FileCheckProc --
   1.283 + *
   1.284 + *	This procedure is called by Tcl_DoOneEvent to check the file
   1.285 + *	event source for events. 
   1.286 + *
   1.287 + * Results:
   1.288 + *	None.
   1.289 + *
   1.290 + * Side effects:
   1.291 + *	May queue an event.
   1.292 + *
   1.293 + *----------------------------------------------------------------------
   1.294 + */
   1.295 +
   1.296 +static void
   1.297 +FileCheckProc(
   1.298 +    ClientData data,		/* Not used. */
   1.299 +    int flags)			/* Event flags as passed to Tcl_DoOneEvent. */
   1.300 +{
   1.301 +    FileEvent *evPtr;
   1.302 +    FileState *infoPtr;
   1.303 +    int sentMsg = 0;
   1.304 +    Tcl_Time blockTime = { 0, 0 };
   1.305 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.306 +
   1.307 +    if (!(flags & TCL_FILE_EVENTS)) {
   1.308 +	return;
   1.309 +    }
   1.310 +    
   1.311 +    /*
   1.312 +     * Queue events for any ready files that don't already have events
   1.313 +     * queued (caused by persistent states that won't generate WinSock
   1.314 +     * events).
   1.315 +     */
   1.316 +
   1.317 +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; 
   1.318 +	    infoPtr = infoPtr->nextPtr) {
   1.319 +	if (infoPtr->watchMask && !infoPtr->pending) {
   1.320 +	    infoPtr->pending = 1;
   1.321 +	    evPtr = (FileEvent *) ckalloc(sizeof(FileEvent));
   1.322 +	    evPtr->header.proc = FileEventProc;
   1.323 +	    evPtr->infoPtr = infoPtr;
   1.324 +	    Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
   1.325 +	}
   1.326 +    }
   1.327 +}
   1.328 +
   1.329 +/*----------------------------------------------------------------------
   1.330 + *
   1.331 + * FileEventProc --
   1.332 + *
   1.333 + *	This function is invoked by Tcl_ServiceEvent when a file event
   1.334 + *	reaches the front of the event queue.  This procedure invokes
   1.335 + *	Tcl_NotifyChannel on the file.
   1.336 + *
   1.337 + * Results:
   1.338 + *	Returns 1 if the event was handled, meaning it should be removed
   1.339 + *	from the queue.  Returns 0 if the event was not handled, meaning
   1.340 + *	it should stay on the queue.  The only time the event isn't
   1.341 + *	handled is if the TCL_FILE_EVENTS flag bit isn't set.
   1.342 + *
   1.343 + * Side effects:
   1.344 + *	Whatever the notifier callback does.
   1.345 + *
   1.346 + *----------------------------------------------------------------------
   1.347 + */
   1.348 +
   1.349 +static int
   1.350 +FileEventProc(
   1.351 +    Tcl_Event *evPtr,		/* Event to service. */
   1.352 +    int flags)			/* Flags that indicate what events to
   1.353 +				 * handle, such as TCL_FILE_EVENTS. */
   1.354 +{
   1.355 +    FileEvent *fileEvPtr = (FileEvent *)evPtr;
   1.356 +    FileState *infoPtr;
   1.357 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.358 +
   1.359 +    if (!(flags & TCL_FILE_EVENTS)) {
   1.360 +	return 0;
   1.361 +    }
   1.362 +
   1.363 +    /*
   1.364 +     * Search through the list of watched files for the one whose handle
   1.365 +     * matches the event.  We do this rather than simply dereferencing
   1.366 +     * the handle in the event so that files can be deleted while the
   1.367 +     * event is in the queue.
   1.368 +     */
   1.369 +
   1.370 +    for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL; 
   1.371 +	    infoPtr = infoPtr->nextPtr) {
   1.372 +	if (fileEvPtr->infoPtr == infoPtr) {
   1.373 +	    infoPtr->pending = 0;
   1.374 +	    Tcl_NotifyChannel(infoPtr->fileChan, infoPtr->watchMask);
   1.375 +	    break;
   1.376 +	}
   1.377 +    }
   1.378 +    return 1;
   1.379 +}
   1.380 +
   1.381 +/*
   1.382 + *----------------------------------------------------------------------
   1.383 + *
   1.384 + * StdIOBlockMode --
   1.385 + *
   1.386 + *	Set blocking or non-blocking mode on channel.
   1.387 + *
   1.388 + * Results:
   1.389 + *	0 if successful, errno when failed.
   1.390 + *
   1.391 + * Side effects:
   1.392 + *	Sets the device into blocking or non-blocking mode.
   1.393 + *
   1.394 + *----------------------------------------------------------------------
   1.395 + */
   1.396 +
   1.397 +static int
   1.398 +StdIOBlockMode(
   1.399 +    ClientData instanceData,		/* Unused. */
   1.400 +    int mode)				/* The mode to set. */
   1.401 +{
   1.402 +    /*
   1.403 +     * Do not allow putting stdin, stdout or stderr into nonblocking mode.
   1.404 +     */
   1.405 +    
   1.406 +    if (mode == TCL_MODE_NONBLOCKING) {
   1.407 +	return EFAULT;
   1.408 +    }
   1.409 +    
   1.410 +    return 0;
   1.411 +}
   1.412 +
   1.413 +/*
   1.414 + *----------------------------------------------------------------------
   1.415 + *
   1.416 + * StdIOClose --
   1.417 + *
   1.418 + *	Closes the IO channel.
   1.419 + *
   1.420 + * Results:
   1.421 + *	0 if successful, the value of errno if failed.
   1.422 + *
   1.423 + * Side effects:
   1.424 + *	Closes the physical channel
   1.425 + *
   1.426 + *----------------------------------------------------------------------
   1.427 + */
   1.428 +
   1.429 +static int
   1.430 +StdIOClose(
   1.431 +    ClientData instanceData,	/* Unused. */
   1.432 +    Tcl_Interp *interp)		/* Unused. */
   1.433 +{
   1.434 +    int fd, errorCode = 0;
   1.435 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
   1.436 +
   1.437 +    /*
   1.438 +     * Invalidate the stdio cache if necessary.  Note that we assume that
   1.439 +     * the stdio file and channel pointers will become invalid at the same
   1.440 +     * time.
   1.441 +     * Do not close standard channels while in thread-exit.
   1.442 +     */
   1.443 +
   1.444 +    fd = (int) ((FileState*)instanceData)->fileRef;
   1.445 +    if (!TclInThreadExit()) {
   1.446 +	if (fd == 0) {
   1.447 +	    tsdPtr->stdinChannel = NULL;
   1.448 +	} else if (fd == 1) {
   1.449 +	    tsdPtr->stdoutChannel = NULL;
   1.450 +	} else if (fd == 2) {
   1.451 +	    tsdPtr->stderrChannel = NULL;
   1.452 +	} else {
   1.453 +	    panic("recieved invalid std file");
   1.454 +	}
   1.455 +    
   1.456 +	if (close(fd) < 0) {
   1.457 +	    errorCode = errno;
   1.458 +	}
   1.459 +    }
   1.460 +    return errorCode;
   1.461 +}
   1.462 +
   1.463 +/*
   1.464 + *----------------------------------------------------------------------
   1.465 + *
   1.466 + * CommonGetHandle --
   1.467 + *
   1.468 + *	Called from Tcl_GetChannelHandle to retrieve OS handles from inside
   1.469 + *	a file based channel.
   1.470 + *
   1.471 + * Results:
   1.472 + *	The appropriate handle or NULL if not present. 
   1.473 + *
   1.474 + * Side effects:
   1.475 + *	None.
   1.476 + *
   1.477 + *----------------------------------------------------------------------
   1.478 + */
   1.479 +
   1.480 +static int
   1.481 +CommonGetHandle(
   1.482 +    ClientData instanceData,		/* The file state. */
   1.483 +    int direction,			/* Which handle to retrieve? */
   1.484 +    ClientData *handlePtr)
   1.485 +{
   1.486 +    if ((direction == TCL_READABLE) || (direction == TCL_WRITABLE)) {
   1.487 +	*handlePtr = (ClientData) ((FileState*)instanceData)->fileRef;
   1.488 +	return TCL_OK;
   1.489 +    }
   1.490 +    return TCL_ERROR;
   1.491 +}
   1.492 +
   1.493 +/*
   1.494 + *----------------------------------------------------------------------
   1.495 + *
   1.496 + * StdIOInput --
   1.497 + *
   1.498 + *	Reads input from the IO channel into the buffer given. Returns
   1.499 + *	count of how many bytes were actually read, and an error indication.
   1.500 + *
   1.501 + * Results:
   1.502 + *	A count of how many bytes were read is returned and an error
   1.503 + *	indication is returned in an output argument.
   1.504 + *
   1.505 + * Side effects:
   1.506 + *	Reads input from the actual channel.
   1.507 + *
   1.508 + *----------------------------------------------------------------------
   1.509 + */
   1.510 +
   1.511 +int
   1.512 +StdIOInput(
   1.513 +    ClientData instanceData,		/* Unused. */
   1.514 +    char *buf,				/* Where to store data read. */
   1.515 +    int bufSize,			/* How much space is available
   1.516 +                                         * in the buffer? */
   1.517 +    int *errorCode)			/* Where to store error code. */
   1.518 +{
   1.519 +    int fd;
   1.520 +    int bytesRead;			/* How many bytes were read? */
   1.521 +
   1.522 +    *errorCode = 0;
   1.523 +    errno = 0;
   1.524 +    fd = (int) ((FileState*)instanceData)->fileRef;
   1.525 +    bytesRead = read(fd, buf, (size_t) bufSize);
   1.526 +    if (bytesRead > -1) {
   1.527 +        return bytesRead;
   1.528 +    }
   1.529 +    *errorCode = errno;
   1.530 +    return -1;
   1.531 +}
   1.532 +
   1.533 +/*
   1.534 + *----------------------------------------------------------------------
   1.535 + *
   1.536 + * StdIOOutput--
   1.537 + *
   1.538 + *	Writes the given output on the IO channel. Returns count of how
   1.539 + *	many characters were actually written, and an error indication.
   1.540 + *
   1.541 + * Results:
   1.542 + *	A count of how many characters were written is returned and an
   1.543 + *	error indication is returned in an output argument.
   1.544 + *
   1.545 + * Side effects:
   1.546 + *	Writes output on the actual channel.
   1.547 + *
   1.548 + *----------------------------------------------------------------------
   1.549 + */
   1.550 +
   1.551 +static int
   1.552 +StdIOOutput(
   1.553 +    ClientData instanceData,		/* Unused. */
   1.554 +    CONST char *buf,			/* The data buffer. */
   1.555 +    int toWrite,			/* How many bytes to write? */
   1.556 +    int *errorCode)			/* Where to store error code. */
   1.557 +{
   1.558 +    int written;
   1.559 +    int fd;
   1.560 +
   1.561 +    *errorCode = 0;
   1.562 +    errno = 0;
   1.563 +    fd = (int) ((FileState*)instanceData)->fileRef;
   1.564 +    written = write(fd, (void*)buf, (size_t) toWrite);
   1.565 +    if (written > -1) {
   1.566 +        return written;
   1.567 +    }
   1.568 +    *errorCode = errno;
   1.569 +    return -1;
   1.570 +}
   1.571 +
   1.572 +/*
   1.573 + *----------------------------------------------------------------------
   1.574 + *
   1.575 + * StdIOSeek --
   1.576 + *
   1.577 + *	Seeks on an IO channel. Returns the new position.
   1.578 + *
   1.579 + * Results:
   1.580 + *	-1 if failed, the new position if successful. If failed, it
   1.581 + *	also sets *errorCodePtr to the error code.
   1.582 + *
   1.583 + * Side effects:
   1.584 + *	Moves the location at which the channel will be accessed in
   1.585 + *	future operations.
   1.586 + *
   1.587 + *----------------------------------------------------------------------
   1.588 + */
   1.589 +
   1.590 +static int
   1.591 +StdIOSeek(
   1.592 +    ClientData instanceData,	/* Unused. */
   1.593 +    long offset,		/* Offset to seek to. */
   1.594 +    int mode,			/* Relative to where should we seek? */
   1.595 +    int *errorCodePtr)		/* To store error code. */
   1.596 +{
   1.597 +    int newLoc;
   1.598 +    int fd;
   1.599 +
   1.600 +    *errorCodePtr = 0;
   1.601 +    fd = (int) ((FileState*)instanceData)->fileRef;
   1.602 +    newLoc = lseek(fd, offset, mode);
   1.603 +    if (newLoc > -1) {
   1.604 +        return newLoc;
   1.605 +    }
   1.606 +    *errorCodePtr = errno;
   1.607 +    return -1;
   1.608 +}
   1.609 +
   1.610 +/*
   1.611 + *----------------------------------------------------------------------
   1.612 + *
   1.613 + * Tcl_PidObjCmd --
   1.614 + *
   1.615 + *      This procedure is invoked to process the "pid" Tcl command.
   1.616 + *      See the user documentation for details on what it does.
   1.617 + *
   1.618 + * Results:
   1.619 + *      A standard Tcl result.
   1.620 + *
   1.621 + * Side effects:
   1.622 + *      See the user documentation.
   1.623 + *
   1.624 + *----------------------------------------------------------------------
   1.625 + */
   1.626 +
   1.627 +        /* ARGSUSED */
   1.628 +int
   1.629 +Tcl_PidObjCmd(dummy, interp, objc, objv)
   1.630 +    ClientData dummy;           /* Not used. */
   1.631 +    Tcl_Interp *interp;         /* Current interpreter. */
   1.632 +    int objc;                   /* Number of arguments. */
   1.633 +    Tcl_Obj *CONST *objv;       /* Argument strings. */
   1.634 +{
   1.635 +    ProcessSerialNumber psn;
   1.636 +    char buf[20]; 
   1.637 +    Tcl_Channel chan;
   1.638 +    Tcl_Obj *resultPtr;
   1.639 +
   1.640 +    if (objc > 2) {
   1.641 +        Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
   1.642 +        return TCL_ERROR;
   1.643 +    }
   1.644 +    if (objc == 1) {
   1.645 +        resultPtr = Tcl_GetObjResult(interp);
   1.646 +	GetCurrentProcess(&psn);
   1.647 +	sprintf(buf, "0x%08x%08x", psn.highLongOfPSN, psn.lowLongOfPSN);
   1.648 +        Tcl_SetStringObj(resultPtr, buf, -1);
   1.649 +    } else {
   1.650 +        chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]),
   1.651 +                NULL);
   1.652 +        if (chan == (Tcl_Channel) NULL) {
   1.653 +            return TCL_ERROR;
   1.654 +        } 
   1.655 +	/*
   1.656 +	 * We can't create pipelines on the Mac so
   1.657 +	 * this will always return an empty list.
   1.658 +	 */
   1.659 +    }
   1.660 +    
   1.661 +    return TCL_OK;
   1.662 +}
   1.663 +
   1.664 +/*
   1.665 + *----------------------------------------------------------------------
   1.666 + *
   1.667 + * TclpGetDefaultStdChannel --
   1.668 + *
   1.669 + *	Constructs a channel for the specified standard OS handle.
   1.670 + *
   1.671 + * Results:
   1.672 + *	Returns the specified default standard channel, or NULL.
   1.673 + *
   1.674 + * Side effects:
   1.675 + *	May cause the creation of a standard channel and the underlying
   1.676 + *	file.
   1.677 + *
   1.678 + *----------------------------------------------------------------------
   1.679 + */
   1.680 +
   1.681 +Tcl_Channel
   1.682 +TclpGetDefaultStdChannel(
   1.683 +    int type)			/* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */
   1.684 +{
   1.685 +    Tcl_Channel channel = NULL;
   1.686 +    int fd = 0;			/* Initializations needed to prevent */
   1.687 +    int mode = 0;		/* compiler warning (used before set). */
   1.688 +    char *bufMode = NULL;
   1.689 +    char channelName[16 + TCL_INTEGER_SPACE];
   1.690 +    int channelPermissions;
   1.691 +    FileState *fileState;
   1.692 +
   1.693 +    /*
   1.694 +     * If the channels were not created yet, create them now and
   1.695 +     * store them in the static variables.
   1.696 +     */
   1.697 +
   1.698 +    switch (type) {
   1.699 +	case TCL_STDIN:
   1.700 +	    fd = 0;
   1.701 +	    channelPermissions = TCL_READABLE;
   1.702 +	    bufMode = "line";
   1.703 +	    break;
   1.704 +	case TCL_STDOUT:
   1.705 +	    fd = 1;
   1.706 +	    channelPermissions = TCL_WRITABLE;
   1.707 +	    bufMode = "line";
   1.708 +	    break;
   1.709 +	case TCL_STDERR:
   1.710 +	    fd = 2;
   1.711 +	    channelPermissions = TCL_WRITABLE;
   1.712 +	    bufMode = "none";
   1.713 +	    break;
   1.714 +	default:
   1.715 +	    panic("TclGetDefaultStdChannel: Unexpected channel type");
   1.716 +	    break;
   1.717 +    }
   1.718 +
   1.719 +    sprintf(channelName, "console%d", (int) fd);
   1.720 +    fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
   1.721 +    channel = Tcl_CreateChannel(&consoleChannelType, channelName,
   1.722 +	    (ClientData) fileState, channelPermissions);
   1.723 +    fileState->fileChan = channel;
   1.724 +    fileState->fileRef = fd;
   1.725 +
   1.726 +    /*
   1.727 +     * Set up the normal channel options for stdio handles.
   1.728 +     */
   1.729 +
   1.730 +    Tcl_SetChannelOption(NULL, channel, "-translation", "cr");
   1.731 +    Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode);
   1.732 +    
   1.733 +    return channel;
   1.734 +}
   1.735 +
   1.736 +/*
   1.737 + *----------------------------------------------------------------------
   1.738 + *
   1.739 + * TclpOpenFileChannel --
   1.740 + *
   1.741 + *	Open a File based channel on MacOS systems.
   1.742 + *
   1.743 + * Results:
   1.744 + *	The new channel or NULL. If NULL, the output argument
   1.745 + *	errorCodePtr is set to a POSIX error.
   1.746 + *
   1.747 + * Side effects:
   1.748 + *	May open the channel and may cause creation of a file on the
   1.749 + *	file system.
   1.750 + *
   1.751 + *----------------------------------------------------------------------
   1.752 + */
   1.753 +
   1.754 +Tcl_Channel
   1.755 +TclpOpenFileChannel(
   1.756 +    Tcl_Interp *interp,			/* Interpreter for error reporting;
   1.757 +                                         * can be NULL. */
   1.758 +    Tcl_Obj *pathPtr,			/* Name of file to open. */
   1.759 +    int mode,				/* POSIX open mode. */
   1.760 +    int permissions)			/* If the open involves creating a
   1.761 +                                         * file, with what modes to create
   1.762 +                                         * it? */
   1.763 +{
   1.764 +    Tcl_Channel chan;
   1.765 +    CONST char *native;
   1.766 +    int errorCode;
   1.767 +    
   1.768 +    native = Tcl_FSGetNativePath(pathPtr);
   1.769 +    if (native == NULL) {
   1.770 +	return NULL;
   1.771 +    }
   1.772 +    chan = OpenFileChannel(native, mode, permissions, &errorCode);
   1.773 +
   1.774 +    if (chan == NULL) {
   1.775 +	Tcl_SetErrno(errorCode);
   1.776 +	if (interp != (Tcl_Interp *) NULL) {
   1.777 +            Tcl_AppendResult(interp, "couldn't open \"", 
   1.778 +			     Tcl_GetString(pathPtr), "\": ",
   1.779 +			     Tcl_PosixError(interp), (char *) NULL);
   1.780 +        }
   1.781 +	return NULL;
   1.782 +    }
   1.783 +    
   1.784 +    return chan;
   1.785 +}
   1.786 +
   1.787 +/*
   1.788 + *----------------------------------------------------------------------
   1.789 + *
   1.790 + * OpenFileChannel--
   1.791 + *
   1.792 + *	Opens a Macintosh file and creates a Tcl channel to control it.
   1.793 + *
   1.794 + * Results:
   1.795 + *	A Tcl channel.
   1.796 + *
   1.797 + * Side effects:
   1.798 + *	Will open a Macintosh file.
   1.799 + *
   1.800 + *----------------------------------------------------------------------
   1.801 + */
   1.802 +
   1.803 +static Tcl_Channel
   1.804 +OpenFileChannel(
   1.805 +    CONST char *fileName,		/* Name of file to open (native). */
   1.806 +    int mode,				/* Mode for opening file. */
   1.807 +    int permissions,			/* If the open involves creating a
   1.808 +                                         * file, with what modes to create
   1.809 +                                         * it? */
   1.810 +    int *errorCodePtr)			/* Where to store error code. */
   1.811 +{
   1.812 +    int channelPermissions;
   1.813 +    Tcl_Channel chan;
   1.814 +    char macPermision;
   1.815 +    FSSpec fileSpec;
   1.816 +    OSErr err;
   1.817 +    short fileRef;
   1.818 +    FileState *fileState;
   1.819 +    char channelName[16 + TCL_INTEGER_SPACE];
   1.820 +    ThreadSpecificData *tsdPtr;
   1.821 +    
   1.822 +    tsdPtr = FileInit();
   1.823 +
   1.824 +    /*
   1.825 +     * Note we use fsRdWrShPerm instead of fsRdWrPerm which allows shared
   1.826 +     * writes on a file.  This isn't common on a mac but is common with 
   1.827 +     * Windows and UNIX and the feature is used by Tcl.
   1.828 +     */
   1.829 +
   1.830 +    switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
   1.831 +	case O_RDWR:
   1.832 +	    channelPermissions = (TCL_READABLE | TCL_WRITABLE);
   1.833 +	    macPermision = fsRdWrShPerm;
   1.834 +	    break;
   1.835 +	case O_WRONLY:
   1.836 +	    /*
   1.837 +	     * Mac's fsRdPerm permission actually defaults to fsRdWrPerm because
   1.838 +	     * the Mac OS doesn't realy support write only access.  We explicitly
   1.839 +	     * set the permission fsRdWrShPerm so that we can have shared write
   1.840 +	     * access.
   1.841 +	     */
   1.842 +	    channelPermissions = TCL_WRITABLE;
   1.843 +	    macPermision = fsRdWrShPerm;
   1.844 +	    break;
   1.845 +	case O_RDONLY:
   1.846 +	default:
   1.847 +	    channelPermissions = TCL_READABLE;
   1.848 +	    macPermision = fsRdPerm;
   1.849 +	    break;
   1.850 +    }
   1.851 +     
   1.852 +    err = FSpLocationFromPath(strlen(fileName), fileName, &fileSpec);
   1.853 +    if ((err != noErr) && (err != fnfErr)) {
   1.854 +	*errorCodePtr = errno = TclMacOSErrorToPosixError(err);
   1.855 +	Tcl_SetErrno(errno);
   1.856 +	return NULL;
   1.857 +    }
   1.858 +
   1.859 +    if ((err == fnfErr) && (mode & O_CREAT)) {
   1.860 +	err = HCreate(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, TCL_FILE_CREATOR, 'TEXT');
   1.861 +	if (err != noErr) {
   1.862 +	    *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
   1.863 +	    Tcl_SetErrno(errno);
   1.864 +	    return NULL;
   1.865 +	}
   1.866 +    } else if ((mode & O_CREAT) && (mode & O_EXCL)) {
   1.867 +        *errorCodePtr = errno = EEXIST;
   1.868 +	Tcl_SetErrno(errno);
   1.869 +        return NULL;
   1.870 +    }
   1.871 +
   1.872 +    err = HOpenDF(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, macPermision, &fileRef);
   1.873 +    if (err != noErr) {
   1.874 +	*errorCodePtr = errno = TclMacOSErrorToPosixError(err);
   1.875 +	Tcl_SetErrno(errno);
   1.876 +	return NULL;
   1.877 +    }
   1.878 +
   1.879 +    if (mode & O_TRUNC) {
   1.880 +	SetEOF(fileRef, 0);
   1.881 +    }
   1.882 +    
   1.883 +    sprintf(channelName, "file%d", (int) fileRef);
   1.884 +    fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
   1.885 +    chan = Tcl_CreateChannel(&fileChannelType, channelName, 
   1.886 +	(ClientData) fileState, channelPermissions);
   1.887 +    if (chan == (Tcl_Channel) NULL) {
   1.888 +	*errorCodePtr = errno = EFAULT;
   1.889 +	Tcl_SetErrno(errno);
   1.890 +	FSClose(fileRef);
   1.891 +	ckfree((char *) fileState);
   1.892 +        return NULL;
   1.893 +    }
   1.894 +
   1.895 +    fileState->fileChan = chan;
   1.896 +    fileState->nextPtr = tsdPtr->firstFilePtr;
   1.897 +    tsdPtr->firstFilePtr = fileState;
   1.898 +    fileState->volumeRef = fileSpec.vRefNum;
   1.899 +    fileState->fileRef = fileRef;
   1.900 +    fileState->pending = 0;
   1.901 +    fileState->watchMask = 0;
   1.902 +    if (mode & O_APPEND) {
   1.903 +	fileState->appendMode = true;
   1.904 +    } else {
   1.905 +	fileState->appendMode = false;
   1.906 +    }
   1.907 +        
   1.908 +    if ((mode & O_APPEND) || (mode & O_APPEND)) {
   1.909 +        if (Tcl_Seek(chan, 0, SEEK_END) < 0) {
   1.910 +	    *errorCodePtr = errno = EFAULT;
   1.911 +	    Tcl_SetErrno(errno);
   1.912 +            Tcl_Close(NULL, chan);
   1.913 +            FSClose(fileRef);
   1.914 +            ckfree((char *) fileState);
   1.915 +            return NULL;
   1.916 +        }
   1.917 +    }
   1.918 +    
   1.919 +    return chan;
   1.920 +}
   1.921 +
   1.922 +/*
   1.923 + *----------------------------------------------------------------------
   1.924 + *
   1.925 + * Tcl_MakeFileChannel --
   1.926 + *
   1.927 + *	Makes a Tcl_Channel from an existing OS level file handle.
   1.928 + *
   1.929 + * Results:
   1.930 + *	The Tcl_Channel created around the preexisting OS level file handle.
   1.931 + *
   1.932 + * Side effects:
   1.933 + *	None.
   1.934 + *
   1.935 + *----------------------------------------------------------------------
   1.936 + */
   1.937 +
   1.938 +Tcl_Channel
   1.939 +Tcl_MakeFileChannel(handle, mode)
   1.940 +    ClientData handle;		/* OS level handle. */
   1.941 +    int mode;			/* ORed combination of TCL_READABLE and
   1.942 +                                 * TCL_WRITABLE to indicate file mode. */
   1.943 +{
   1.944 +    /*
   1.945 +     * Not implemented yet.
   1.946 +     */
   1.947 +
   1.948 +    return NULL;
   1.949 +}
   1.950 +
   1.951 +/*
   1.952 + *----------------------------------------------------------------------
   1.953 + *
   1.954 + * FileBlockMode --
   1.955 + *
   1.956 + *	Set blocking or non-blocking mode on channel.  Macintosh files
   1.957 + *	can never really be set to blocking or non-blocking modes.
   1.958 + *	However, we don't generate an error - we just return success.
   1.959 + *
   1.960 + * Results:
   1.961 + *	0 if successful, errno when failed.
   1.962 + *
   1.963 + * Side effects:
   1.964 + *	Sets the device into blocking or non-blocking mode.
   1.965 + *
   1.966 + *----------------------------------------------------------------------
   1.967 + */
   1.968 +
   1.969 +static int
   1.970 +FileBlockMode(
   1.971 +    ClientData instanceData,		/* Unused. */
   1.972 +    int mode)				/* The mode to set. */
   1.973 +{
   1.974 +    return 0;
   1.975 +}
   1.976 +
   1.977 +/*
   1.978 + *----------------------------------------------------------------------
   1.979 + *
   1.980 + * FileClose --
   1.981 + *
   1.982 + *	Closes the IO channel.
   1.983 + *
   1.984 + * Results:
   1.985 + *	0 if successful, the value of errno if failed.
   1.986 + *
   1.987 + * Side effects:
   1.988 + *	Closes the physical channel
   1.989 + *
   1.990 + *----------------------------------------------------------------------
   1.991 + */
   1.992 +
   1.993 +static int
   1.994 +FileClose(
   1.995 +    ClientData instanceData,	/* Unused. */
   1.996 +    Tcl_Interp *interp)		/* Unused. */
   1.997 +{
   1.998 +    FileState *fileState = (FileState *) instanceData;
   1.999 +    int errorCode = 0;
  1.1000 +    OSErr err;
  1.1001 +
  1.1002 +    err = FSClose(fileState->fileRef);
  1.1003 +    FlushVol(NULL, fileState->volumeRef);
  1.1004 +    if (err != noErr) {
  1.1005 +	errorCode = errno = TclMacOSErrorToPosixError(err);
  1.1006 +	panic("error during file close");
  1.1007 +    }
  1.1008 +
  1.1009 +    ckfree((char *) fileState);
  1.1010 +    Tcl_SetErrno(errorCode);
  1.1011 +    return errorCode;
  1.1012 +}
  1.1013 +
  1.1014 +/*
  1.1015 + *----------------------------------------------------------------------
  1.1016 + *
  1.1017 + * FileInput --
  1.1018 + *
  1.1019 + *	Reads input from the IO channel into the buffer given. Returns
  1.1020 + *	count of how many bytes were actually read, and an error indication.
  1.1021 + *
  1.1022 + * Results:
  1.1023 + *	A count of how many bytes were read is returned and an error
  1.1024 + *	indication is returned in an output argument.
  1.1025 + *
  1.1026 + * Side effects:
  1.1027 + *	Reads input from the actual channel.
  1.1028 + *
  1.1029 + *----------------------------------------------------------------------
  1.1030 + */
  1.1031 +
  1.1032 +int
  1.1033 +FileInput(
  1.1034 +    ClientData instanceData,	/* Unused. */
  1.1035 +    char *buffer,				/* Where to store data read. */
  1.1036 +    int bufSize,				/* How much space is available
  1.1037 +                                 * in the buffer? */
  1.1038 +    int *errorCodePtr)			/* Where to store error code. */
  1.1039 +{
  1.1040 +    FileState *fileState = (FileState *) instanceData;
  1.1041 +    OSErr err;
  1.1042 +    long length = bufSize;
  1.1043 +
  1.1044 +    *errorCodePtr = 0;
  1.1045 +    errno = 0;
  1.1046 +    err = FSRead(fileState->fileRef, &length, buffer);
  1.1047 +    if ((err == noErr) || (err == eofErr)) {
  1.1048 +	return length;
  1.1049 +    } else {
  1.1050 +	switch (err) {
  1.1051 +	    case ioErr:
  1.1052 +		*errorCodePtr = errno = EIO;
  1.1053 +	    case afpAccessDenied:
  1.1054 +		*errorCodePtr = errno = EACCES;
  1.1055 +	    default:
  1.1056 +		*errorCodePtr = errno = EINVAL;
  1.1057 +	}
  1.1058 +        return -1;	
  1.1059 +    }
  1.1060 +    *errorCodePtr = errno;
  1.1061 +    return -1;
  1.1062 +}
  1.1063 +
  1.1064 +/*
  1.1065 + *----------------------------------------------------------------------
  1.1066 + *
  1.1067 + * FileOutput--
  1.1068 + *
  1.1069 + *	Writes the given output on the IO channel. Returns count of how
  1.1070 + *	many characters were actually written, and an error indication.
  1.1071 + *
  1.1072 + * Results:
  1.1073 + *	A count of how many characters were written is returned and an
  1.1074 + *	error indication is returned in an output argument.
  1.1075 + *
  1.1076 + * Side effects:
  1.1077 + *	Writes output on the actual channel.
  1.1078 + *
  1.1079 + *----------------------------------------------------------------------
  1.1080 + */
  1.1081 +
  1.1082 +static int
  1.1083 +FileOutput(
  1.1084 +    ClientData instanceData,		/* Unused. */
  1.1085 +    CONST char *buffer,			/* The data buffer. */
  1.1086 +    int toWrite,			/* How many bytes to write? */
  1.1087 +    int *errorCodePtr)			/* Where to store error code. */
  1.1088 +{
  1.1089 +    FileState *fileState = (FileState *) instanceData;
  1.1090 +    long length = toWrite;
  1.1091 +    OSErr err;
  1.1092 +
  1.1093 +    *errorCodePtr = 0;
  1.1094 +    errno = 0;
  1.1095 +    
  1.1096 +    if (fileState->appendMode == true) {
  1.1097 +	FileSeek(instanceData, 0, SEEK_END, errorCodePtr);
  1.1098 +	*errorCodePtr = 0;
  1.1099 +    }
  1.1100 +    
  1.1101 +    err = FSWrite(fileState->fileRef, &length, buffer);
  1.1102 +    if (err == noErr) {
  1.1103 +	err = FlushFile(fileState->fileRef);
  1.1104 +    } else {
  1.1105 +	*errorCodePtr = errno = TclMacOSErrorToPosixError(err);
  1.1106 +	return -1;
  1.1107 +    }
  1.1108 +    return length;
  1.1109 +}
  1.1110 +
  1.1111 +/*
  1.1112 + *----------------------------------------------------------------------
  1.1113 + *
  1.1114 + * FileSeek --
  1.1115 + *
  1.1116 + *	Seeks on an IO channel. Returns the new position.
  1.1117 + *
  1.1118 + * Results:
  1.1119 + *	-1 if failed, the new position if successful. If failed, it
  1.1120 + *	also sets *errorCodePtr to the error code.
  1.1121 + *
  1.1122 + * Side effects:
  1.1123 + *	Moves the location at which the channel will be accessed in
  1.1124 + *	future operations.
  1.1125 + *
  1.1126 + *----------------------------------------------------------------------
  1.1127 + */
  1.1128 +
  1.1129 +static int
  1.1130 +FileSeek(
  1.1131 +    ClientData instanceData,	/* Unused. */
  1.1132 +    long offset,		/* Offset to seek to. */
  1.1133 +    int mode,			/* Relative to where should we seek? */
  1.1134 +    int *errorCodePtr)		/* To store error code. */
  1.1135 +{
  1.1136 +    FileState *fileState = (FileState *) instanceData;
  1.1137 +    IOParam pb;
  1.1138 +    OSErr err;
  1.1139 +
  1.1140 +    *errorCodePtr = 0;
  1.1141 +    pb.ioCompletion = NULL;
  1.1142 +    pb.ioRefNum = fileState->fileRef;
  1.1143 +    if (mode == SEEK_SET) {
  1.1144 +	pb.ioPosMode = fsFromStart;
  1.1145 +    } else if (mode == SEEK_END) {
  1.1146 +	pb.ioPosMode = fsFromLEOF;
  1.1147 +    } else if (mode == SEEK_CUR) {
  1.1148 +	err = PBGetFPosSync((ParmBlkPtr) &pb);
  1.1149 +	if (pb.ioResult == noErr) {
  1.1150 +	    if (offset == 0) {
  1.1151 +		return pb.ioPosOffset;
  1.1152 +	    }
  1.1153 +	    offset += pb.ioPosOffset;
  1.1154 +	}
  1.1155 +	pb.ioPosMode = fsFromStart;
  1.1156 +    }
  1.1157 +    pb.ioPosOffset = offset;
  1.1158 +    err = PBSetFPosSync((ParmBlkPtr) &pb);
  1.1159 +    if (pb.ioResult == noErr){
  1.1160 +	return pb.ioPosOffset;
  1.1161 +    } else if (pb.ioResult == eofErr) {
  1.1162 +	long currentEOF, newEOF;
  1.1163 +	long buffer, i, length;
  1.1164 +	
  1.1165 +	err = PBGetEOFSync((ParmBlkPtr) &pb);
  1.1166 +	currentEOF = (long) pb.ioMisc;
  1.1167 +	if (mode == SEEK_SET) {
  1.1168 +	    newEOF = offset;
  1.1169 +	} else if (mode == SEEK_END) {
  1.1170 +	    newEOF = offset + currentEOF;
  1.1171 +	} else if (mode == SEEK_CUR) {
  1.1172 +	    err = PBGetFPosSync((ParmBlkPtr) &pb);
  1.1173 +	    newEOF = offset + pb.ioPosOffset;
  1.1174 +	}
  1.1175 +	
  1.1176 +	/*
  1.1177 +	 * Write 0's to the new EOF.
  1.1178 +	 */
  1.1179 +	pb.ioPosOffset = 0;
  1.1180 +	pb.ioPosMode = fsFromLEOF;
  1.1181 +	err = PBGetFPosSync((ParmBlkPtr) &pb);
  1.1182 +	length = 1;
  1.1183 +	buffer = 0;
  1.1184 +	for (i = 0; i < (newEOF - currentEOF); i++) {
  1.1185 +	    err = FSWrite(fileState->fileRef, &length, &buffer);
  1.1186 +	}
  1.1187 +	err = PBGetFPosSync((ParmBlkPtr) &pb);
  1.1188 +	if (pb.ioResult == noErr){
  1.1189 +	    return pb.ioPosOffset;
  1.1190 +	}
  1.1191 +    }
  1.1192 +    *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
  1.1193 +    return -1;
  1.1194 +}
  1.1195 +
  1.1196 +/*
  1.1197 + *----------------------------------------------------------------------
  1.1198 + *
  1.1199 + * CommonWatch --
  1.1200 + *
  1.1201 + *	Initialize the notifier to watch handles from this channel.
  1.1202 + *
  1.1203 + * Results:
  1.1204 + *	None.
  1.1205 + *
  1.1206 + * Side effects:
  1.1207 + *	None.
  1.1208 + *
  1.1209 + *----------------------------------------------------------------------
  1.1210 + */
  1.1211 +
  1.1212 +static void
  1.1213 +CommonWatch(
  1.1214 +    ClientData instanceData,		/* The file state. */
  1.1215 +    int mask)				/* Events of interest; an OR-ed
  1.1216 +                                         * combination of TCL_READABLE,
  1.1217 +                                         * TCL_WRITABLE and TCL_EXCEPTION. */
  1.1218 +{
  1.1219 +    FileState *infoPtr = (FileState *) instanceData;
  1.1220 +    Tcl_Time blockTime = { 0, 0 };
  1.1221 +
  1.1222 +    infoPtr->watchMask = mask;
  1.1223 +    if (infoPtr->watchMask) {
  1.1224 +	Tcl_SetMaxBlockTime(&blockTime);
  1.1225 +    }
  1.1226 +}
  1.1227 +
  1.1228 +/*
  1.1229 + *----------------------------------------------------------------------
  1.1230 + *
  1.1231 + * FileThreadActionProc --
  1.1232 + *
  1.1233 + *	Insert or remove any thread local refs to this channel.
  1.1234 + *
  1.1235 + * Results:
  1.1236 + *	None.
  1.1237 + *
  1.1238 + * Side effects:
  1.1239 + *	Changes thread local list of valid channels.
  1.1240 + *
  1.1241 + *----------------------------------------------------------------------
  1.1242 + */
  1.1243 +
  1.1244 +static void
  1.1245 +FileThreadActionProc (instanceData, action)
  1.1246 +     ClientData instanceData;
  1.1247 +     int action;
  1.1248 +{
  1.1249 +    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
  1.1250 +    FileState *infoPtr = (FileState *) instanceData;
  1.1251 +
  1.1252 +    if (action == TCL_CHANNEL_THREAD_INSERT) {
  1.1253 +	infoPtr->nextPtr = tsdPtr->firstFilePtr;
  1.1254 +	tsdPtr->firstFilePtr = infoPtr;
  1.1255 +    } else {
  1.1256 +	FileState **nextPtrPtr;
  1.1257 +	int removed = 0;
  1.1258 +
  1.1259 +	for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL;
  1.1260 +	     nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
  1.1261 +	    if ((*nextPtrPtr) == infoPtr) {
  1.1262 +	        (*nextPtrPtr) = infoPtr->nextPtr;
  1.1263 +		removed = 1;
  1.1264 +		break;
  1.1265 +	    }
  1.1266 +	}
  1.1267 +
  1.1268 +	/*
  1.1269 +	 * This could happen if the channel was created in one thread
  1.1270 +	 * and then moved to another without updating the thread
  1.1271 +	 * local data in each thread.
  1.1272 +	 */
  1.1273 +
  1.1274 +	if (!removed) {
  1.1275 +	    panic("file info ptr not on thread channel list");
  1.1276 +	}
  1.1277 +    }
  1.1278 +}