/[dtapublic]/projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclioutil.c
ViewVC logotype

Diff of /projs/trunk/shared_source/c_tcl_base_7_5_w_mods/tclioutil.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 70 by dashley, Sun Oct 30 21:57:38 2016 UTC revision 71 by dashley, Sat Nov 5 11:07:06 2016 UTC
# Line 1  Line 1 
1  /* $Header$ */  /* $Header$ */
2  /*  /*
3   * tclIOUtil.c --   * tclIOUtil.c --
4   *   *
5   *      This file contains a collection of utility procedures that   *      This file contains a collection of utility procedures that
6   *      are shared by the platform specific IO drivers.   *      are shared by the platform specific IO drivers.
7   *   *
8   *      Parts of this file are based on code contributed by Karl   *      Parts of this file are based on code contributed by Karl
9   *      Lehenbauer, Mark Diekhans and Peter da Silva.   *      Lehenbauer, Mark Diekhans and Peter da Silva.
10   *   *
11   * Copyright (c) 1991-1994 The Regents of the University of California.   * Copyright (c) 1991-1994 The Regents of the University of California.
12   * Copyright (c) 1994-1997 Sun Microsystems, Inc.   * Copyright (c) 1994-1997 Sun Microsystems, Inc.
13   *   *
14   * See the file "license.terms" for information on usage and redistribution   * See the file "license.terms" for information on usage and redistribution
15   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.   * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16   *   *
17   * RCS: @(#) $Id: tclioutil.c,v 1.1.1.1 2001/06/13 04:42:24 dtashley Exp $   * RCS: @(#) $Id: tclioutil.c,v 1.1.1.1 2001/06/13 04:42:24 dtashley Exp $
18   */   */
19    
20  #include "tclInt.h"  #include "tclInt.h"
21  #include "tclPort.h"  #include "tclPort.h"
22    
23  /*  /*
24   * The following typedef declarations allow for hooking into the chain   * The following typedef declarations allow for hooking into the chain
25   * of functions maintained for 'Tcl_Stat(...)', 'Tcl_Access(...)' &   * of functions maintained for 'Tcl_Stat(...)', 'Tcl_Access(...)' &
26   * 'Tcl_OpenFileChannel(...)'.  Basically for each hookable function   * 'Tcl_OpenFileChannel(...)'.  Basically for each hookable function
27   * a linked list is defined.   * a linked list is defined.
28   */   */
29    
30  typedef struct StatProc {  typedef struct StatProc {
31      TclStatProc_ *proc;          /* Function to process a 'stat()' call */      TclStatProc_ *proc;          /* Function to process a 'stat()' call */
32      struct StatProc *nextPtr;    /* The next 'stat()' function to call */      struct StatProc *nextPtr;    /* The next 'stat()' function to call */
33  } StatProc;  } StatProc;
34    
35  typedef struct AccessProc {  typedef struct AccessProc {
36      TclAccessProc_ *proc;        /* Function to process a 'access()' call */      TclAccessProc_ *proc;        /* Function to process a 'access()' call */
37      struct AccessProc *nextPtr;  /* The next 'access()' function to call */      struct AccessProc *nextPtr;  /* The next 'access()' function to call */
38  } AccessProc;  } AccessProc;
39    
40  typedef struct OpenFileChannelProc {  typedef struct OpenFileChannelProc {
41      TclOpenFileChannelProc_ *proc;  /* Function to process a      TclOpenFileChannelProc_ *proc;  /* Function to process a
42                                       * 'Tcl_OpenFileChannel()' call */                                       * 'Tcl_OpenFileChannel()' call */
43      struct OpenFileChannelProc *nextPtr;      struct OpenFileChannelProc *nextPtr;
44                                      /* The next 'Tcl_OpenFileChannel()'                                      /* The next 'Tcl_OpenFileChannel()'
45                                       * function to call */                                       * function to call */
46  } OpenFileChannelProc;  } OpenFileChannelProc;
47    
48  /*  /*
49   * For each type of hookable function, a static node is declared to   * For each type of hookable function, a static node is declared to
50   * hold the function pointer for the "built-in" routine (e.g.   * hold the function pointer for the "built-in" routine (e.g.
51   * 'TclpStat(...)') and the respective list is initialized as a pointer   * 'TclpStat(...)') and the respective list is initialized as a pointer
52   * to that node.   * to that node.
53   *   *
54   * The "delete" functions (e.g. 'TclStatDeleteProc(...)') ensure that   * The "delete" functions (e.g. 'TclStatDeleteProc(...)') ensure that
55   * these statically declared list entry cannot be inadvertently removed.   * these statically declared list entry cannot be inadvertently removed.
56   *   *
57   * This method avoids the need to call any sort of "initialization"   * This method avoids the need to call any sort of "initialization"
58   * function.   * function.
59   *   *
60   * All three lists are protected by a global hookMutex.   * All three lists are protected by a global hookMutex.
61   */   */
62    
63  static StatProc defaultStatProc = {  static StatProc defaultStatProc = {
64      &TclpStat, NULL      &TclpStat, NULL
65  };  };
66  static StatProc *statProcList = &defaultStatProc;  static StatProc *statProcList = &defaultStatProc;
67    
68  static AccessProc defaultAccessProc = {  static AccessProc defaultAccessProc = {
69      &TclpAccess, NULL      &TclpAccess, NULL
70  };  };
71  static AccessProc *accessProcList = &defaultAccessProc;  static AccessProc *accessProcList = &defaultAccessProc;
72    
73  static OpenFileChannelProc defaultOpenFileChannelProc = {  static OpenFileChannelProc defaultOpenFileChannelProc = {
74      &TclpOpenFileChannel, NULL      &TclpOpenFileChannel, NULL
75  };  };
76  static OpenFileChannelProc *openFileChannelProcList =  static OpenFileChannelProc *openFileChannelProcList =
77          &defaultOpenFileChannelProc;          &defaultOpenFileChannelProc;
78    
79  TCL_DECLARE_MUTEX(hookMutex)  TCL_DECLARE_MUTEX(hookMutex)
80    
81  /*  /*
82   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
83   *   *
84   * TclGetOpenMode --   * TclGetOpenMode --
85   *   *
86   * Description:   * Description:
87   *      Computes a POSIX mode mask for opening a file, from a given string,   *      Computes a POSIX mode mask for opening a file, from a given string,
88   *      and also sets a flag to indicate whether the caller should seek to   *      and also sets a flag to indicate whether the caller should seek to
89   *      EOF after opening the file.   *      EOF after opening the file.
90   *   *
91   * Results:   * Results:
92   *      On success, returns mode to pass to "open". If an error occurs, the   *      On success, returns mode to pass to "open". If an error occurs, the
93   *      return value is -1 and if interp is not NULL, sets interp's result   *      return value is -1 and if interp is not NULL, sets interp's result
94   *      object to an error message.   *      object to an error message.
95   *   *
96   * Side effects:   * Side effects:
97   *      Sets the integer referenced by seekFlagPtr to 1 to tell the caller   *      Sets the integer referenced by seekFlagPtr to 1 to tell the caller
98   *      to seek to EOF after opening the file.   *      to seek to EOF after opening the file.
99   *   *
100   * Special note:   * Special note:
101   *      This code is based on a prototype implementation contributed   *      This code is based on a prototype implementation contributed
102   *      by Mark Diekhans.   *      by Mark Diekhans.
103   *   *
104   *---------------------------------------------------------------------------   *---------------------------------------------------------------------------
105   */   */
106    
107  int  int
108  TclGetOpenMode(interp, string, seekFlagPtr)  TclGetOpenMode(interp, string, seekFlagPtr)
109      Tcl_Interp *interp;                 /* Interpreter to use for error      Tcl_Interp *interp;                 /* Interpreter to use for error
110                                           * reporting - may be NULL. */                                           * reporting - may be NULL. */
111      char *string;                       /* Mode string, e.g. "r+" or      char *string;                       /* Mode string, e.g. "r+" or
112                                           * "RDONLY CREAT". */                                           * "RDONLY CREAT". */
113      int *seekFlagPtr;                   /* Set this to 1 if the caller      int *seekFlagPtr;                   /* Set this to 1 if the caller
114                                           * should seek to EOF during the                                           * should seek to EOF during the
115                                           * opening of the file. */                                           * opening of the file. */
116  {  {
117      int mode, modeArgc, c, i, gotRW;      int mode, modeArgc, c, i, gotRW;
118      char **modeArgv, *flag;      char **modeArgv, *flag;
119  #define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR)  #define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR)
120    
121      /*      /*
122       * Check for the simpler fopen-like access modes (e.g. "r").  They       * Check for the simpler fopen-like access modes (e.g. "r").  They
123       * are distinguished from the POSIX access modes by the presence       * are distinguished from the POSIX access modes by the presence
124       * of a lower-case first letter.       * of a lower-case first letter.
125       */       */
126    
127      *seekFlagPtr = 0;      *seekFlagPtr = 0;
128      mode = 0;      mode = 0;
129    
130      /*      /*
131       * Guard against international characters before using byte oriented       * Guard against international characters before using byte oriented
132       * routines.       * routines.
133       */       */
134    
135      if (!(string[0] & 0x80)      if (!(string[0] & 0x80)
136              && islower(UCHAR(string[0]))) { /* INTL: ISO only. */              && islower(UCHAR(string[0]))) { /* INTL: ISO only. */
137          switch (string[0]) {          switch (string[0]) {
138              case 'r':              case 'r':
139                  mode = O_RDONLY;                  mode = O_RDONLY;
140                  break;                  break;
141              case 'w':              case 'w':
142                  mode = O_WRONLY|O_CREAT|O_TRUNC;                  mode = O_WRONLY|O_CREAT|O_TRUNC;
143                  break;                  break;
144              case 'a':              case 'a':
145                  mode = O_WRONLY|O_CREAT;                  mode = O_WRONLY|O_CREAT;
146                  *seekFlagPtr = 1;                  *seekFlagPtr = 1;
147                  break;                  break;
148              default:              default:
149                  error:                  error:
150                  if (interp != (Tcl_Interp *) NULL) {                  if (interp != (Tcl_Interp *) NULL) {
151                      Tcl_AppendResult(interp,                      Tcl_AppendResult(interp,
152                              "illegal access mode \"", string, "\"",                              "illegal access mode \"", string, "\"",
153                              (char *) NULL);                              (char *) NULL);
154                  }                  }
155                  return -1;                  return -1;
156          }          }
157          if (string[1] == '+') {          if (string[1] == '+') {
158              mode &= ~(O_RDONLY|O_WRONLY);              mode &= ~(O_RDONLY|O_WRONLY);
159              mode |= O_RDWR;              mode |= O_RDWR;
160              if (string[2] != 0) {              if (string[2] != 0) {
161                  goto error;                  goto error;
162              }              }
163          } else if (string[1] != 0) {          } else if (string[1] != 0) {
164              goto error;              goto error;
165          }          }
166          return mode;          return mode;
167      }      }
168    
169      /*      /*
170       * The access modes are specified using a list of POSIX modes       * The access modes are specified using a list of POSIX modes
171       * such as O_CREAT.       * such as O_CREAT.
172       *       *
173       * IMPORTANT NOTE: We rely on Tcl_SplitList working correctly when       * IMPORTANT NOTE: We rely on Tcl_SplitList working correctly when
174       * a NULL interpreter is passed in.       * a NULL interpreter is passed in.
175       */       */
176    
177      if (Tcl_SplitList(interp, string, &modeArgc, &modeArgv) != TCL_OK) {      if (Tcl_SplitList(interp, string, &modeArgc, &modeArgv) != TCL_OK) {
178          if (interp != (Tcl_Interp *) NULL) {          if (interp != (Tcl_Interp *) NULL) {
179              Tcl_AddErrorInfo(interp,              Tcl_AddErrorInfo(interp,
180                      "\n    while processing open access modes \"");                      "\n    while processing open access modes \"");
181              Tcl_AddErrorInfo(interp, string);              Tcl_AddErrorInfo(interp, string);
182              Tcl_AddErrorInfo(interp, "\"");              Tcl_AddErrorInfo(interp, "\"");
183          }          }
184          return -1;          return -1;
185      }      }
186            
187      gotRW = 0;      gotRW = 0;
188      for (i = 0; i < modeArgc; i++) {      for (i = 0; i < modeArgc; i++) {
189          flag = modeArgv[i];          flag = modeArgv[i];
190          c = flag[0];          c = flag[0];
191          if ((c == 'R') && (strcmp(flag, "RDONLY") == 0)) {          if ((c == 'R') && (strcmp(flag, "RDONLY") == 0)) {
192              mode = (mode & ~RW_MODES) | O_RDONLY;              mode = (mode & ~RW_MODES) | O_RDONLY;
193              gotRW = 1;              gotRW = 1;
194          } else if ((c == 'W') && (strcmp(flag, "WRONLY") == 0)) {          } else if ((c == 'W') && (strcmp(flag, "WRONLY") == 0)) {
195              mode = (mode & ~RW_MODES) | O_WRONLY;              mode = (mode & ~RW_MODES) | O_WRONLY;
196              gotRW = 1;              gotRW = 1;
197          } else if ((c == 'R') && (strcmp(flag, "RDWR") == 0)) {          } else if ((c == 'R') && (strcmp(flag, "RDWR") == 0)) {
198              mode = (mode & ~RW_MODES) | O_RDWR;              mode = (mode & ~RW_MODES) | O_RDWR;
199              gotRW = 1;              gotRW = 1;
200          } else if ((c == 'A') && (strcmp(flag, "APPEND") == 0)) {          } else if ((c == 'A') && (strcmp(flag, "APPEND") == 0)) {
201              mode |= O_APPEND;              mode |= O_APPEND;
202              *seekFlagPtr = 1;              *seekFlagPtr = 1;
203          } else if ((c == 'C') && (strcmp(flag, "CREAT") == 0)) {          } else if ((c == 'C') && (strcmp(flag, "CREAT") == 0)) {
204              mode |= O_CREAT;              mode |= O_CREAT;
205          } else if ((c == 'E') && (strcmp(flag, "EXCL") == 0)) {          } else if ((c == 'E') && (strcmp(flag, "EXCL") == 0)) {
206              mode |= O_EXCL;              mode |= O_EXCL;
207          } else if ((c == 'N') && (strcmp(flag, "NOCTTY") == 0)) {          } else if ((c == 'N') && (strcmp(flag, "NOCTTY") == 0)) {
208  #ifdef O_NOCTTY  #ifdef O_NOCTTY
209              mode |= O_NOCTTY;              mode |= O_NOCTTY;
210  #else  #else
211              if (interp != (Tcl_Interp *) NULL) {              if (interp != (Tcl_Interp *) NULL) {
212                  Tcl_AppendResult(interp, "access mode \"", flag,                  Tcl_AppendResult(interp, "access mode \"", flag,
213                          "\" not supported by this system", (char *) NULL);                          "\" not supported by this system", (char *) NULL);
214              }              }
215              ckfree((char *) modeArgv);              ckfree((char *) modeArgv);
216              return -1;              return -1;
217  #endif  #endif
218          } else if ((c == 'N') && (strcmp(flag, "NONBLOCK") == 0)) {          } else if ((c == 'N') && (strcmp(flag, "NONBLOCK") == 0)) {
219  #if defined(O_NDELAY) || defined(O_NONBLOCK)  #if defined(O_NDELAY) || defined(O_NONBLOCK)
220  #   ifdef O_NONBLOCK  #   ifdef O_NONBLOCK
221              mode |= O_NONBLOCK;              mode |= O_NONBLOCK;
222  #   else  #   else
223              mode |= O_NDELAY;              mode |= O_NDELAY;
224  #   endif  #   endif
225  #else  #else
226              if (interp != (Tcl_Interp *) NULL) {              if (interp != (Tcl_Interp *) NULL) {
227                  Tcl_AppendResult(interp, "access mode \"", flag,                  Tcl_AppendResult(interp, "access mode \"", flag,
228                          "\" not supported by this system", (char *) NULL);                          "\" not supported by this system", (char *) NULL);
229              }              }
230              ckfree((char *) modeArgv);              ckfree((char *) modeArgv);
231              return -1;              return -1;
232  #endif  #endif
233          } else if ((c == 'T') && (strcmp(flag, "TRUNC") == 0)) {          } else if ((c == 'T') && (strcmp(flag, "TRUNC") == 0)) {
234              mode |= O_TRUNC;              mode |= O_TRUNC;
235          } else {          } else {
236              if (interp != (Tcl_Interp *) NULL) {              if (interp != (Tcl_Interp *) NULL) {
237                  Tcl_AppendResult(interp, "invalid access mode \"", flag,                  Tcl_AppendResult(interp, "invalid access mode \"", flag,
238                          "\": must be RDONLY, WRONLY, RDWR, APPEND, CREAT",                          "\": must be RDONLY, WRONLY, RDWR, APPEND, CREAT",
239                          " EXCL, NOCTTY, NONBLOCK, or TRUNC", (char *) NULL);                          " EXCL, NOCTTY, NONBLOCK, or TRUNC", (char *) NULL);
240              }              }
241              ckfree((char *) modeArgv);              ckfree((char *) modeArgv);
242              return -1;              return -1;
243          }          }
244      }      }
245      ckfree((char *) modeArgv);      ckfree((char *) modeArgv);
246      if (!gotRW) {      if (!gotRW) {
247          if (interp != (Tcl_Interp *) NULL) {          if (interp != (Tcl_Interp *) NULL) {
248              Tcl_AppendResult(interp, "access mode must include either",              Tcl_AppendResult(interp, "access mode must include either",
249                      " RDONLY, WRONLY, or RDWR", (char *) NULL);                      " RDONLY, WRONLY, or RDWR", (char *) NULL);
250          }          }
251          return -1;          return -1;
252      }      }
253      return mode;      return mode;
254  }  }
255    
256  /*  /*
257   *----------------------------------------------------------------------   *----------------------------------------------------------------------
258   *   *
259   * Tcl_EvalFile --   * Tcl_EvalFile --
260   *   *
261   *      Read in a file and process the entire file as one gigantic   *      Read in a file and process the entire file as one gigantic
262   *      Tcl command.   *      Tcl command.
263   *   *
264   * Results:   * Results:
265   *      A standard Tcl result, which is either the result of executing   *      A standard Tcl result, which is either the result of executing
266   *      the file or an error indicating why the file couldn't be read.   *      the file or an error indicating why the file couldn't be read.
267   *   *
268   * Side effects:   * Side effects:
269   *      Depends on the commands in the file.   *      Depends on the commands in the file.
270   *   *
271   *----------------------------------------------------------------------   *----------------------------------------------------------------------
272   */   */
273    
274  int  int
275  Tcl_EvalFile(interp, fileName)  Tcl_EvalFile(interp, fileName)
276      Tcl_Interp *interp;         /* Interpreter in which to process file. */      Tcl_Interp *interp;         /* Interpreter in which to process file. */
277      char *fileName;             /* Name of file to process.  Tilde-substitution      char *fileName;             /* Name of file to process.  Tilde-substitution
278                                   * will be performed on this name. */                                   * will be performed on this name. */
279  {  {
280      int result, length;      int result, length;
281      struct stat statBuf;      struct stat statBuf;
282      char *oldScriptFile;      char *oldScriptFile;
283      Interp *iPtr;      Interp *iPtr;
284      Tcl_DString nameString;      Tcl_DString nameString;
285      char *name, *string;      char *name, *string;
286      Tcl_Channel chan;      Tcl_Channel chan;
287      Tcl_Obj *objPtr;      Tcl_Obj *objPtr;
288    
289      name = Tcl_TranslateFileName(interp, fileName, &nameString);      name = Tcl_TranslateFileName(interp, fileName, &nameString);
290      if (name == NULL) {      if (name == NULL) {
291          return TCL_ERROR;          return TCL_ERROR;
292      }      }
293    
294      result = TCL_ERROR;      result = TCL_ERROR;
295      objPtr = Tcl_NewObj();      objPtr = Tcl_NewObj();
296    
297      if (TclStat(name, &statBuf) == -1) {      if (TclStat(name, &statBuf) == -1) {
298          Tcl_SetErrno(errno);          Tcl_SetErrno(errno);
299          Tcl_AppendResult(interp, "couldn't read file \"", fileName,          Tcl_AppendResult(interp, "couldn't read file \"", fileName,
300                  "\": ", Tcl_PosixError(interp), (char *) NULL);                  "\": ", Tcl_PosixError(interp), (char *) NULL);
301          goto end;          goto end;
302      }      }
303      chan = Tcl_OpenFileChannel(interp, name, "r", 0644);      chan = Tcl_OpenFileChannel(interp, name, "r", 0644);
304      if (chan == (Tcl_Channel) NULL) {      if (chan == (Tcl_Channel) NULL) {
305          Tcl_ResetResult(interp);          Tcl_ResetResult(interp);
306          Tcl_AppendResult(interp, "couldn't read file \"", fileName,          Tcl_AppendResult(interp, "couldn't read file \"", fileName,
307                  "\": ", Tcl_PosixError(interp), (char *) NULL);                  "\": ", Tcl_PosixError(interp), (char *) NULL);
308          goto end;          goto end;
309      }      }
310      if (Tcl_ReadChars(chan, objPtr, -1, 0) < 0) {      if (Tcl_ReadChars(chan, objPtr, -1, 0) < 0) {
311          Tcl_Close(interp, chan);          Tcl_Close(interp, chan);
312          Tcl_AppendResult(interp, "couldn't read file \"", fileName,          Tcl_AppendResult(interp, "couldn't read file \"", fileName,
313                  "\": ", Tcl_PosixError(interp), (char *) NULL);                  "\": ", Tcl_PosixError(interp), (char *) NULL);
314          goto end;          goto end;
315      }      }
316      if (Tcl_Close(interp, chan) != TCL_OK) {      if (Tcl_Close(interp, chan) != TCL_OK) {
317          goto end;          goto end;
318      }      }
319    
320      iPtr = (Interp *) interp;      iPtr = (Interp *) interp;
321      oldScriptFile = iPtr->scriptFile;      oldScriptFile = iPtr->scriptFile;
322      iPtr->scriptFile = fileName;      iPtr->scriptFile = fileName;
323      string = Tcl_GetStringFromObj(objPtr, &length);      string = Tcl_GetStringFromObj(objPtr, &length);
324      result = Tcl_EvalEx(interp, string, length, 0);      result = Tcl_EvalEx(interp, string, length, 0);
325      iPtr->scriptFile = oldScriptFile;      iPtr->scriptFile = oldScriptFile;
326    
327      if (result == TCL_RETURN) {      if (result == TCL_RETURN) {
328          result = TclUpdateReturnInfo(iPtr);          result = TclUpdateReturnInfo(iPtr);
329      } else if (result == TCL_ERROR) {      } else if (result == TCL_ERROR) {
330          char msg[200 + TCL_INTEGER_SPACE];          char msg[200 + TCL_INTEGER_SPACE];
331    
332          /*          /*
333           * Record information telling where the error occurred.           * Record information telling where the error occurred.
334           */           */
335    
336          sprintf(msg, "\n    (file \"%.150s\" line %d)", fileName,          sprintf(msg, "\n    (file \"%.150s\" line %d)", fileName,
337                  interp->errorLine);                  interp->errorLine);
338          Tcl_AddErrorInfo(interp, msg);          Tcl_AddErrorInfo(interp, msg);
339      }      }
340    
341      end:      end:
342      Tcl_DecrRefCount(objPtr);      Tcl_DecrRefCount(objPtr);
343      Tcl_DStringFree(&nameString);      Tcl_DStringFree(&nameString);
344      return result;      return result;
345  }  }
346    
347  /*  /*
348   *----------------------------------------------------------------------   *----------------------------------------------------------------------
349   *   *
350   * Tcl_GetErrno --   * Tcl_GetErrno --
351   *   *
352   *      Gets the current value of the Tcl error code variable. This is   *      Gets the current value of the Tcl error code variable. This is
353   *      currently the global variable "errno" but could in the future   *      currently the global variable "errno" but could in the future
354   *      change to something else.   *      change to something else.
355   *   *
356   * Results:   * Results:
357   *      The value of the Tcl error code variable.   *      The value of the Tcl error code variable.
358   *   *
359   * Side effects:   * Side effects:
360   *      None. Note that the value of the Tcl error code variable is   *      None. Note that the value of the Tcl error code variable is
361   *      UNDEFINED if a call to Tcl_SetErrno did not precede this call.   *      UNDEFINED if a call to Tcl_SetErrno did not precede this call.
362   *   *
363   *----------------------------------------------------------------------   *----------------------------------------------------------------------
364   */   */
365    
366  int  int
367  Tcl_GetErrno()  Tcl_GetErrno()
368  {  {
369      return errno;      return errno;
370  }  }
371    
372  /*  /*
373   *----------------------------------------------------------------------   *----------------------------------------------------------------------
374   *   *
375   * Tcl_SetErrno --   * Tcl_SetErrno --
376   *   *
377   *      Sets the Tcl error code variable to the supplied value.   *      Sets the Tcl error code variable to the supplied value.
378   *   *
379   * Results:   * Results:
380   *      None.   *      None.
381   *   *
382   * Side effects:   * Side effects:
383   *      Modifies the value of the Tcl error code variable.   *      Modifies the value of the Tcl error code variable.
384   *   *
385   *----------------------------------------------------------------------   *----------------------------------------------------------------------
386   */   */
387    
388  void  void
389  Tcl_SetErrno(err)  Tcl_SetErrno(err)
390      int err;                    /* The new value. */      int err;                    /* The new value. */
391  {  {
392      errno = err;      errno = err;
393  }  }
394    
395  /*  /*
396   *----------------------------------------------------------------------   *----------------------------------------------------------------------
397   *   *
398   * Tcl_PosixError --   * Tcl_PosixError --
399   *   *
400   *      This procedure is typically called after UNIX kernel calls   *      This procedure is typically called after UNIX kernel calls
401   *      return errors.  It stores machine-readable information about   *      return errors.  It stores machine-readable information about
402   *      the error in $errorCode returns an information string for   *      the error in $errorCode returns an information string for
403   *      the caller's use.   *      the caller's use.
404   *   *
405   * Results:   * Results:
406   *      The return value is a human-readable string describing the   *      The return value is a human-readable string describing the
407   *      error.   *      error.
408   *   *
409   * Side effects:   * Side effects:
410   *      The global variable $errorCode is reset.   *      The global variable $errorCode is reset.
411   *   *
412   *----------------------------------------------------------------------   *----------------------------------------------------------------------
413   */   */
414    
415  char *  char *
416  Tcl_PosixError(interp)  Tcl_PosixError(interp)
417      Tcl_Interp *interp;         /* Interpreter whose $errorCode variable      Tcl_Interp *interp;         /* Interpreter whose $errorCode variable
418                                   * is to be changed. */                                   * is to be changed. */
419  {  {
420      char *id, *msg;      char *id, *msg;
421    
422      msg = Tcl_ErrnoMsg(errno);      msg = Tcl_ErrnoMsg(errno);
423      id = Tcl_ErrnoId();      id = Tcl_ErrnoId();
424      Tcl_SetErrorCode(interp, "POSIX", id, msg, (char *) NULL);      Tcl_SetErrorCode(interp, "POSIX", id, msg, (char *) NULL);
425      return msg;      return msg;
426  }  }
427    
428  /*  /*
429   *----------------------------------------------------------------------   *----------------------------------------------------------------------
430   *   *
431   * TclStat --   * TclStat --
432   *   *
433   *      This procedure replaces the library version of stat and lsat.   *      This procedure replaces the library version of stat and lsat.
434   *      The chain of functions that have been "inserted" into the   *      The chain of functions that have been "inserted" into the
435   *      'statProcList' will be called in succession until either   *      'statProcList' will be called in succession until either
436   *      a value of zero is returned, or the entire list is visited.   *      a value of zero is returned, or the entire list is visited.
437   *   *
438   * Results:   * Results:
439   *      See stat documentation.   *      See stat documentation.
440   *   *
441   * Side effects:   * Side effects:
442   *      See stat documentation.   *      See stat documentation.
443   *   *
444   *----------------------------------------------------------------------   *----------------------------------------------------------------------
445   */   */
446    
447  int  int
448  TclStat(path, buf)  TclStat(path, buf)
449      CONST char *path;           /* Path of file to stat (in current CP). */      CONST char *path;           /* Path of file to stat (in current CP). */
450      struct stat *buf;           /* Filled with results of stat call. */      struct stat *buf;           /* Filled with results of stat call. */
451  {  {
452      StatProc *statProcPtr;      StatProc *statProcPtr;
453      int retVal = -1;      int retVal = -1;
454    
455      /*      /*
456       * Call each of the "stat" function in succession.  A non-return       * Call each of the "stat" function in succession.  A non-return
457       * value of -1 indicates the particular function has succeeded.       * value of -1 indicates the particular function has succeeded.
458       */       */
459    
460      Tcl_MutexLock(&hookMutex);      Tcl_MutexLock(&hookMutex);
461      statProcPtr = statProcList;      statProcPtr = statProcList;
462      while ((retVal == -1) && (statProcPtr != NULL)) {      while ((retVal == -1) && (statProcPtr != NULL)) {
463          retVal = (*statProcPtr->proc)(path, buf);          retVal = (*statProcPtr->proc)(path, buf);
464          statProcPtr = statProcPtr->nextPtr;          statProcPtr = statProcPtr->nextPtr;
465      }      }
466      Tcl_MutexUnlock(&hookMutex);      Tcl_MutexUnlock(&hookMutex);
467    
468      return (retVal);      return (retVal);
469  }  }
470    
471  /*  /*
472   *----------------------------------------------------------------------   *----------------------------------------------------------------------
473   *   *
474   * TclAccess --   * TclAccess --
475   *   *
476   *      This procedure replaces the library version of access.   *      This procedure replaces the library version of access.
477   *      The chain of functions that have been "inserted" into the   *      The chain of functions that have been "inserted" into the
478   *      'accessProcList' will be called in succession until either   *      'accessProcList' will be called in succession until either
479   *      a value of zero is returned, or the entire list is visited.   *      a value of zero is returned, or the entire list is visited.
480   *   *
481   * Results:   * Results:
482   *      See access documentation.   *      See access documentation.
483   *   *
484   * Side effects:   * Side effects:
485   *      See access documentation.   *      See access documentation.
486   *   *
487   *----------------------------------------------------------------------   *----------------------------------------------------------------------
488   */   */
489    
490  int  int
491  TclAccess(path, mode)  TclAccess(path, mode)
492      CONST char *path;           /* Path of file to access (in current CP). */      CONST char *path;           /* Path of file to access (in current CP). */
493      int mode;                   /* Permission setting. */      int mode;                   /* Permission setting. */
494  {  {
495      AccessProc *accessProcPtr;      AccessProc *accessProcPtr;
496      int retVal = -1;      int retVal = -1;
497    
498      /*      /*
499       * Call each of the "access" function in succession.  A non-return       * Call each of the "access" function in succession.  A non-return
500       * value of -1 indicates the particular function has succeeded.       * value of -1 indicates the particular function has succeeded.
501       */       */
502    
503      Tcl_MutexLock(&hookMutex);      Tcl_MutexLock(&hookMutex);
504      accessProcPtr = accessProcList;      accessProcPtr = accessProcList;
505      while ((retVal == -1) && (accessProcPtr != NULL)) {      while ((retVal == -1) && (accessProcPtr != NULL)) {
506          retVal = (*accessProcPtr->proc)(path, mode);          retVal = (*accessProcPtr->proc)(path, mode);
507          accessProcPtr = accessProcPtr->nextPtr;          accessProcPtr = accessProcPtr->nextPtr;
508      }      }
509      Tcl_MutexUnlock(&hookMutex);      Tcl_MutexUnlock(&hookMutex);
510    
511      return (retVal);      return (retVal);
512  }  }
513    
514  /*  /*
515   *----------------------------------------------------------------------   *----------------------------------------------------------------------
516   *   *
517   * Tcl_OpenFileChannel --   * Tcl_OpenFileChannel --
518   *   *
519   *      The chain of functions that have been "inserted" into the   *      The chain of functions that have been "inserted" into the
520   *      'openFileChannelProcList' will be called in succession until   *      'openFileChannelProcList' will be called in succession until
521   *      either a valid file channel is returned, or the entire list is   *      either a valid file channel is returned, or the entire list is
522   *      visited.   *      visited.
523   *   *
524   * Results:   * Results:
525   *      The new channel or NULL, if the named file could not be opened.   *      The new channel or NULL, if the named file could not be opened.
526   *   *
527   * Side effects:   * Side effects:
528   *      May open the channel and may cause creation of a file on the   *      May open the channel and may cause creation of a file on the
529   *      file system.   *      file system.
530   *   *
531   *----------------------------------------------------------------------   *----------------------------------------------------------------------
532   */   */
533    
534  Tcl_Channel  Tcl_Channel
535  Tcl_OpenFileChannel(interp, fileName, modeString, permissions)  Tcl_OpenFileChannel(interp, fileName, modeString, permissions)
536      Tcl_Interp *interp;                 /* Interpreter for error reporting;      Tcl_Interp *interp;                 /* Interpreter for error reporting;
537                                           * can be NULL. */                                           * can be NULL. */
538      char *fileName;                     /* Name of file to open. */      char *fileName;                     /* Name of file to open. */
539      char *modeString;                   /* A list of POSIX open modes or      char *modeString;                   /* A list of POSIX open modes or
540                                           * a string such as "rw". */                                           * a string such as "rw". */
541      int permissions;                    /* If the open involves creating a      int permissions;                    /* If the open involves creating a
542                                           * file, with what modes to create                                           * file, with what modes to create
543                                           * it? */                                           * it? */
544  {  {
545      OpenFileChannelProc *openFileChannelProcPtr;      OpenFileChannelProc *openFileChannelProcPtr;
546      Tcl_Channel retVal = NULL;      Tcl_Channel retVal = NULL;
547    
548      /*      /*
549       * Call each of the "Tcl_OpenFileChannel" function in succession.       * Call each of the "Tcl_OpenFileChannel" function in succession.
550       * A non-NULL return value indicates the particular function has       * A non-NULL return value indicates the particular function has
551       * succeeded.       * succeeded.
552       */       */
553    
554      Tcl_MutexLock(&hookMutex);      Tcl_MutexLock(&hookMutex);
555      openFileChannelProcPtr = openFileChannelProcList;      openFileChannelProcPtr = openFileChannelProcList;
556      while ((retVal == NULL) && (openFileChannelProcPtr != NULL)) {      while ((retVal == NULL) && (openFileChannelProcPtr != NULL)) {
557          retVal = (*openFileChannelProcPtr->proc)(interp, fileName,          retVal = (*openFileChannelProcPtr->proc)(interp, fileName,
558                  modeString, permissions);                  modeString, permissions);
559          openFileChannelProcPtr = openFileChannelProcPtr->nextPtr;          openFileChannelProcPtr = openFileChannelProcPtr->nextPtr;
560      }      }
561      Tcl_MutexUnlock(&hookMutex);      Tcl_MutexUnlock(&hookMutex);
562    
563      return (retVal);      return (retVal);
564  }  }
565    
566  /*  /*
567   *----------------------------------------------------------------------   *----------------------------------------------------------------------
568   *   *
569   * TclStatInsertProc --   * TclStatInsertProc --
570   *   *
571   *      Insert the passed procedure pointer at the head of the list of   *      Insert the passed procedure pointer at the head of the list of
572   *      functions which are used during a call to 'TclStat(...)'. The   *      functions which are used during a call to 'TclStat(...)'. The
573   *      passed function should be have exactly like 'TclStat' when called   *      passed function should be have exactly like 'TclStat' when called
574   *      during that time (see 'TclStat(...)' for more informatin).   *      during that time (see 'TclStat(...)' for more informatin).
575   *      The function will be added even if it already in the list.   *      The function will be added even if it already in the list.
576   *   *
577   * Results:   * Results:
578   *      Normally TCL_OK; TCL_ERROR if memory for a new node in the list   *      Normally TCL_OK; TCL_ERROR if memory for a new node in the list
579   *      could not be allocated.   *      could not be allocated.
580   *   *
581   * Side effects:   * Side effects:
582   *      Memory allocataed and modifies the link list for 'TclStat'   *      Memory allocataed and modifies the link list for 'TclStat'
583   *      functions.   *      functions.
584   *   *
585   *----------------------------------------------------------------------   *----------------------------------------------------------------------
586   */   */
587    
588  int  int
589  TclStatInsertProc (proc)  TclStatInsertProc (proc)
590      TclStatProc_ *proc;      TclStatProc_ *proc;
591  {  {
592      int retVal = TCL_ERROR;      int retVal = TCL_ERROR;
593    
594      if (proc != NULL) {      if (proc != NULL) {
595          StatProc *newStatProcPtr;          StatProc *newStatProcPtr;
596    
597          newStatProcPtr = (StatProc *)ckalloc(sizeof(StatProc));          newStatProcPtr = (StatProc *)ckalloc(sizeof(StatProc));
598    
599          if (newStatProcPtr != NULL) {          if (newStatProcPtr != NULL) {
600              newStatProcPtr->proc = proc;              newStatProcPtr->proc = proc;
601              Tcl_MutexLock(&hookMutex);              Tcl_MutexLock(&hookMutex);
602              newStatProcPtr->nextPtr = statProcList;              newStatProcPtr->nextPtr = statProcList;
603              statProcList = newStatProcPtr;              statProcList = newStatProcPtr;
604              Tcl_MutexUnlock(&hookMutex);              Tcl_MutexUnlock(&hookMutex);
605    
606              retVal = TCL_OK;              retVal = TCL_OK;
607          }          }
608      }      }
609    
610      return (retVal);      return (retVal);
611  }  }
612    
613  /*  /*
614   *----------------------------------------------------------------------   *----------------------------------------------------------------------
615   *   *
616   * TclStatDeleteProc --   * TclStatDeleteProc --
617   *   *
618   *      Removed the passed function pointer from the list of 'TclStat'   *      Removed the passed function pointer from the list of 'TclStat'
619   *      functions.  Ensures that the built-in stat function is not   *      functions.  Ensures that the built-in stat function is not
620   *      removvable.   *      removvable.
621   *   *
622   * Results:   * Results:
623   *      TCL_OK if the procedure pointer was successfully removed,   *      TCL_OK if the procedure pointer was successfully removed,
624   *      TCL_ERROR otherwise.   *      TCL_ERROR otherwise.
625   *   *
626   * Side effects:   * Side effects:
627   *      Memory is deallocated and the respective list updated.   *      Memory is deallocated and the respective list updated.
628   *   *
629   *----------------------------------------------------------------------   *----------------------------------------------------------------------
630   */   */
631    
632  int  int
633  TclStatDeleteProc (proc)  TclStatDeleteProc (proc)
634      TclStatProc_ *proc;      TclStatProc_ *proc;
635  {  {
636      int retVal = TCL_ERROR;      int retVal = TCL_ERROR;
637      StatProc *tmpStatProcPtr;      StatProc *tmpStatProcPtr;
638      StatProc *prevStatProcPtr = NULL;      StatProc *prevStatProcPtr = NULL;
639    
640      Tcl_MutexLock(&hookMutex);      Tcl_MutexLock(&hookMutex);
641      tmpStatProcPtr = statProcList;      tmpStatProcPtr = statProcList;
642      /*      /*
643       * Traverse the 'statProcList' looking for the particular node       * Traverse the 'statProcList' looking for the particular node
644       * whose 'proc' member matches 'proc' and remove that one from       * whose 'proc' member matches 'proc' and remove that one from
645       * the list.  Ensure that the "default" node cannot be removed.       * the list.  Ensure that the "default" node cannot be removed.
646       */       */
647    
648      while ((retVal == TCL_ERROR) && (tmpStatProcPtr != &defaultStatProc)) {      while ((retVal == TCL_ERROR) && (tmpStatProcPtr != &defaultStatProc)) {
649          if (tmpStatProcPtr->proc == proc) {          if (tmpStatProcPtr->proc == proc) {
650              if (prevStatProcPtr == NULL) {              if (prevStatProcPtr == NULL) {
651                  statProcList = tmpStatProcPtr->nextPtr;                  statProcList = tmpStatProcPtr->nextPtr;
652              } else {              } else {
653                  prevStatProcPtr->nextPtr = tmpStatProcPtr->nextPtr;                  prevStatProcPtr->nextPtr = tmpStatProcPtr->nextPtr;
654              }              }
655    
656              Tcl_Free((char *)tmpStatProcPtr);              Tcl_Free((char *)tmpStatProcPtr);
657    
658              retVal = TCL_OK;              retVal = TCL_OK;
659          } else {          } else {
660              prevStatProcPtr = tmpStatProcPtr;              prevStatProcPtr = tmpStatProcPtr;
661              tmpStatProcPtr = tmpStatProcPtr->nextPtr;              tmpStatProcPtr = tmpStatProcPtr->nextPtr;
662          }          }
663      }      }
664    
665      Tcl_MutexUnlock(&hookMutex);      Tcl_MutexUnlock(&hookMutex);
666      return (retVal);      return (retVal);
667  }  }
668    
669  /*  /*
670   *----------------------------------------------------------------------   *----------------------------------------------------------------------
671   *   *
672   * TclAccessInsertProc --   * TclAccessInsertProc --
673   *   *
674   *      Insert the passed procedure pointer at the head of the list of   *      Insert the passed procedure pointer at the head of the list of
675   *      functions which are used during a call to 'TclAccess(...)'. The   *      functions which are used during a call to 'TclAccess(...)'. The
676   *      passed function should be have exactly like 'TclAccess' when   *      passed function should be have exactly like 'TclAccess' when
677   *      called during that time (see 'TclAccess(...)' for more informatin).   *      called during that time (see 'TclAccess(...)' for more informatin).
678   *      The function will be added even if it already in the list.   *      The function will be added even if it already in the list.
679   *   *
680   * Results:   * Results:
681   *      Normally TCL_OK; TCL_ERROR if memory for a new node in the list   *      Normally TCL_OK; TCL_ERROR if memory for a new node in the list
682   *      could not be allocated.   *      could not be allocated.
683   *   *
684   * Side effects:   * Side effects:
685   *      Memory allocataed and modifies the link list for 'TclAccess'   *      Memory allocataed and modifies the link list for 'TclAccess'
686   *      functions.   *      functions.
687   *   *
688   *----------------------------------------------------------------------   *----------------------------------------------------------------------
689   */   */
690    
691  int  int
692  TclAccessInsertProc(proc)  TclAccessInsertProc(proc)
693      TclAccessProc_ *proc;      TclAccessProc_ *proc;
694  {  {
695      int retVal = TCL_ERROR;      int retVal = TCL_ERROR;
696    
697      if (proc != NULL) {      if (proc != NULL) {
698          AccessProc *newAccessProcPtr;          AccessProc *newAccessProcPtr;
699    
700          newAccessProcPtr = (AccessProc *)ckalloc(sizeof(AccessProc));          newAccessProcPtr = (AccessProc *)ckalloc(sizeof(AccessProc));
701    
702          if (newAccessProcPtr != NULL) {          if (newAccessProcPtr != NULL) {
703              newAccessProcPtr->proc = proc;              newAccessProcPtr->proc = proc;
704              Tcl_MutexLock(&hookMutex);              Tcl_MutexLock(&hookMutex);
705              newAccessProcPtr->nextPtr = accessProcList;              newAccessProcPtr->nextPtr = accessProcList;
706              accessProcList = newAccessProcPtr;              accessProcList = newAccessProcPtr;
707              Tcl_MutexUnlock(&hookMutex);              Tcl_MutexUnlock(&hookMutex);
708    
709              retVal = TCL_OK;              retVal = TCL_OK;
710          }          }
711      }      }
712    
713      return (retVal);      return (retVal);
714  }  }
715    
716  /*  /*
717   *----------------------------------------------------------------------   *----------------------------------------------------------------------
718   *   *
719   * TclAccessDeleteProc --   * TclAccessDeleteProc --
720   *   *
721   *      Removed the passed function pointer from the list of 'TclAccess'   *      Removed the passed function pointer from the list of 'TclAccess'
722   *      functions.  Ensures that the built-in access function is not   *      functions.  Ensures that the built-in access function is not
723   *      removvable.   *      removvable.
724   *   *
725   * Results:   * Results:
726   *      TCL_OK if the procedure pointer was successfully removed,   *      TCL_OK if the procedure pointer was successfully removed,
727   *      TCL_ERROR otherwise.   *      TCL_ERROR otherwise.
728   *   *
729   * Side effects:   * Side effects:
730   *      Memory is deallocated and the respective list updated.   *      Memory is deallocated and the respective list updated.
731   *   *
732   *----------------------------------------------------------------------   *----------------------------------------------------------------------
733   */   */
734    
735  int  int
736  TclAccessDeleteProc(proc)  TclAccessDeleteProc(proc)
737      TclAccessProc_ *proc;      TclAccessProc_ *proc;
738  {  {
739      int retVal = TCL_ERROR;      int retVal = TCL_ERROR;
740      AccessProc *tmpAccessProcPtr;      AccessProc *tmpAccessProcPtr;
741      AccessProc *prevAccessProcPtr = NULL;      AccessProc *prevAccessProcPtr = NULL;
742    
743      /*      /*
744       * Traverse the 'accessProcList' looking for the particular node       * Traverse the 'accessProcList' looking for the particular node
745       * whose 'proc' member matches 'proc' and remove that one from       * whose 'proc' member matches 'proc' and remove that one from
746       * the list.  Ensure that the "default" node cannot be removed.       * the list.  Ensure that the "default" node cannot be removed.
747       */       */
748    
749      Tcl_MutexLock(&hookMutex);      Tcl_MutexLock(&hookMutex);
750      tmpAccessProcPtr = accessProcList;      tmpAccessProcPtr = accessProcList;
751      while ((retVal == TCL_ERROR) && (tmpAccessProcPtr != &defaultAccessProc)) {      while ((retVal == TCL_ERROR) && (tmpAccessProcPtr != &defaultAccessProc)) {
752          if (tmpAccessProcPtr->proc == proc) {          if (tmpAccessProcPtr->proc == proc) {
753              if (prevAccessProcPtr == NULL) {              if (prevAccessProcPtr == NULL) {
754                  accessProcList = tmpAccessProcPtr->nextPtr;                  accessProcList = tmpAccessProcPtr->nextPtr;
755              } else {              } else {
756                  prevAccessProcPtr->nextPtr = tmpAccessProcPtr->nextPtr;                  prevAccessProcPtr->nextPtr = tmpAccessProcPtr->nextPtr;
757              }              }
758    
759              Tcl_Free((char *)tmpAccessProcPtr);              Tcl_Free((char *)tmpAccessProcPtr);
760    
761              retVal = TCL_OK;              retVal = TCL_OK;
762          } else {          } else {
763              prevAccessProcPtr = tmpAccessProcPtr;              prevAccessProcPtr = tmpAccessProcPtr;
764              tmpAccessProcPtr = tmpAccessProcPtr->nextPtr;              tmpAccessProcPtr = tmpAccessProcPtr->nextPtr;
765          }          }
766      }      }
767      Tcl_MutexUnlock(&hookMutex);      Tcl_MutexUnlock(&hookMutex);
768    
769      return (retVal);      return (retVal);
770  }  }
771    
772  /*  /*
773   *----------------------------------------------------------------------   *----------------------------------------------------------------------
774   *   *
775   * TclOpenFileChannelInsertProc --   * TclOpenFileChannelInsertProc --
776   *   *
777   *      Insert the passed procedure pointer at the head of the list of   *      Insert the passed procedure pointer at the head of the list of
778   *      functions which are used during a call to   *      functions which are used during a call to
779   *      'Tcl_OpenFileChannel(...)'. The passed function should be have   *      'Tcl_OpenFileChannel(...)'. The passed function should be have
780   *      exactly like 'Tcl_OpenFileChannel' when called during that time   *      exactly like 'Tcl_OpenFileChannel' when called during that time
781   *      (see 'Tcl_OpenFileChannel(...)' for more informatin). The   *      (see 'Tcl_OpenFileChannel(...)' for more informatin). The
782   *      function will be added even if it already in the list.   *      function will be added even if it already in the list.
783   *   *
784   * Results:   * Results:
785   *      Normally TCL_OK; TCL_ERROR if memory for a new node in the list   *      Normally TCL_OK; TCL_ERROR if memory for a new node in the list
786   *      could not be allocated.   *      could not be allocated.
787   *   *
788   * Side effects:   * Side effects:
789   *      Memory allocataed and modifies the link list for   *      Memory allocataed and modifies the link list for
790   *      'Tcl_OpenFileChannel' functions.   *      'Tcl_OpenFileChannel' functions.
791   *   *
792   *----------------------------------------------------------------------   *----------------------------------------------------------------------
793   */   */
794    
795  int  int
796  TclOpenFileChannelInsertProc(proc)  TclOpenFileChannelInsertProc(proc)
797      TclOpenFileChannelProc_ *proc;      TclOpenFileChannelProc_ *proc;
798  {  {
799      int retVal = TCL_ERROR;      int retVal = TCL_ERROR;
800    
801      if (proc != NULL) {      if (proc != NULL) {
802          OpenFileChannelProc *newOpenFileChannelProcPtr;          OpenFileChannelProc *newOpenFileChannelProcPtr;
803    
804          newOpenFileChannelProcPtr =          newOpenFileChannelProcPtr =
805                  (OpenFileChannelProc *)ckalloc(sizeof(OpenFileChannelProc));                  (OpenFileChannelProc *)ckalloc(sizeof(OpenFileChannelProc));
806    
807          if (newOpenFileChannelProcPtr != NULL) {          if (newOpenFileChannelProcPtr != NULL) {
808              newOpenFileChannelProcPtr->proc = proc;              newOpenFileChannelProcPtr->proc = proc;
809              Tcl_MutexLock(&hookMutex);              Tcl_MutexLock(&hookMutex);
810              newOpenFileChannelProcPtr->nextPtr = openFileChannelProcList;              newOpenFileChannelProcPtr->nextPtr = openFileChannelProcList;
811              openFileChannelProcList = newOpenFileChannelProcPtr;              openFileChannelProcList = newOpenFileChannelProcPtr;
812              Tcl_MutexUnlock(&hookMutex);              Tcl_MutexUnlock(&hookMutex);
813    
814              retVal = TCL_OK;              retVal = TCL_OK;
815          }          }
816      }      }
817    
818      return (retVal);      return (retVal);
819  }  }
820    
821  /*  /*
822   *----------------------------------------------------------------------   *----------------------------------------------------------------------
823   *   *
824   * TclOpenFileChannelDeleteProc --   * TclOpenFileChannelDeleteProc --
825   *   *
826   *      Removed the passed function pointer from the list of   *      Removed the passed function pointer from the list of
827   *      'Tcl_OpenFileChannel' functions.  Ensures that the built-in   *      'Tcl_OpenFileChannel' functions.  Ensures that the built-in
828   *      open file channel function is not removvable.   *      open file channel function is not removvable.
829   *   *
830   * Results:   * Results:
831   *      TCL_OK if the procedure pointer was successfully removed,   *      TCL_OK if the procedure pointer was successfully removed,
832   *      TCL_ERROR otherwise.   *      TCL_ERROR otherwise.
833   *   *
834   * Side effects:   * Side effects:
835   *      Memory is deallocated and the respective list updated.   *      Memory is deallocated and the respective list updated.
836   *   *
837   *----------------------------------------------------------------------   *----------------------------------------------------------------------
838   */   */
839    
840  int  int
841  TclOpenFileChannelDeleteProc(proc)  TclOpenFileChannelDeleteProc(proc)
842      TclOpenFileChannelProc_ *proc;      TclOpenFileChannelProc_ *proc;
843  {  {
844      int retVal = TCL_ERROR;      int retVal = TCL_ERROR;
845      OpenFileChannelProc *tmpOpenFileChannelProcPtr = openFileChannelProcList;      OpenFileChannelProc *tmpOpenFileChannelProcPtr = openFileChannelProcList;
846      OpenFileChannelProc *prevOpenFileChannelProcPtr = NULL;      OpenFileChannelProc *prevOpenFileChannelProcPtr = NULL;
847    
848      /*      /*
849       * Traverse the 'openFileChannelProcList' looking for the particular       * Traverse the 'openFileChannelProcList' looking for the particular
850       * node whose 'proc' member matches 'proc' and remove that one from       * node whose 'proc' member matches 'proc' and remove that one from
851       * the list.  Ensure that the "default" node cannot be removed.       * the list.  Ensure that the "default" node cannot be removed.
852       */       */
853    
854      Tcl_MutexLock(&hookMutex);      Tcl_MutexLock(&hookMutex);
855      tmpOpenFileChannelProcPtr = openFileChannelProcList;      tmpOpenFileChannelProcPtr = openFileChannelProcList;
856      while ((retVal == TCL_ERROR) &&      while ((retVal == TCL_ERROR) &&
857              (tmpOpenFileChannelProcPtr != &defaultOpenFileChannelProc)) {              (tmpOpenFileChannelProcPtr != &defaultOpenFileChannelProc)) {
858          if (tmpOpenFileChannelProcPtr->proc == proc) {          if (tmpOpenFileChannelProcPtr->proc == proc) {
859              if (prevOpenFileChannelProcPtr == NULL) {              if (prevOpenFileChannelProcPtr == NULL) {
860                  openFileChannelProcList = tmpOpenFileChannelProcPtr->nextPtr;                  openFileChannelProcList = tmpOpenFileChannelProcPtr->nextPtr;
861              } else {              } else {
862                  prevOpenFileChannelProcPtr->nextPtr =                  prevOpenFileChannelProcPtr->nextPtr =
863                          tmpOpenFileChannelProcPtr->nextPtr;                          tmpOpenFileChannelProcPtr->nextPtr;
864              }              }
865    
866              Tcl_Free((char *)tmpOpenFileChannelProcPtr);              Tcl_Free((char *)tmpOpenFileChannelProcPtr);
867    
868              retVal = TCL_OK;              retVal = TCL_OK;
869          } else {          } else {
870              prevOpenFileChannelProcPtr = tmpOpenFileChannelProcPtr;              prevOpenFileChannelProcPtr = tmpOpenFileChannelProcPtr;
871              tmpOpenFileChannelProcPtr = tmpOpenFileChannelProcPtr->nextPtr;              tmpOpenFileChannelProcPtr = tmpOpenFileChannelProcPtr->nextPtr;
872          }          }
873      }      }
874      Tcl_MutexUnlock(&hookMutex);      Tcl_MutexUnlock(&hookMutex);
875    
876      return (retVal);      return (retVal);
877  }  }
878    
879  /* End of tclioutil.c */  /* End of tclioutil.c */

Legend:
Removed from v.70  
changed lines
  Added in v.71

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25