os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacChan.c
Update contrib.
4 * Channel drivers for Macintosh channels for the
7 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * RCS: @(#) $Id: tclMacChan.c,v 1.21.2.1 2005/01/27 22:53:34 andreas_kupries Exp $
17 #include "tclMacInt.h"
22 #include <Processes.h>
24 #include <FSpCompat.h>
25 #include <MoreFiles.h>
26 #include <MoreFilesExtras.h>
31 #define TCL_FILE_CREATOR (__getcreator(0))
33 #define TCL_FILE_CREATOR 'MPW '
37 * This structure describes per-instance state of a
38 * macintosh file based channel.
41 typedef struct FileState {
42 short fileRef; /* Macintosh file reference number. */
43 Tcl_Channel fileChan; /* Pointer to the channel for this file. */
44 int watchMask; /* OR'ed set of flags indicating which events
45 * are being watched. */
46 int appendMode; /* Flag to tell if in O_APPEND mode or not. */
47 int volumeRef; /* Flag to tell if in O_APPEND mode or not. */
48 int pending; /* 1 if message is pending on queue. */
49 struct FileState *nextPtr; /* Pointer to next registered file. */
52 typedef struct ThreadSpecificData {
53 int initialized; /* True after the thread initializes */
54 FileState *firstFilePtr; /* the head of the list of files managed
55 * that are being watched for file events. */
56 Tcl_Channel stdinChannel;
57 Tcl_Channel stdoutChannel; /* Note - these seem unused */
58 Tcl_Channel stderrChannel;
61 static Tcl_ThreadDataKey dataKey;
64 * The following structure is what is added to the Tcl event queue when
65 * file events are generated.
68 typedef struct FileEvent {
69 Tcl_Event header; /* Information that is standard for
71 FileState *infoPtr; /* Pointer to file info structure. Note
72 * that we still have to verify that the
73 * file exists before dereferencing this
79 * Static routines for this file:
82 static int CommonGetHandle _ANSI_ARGS_((ClientData instanceData,
83 int direction, ClientData *handlePtr));
84 static void CommonWatch _ANSI_ARGS_((ClientData instanceData,
86 static int FileBlockMode _ANSI_ARGS_((ClientData instanceData,
88 static void FileChannelExitHandler _ANSI_ARGS_((
89 ClientData clientData));
90 static void FileCheckProc _ANSI_ARGS_((ClientData clientData,
92 static int FileClose _ANSI_ARGS_((ClientData instanceData,
94 static int FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
96 static ThreadSpecificData *FileInit _ANSI_ARGS_((void));
97 static int FileInput _ANSI_ARGS_((ClientData instanceData,
98 char *buf, int toRead, int *errorCode));
99 static int FileOutput _ANSI_ARGS_((ClientData instanceData,
100 CONST char *buf, int toWrite, int *errorCode));
101 static int FileSeek _ANSI_ARGS_((ClientData instanceData,
102 long offset, int mode, int *errorCode));
103 static void FileSetupProc _ANSI_ARGS_((ClientData clientData,
105 static void FileThreadActionProc _ANSI_ARGS_ ((
106 ClientData instanceData, int action));
107 static Tcl_Channel OpenFileChannel _ANSI_ARGS_((CONST char *fileName,
108 int mode, int permissions, int *errorCodePtr));
109 static int StdIOBlockMode _ANSI_ARGS_((ClientData instanceData,
111 static int StdIOClose _ANSI_ARGS_((ClientData instanceData,
112 Tcl_Interp *interp));
113 static int StdIOInput _ANSI_ARGS_((ClientData instanceData,
114 char *buf, int toRead, int *errorCode));
115 static int StdIOOutput _ANSI_ARGS_((ClientData instanceData,
116 CONST char *buf, int toWrite, int *errorCode));
117 static int StdIOSeek _ANSI_ARGS_((ClientData instanceData,
118 long offset, int mode, int *errorCode));
119 static int StdReady _ANSI_ARGS_((ClientData instanceData,
123 * This structure describes the channel type structure for file based IO:
126 static Tcl_ChannelType consoleChannelType = {
127 "file", /* Type name. */
128 TCL_CHANNEL_VERSION_4, /* v4 channel */
129 StdIOClose, /* Close proc. */
130 StdIOInput, /* Input proc. */
131 StdIOOutput, /* Output proc. */
132 StdIOSeek, /* Seek proc. */
133 NULL, /* Set option proc. */
134 NULL, /* Get option proc. */
135 CommonWatch, /* Initialize notifier. */
136 CommonGetHandle /* Get OS handles out of channel. */
137 NULL, /* close2proc. */
138 StdIOBlockMode, /* Set blocking/nonblocking mode.*/
139 NULL, /* flush proc. */
140 NULL, /* handler proc. */
141 NULL, /* wide seek proc. */
142 NULL, /* thread actions */
146 * This variable describes the channel type structure for file based IO.
149 static Tcl_ChannelType fileChannelType = {
150 "file", /* Type name. */
151 TCL_CHANNEL_VERSION_4, /* v4 channel */
152 FileClose, /* Close proc. */
153 FileInput, /* Input proc. */
154 FileOutput, /* Output proc. */
155 FileSeek, /* Seek proc. */
156 NULL, /* Set option proc. */
157 NULL, /* Get option proc. */
158 CommonWatch, /* Initialize notifier. */
159 CommonGetHandle /* Get OS handles out of channel. */
160 NULL, /* close2proc. */
161 FileBlockMode, /* Set blocking/nonblocking mode.*/
162 NULL, /* flush proc. */
163 NULL, /* handler proc. */
164 NULL, /* wide seek proc. */
165 FileThreadActionProc, /* thread actions */
170 * Hack to allow Mac Tk to override the TclGetStdChannels function.
173 typedef void (*TclGetStdChannelsProc) _ANSI_ARGS_((Tcl_Channel *stdinPtr,
174 Tcl_Channel *stdoutPtr, Tcl_Channel *stderrPtr));
176 TclGetStdChannelsProc getStdChannelsProc = NULL;
180 *----------------------------------------------------------------------
184 * This function initializes the file channel event source.
190 * Creates a new event source.
192 *----------------------------------------------------------------------
195 static ThreadSpecificData *
198 ThreadSpecificData *tsdPtr =
199 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
200 if (tsdPtr == NULL) {
201 tsdPtr = TCL_TSD_INIT(&dataKey);
202 tsdPtr->firstFilePtr = NULL;
203 Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL);
204 Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL);
210 *----------------------------------------------------------------------
212 * FileChannelExitHandler --
214 * This function is called to cleanup the channel driver before
221 * Destroys the communication window.
223 *----------------------------------------------------------------------
227 FileChannelExitHandler(
228 ClientData clientData) /* Old window proc */
230 Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);
234 *----------------------------------------------------------------------
238 * This procedure is invoked before Tcl_DoOneEvent blocks waiting
245 * Adjusts the block time if needed.
247 *----------------------------------------------------------------------
252 ClientData data, /* Not used. */
253 int flags) /* Event flags as passed to Tcl_DoOneEvent. */
256 Tcl_Time blockTime = { 0, 0 };
257 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
259 if (!(flags & TCL_FILE_EVENTS)) {
264 * Check to see if there is a ready file. If so, poll.
267 for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
268 infoPtr = infoPtr->nextPtr) {
269 if (infoPtr->watchMask) {
270 Tcl_SetMaxBlockTime(&blockTime);
277 *----------------------------------------------------------------------
281 * This procedure is called by Tcl_DoOneEvent to check the file
282 * event source for events.
288 * May queue an event.
290 *----------------------------------------------------------------------
295 ClientData data, /* Not used. */
296 int flags) /* Event flags as passed to Tcl_DoOneEvent. */
301 Tcl_Time blockTime = { 0, 0 };
302 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
304 if (!(flags & TCL_FILE_EVENTS)) {
309 * Queue events for any ready files that don't already have events
310 * queued (caused by persistent states that won't generate WinSock
314 for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
315 infoPtr = infoPtr->nextPtr) {
316 if (infoPtr->watchMask && !infoPtr->pending) {
317 infoPtr->pending = 1;
318 evPtr = (FileEvent *) ckalloc(sizeof(FileEvent));
319 evPtr->header.proc = FileEventProc;
320 evPtr->infoPtr = infoPtr;
321 Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
326 /*----------------------------------------------------------------------
330 * This function is invoked by Tcl_ServiceEvent when a file event
331 * reaches the front of the event queue. This procedure invokes
332 * Tcl_NotifyChannel on the file.
335 * Returns 1 if the event was handled, meaning it should be removed
336 * from the queue. Returns 0 if the event was not handled, meaning
337 * it should stay on the queue. The only time the event isn't
338 * handled is if the TCL_FILE_EVENTS flag bit isn't set.
341 * Whatever the notifier callback does.
343 *----------------------------------------------------------------------
348 Tcl_Event *evPtr, /* Event to service. */
349 int flags) /* Flags that indicate what events to
350 * handle, such as TCL_FILE_EVENTS. */
352 FileEvent *fileEvPtr = (FileEvent *)evPtr;
354 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
356 if (!(flags & TCL_FILE_EVENTS)) {
361 * Search through the list of watched files for the one whose handle
362 * matches the event. We do this rather than simply dereferencing
363 * the handle in the event so that files can be deleted while the
364 * event is in the queue.
367 for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
368 infoPtr = infoPtr->nextPtr) {
369 if (fileEvPtr->infoPtr == infoPtr) {
370 infoPtr->pending = 0;
371 Tcl_NotifyChannel(infoPtr->fileChan, infoPtr->watchMask);
379 *----------------------------------------------------------------------
383 * Set blocking or non-blocking mode on channel.
386 * 0 if successful, errno when failed.
389 * Sets the device into blocking or non-blocking mode.
391 *----------------------------------------------------------------------
396 ClientData instanceData, /* Unused. */
397 int mode) /* The mode to set. */
400 * Do not allow putting stdin, stdout or stderr into nonblocking mode.
403 if (mode == TCL_MODE_NONBLOCKING) {
411 *----------------------------------------------------------------------
415 * Closes the IO channel.
418 * 0 if successful, the value of errno if failed.
421 * Closes the physical channel
423 *----------------------------------------------------------------------
428 ClientData instanceData, /* Unused. */
429 Tcl_Interp *interp) /* Unused. */
431 int fd, errorCode = 0;
432 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
435 * Invalidate the stdio cache if necessary. Note that we assume that
436 * the stdio file and channel pointers will become invalid at the same
438 * Do not close standard channels while in thread-exit.
441 fd = (int) ((FileState*)instanceData)->fileRef;
442 if (!TclInThreadExit()) {
444 tsdPtr->stdinChannel = NULL;
445 } else if (fd == 1) {
446 tsdPtr->stdoutChannel = NULL;
447 } else if (fd == 2) {
448 tsdPtr->stderrChannel = NULL;
450 panic("recieved invalid std file");
461 *----------------------------------------------------------------------
465 * Called from Tcl_GetChannelHandle to retrieve OS handles from inside
466 * a file based channel.
469 * The appropriate handle or NULL if not present.
474 *----------------------------------------------------------------------
479 ClientData instanceData, /* The file state. */
480 int direction, /* Which handle to retrieve? */
481 ClientData *handlePtr)
483 if ((direction == TCL_READABLE) || (direction == TCL_WRITABLE)) {
484 *handlePtr = (ClientData) ((FileState*)instanceData)->fileRef;
491 *----------------------------------------------------------------------
495 * Reads input from the IO channel into the buffer given. Returns
496 * count of how many bytes were actually read, and an error indication.
499 * A count of how many bytes were read is returned and an error
500 * indication is returned in an output argument.
503 * Reads input from the actual channel.
505 *----------------------------------------------------------------------
510 ClientData instanceData, /* Unused. */
511 char *buf, /* Where to store data read. */
512 int bufSize, /* How much space is available
514 int *errorCode) /* Where to store error code. */
517 int bytesRead; /* How many bytes were read? */
521 fd = (int) ((FileState*)instanceData)->fileRef;
522 bytesRead = read(fd, buf, (size_t) bufSize);
523 if (bytesRead > -1) {
531 *----------------------------------------------------------------------
535 * Writes the given output on the IO channel. Returns count of how
536 * many characters were actually written, and an error indication.
539 * A count of how many characters were written is returned and an
540 * error indication is returned in an output argument.
543 * Writes output on the actual channel.
545 *----------------------------------------------------------------------
550 ClientData instanceData, /* Unused. */
551 CONST char *buf, /* The data buffer. */
552 int toWrite, /* How many bytes to write? */
553 int *errorCode) /* Where to store error code. */
560 fd = (int) ((FileState*)instanceData)->fileRef;
561 written = write(fd, (void*)buf, (size_t) toWrite);
570 *----------------------------------------------------------------------
574 * Seeks on an IO channel. Returns the new position.
577 * -1 if failed, the new position if successful. If failed, it
578 * also sets *errorCodePtr to the error code.
581 * Moves the location at which the channel will be accessed in
584 *----------------------------------------------------------------------
589 ClientData instanceData, /* Unused. */
590 long offset, /* Offset to seek to. */
591 int mode, /* Relative to where should we seek? */
592 int *errorCodePtr) /* To store error code. */
598 fd = (int) ((FileState*)instanceData)->fileRef;
599 newLoc = lseek(fd, offset, mode);
603 *errorCodePtr = errno;
608 *----------------------------------------------------------------------
612 * This procedure is invoked to process the "pid" Tcl command.
613 * See the user documentation for details on what it does.
616 * A standard Tcl result.
619 * See the user documentation.
621 *----------------------------------------------------------------------
626 Tcl_PidObjCmd(dummy, interp, objc, objv)
627 ClientData dummy; /* Not used. */
628 Tcl_Interp *interp; /* Current interpreter. */
629 int objc; /* Number of arguments. */
630 Tcl_Obj *CONST *objv; /* Argument strings. */
632 ProcessSerialNumber psn;
638 Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
642 resultPtr = Tcl_GetObjResult(interp);
643 GetCurrentProcess(&psn);
644 sprintf(buf, "0x%08x%08x", psn.highLongOfPSN, psn.lowLongOfPSN);
645 Tcl_SetStringObj(resultPtr, buf, -1);
647 chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]),
649 if (chan == (Tcl_Channel) NULL) {
653 * We can't create pipelines on the Mac so
654 * this will always return an empty list.
662 *----------------------------------------------------------------------
664 * TclpGetDefaultStdChannel --
666 * Constructs a channel for the specified standard OS handle.
669 * Returns the specified default standard channel, or NULL.
672 * May cause the creation of a standard channel and the underlying
675 *----------------------------------------------------------------------
679 TclpGetDefaultStdChannel(
680 int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */
682 Tcl_Channel channel = NULL;
683 int fd = 0; /* Initializations needed to prevent */
684 int mode = 0; /* compiler warning (used before set). */
685 char *bufMode = NULL;
686 char channelName[16 + TCL_INTEGER_SPACE];
687 int channelPermissions;
688 FileState *fileState;
691 * If the channels were not created yet, create them now and
692 * store them in the static variables.
698 channelPermissions = TCL_READABLE;
703 channelPermissions = TCL_WRITABLE;
708 channelPermissions = TCL_WRITABLE;
712 panic("TclGetDefaultStdChannel: Unexpected channel type");
716 sprintf(channelName, "console%d", (int) fd);
717 fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
718 channel = Tcl_CreateChannel(&consoleChannelType, channelName,
719 (ClientData) fileState, channelPermissions);
720 fileState->fileChan = channel;
721 fileState->fileRef = fd;
724 * Set up the normal channel options for stdio handles.
727 Tcl_SetChannelOption(NULL, channel, "-translation", "cr");
728 Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode);
734 *----------------------------------------------------------------------
736 * TclpOpenFileChannel --
738 * Open a File based channel on MacOS systems.
741 * The new channel or NULL. If NULL, the output argument
742 * errorCodePtr is set to a POSIX error.
745 * May open the channel and may cause creation of a file on the
748 *----------------------------------------------------------------------
753 Tcl_Interp *interp, /* Interpreter for error reporting;
755 Tcl_Obj *pathPtr, /* Name of file to open. */
756 int mode, /* POSIX open mode. */
757 int permissions) /* If the open involves creating a
758 * file, with what modes to create
765 native = Tcl_FSGetNativePath(pathPtr);
766 if (native == NULL) {
769 chan = OpenFileChannel(native, mode, permissions, &errorCode);
772 Tcl_SetErrno(errorCode);
773 if (interp != (Tcl_Interp *) NULL) {
774 Tcl_AppendResult(interp, "couldn't open \"",
775 Tcl_GetString(pathPtr), "\": ",
776 Tcl_PosixError(interp), (char *) NULL);
785 *----------------------------------------------------------------------
789 * Opens a Macintosh file and creates a Tcl channel to control it.
795 * Will open a Macintosh file.
797 *----------------------------------------------------------------------
802 CONST char *fileName, /* Name of file to open (native). */
803 int mode, /* Mode for opening file. */
804 int permissions, /* If the open involves creating a
805 * file, with what modes to create
807 int *errorCodePtr) /* Where to store error code. */
809 int channelPermissions;
815 FileState *fileState;
816 char channelName[16 + TCL_INTEGER_SPACE];
817 ThreadSpecificData *tsdPtr;
822 * Note we use fsRdWrShPerm instead of fsRdWrPerm which allows shared
823 * writes on a file. This isn't common on a mac but is common with
824 * Windows and UNIX and the feature is used by Tcl.
827 switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
829 channelPermissions = (TCL_READABLE | TCL_WRITABLE);
830 macPermision = fsRdWrShPerm;
834 * Mac's fsRdPerm permission actually defaults to fsRdWrPerm because
835 * the Mac OS doesn't realy support write only access. We explicitly
836 * set the permission fsRdWrShPerm so that we can have shared write
839 channelPermissions = TCL_WRITABLE;
840 macPermision = fsRdWrShPerm;
844 channelPermissions = TCL_READABLE;
845 macPermision = fsRdPerm;
849 err = FSpLocationFromPath(strlen(fileName), fileName, &fileSpec);
850 if ((err != noErr) && (err != fnfErr)) {
851 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
856 if ((err == fnfErr) && (mode & O_CREAT)) {
857 err = HCreate(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, TCL_FILE_CREATOR, 'TEXT');
859 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
863 } else if ((mode & O_CREAT) && (mode & O_EXCL)) {
864 *errorCodePtr = errno = EEXIST;
869 err = HOpenDF(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, macPermision, &fileRef);
871 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
876 if (mode & O_TRUNC) {
880 sprintf(channelName, "file%d", (int) fileRef);
881 fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
882 chan = Tcl_CreateChannel(&fileChannelType, channelName,
883 (ClientData) fileState, channelPermissions);
884 if (chan == (Tcl_Channel) NULL) {
885 *errorCodePtr = errno = EFAULT;
888 ckfree((char *) fileState);
892 fileState->fileChan = chan;
893 fileState->nextPtr = tsdPtr->firstFilePtr;
894 tsdPtr->firstFilePtr = fileState;
895 fileState->volumeRef = fileSpec.vRefNum;
896 fileState->fileRef = fileRef;
897 fileState->pending = 0;
898 fileState->watchMask = 0;
899 if (mode & O_APPEND) {
900 fileState->appendMode = true;
902 fileState->appendMode = false;
905 if ((mode & O_APPEND) || (mode & O_APPEND)) {
906 if (Tcl_Seek(chan, 0, SEEK_END) < 0) {
907 *errorCodePtr = errno = EFAULT;
909 Tcl_Close(NULL, chan);
911 ckfree((char *) fileState);
920 *----------------------------------------------------------------------
922 * Tcl_MakeFileChannel --
924 * Makes a Tcl_Channel from an existing OS level file handle.
927 * The Tcl_Channel created around the preexisting OS level file handle.
932 *----------------------------------------------------------------------
936 Tcl_MakeFileChannel(handle, mode)
937 ClientData handle; /* OS level handle. */
938 int mode; /* ORed combination of TCL_READABLE and
939 * TCL_WRITABLE to indicate file mode. */
942 * Not implemented yet.
949 *----------------------------------------------------------------------
953 * Set blocking or non-blocking mode on channel. Macintosh files
954 * can never really be set to blocking or non-blocking modes.
955 * However, we don't generate an error - we just return success.
958 * 0 if successful, errno when failed.
961 * Sets the device into blocking or non-blocking mode.
963 *----------------------------------------------------------------------
968 ClientData instanceData, /* Unused. */
969 int mode) /* The mode to set. */
975 *----------------------------------------------------------------------
979 * Closes the IO channel.
982 * 0 if successful, the value of errno if failed.
985 * Closes the physical channel
987 *----------------------------------------------------------------------
992 ClientData instanceData, /* Unused. */
993 Tcl_Interp *interp) /* Unused. */
995 FileState *fileState = (FileState *) instanceData;
999 err = FSClose(fileState->fileRef);
1000 FlushVol(NULL, fileState->volumeRef);
1002 errorCode = errno = TclMacOSErrorToPosixError(err);
1003 panic("error during file close");
1006 ckfree((char *) fileState);
1007 Tcl_SetErrno(errorCode);
1012 *----------------------------------------------------------------------
1016 * Reads input from the IO channel into the buffer given. Returns
1017 * count of how many bytes were actually read, and an error indication.
1020 * A count of how many bytes were read is returned and an error
1021 * indication is returned in an output argument.
1024 * Reads input from the actual channel.
1026 *----------------------------------------------------------------------
1031 ClientData instanceData, /* Unused. */
1032 char *buffer, /* Where to store data read. */
1033 int bufSize, /* How much space is available
1035 int *errorCodePtr) /* Where to store error code. */
1037 FileState *fileState = (FileState *) instanceData;
1039 long length = bufSize;
1043 err = FSRead(fileState->fileRef, &length, buffer);
1044 if ((err == noErr) || (err == eofErr)) {
1049 *errorCodePtr = errno = EIO;
1050 case afpAccessDenied:
1051 *errorCodePtr = errno = EACCES;
1053 *errorCodePtr = errno = EINVAL;
1057 *errorCodePtr = errno;
1062 *----------------------------------------------------------------------
1066 * Writes the given output on the IO channel. Returns count of how
1067 * many characters were actually written, and an error indication.
1070 * A count of how many characters were written is returned and an
1071 * error indication is returned in an output argument.
1074 * Writes output on the actual channel.
1076 *----------------------------------------------------------------------
1081 ClientData instanceData, /* Unused. */
1082 CONST char *buffer, /* The data buffer. */
1083 int toWrite, /* How many bytes to write? */
1084 int *errorCodePtr) /* Where to store error code. */
1086 FileState *fileState = (FileState *) instanceData;
1087 long length = toWrite;
1093 if (fileState->appendMode == true) {
1094 FileSeek(instanceData, 0, SEEK_END, errorCodePtr);
1098 err = FSWrite(fileState->fileRef, &length, buffer);
1100 err = FlushFile(fileState->fileRef);
1102 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
1109 *----------------------------------------------------------------------
1113 * Seeks on an IO channel. Returns the new position.
1116 * -1 if failed, the new position if successful. If failed, it
1117 * also sets *errorCodePtr to the error code.
1120 * Moves the location at which the channel will be accessed in
1121 * future operations.
1123 *----------------------------------------------------------------------
1128 ClientData instanceData, /* Unused. */
1129 long offset, /* Offset to seek to. */
1130 int mode, /* Relative to where should we seek? */
1131 int *errorCodePtr) /* To store error code. */
1133 FileState *fileState = (FileState *) instanceData;
1138 pb.ioCompletion = NULL;
1139 pb.ioRefNum = fileState->fileRef;
1140 if (mode == SEEK_SET) {
1141 pb.ioPosMode = fsFromStart;
1142 } else if (mode == SEEK_END) {
1143 pb.ioPosMode = fsFromLEOF;
1144 } else if (mode == SEEK_CUR) {
1145 err = PBGetFPosSync((ParmBlkPtr) &pb);
1146 if (pb.ioResult == noErr) {
1148 return pb.ioPosOffset;
1150 offset += pb.ioPosOffset;
1152 pb.ioPosMode = fsFromStart;
1154 pb.ioPosOffset = offset;
1155 err = PBSetFPosSync((ParmBlkPtr) &pb);
1156 if (pb.ioResult == noErr){
1157 return pb.ioPosOffset;
1158 } else if (pb.ioResult == eofErr) {
1159 long currentEOF, newEOF;
1160 long buffer, i, length;
1162 err = PBGetEOFSync((ParmBlkPtr) &pb);
1163 currentEOF = (long) pb.ioMisc;
1164 if (mode == SEEK_SET) {
1166 } else if (mode == SEEK_END) {
1167 newEOF = offset + currentEOF;
1168 } else if (mode == SEEK_CUR) {
1169 err = PBGetFPosSync((ParmBlkPtr) &pb);
1170 newEOF = offset + pb.ioPosOffset;
1174 * Write 0's to the new EOF.
1177 pb.ioPosMode = fsFromLEOF;
1178 err = PBGetFPosSync((ParmBlkPtr) &pb);
1181 for (i = 0; i < (newEOF - currentEOF); i++) {
1182 err = FSWrite(fileState->fileRef, &length, &buffer);
1184 err = PBGetFPosSync((ParmBlkPtr) &pb);
1185 if (pb.ioResult == noErr){
1186 return pb.ioPosOffset;
1189 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
1194 *----------------------------------------------------------------------
1198 * Initialize the notifier to watch handles from this channel.
1206 *----------------------------------------------------------------------
1211 ClientData instanceData, /* The file state. */
1212 int mask) /* Events of interest; an OR-ed
1213 * combination of TCL_READABLE,
1214 * TCL_WRITABLE and TCL_EXCEPTION. */
1216 FileState *infoPtr = (FileState *) instanceData;
1217 Tcl_Time blockTime = { 0, 0 };
1219 infoPtr->watchMask = mask;
1220 if (infoPtr->watchMask) {
1221 Tcl_SetMaxBlockTime(&blockTime);
1226 *----------------------------------------------------------------------
1228 * FileThreadActionProc --
1230 * Insert or remove any thread local refs to this channel.
1236 * Changes thread local list of valid channels.
1238 *----------------------------------------------------------------------
1242 FileThreadActionProc (instanceData, action)
1243 ClientData instanceData;
1246 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
1247 FileState *infoPtr = (FileState *) instanceData;
1249 if (action == TCL_CHANNEL_THREAD_INSERT) {
1250 infoPtr->nextPtr = tsdPtr->firstFilePtr;
1251 tsdPtr->firstFilePtr = infoPtr;
1253 FileState **nextPtrPtr;
1256 for (nextPtrPtr = &(tsdPtr->firstFilePtr); (*nextPtrPtr) != NULL;
1257 nextPtrPtr = &((*nextPtrPtr)->nextPtr)) {
1258 if ((*nextPtrPtr) == infoPtr) {
1259 (*nextPtrPtr) = infoPtr->nextPtr;
1266 * This could happen if the channel was created in one thread
1267 * and then moved to another without updating the thread
1268 * local data in each thread.
1272 panic("file info ptr not on thread channel list");