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.
17 #include "tclMacInt.h"
22 #include <Processes.h>
24 #include <FSpCompat.h>
25 #include <MoreFiles.h>
26 #include <MoreFilesExtras.h>
30 #define TCL_FILE_CREATOR (__getcreator(0))
32 #define TCL_FILE_CREATOR 'MPW '
36 * This structure describes per-instance state of a
37 * macintosh file based channel.
40 typedef struct FileState {
41 short fileRef; /* Macintosh file reference number. */
42 Tcl_Channel fileChan; /* Pointer to the channel for this file. */
43 int watchMask; /* OR'ed set of flags indicating which events
44 * are being watched. */
45 int appendMode; /* Flag to tell if in O_APPEND mode or not. */
46 int volumeRef; /* Flag to tell if in O_APPEND mode or not. */
47 int pending; /* 1 if message is pending on queue. */
48 struct FileState *nextPtr; /* Pointer to next registered file. */
51 typedef struct ThreadSpecificData {
52 int initialized; /* True after the thread initializes */
53 FileState *firstFilePtr; /* the head of the list of files managed
54 * that are being watched for file events. */
55 Tcl_Channel stdinChannel;
56 Tcl_Channel stdoutChannel; /* Note - these seem unused */
57 Tcl_Channel stderrChannel;
60 static Tcl_ThreadDataKey dataKey;
63 * The following structure is what is added to the Tcl event queue when
64 * file events are generated.
67 typedef struct FileEvent {
68 Tcl_Event header; /* Information that is standard for
70 FileState *infoPtr; /* Pointer to file info structure. Note
71 * that we still have to verify that the
72 * file exists before dereferencing this
78 * Static routines for this file:
81 static int CommonGetHandle _ANSI_ARGS_((ClientData instanceData,
82 int direction, ClientData *handlePtr));
83 static void CommonWatch _ANSI_ARGS_((ClientData instanceData,
85 static int FileBlockMode _ANSI_ARGS_((ClientData instanceData,
87 static void FileChannelExitHandler _ANSI_ARGS_((
88 ClientData clientData));
89 static void FileCheckProc _ANSI_ARGS_((ClientData clientData,
91 static int FileClose _ANSI_ARGS_((ClientData instanceData,
93 static int FileEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
95 static ThreadSpecificData *FileInit _ANSI_ARGS_((void));
96 static int FileInput _ANSI_ARGS_((ClientData instanceData,
97 char *buf, int toRead, int *errorCode));
98 static int FileOutput _ANSI_ARGS_((ClientData instanceData,
99 CONST char *buf, int toWrite, int *errorCode));
100 static int FileSeek _ANSI_ARGS_((ClientData instanceData,
101 long offset, int mode, int *errorCode));
102 static void FileSetupProc _ANSI_ARGS_((ClientData clientData,
104 static Tcl_Channel OpenFileChannel _ANSI_ARGS_((CONST char *fileName,
105 int mode, int permissions, int *errorCodePtr));
106 static int StdIOBlockMode _ANSI_ARGS_((ClientData instanceData,
108 static int StdIOClose _ANSI_ARGS_((ClientData instanceData,
109 Tcl_Interp *interp));
110 static int StdIOInput _ANSI_ARGS_((ClientData instanceData,
111 char *buf, int toRead, int *errorCode));
112 static int StdIOOutput _ANSI_ARGS_((ClientData instanceData,
113 CONST char *buf, int toWrite, int *errorCode));
114 static int StdIOSeek _ANSI_ARGS_((ClientData instanceData,
115 long offset, int mode, int *errorCode));
116 static int StdReady _ANSI_ARGS_((ClientData instanceData,
120 * This structure describes the channel type structure for file based IO:
123 static Tcl_ChannelType consoleChannelType = {
124 "file", /* Type name. */
125 (Tcl_ChannelTypeVersion)StdIOBlockMode, /* Set blocking/nonblocking mode.*/
126 StdIOClose, /* Close proc. */
127 StdIOInput, /* Input proc. */
128 StdIOOutput, /* Output proc. */
129 StdIOSeek, /* Seek proc. */
130 NULL, /* Set option proc. */
131 NULL, /* Get option proc. */
132 CommonWatch, /* Initialize notifier. */
133 CommonGetHandle /* Get OS handles out of channel. */
137 * This variable describes the channel type structure for file based IO.
140 static Tcl_ChannelType fileChannelType = {
141 "file", /* Type name. */
142 (Tcl_ChannelTypeVersion)FileBlockMode, /* Set blocking or
143 * non-blocking mode.*/
144 FileClose, /* Close proc. */
145 FileInput, /* Input proc. */
146 FileOutput, /* Output proc. */
147 FileSeek, /* Seek proc. */
148 NULL, /* Set option proc. */
149 NULL, /* Get option proc. */
150 CommonWatch, /* Initialize notifier. */
151 CommonGetHandle /* Get OS handles out of channel. */
156 * Hack to allow Mac Tk to override the TclGetStdChannels function.
159 typedef void (*TclGetStdChannelsProc) _ANSI_ARGS_((Tcl_Channel *stdinPtr,
160 Tcl_Channel *stdoutPtr, Tcl_Channel *stderrPtr));
162 TclGetStdChannelsProc getStdChannelsProc = NULL;
166 *----------------------------------------------------------------------
170 * This function initializes the file channel event source.
176 * Creates a new event source.
178 *----------------------------------------------------------------------
181 static ThreadSpecificData *
184 ThreadSpecificData *tsdPtr =
185 (ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);
186 if (tsdPtr == NULL) {
187 tsdPtr = TCL_TSD_INIT(&dataKey);
188 tsdPtr->firstFilePtr = NULL;
189 Tcl_CreateEventSource(FileSetupProc, FileCheckProc, NULL);
190 Tcl_CreateThreadExitHandler(FileChannelExitHandler, NULL);
196 *----------------------------------------------------------------------
198 * FileChannelExitHandler --
200 * This function is called to cleanup the channel driver before
207 * Destroys the communication window.
209 *----------------------------------------------------------------------
213 FileChannelExitHandler(
214 ClientData clientData) /* Old window proc */
216 Tcl_DeleteEventSource(FileSetupProc, FileCheckProc, NULL);
220 *----------------------------------------------------------------------
224 * This procedure is invoked before Tcl_DoOneEvent blocks waiting
231 * Adjusts the block time if needed.
233 *----------------------------------------------------------------------
238 ClientData data, /* Not used. */
239 int flags) /* Event flags as passed to Tcl_DoOneEvent. */
242 Tcl_Time blockTime = { 0, 0 };
243 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
245 if (!(flags & TCL_FILE_EVENTS)) {
250 * Check to see if there is a ready file. If so, poll.
253 for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
254 infoPtr = infoPtr->nextPtr) {
255 if (infoPtr->watchMask) {
256 Tcl_SetMaxBlockTime(&blockTime);
263 *----------------------------------------------------------------------
267 * This procedure is called by Tcl_DoOneEvent to check the file
268 * event source for events.
274 * May queue an event.
276 *----------------------------------------------------------------------
281 ClientData data, /* Not used. */
282 int flags) /* Event flags as passed to Tcl_DoOneEvent. */
287 Tcl_Time blockTime = { 0, 0 };
288 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
290 if (!(flags & TCL_FILE_EVENTS)) {
295 * Queue events for any ready files that don't already have events
296 * queued (caused by persistent states that won't generate WinSock
300 for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
301 infoPtr = infoPtr->nextPtr) {
302 if (infoPtr->watchMask && !infoPtr->pending) {
303 infoPtr->pending = 1;
304 evPtr = (FileEvent *) ckalloc(sizeof(FileEvent));
305 evPtr->header.proc = FileEventProc;
306 evPtr->infoPtr = infoPtr;
307 Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL);
312 /*----------------------------------------------------------------------
316 * This function is invoked by Tcl_ServiceEvent when a file event
317 * reaches the front of the event queue. This procedure invokes
318 * Tcl_NotifyChannel on the file.
321 * Returns 1 if the event was handled, meaning it should be removed
322 * from the queue. Returns 0 if the event was not handled, meaning
323 * it should stay on the queue. The only time the event isn't
324 * handled is if the TCL_FILE_EVENTS flag bit isn't set.
327 * Whatever the notifier callback does.
329 *----------------------------------------------------------------------
334 Tcl_Event *evPtr, /* Event to service. */
335 int flags) /* Flags that indicate what events to
336 * handle, such as TCL_FILE_EVENTS. */
338 FileEvent *fileEvPtr = (FileEvent *)evPtr;
340 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
342 if (!(flags & TCL_FILE_EVENTS)) {
347 * Search through the list of watched files for the one whose handle
348 * matches the event. We do this rather than simply dereferencing
349 * the handle in the event so that files can be deleted while the
350 * event is in the queue.
353 for (infoPtr = tsdPtr->firstFilePtr; infoPtr != NULL;
354 infoPtr = infoPtr->nextPtr) {
355 if (fileEvPtr->infoPtr == infoPtr) {
356 infoPtr->pending = 0;
357 Tcl_NotifyChannel(infoPtr->fileChan, infoPtr->watchMask);
365 *----------------------------------------------------------------------
369 * Set blocking or non-blocking mode on channel.
372 * 0 if successful, errno when failed.
375 * Sets the device into blocking or non-blocking mode.
377 *----------------------------------------------------------------------
382 ClientData instanceData, /* Unused. */
383 int mode) /* The mode to set. */
386 * Do not allow putting stdin, stdout or stderr into nonblocking mode.
389 if (mode == TCL_MODE_NONBLOCKING) {
397 *----------------------------------------------------------------------
401 * Closes the IO channel.
404 * 0 if successful, the value of errno if failed.
407 * Closes the physical channel
409 *----------------------------------------------------------------------
414 ClientData instanceData, /* Unused. */
415 Tcl_Interp *interp) /* Unused. */
417 int fd, errorCode = 0;
418 ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
421 * Invalidate the stdio cache if necessary. Note that we assume that
422 * the stdio file and channel pointers will become invalid at the same
424 * Do not close standard channels while in thread-exit.
427 fd = (int) ((FileState*)instanceData)->fileRef;
430 tsdPtr->stdinChannel = NULL;
431 } else if (fd == 1) {
432 tsdPtr->stdoutChannel = NULL;
433 } else if (fd == 2) {
434 tsdPtr->stderrChannel = NULL;
436 panic("recieved invalid std file");
447 *----------------------------------------------------------------------
451 * Called from Tcl_GetChannelHandle to retrieve OS handles from inside
452 * a file based channel.
455 * The appropriate handle or NULL if not present.
460 *----------------------------------------------------------------------
465 ClientData instanceData, /* The file state. */
466 int direction, /* Which handle to retrieve? */
467 ClientData *handlePtr)
469 if ((direction == TCL_READABLE) || (direction == TCL_WRITABLE)) {
470 *handlePtr = (ClientData) ((FileState*)instanceData)->fileRef;
477 *----------------------------------------------------------------------
481 * Reads input from the IO channel into the buffer given. Returns
482 * count of how many bytes were actually read, and an error indication.
485 * A count of how many bytes were read is returned and an error
486 * indication is returned in an output argument.
489 * Reads input from the actual channel.
491 *----------------------------------------------------------------------
496 ClientData instanceData, /* Unused. */
497 char *buf, /* Where to store data read. */
498 int bufSize, /* How much space is available
500 int *errorCode) /* Where to store error code. */
503 int bytesRead; /* How many bytes were read? */
507 fd = (int) ((FileState*)instanceData)->fileRef;
508 bytesRead = read(fd, buf, (size_t) bufSize);
509 if (bytesRead > -1) {
517 *----------------------------------------------------------------------
521 * Writes the given output on the IO channel. Returns count of how
522 * many characters were actually written, and an error indication.
525 * A count of how many characters were written is returned and an
526 * error indication is returned in an output argument.
529 * Writes output on the actual channel.
531 *----------------------------------------------------------------------
536 ClientData instanceData, /* Unused. */
537 CONST char *buf, /* The data buffer. */
538 int toWrite, /* How many bytes to write? */
539 int *errorCode) /* Where to store error code. */
546 fd = (int) ((FileState*)instanceData)->fileRef;
547 written = write(fd, (void*)buf, (size_t) toWrite);
556 *----------------------------------------------------------------------
560 * Seeks on an IO channel. Returns the new position.
563 * -1 if failed, the new position if successful. If failed, it
564 * also sets *errorCodePtr to the error code.
567 * Moves the location at which the channel will be accessed in
570 *----------------------------------------------------------------------
575 ClientData instanceData, /* Unused. */
576 long offset, /* Offset to seek to. */
577 int mode, /* Relative to where should we seek? */
578 int *errorCodePtr) /* To store error code. */
584 fd = (int) ((FileState*)instanceData)->fileRef;
585 newLoc = lseek(fd, offset, mode);
589 *errorCodePtr = errno;
594 *----------------------------------------------------------------------
598 * This procedure is invoked to process the "pid" Tcl command.
599 * See the user documentation for details on what it does.
602 * A standard Tcl result.
605 * See the user documentation.
607 *----------------------------------------------------------------------
612 Tcl_PidObjCmd(dummy, interp, objc, objv)
613 ClientData dummy; /* Not used. */
614 Tcl_Interp *interp; /* Current interpreter. */
615 int objc; /* Number of arguments. */
616 Tcl_Obj *CONST *objv; /* Argument strings. */
618 ProcessSerialNumber psn;
624 Tcl_WrongNumArgs(interp, 1, objv, "?channelId?");
628 resultPtr = Tcl_GetObjResult(interp);
629 GetCurrentProcess(&psn);
630 sprintf(buf, "0x%08x%08x", psn.highLongOfPSN, psn.lowLongOfPSN);
631 Tcl_SetStringObj(resultPtr, buf, -1);
633 chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]),
635 if (chan == (Tcl_Channel) NULL) {
639 * We can't create pipelines on the Mac so
640 * this will always return an empty list.
648 *----------------------------------------------------------------------
650 * TclpGetDefaultStdChannel --
652 * Constructs a channel for the specified standard OS handle.
655 * Returns the specified default standard channel, or NULL.
658 * May cause the creation of a standard channel and the underlying
661 *----------------------------------------------------------------------
665 TclpGetDefaultStdChannel(
666 int type) /* One of TCL_STDIN, TCL_STDOUT, TCL_STDERR. */
668 Tcl_Channel channel = NULL;
669 int fd = 0; /* Initializations needed to prevent */
670 int mode = 0; /* compiler warning (used before set). */
671 char *bufMode = NULL;
672 char channelName[16 + TCL_INTEGER_SPACE];
673 int channelPermissions;
674 FileState *fileState;
677 * If the channels were not created yet, create them now and
678 * store them in the static variables.
684 channelPermissions = TCL_READABLE;
689 channelPermissions = TCL_WRITABLE;
694 channelPermissions = TCL_WRITABLE;
698 panic("TclGetDefaultStdChannel: Unexpected channel type");
702 sprintf(channelName, "console%d", (int) fd);
703 fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
704 channel = Tcl_CreateChannel(&consoleChannelType, channelName,
705 (ClientData) fileState, channelPermissions);
706 fileState->fileChan = channel;
707 fileState->fileRef = fd;
710 * Set up the normal channel options for stdio handles.
713 Tcl_SetChannelOption(NULL, channel, "-translation", "cr");
714 Tcl_SetChannelOption(NULL, channel, "-buffering", bufMode);
720 *----------------------------------------------------------------------
722 * TclpOpenFileChannel --
724 * Open a File based channel on MacOS systems.
727 * The new channel or NULL. If NULL, the output argument
728 * errorCodePtr is set to a POSIX error.
731 * May open the channel and may cause creation of a file on the
734 *----------------------------------------------------------------------
739 Tcl_Interp *interp, /* Interpreter for error reporting;
741 Tcl_Obj *pathPtr, /* Name of file to open. */
742 int mode, /* POSIX open mode. */
743 int permissions) /* If the open involves creating a
744 * file, with what modes to create
751 native = Tcl_FSGetNativePath(pathPtr);
752 if (native == NULL) {
755 chan = OpenFileChannel(native, mode, permissions, &errorCode);
758 Tcl_SetErrno(errorCode);
759 if (interp != (Tcl_Interp *) NULL) {
760 Tcl_AppendResult(interp, "couldn't open \"",
761 Tcl_GetString(pathPtr), "\": ",
762 Tcl_PosixError(interp), (char *) NULL);
771 *----------------------------------------------------------------------
775 * Opens a Macintosh file and creates a Tcl channel to control it.
781 * Will open a Macintosh file.
783 *----------------------------------------------------------------------
788 CONST char *fileName, /* Name of file to open (native). */
789 int mode, /* Mode for opening file. */
790 int permissions, /* If the open involves creating a
791 * file, with what modes to create
793 int *errorCodePtr) /* Where to store error code. */
795 int channelPermissions;
801 FileState *fileState;
802 char channelName[16 + TCL_INTEGER_SPACE];
805 * Note we use fsRdWrShPerm instead of fsRdWrPerm which allows shared
806 * writes on a file. This isn't common on a mac but is common with
807 * Windows and UNIX and the feature is used by Tcl.
810 switch (mode & (O_RDONLY | O_WRONLY | O_RDWR)) {
812 channelPermissions = (TCL_READABLE | TCL_WRITABLE);
813 macPermision = fsRdWrShPerm;
817 * Mac's fsRdPerm permission actually defaults to fsRdWrPerm because
818 * the Mac OS doesn't realy support write only access. We explicitly
819 * set the permission fsRdWrShPerm so that we can have shared write
822 channelPermissions = TCL_WRITABLE;
823 macPermision = fsRdWrShPerm;
827 channelPermissions = TCL_READABLE;
828 macPermision = fsRdPerm;
832 err = FSpLocationFromPath(strlen(fileName), fileName, &fileSpec);
833 if ((err != noErr) && (err != fnfErr)) {
834 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
839 if ((err == fnfErr) && (mode & O_CREAT)) {
840 err = HCreate(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, TCL_FILE_CREATOR, 'TEXT');
842 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
846 } else if ((mode & O_CREAT) && (mode & O_EXCL)) {
847 *errorCodePtr = errno = EEXIST;
852 err = HOpenDF(fileSpec.vRefNum, fileSpec.parID, fileSpec.name, macPermision, &fileRef);
854 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
859 if (mode & O_TRUNC) {
863 sprintf(channelName, "file%d", (int) fileRef);
864 fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
865 chan = Tcl_CreateChannel(&fileChannelType, channelName,
866 (ClientData) fileState, channelPermissions);
867 if (chan == (Tcl_Channel) NULL) {
868 *errorCodePtr = errno = EFAULT;
871 ckfree((char *) fileState);
875 fileState->fileChan = chan;
876 fileState->volumeRef = fileSpec.vRefNum;
877 fileState->fileRef = fileRef;
878 fileState->pending = 0;
879 fileState->watchMask = 0;
880 if (mode & O_APPEND) {
881 fileState->appendMode = true;
883 fileState->appendMode = false;
886 if ((mode & O_APPEND) || (mode & O_APPEND)) {
887 if (Tcl_Seek(chan, 0, SEEK_END) < 0) {
888 *errorCodePtr = errno = EFAULT;
890 Tcl_Close(NULL, chan);
892 ckfree((char *) fileState);
901 *----------------------------------------------------------------------
903 * Tcl_MakeFileChannel --
905 * Makes a Tcl_Channel from an existing OS level file handle.
908 * The Tcl_Channel created around the preexisting OS level file handle.
913 *----------------------------------------------------------------------
917 Tcl_MakeFileChannel(handle, mode)
918 ClientData handle; /* OS level handle. */
919 int mode; /* ORed combination of TCL_READABLE and
920 * TCL_WRITABLE to indicate file mode. */
923 * Not implemented yet.
930 *----------------------------------------------------------------------
934 * Set blocking or non-blocking mode on channel. Macintosh files
935 * can never really be set to blocking or non-blocking modes.
936 * However, we don't generate an error - we just return success.
939 * 0 if successful, errno when failed.
942 * Sets the device into blocking or non-blocking mode.
944 *----------------------------------------------------------------------
949 ClientData instanceData, /* Unused. */
950 int mode) /* The mode to set. */
956 *----------------------------------------------------------------------
960 * Closes the IO channel.
963 * 0 if successful, the value of errno if failed.
966 * Closes the physical channel
968 *----------------------------------------------------------------------
973 ClientData instanceData, /* Unused. */
974 Tcl_Interp *interp) /* Unused. */
976 FileState *fileState = (FileState *) instanceData;
980 err = FSClose(fileState->fileRef);
981 FlushVol(NULL, fileState->volumeRef);
983 errorCode = errno = TclMacOSErrorToPosixError(err);
984 panic("error during file close");
987 ckfree((char *) fileState);
988 Tcl_SetErrno(errorCode);
993 *----------------------------------------------------------------------
997 * Reads input from the IO channel into the buffer given. Returns
998 * count of how many bytes were actually read, and an error indication.
1001 * A count of how many bytes were read is returned and an error
1002 * indication is returned in an output argument.
1005 * Reads input from the actual channel.
1007 *----------------------------------------------------------------------
1012 ClientData instanceData, /* Unused. */
1013 char *buffer, /* Where to store data read. */
1014 int bufSize, /* How much space is available
1016 int *errorCodePtr) /* Where to store error code. */
1018 FileState *fileState = (FileState *) instanceData;
1020 long length = bufSize;
1024 err = FSRead(fileState->fileRef, &length, buffer);
1025 if ((err == noErr) || (err == eofErr)) {
1030 *errorCodePtr = errno = EIO;
1031 case afpAccessDenied:
1032 *errorCodePtr = errno = EACCES;
1034 *errorCodePtr = errno = EINVAL;
1038 *errorCodePtr = errno;
1043 *----------------------------------------------------------------------
1047 * Writes the given output on the IO channel. Returns count of how
1048 * many characters were actually written, and an error indication.
1051 * A count of how many characters were written is returned and an
1052 * error indication is returned in an output argument.
1055 * Writes output on the actual channel.
1057 *----------------------------------------------------------------------
1062 ClientData instanceData, /* Unused. */
1063 CONST char *buffer, /* The data buffer. */
1064 int toWrite, /* How many bytes to write? */
1065 int *errorCodePtr) /* Where to store error code. */
1067 FileState *fileState = (FileState *) instanceData;
1068 long length = toWrite;
1074 if (fileState->appendMode == true) {
1075 FileSeek(instanceData, 0, SEEK_END, errorCodePtr);
1079 err = FSWrite(fileState->fileRef, &length, buffer);
1081 err = FlushFile(fileState->fileRef);
1083 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
1090 *----------------------------------------------------------------------
1094 * Seeks on an IO channel. Returns the new position.
1097 * -1 if failed, the new position if successful. If failed, it
1098 * also sets *errorCodePtr to the error code.
1101 * Moves the location at which the channel will be accessed in
1102 * future operations.
1104 *----------------------------------------------------------------------
1109 ClientData instanceData, /* Unused. */
1110 long offset, /* Offset to seek to. */
1111 int mode, /* Relative to where should we seek? */
1112 int *errorCodePtr) /* To store error code. */
1114 FileState *fileState = (FileState *) instanceData;
1119 pb.ioCompletion = NULL;
1120 pb.ioRefNum = fileState->fileRef;
1121 if (mode == SEEK_SET) {
1122 pb.ioPosMode = fsFromStart;
1123 } else if (mode == SEEK_END) {
1124 pb.ioPosMode = fsFromLEOF;
1125 } else if (mode == SEEK_CUR) {
1126 err = PBGetFPosSync((ParmBlkPtr) &pb);
1127 if (pb.ioResult == noErr) {
1129 return pb.ioPosOffset;
1131 offset += pb.ioPosOffset;
1133 pb.ioPosMode = fsFromStart;
1135 pb.ioPosOffset = offset;
1136 err = PBSetFPosSync((ParmBlkPtr) &pb);
1137 if (pb.ioResult == noErr){
1138 return pb.ioPosOffset;
1139 } else if (pb.ioResult == eofErr) {
1140 long currentEOF, newEOF;
1141 long buffer, i, length;
1143 err = PBGetEOFSync((ParmBlkPtr) &pb);
1144 currentEOF = (long) pb.ioMisc;
1145 if (mode == SEEK_SET) {
1147 } else if (mode == SEEK_END) {
1148 newEOF = offset + currentEOF;
1149 } else if (mode == SEEK_CUR) {
1150 err = PBGetFPosSync((ParmBlkPtr) &pb);
1151 newEOF = offset + pb.ioPosOffset;
1155 * Write 0's to the new EOF.
1158 pb.ioPosMode = fsFromLEOF;
1159 err = PBGetFPosSync((ParmBlkPtr) &pb);
1162 for (i = 0; i < (newEOF - currentEOF); i++) {
1163 err = FSWrite(fileState->fileRef, &length, &buffer);
1165 err = PBGetFPosSync((ParmBlkPtr) &pb);
1166 if (pb.ioResult == noErr){
1167 return pb.ioPosOffset;
1170 *errorCodePtr = errno = TclMacOSErrorToPosixError(err);
1175 *----------------------------------------------------------------------
1179 * Initialize the notifier to watch handles from this channel.
1187 *----------------------------------------------------------------------
1192 ClientData instanceData, /* The file state. */
1193 int mask) /* Events of interest; an OR-ed
1194 * combination of TCL_READABLE,
1195 * TCL_WRITABLE and TCL_EXCEPTION. */
1197 FileState **nextPtrPtr, *ptr;
1198 FileState *infoPtr = (FileState *) instanceData;
1199 int oldMask = infoPtr->watchMask;
1200 ThreadSpecificData *tsdPtr;
1202 tsdPtr = FileInit();
1204 infoPtr->watchMask = mask;
1205 if (infoPtr->watchMask) {
1207 infoPtr->nextPtr = tsdPtr->firstFilePtr;
1208 tsdPtr->firstFilePtr = infoPtr;
1213 * Remove the file from the list of watched files.
1216 for (nextPtrPtr = &(tsdPtr->firstFilePtr), ptr = *nextPtrPtr;
1218 nextPtrPtr = &ptr->nextPtr, ptr = *nextPtrPtr) {
1219 if (infoPtr == ptr) {
1220 *nextPtrPtr = ptr->nextPtr;