📄 tclioutil.c
字号:
retVal = TCL_OK; } else { prevFsRecPtr = tmpFsRecPtr; tmpFsRecPtr = tmpFsRecPtr->nextPtr; } } Tcl_MutexUnlock(&filesystemMutex); return (retVal);}/* *---------------------------------------------------------------------- * * Tcl_FSMountsChanged -- * * Notify the filesystem that the available mounted filesystems * (or within any one filesystem type, the number or location of * mount points) have changed. * * Results: * None. * * Side effects: * The global filesystem variable 'theFilesystemEpoch' is * incremented. The effect of this is to make all cached * path representations invalid. Clearly it should only therefore * be called when it is really required! There are a few * circumstances when it should be called: * * (1) when a new filesystem is registered or unregistered. * Strictly speaking this is only necessary if the new filesystem * accepts file paths as is (normally the filesystem itself is * really a shell which hasn't yet had any mount points established * and so its 'pathInFilesystem' proc will always fail). However, * for safety, Tcl always calls this for you in these circumstances. * * (2) when additional mount points are established inside any * existing filesystem (except the native fs) * * (3) when any filesystem (except the native fs) changes the list * of available volumes. * * (4) when the mapping from a string representation of a file to * a full, normalized path changes. For example, if 'env(HOME)' * is modified, then any path containing '~' will map to a different * filesystem location. Therefore all such paths need to have * their internal representation invalidated. * * Tcl has no control over (2) and (3), so any registered filesystem * must make sure it calls this function when those situations * occur. * * (Note: the reason for the exception in 2,3 for the native * filesystem is that the native filesystem by default claims all * unknown files even if it really doesn't understand them or if * they don't exist). * *---------------------------------------------------------------------- */voidTcl_FSMountsChanged(fsPtr) Tcl_Filesystem *fsPtr;{ /* * We currently don't do anything with this parameter. We * could in the future only invalidate files for this filesystem * or otherwise take more advanced action. */ (void)fsPtr; /* * Increment the filesystem epoch counter, since existing paths * might now belong to different filesystems. */ Tcl_MutexLock(&filesystemMutex); theFilesystemEpoch++; Tcl_MutexUnlock(&filesystemMutex);}/* *---------------------------------------------------------------------- * * Tcl_FSData -- * * Retrieve the clientData field for the filesystem given, * or NULL if that filesystem is not registered. * * Results: * A clientData value, or NULL. Note that if the filesystem * was registered with a NULL clientData field, this function * will return that NULL value. * * Side effects: * None. * *---------------------------------------------------------------------- */ClientDataTcl_FSData(fsPtr) Tcl_Filesystem *fsPtr; /* The filesystem record to query. */{ ClientData retVal = NULL; FilesystemRecord *tmpFsRecPtr; tmpFsRecPtr = FsGetIterator(); /* * Traverse the 'filesystemList' looking for the particular node * whose 'fsPtr' member matches 'fsPtr' and remove that one from * the list. Ensure that the "default" node cannot be removed. */ while ((retVal == NULL) && (tmpFsRecPtr != NULL)) { if (tmpFsRecPtr->fsPtr == fsPtr) { retVal = tmpFsRecPtr->clientData; } tmpFsRecPtr = tmpFsRecPtr->nextPtr; } FsReleaseIterator(); return (retVal);}/* *--------------------------------------------------------------------------- * * FSNormalizeAbsolutePath -- * * Description: * Takes an absolute path specification and computes a 'normalized' * path from it. * * A normalized path is one which has all '../', './' removed. * Also it is one which is in the 'standard' format for the native * platform. On MacOS, Unix, this means the path must be free of * symbolic links/aliases, and on Windows it means we want the * long form, with that long form's case-dependence (which gives * us a unique, case-dependent path). * * The behaviour of this function if passed a non-absolute path * is NOT defined. * * Results: * The result is returned in a Tcl_Obj with a refCount of 1, * which is therefore owned by the caller. It must be * freed (with Tcl_DecrRefCount) by the caller when no longer needed. * * Side effects: * None (beyond the memory allocation for the result). * * Special note: * This code is based on code from Matt Newman and Jean-Claude * Wippler, with additions from Vince Darley and is copyright * those respective authors. * *--------------------------------------------------------------------------- */static Tcl_Obj*FSNormalizeAbsolutePath(interp, pathPtr) Tcl_Interp* interp; /* Interpreter to use */ Tcl_Obj *pathPtr; /* Absolute path to normalize */{ int splen = 0, nplen, eltLen, i; char *eltName; Tcl_Obj *retVal; Tcl_Obj *split; Tcl_Obj *elt; /* Split has refCount zero */ split = Tcl_FSSplitPath(pathPtr, &splen); /* * Modify the list of entries in place, by removing '.', and * removing '..' and the entry before -- unless that entry before * is the top-level entry, i.e. the name of a volume. */ nplen = 0; for (i = 0; i < splen; i++) { Tcl_ListObjIndex(NULL, split, nplen, &elt); eltName = Tcl_GetStringFromObj(elt, &eltLen); if ((eltLen == 1) && (eltName[0] == '.')) { Tcl_ListObjReplace(NULL, split, nplen, 1, 0, NULL); } else if ((eltLen == 2) && (eltName[0] == '.') && (eltName[1] == '.')) { if (nplen > 1) { nplen--; Tcl_ListObjReplace(NULL, split, nplen, 2, 0, NULL); } else { Tcl_ListObjReplace(NULL, split, nplen, 1, 0, NULL); } } else { nplen++; } } if (nplen > 0) { retVal = Tcl_FSJoinPath(split, nplen); /* * Now we have an absolute path, with no '..', '.' sequences, * but it still may not be in 'unique' form, depending on the * platform. For instance, Unix is case-sensitive, so the * path is ok. Windows is case-insensitive, and also has the * weird 'longname/shortname' thing (e.g. C:/Program Files/ and * C:/Progra~1/ are equivalent). MacOS is case-insensitive. * * Virtual file systems which may be registered may have * other criteria for normalizing a path. */ Tcl_IncrRefCount(retVal); TclNormalizeToUniquePath(interp, retVal, 0); /* * Since we know it is a normalized path, we can * actually convert this object into an FsPath for * greater efficiency */ SetFsPathFromAbsoluteNormalized(interp, retVal); } else { /* Init to an empty string */ retVal = Tcl_NewStringObj("",0); Tcl_IncrRefCount(retVal); } /* * We increment and then decrement the refCount of split to free * it. We do this right at the end, in case there are * optimisations in Tcl_FSJoinPath(split, nplen) above which would * let it make use of split more effectively if it has a refCount * of zero. Also we can't just decrement the ref count, in case * 'split' was actually returned by the join call above, in a * single-element optimisation when nplen == 1. */ Tcl_IncrRefCount(split); Tcl_DecrRefCount(split); /* This has a refCount of 1 for the caller */ return retVal;}/* *--------------------------------------------------------------------------- * * TclNormalizeToUniquePath -- * * Description: * Takes a path specification containing no ../, ./ sequences, * and converts it into a unique path for the given platform. * On MacOS, Unix, this means the path must be free of * symbolic links/aliases, and on Windows it means we want the * long form, with that long form's case-dependence (which gives * us a unique, case-dependent path). * * Results: * The pathPtr is modified in place. The return value is * the last byte offset which was recognised in the path * string. * * Side effects: * None (beyond the memory allocation for the result). * * Special notes: * If the filesystem-specific normalizePathProcs can re-introduce * ../, ./ sequences into the path, then this function will * not return the correct result. This may be possible with * symbolic links on unix/macos. * * Important assumption: if startAt is non-zero, it must point * to a directory separator that we know exists and is already * normalized (so it is important not to point to the char just * after the separator). *--------------------------------------------------------------------------- */static intTclNormalizeToUniquePath(interp, pathPtr, startAt) Tcl_Interp *interp; Tcl_Obj *pathPtr; int startAt;{ FilesystemRecord *fsRecPtr; /* * Call each of the "normalise path" functions in succession. This is * a special case, in which if we have a native filesystem handler, * we call it first. This is because the root of Tcl's filesystem * is always a native filesystem (i.e. '/' on unix is native). */ fsRecPtr = FsGetIterator(); while (fsRecPtr != NULL) { if (fsRecPtr == &nativeFilesystemRecord) { Tcl_FSNormalizePathProc *proc = fsRecPtr->fsPtr->normalizePathProc; if (proc != NULL) { startAt = (*proc)(interp, pathPtr, startAt); } break; } fsRecPtr = fsRecPtr->nextPtr; } FsReleaseIterator(); fsRecPtr = FsGetIterator(); while (fsRecPtr != NULL) { /* Skip the native system next time through */ if (fsRecPtr != &nativeFilesystemRecord) { Tcl_FSNormalizePathProc *proc = fsRecPtr->fsPtr->normalizePathProc; if (proc != NULL) { startAt = (*proc)(interp, pathPtr, startAt); } /* * We could add an efficiency check like this: * * if (retVal == length-of(pathPtr)) {break;} * * but there's not much benefit. */ } fsRecPtr = fsRecPtr->nextPtr; } FsReleaseIterator(); return (startAt);}/* *--------------------------------------------------------------------------- * * TclGetOpenMode -- * * Description: * Computes a POSIX mode mask for opening a file, from a given string, * and also sets a flag to indicate whether the caller should seek to * EOF after opening the file. * * Results: * On success, returns mode to pass to "open". If an error occurs, the * return value is -1 and if interp is not NULL, sets interp's result * object to an error message. * * Side effects: * Sets the integer referenced by seekFlagPtr to 1 to tell the caller * to seek to EOF after opening the file. * * Special note: * This code is based on a prototype implementation contributed * by Mark Diekhans. * *--------------------------------------------------------------------------- */intTclGetOpenMode(interp, string, seekFlagPtr) Tcl_Interp *interp; /* Interpreter to use for error * reporting - may be NULL. */ CONST char *string; /* Mode string, e.g. "r+" or * "RDONLY CREAT". */ int *seekFlagPtr; /* Set this to 1 if the caller * should seek to EOF during the * opening of the file. */{ int mode, modeArgc, c, i, gotRW; CONST char **modeArgv, *flag;#define RW_MODES (O_RDONLY|O_WRONLY|O_RDWR) /* * Check for the simpler fopen-like access modes (e.g. "r"). They * are distinguished from the POSIX access modes by the presence * of a lower-case first letter. */ *seekFlagPtr = 0; mode = 0; /* * Guard against international characters before using byte oriented * routines. */ if (!(string[0] & 0x80) && islower(UCHAR(string[0]))) { /* INTL: ISO only. */ switch (string[0]) { case 'r': mode = O_RDONLY; break; case 'w': mode = O_WRONLY|O_CREAT|O_TRUNC; break; case 'a': mode = O_WRONLY|O_CREAT; *seekFlagPtr = 1; break; default: error: if (interp != (Tcl_Interp *) NULL) { Tcl_AppendResult(interp, "illegal access mode \"", string, "\"", (char *) NULL); } return -1; } if (string[1] == '+') { mode &= ~(O_RDONLY|O_WRONLY); mode |= O_RDWR; if (string[2] != 0) { goto error; } } else if (string[1] != 0) { goto error; } return mode; } /* * The access modes are specified using a list of POSIX modes * such as O_CREAT. * * IMPORTANT NOTE: We rely on Tcl_SplitList working correctly when * a NULL interpreter is passed in. */ if (Tcl_SplitList(interp, string, &modeArgc, &modeArgv) != TCL_OK) { if (interp != (Tcl_Interp *) NULL) { Tcl_AddErrorInfo(interp, "\n while processing open access modes \"");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -