diff options
author | vincentdarley <vincentdarley> | 2004-01-21 19:59:32 (GMT) |
---|---|---|
committer | vincentdarley <vincentdarley> | 2004-01-21 19:59:32 (GMT) |
commit | aa7a81aef5d2a5e07732a9d10432071098bbe532 (patch) | |
tree | 0ffe5e984dd325a6bea1e24606e505aa4f37574b /generic/tclPathObj.c | |
parent | 255a92739ba23b8db77bffe62d4f6e3ef06d099f (diff) | |
download | tcl-aa7a81aef5d2a5e07732a9d10432071098bbe532.zip tcl-aa7a81aef5d2a5e07732a9d10432071098bbe532.tar.gz tcl-aa7a81aef5d2a5e07732a9d10432071098bbe532.tar.bz2 |
filesystem optimisation -- Three main issues accomplished: (1) cleaned up variable names in
Diffstat (limited to 'generic/tclPathObj.c')
-rw-r--r-- | generic/tclPathObj.c | 752 |
1 files changed, 541 insertions, 211 deletions
diff --git a/generic/tclPathObj.c b/generic/tclPathObj.c index 30bffcc..acb16b7 100644 --- a/generic/tclPathObj.c +++ b/generic/tclPathObj.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclPathObj.c,v 1.19 2003/12/24 04:18:20 davygrvy Exp $ + * RCS: @(#) $Id: tclPathObj.c,v 1.20 2004/01/21 19:59:33 vincentdarley Exp $ */ #include "tclInt.h" @@ -26,12 +26,13 @@ static void DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *copyPtr)); -static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr)); -static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *objPtr)); +static void FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *pathPtr)); +static void UpdateStringOfFsPath _ANSI_ARGS_((Tcl_Obj *pathPtr)); static int SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp, - Tcl_Obj *objPtr)); + Tcl_Obj *pathPtr)); static int FindSplitPos _ANSI_ARGS_((CONST char *path, int separator)); static int IsSeparatorOrNull _ANSI_ARGS_((int ch)); +static Tcl_Obj* GetExtension _ANSI_ARGS_((Tcl_Obj *pathPtr)); /* @@ -54,8 +55,25 @@ Tcl_ObjType tclFsPathType = { * certain optimisations when used to represent paths which are * already normalized and absolute. * - * Note that 'normPathPtr' can be a circular reference to the - * container Tcl_Obj of this FsPath. + * Note that both 'translatedPathPtr' and 'normPathPtr' can be a + * circular reference to the container Tcl_Obj of this FsPath. + * + * There are two cases, with the first being the most common: + * + * (i) flags == 0, => Ordinary path. + * + * translatedPathPtr contains the translated path (which may be + * a circular reference to the object itself). If it is NULL + * then the path is pure normalized (and the normPathPtr will be + * a circular reference). cwdPtr is null for an absolute path, + * and non-null for a relative path (unless the cwd has never been + * set, in which case the cwdPtr may also be null for a relative path). + * + * (ii) flags != 0, => Special path, see TclNewFSPathObj + * + * Now, this is a path like 'file join $dir $tail' where, cwdPtr is + * the $dir and normPathPtr is the $tail. + * */ typedef struct FsPath { Tcl_Obj *translatedPathPtr; /* Name without any ~user sequences. @@ -75,7 +93,8 @@ typedef struct FsPath { * this points to the cwd object used * for this path. We have a refCount * on the object. */ - int flags; /* Flags to describe interpretation */ + int flags; /* Flags to describe interpretation - + * see below. */ ClientData nativePathPtr; /* Native representation of this path, * which is filesystem dependent. */ int filesystemEpoch; /* Used to ensure the path representation @@ -87,16 +106,19 @@ typedef struct FsPath { * entry to use for this path. */ } FsPath; +/* + * Flag values for FsPath->flags. + */ +#define TCLPATH_APPENDED 1 + /* * Define some macros to give us convenient access to path-object * specific fields. */ -#define PATHOBJ(objPtr) (objPtr->internalRep.otherValuePtr) -#define PATHFLAGS(objPtr) \ - (((FsPath*)(objPtr->internalRep.otherValuePtr))->flags) +#define PATHOBJ(pathPtr) (pathPtr->internalRep.otherValuePtr) +#define PATHFLAGS(pathPtr) \ + (((FsPath*)(pathPtr->internalRep.otherValuePtr))->flags) -#define TCLPATH_APPENDED 1 -#define TCLPATH_RELATIVE 2 /* *--------------------------------------------------------------------------- @@ -344,10 +366,10 @@ TclFSNormalizeAbsolutePath(interp, pathPtr, clientDataPtr) */ Tcl_PathType -Tcl_FSGetPathType(pathObjPtr) - Tcl_Obj *pathObjPtr; +Tcl_FSGetPathType(pathPtr) + Tcl_Obj *pathPtr; { - return TclFSGetPathType(pathObjPtr, NULL, NULL); + return TclFSGetPathType(pathPtr, NULL, NULL); } /* @@ -375,24 +397,24 @@ Tcl_FSGetPathType(pathObjPtr) */ Tcl_PathType -TclFSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr) - Tcl_Obj *pathObjPtr; +TclFSGetPathType(pathPtr, filesystemPtrPtr, driveNameLengthPtr) + Tcl_Obj *pathPtr; Tcl_Filesystem **filesystemPtrPtr; int *driveNameLengthPtr; { - if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { - return TclGetPathType(pathObjPtr, filesystemPtrPtr, + if (Tcl_FSConvertToPathType(NULL, pathPtr) != TCL_OK) { + return TclGetPathType(pathPtr, filesystemPtrPtr, driveNameLengthPtr, NULL); } else { - FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathPtr); if (fsPathPtr->cwdPtr != NULL) { - if (PATHFLAGS(pathObjPtr) == 0) { + if (PATHFLAGS(pathPtr) == 0) { return TCL_PATH_RELATIVE; } return TclFSGetPathType(fsPathPtr->cwdPtr, filesystemPtrPtr, driveNameLengthPtr); } else { - return TclGetPathType(pathObjPtr, filesystemPtrPtr, + return TclGetPathType(pathPtr, filesystemPtrPtr, driveNameLengthPtr, NULL); } } @@ -401,6 +423,205 @@ TclFSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr) /* *--------------------------------------------------------------------------- * + * TclPathPart + * + * This procedure calculates the requested part of the the given + * path, which can be: + * + * - the directory above ('file dirname') + * - the tail ('file tail') + * - the extension ('file extension') + * - the root ('file root') + * + * The 'portion' parameter dictates which of these to calculate. + * There are a number of special cases both to be more efficient, + * and because the behaviour when given a path with only a single + * element is defined to require the expansion of that single + * element, where possible. + * + * Should look into integrating 'FileBasename' in tclFCmd.c into + * this function. + * + * Results: + * NULL if an error occurred, otherwise a Tcl_Obj owned by + * the caller (i.e. most likely with refCount 1). + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +Tcl_Obj* +TclPathPart(interp, pathPtr, portion) + Tcl_Interp *interp; /* Used for error reporting */ + Tcl_Obj *pathPtr; /* Path to take dirname of */ + Tcl_PathPart portion; /* Requested portion of name */ +{ + if (pathPtr->typePtr == &tclFsPathType) { + FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathPtr); + if (PATHFLAGS(pathPtr) != 0) { + switch (portion) { + case TCL_PATH_DIRNAME: { + Tcl_IncrRefCount(fsPathPtr->cwdPtr); + return fsPathPtr->cwdPtr; + } + case TCL_PATH_TAIL: { + Tcl_IncrRefCount(fsPathPtr->normPathPtr); + return fsPathPtr->normPathPtr; + } + case TCL_PATH_EXTENSION: { + return GetExtension(fsPathPtr->normPathPtr); + } + case TCL_PATH_ROOT: { + /* Unimplemented */ + CONST char *fileName, *extension; + int length; + fileName = Tcl_GetStringFromObj(fsPathPtr->normPathPtr, + &length); + extension = TclGetExtension(fileName); + if (extension == NULL) { + /* + * There is no extension so the root is the + * same as the path we were given. + */ + Tcl_IncrRefCount(pathPtr); + return pathPtr; + } else { + /* + * Duplicate the object we were given and + * then trim off the extension of the + * tail component of the path. + */ + Tcl_Obj *root; + FsPath *fsDupPtr; + root = Tcl_DuplicateObj(pathPtr); + Tcl_IncrRefCount(root); + fsDupPtr = (FsPath*) PATHOBJ(root); + if (Tcl_IsShared(fsDupPtr->normPathPtr)) { + Tcl_DecrRefCount(fsDupPtr->normPathPtr); + fsDupPtr->normPathPtr = Tcl_NewStringObj(fileName, + (int)(length - strlen(extension))); + Tcl_IncrRefCount(fsDupPtr->normPathPtr); + } else { + Tcl_SetObjLength(fsDupPtr->normPathPtr, + (int)(length - strlen(extension))); + } + return root; + } + } + } + } else if (fsPathPtr->cwdPtr != NULL) { + /* Relative path */ + goto standardPath; + } else { + /* Absolute path */ + goto standardPath; + } + } else { + int splitElements; + Tcl_Obj *splitPtr; + Tcl_Obj *resultPtr = NULL; + standardPath: + + if (portion == TCL_PATH_EXTENSION) { + return GetExtension(pathPtr); + } else if (portion == TCL_PATH_ROOT) { + int length; + CONST char *fileName, *extension; + + fileName = Tcl_GetStringFromObj(pathPtr, &length); + extension = TclGetExtension(fileName); + if (extension == NULL) { + Tcl_IncrRefCount(pathPtr); + return pathPtr; + } else { + Tcl_Obj *root = Tcl_NewStringObj(fileName, + (int) (length - strlen(extension))); + Tcl_IncrRefCount(root); + return root; + } + } + + /* + * The behaviour we want here is slightly different to + * the standard Tcl_FSSplitPath in the handling of home + * directories; Tcl_FSSplitPath preserves the "~" while + * this code computes the actual full path name, if we + * had just a single component. + */ + splitPtr = Tcl_FSSplitPath(pathPtr, &splitElements); + Tcl_IncrRefCount(splitPtr); + if ((splitElements == 1) && (Tcl_GetString(pathPtr)[0] == '~')) { + Tcl_Obj *norm; + + Tcl_DecrRefCount(splitPtr); + norm = Tcl_FSGetNormalizedPath(interp, pathPtr); + if (norm == NULL) { + return NULL; + } + splitPtr = Tcl_FSSplitPath(norm, &splitElements); + Tcl_IncrRefCount(splitPtr); + } + if (portion == TCL_PATH_TAIL) { + /* + * Return the last component, unless it is the only component, + * and it is the root of an absolute path. + */ + + if ((splitElements > 0) && ((splitElements > 1) + || (Tcl_FSGetPathType(pathPtr) == TCL_PATH_RELATIVE))) { + Tcl_ListObjIndex(NULL, splitPtr, splitElements-1, &resultPtr); + } else { + resultPtr = Tcl_NewObj(); + } + } else { + /* + * Return all but the last component. If there is only one + * component, return it if the path was non-relative, otherwise + * return the current directory. + */ + + if (splitElements > 1) { + resultPtr = Tcl_FSJoinPath(splitPtr, splitElements - 1); + } else if (splitElements == 0 || + (Tcl_FSGetPathType(pathPtr) == TCL_PATH_RELATIVE)) { + resultPtr = Tcl_NewStringObj( + ((tclPlatform == TCL_PLATFORM_MAC) ? ":" : "."), 1); + } else { + Tcl_ListObjIndex(NULL, splitPtr, 0, &resultPtr); + } + } + Tcl_IncrRefCount(resultPtr); + Tcl_DecrRefCount(splitPtr); + return resultPtr; + } +} + +/* + * Simple helper function + */ +static Tcl_Obj* +GetExtension(pathPtr) + Tcl_Obj *pathPtr; +{ + CONST char *tail, *extension; + Tcl_Obj *ret; + + tail = Tcl_GetString(pathPtr); + extension = TclGetExtension(tail); + if (extension == NULL) { + ret = Tcl_NewObj(); + } else { + ret = Tcl_NewStringObj(extension, -1); + } + Tcl_IncrRefCount(ret); + return ret; +} + +/* + *--------------------------------------------------------------------------- + * * Tcl_FSJoinPath -- * * This function takes the given Tcl_Obj, which should be a valid @@ -408,6 +629,10 @@ TclFSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr) * first 'elements' elements as valid path segments. If elements < 0, * we use the entire list. * + * It is possible that the returned object is actually an element + * of the given list, so the caller should be careful to store a + * refCount to it before freeing the list. + * * Results: * Returns object with refCount of zero, (or if non-zero, it has * references elsewhere in Tcl). Either way, the caller must @@ -420,8 +645,8 @@ TclFSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr) */ Tcl_Obj* Tcl_FSJoinPath(listObj, elements) - Tcl_Obj *listObj; - int elements; + Tcl_Obj *listObj; /* Path elements to join, may have refCount 0 */ + int elements; /* Number of elements to use (-1 = all) */ { Tcl_Obj *res; int i; @@ -446,7 +671,7 @@ Tcl_FSJoinPath(listObj, elements) } } - res = Tcl_NewObj(); + res = NULL; for (i = 0; i < elements; i++) { Tcl_Obj *elt; @@ -485,7 +710,7 @@ Tcl_FSJoinPath(listObj, elements) * '/'. There's no need to return a special path * object, when the base itself is just fine! */ - Tcl_DecrRefCount(res); + if (res != NULL) Tcl_DecrRefCount(res); return elt; } /* @@ -499,7 +724,7 @@ Tcl_FSJoinPath(listObj, elements) */ if (str[0] != '.' && ((tclPlatform != TCL_PLATFORM_WINDOWS) || (strchr(str, '\\') == NULL))) { - Tcl_DecrRefCount(res); + if (res != NULL) Tcl_DecrRefCount(res); return TclNewFSPathObj(elt, str, len); } /* @@ -509,7 +734,7 @@ Tcl_FSJoinPath(listObj, elements) */ } else { if (tclPlatform == TCL_PLATFORM_UNIX) { - Tcl_DecrRefCount(res); + if (res != NULL) Tcl_DecrRefCount(res); return tail; } else { CONST char *str; @@ -517,12 +742,12 @@ Tcl_FSJoinPath(listObj, elements) str = Tcl_GetStringFromObj(tail,&len); if (tclPlatform == TCL_PLATFORM_WINDOWS) { if (strchr(str, '\\') == NULL) { - Tcl_DecrRefCount(res); + if (res != NULL) Tcl_DecrRefCount(res); return tail; } } else if (tclPlatform == TCL_PLATFORM_MAC) { if (strchr(str, '/') == NULL) { - Tcl_DecrRefCount(res); + if (res != NULL) Tcl_DecrRefCount(res); return tail; } } @@ -533,27 +758,101 @@ Tcl_FSJoinPath(listObj, elements) type = TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName); if (type != TCL_PATH_RELATIVE) { /* Zero out the current result */ - Tcl_DecrRefCount(res); + if (res != NULL) Tcl_DecrRefCount(res); + if (driveName != NULL) { + /* + * We've been given a separate drive-name object, + * because the prefix in 'elt' is not in a suitable + * format for us (e.g. it may contain irrelevant + * multiple separators, like C://///foo). + */ res = Tcl_DuplicateObj(driveName); Tcl_DecrRefCount(driveName); + /* + * Do not set driveName to NULL, because we will check + * its value below (but we won't access the contents, + * since those have been cleaned-up). + */ } else { res = Tcl_NewStringObj(strElt, driveNameLength); } strElt += driveNameLength; } - ptr = Tcl_GetStringFromObj(res, &length); + /* + * Optimisation block: if this is the last element to be + * examined, and it is absolute or the only element, and the + * drive-prefix was ok (if there is one), it might be that the + * path is already in a suitable form to be returned. Then we + * can short-cut the rest of this procedure. + */ + if ((driveName == NULL) && (i == (elements - 1)) + && (type != TCL_PATH_RELATIVE || res == NULL)) { + /* + * It's the last path segment. Perform a quick check if + * the path is already in a suitable form. + */ + int equal = 1; + + if (tclPlatform == TCL_PLATFORM_WINDOWS) { + if (strchr(strElt, '\\') != NULL) { + equal = 0; + } + } + if (equal && (tclPlatform != TCL_PLATFORM_MAC)) { + ptr = strElt; + while (*ptr != '\0') { + if (*ptr == '/' && (ptr[1] == '/' || ptr[1] == '\0')) { + equal = 0; + break; + } + ptr++; + } + } + if (equal && (tclPlatform == TCL_PLATFORM_MAC)) { + /* + * If it contains any colons, then it mustn't contain + * any duplicates. Otherwise, the path is in unix-form + * and is no good. + */ + if (strchr(strElt, ':') != NULL) { + ptr = strElt; + while (*ptr != '\0') { + if (*ptr == ':' && (ptr[1] == ':' || ptr[1] == '\0')) { + equal = 0; + break; + } + ptr++; + } + } else { + equal = 0; + } + } + if (equal) { + if (res != NULL) Tcl_DecrRefCount(res); + /* + * This element is just what we want to return already - + * no further manipulation is requred. + */ + return elt; + } + } + + if (res == NULL) { + res = Tcl_NewObj(); + ptr = Tcl_GetStringFromObj(res, &length); + } else { + ptr = Tcl_GetStringFromObj(res, &length); + } /* * Strip off any './' before a tilde, unless this is the * beginning of the path. */ - if (length > 0 && strEltLen > 0) { - if ((strElt[0] == '.') && (strElt[1] == '/') - && (strElt[2] == '~')) { - strElt += 2; - } + if (length > 0 && strEltLen > 0 + && (strElt[0] == '.') && (strElt[1] == '/') && (strElt[2] == '~')) { + strElt += 2; } /* @@ -629,10 +928,10 @@ Tcl_FSJoinPath(listObj, elements) *--------------------------------------------------------------------------- */ int -Tcl_FSConvertToPathType(interp, objPtr) +Tcl_FSConvertToPathType(interp, pathPtr) Tcl_Interp *interp; /* Interpreter in which to store error * message (if necessary). */ - Tcl_Obj *objPtr; /* Object to convert to a valid, current + Tcl_Obj *pathPtr; /* Object to convert to a valid, current * path type. */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); @@ -646,39 +945,39 @@ Tcl_FSConvertToPathType(interp, objPtr) * and is a relative path, we do have to worry about the cwd. * If the cwd has changed, we must recompute the path. */ - if (objPtr->typePtr == &tclFsPathType) { - FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr); + if (pathPtr->typePtr == &tclFsPathType) { + FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathPtr); if (fsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) { - if (objPtr->bytes == NULL) { - UpdateStringOfFsPath(objPtr); + if (pathPtr->bytes == NULL) { + UpdateStringOfFsPath(pathPtr); } - FreeFsPathInternalRep(objPtr); - objPtr->typePtr = NULL; - return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); + FreeFsPathInternalRep(pathPtr); + pathPtr->typePtr = NULL; + return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType); } return TCL_OK; /* - * This code is intentionally never reached. Once fs-optimisation - * is complete, it will be removed/replaced + * We used to have more complex code here: + * + * if (fsPathPtr->cwdPtr == NULL || PATHFLAGS(pathPtr) != 0) { + * return TCL_OK; + * } else { + * if (TclFSCwdPointerEquals(&fsPathPtr->cwdPtr)) { + * return TCL_OK; + * } else { + * if (pathPtr->bytes == NULL) { + * UpdateStringOfFsPath(pathPtr); + * } + * FreeFsPathInternalRep(pathPtr); + * pathPtr->typePtr = NULL; + * return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType); + * } + * } + * + * But we no longer believe this is necessary. */ -#if 0 - if (fsPathPtr->cwdPtr == NULL) { - return TCL_OK; - } else { - if (TclFSCwdPointerEquals(fsPathPtr->cwdPtr)) { - return TCL_OK; - } else { - if (objPtr->bytes == NULL) { - UpdateStringOfFsPath(objPtr); - } - FreeFsPathInternalRep(objPtr); - objPtr->typePtr = NULL; - return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); - } - } -#endif } else { - return Tcl_ConvertToType(interp, objPtr, &tclFsPathType); + return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType); } } @@ -745,9 +1044,10 @@ FindSplitPos(path, separator) * * TclNewFSPathObj -- * - * Creates a path object whose string representation is - * '[file join dirPtr addStrRep]', but does so in a way that - * allows for more efficient caching of normalized paths. + * Creates a path object whose string representation is '[file join + * dirPtr addStrRep]', but does so in a way that allows for more + * efficient creation and caching of normalized paths, and more + * efficient 'file dirname', 'file tail', etc. * * Assumptions: * 'dirPtr' must be an absolute path. @@ -766,10 +1066,12 @@ Tcl_Obj* TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) { FsPath *fsPathPtr; - Tcl_Obj *objPtr; - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); + Tcl_Obj *pathPtr; + ThreadSpecificData *tsdPtr; - objPtr = Tcl_NewObj(); + tsdPtr = TCL_TSD_INIT(&tclFsDataKey); + + pathPtr = Tcl_NewObj(); fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); if (tclPlatform == TCL_PLATFORM_MAC) { @@ -783,7 +1085,7 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) addStrRep++; len--; } - } + } /* Setup the path */ fsPathPtr->translatedPathPtr = NULL; fsPathPtr->normPathPtr = Tcl_NewStringObj(addStrRep, len); @@ -794,13 +1096,13 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) fsPathPtr->fsRecPtr = NULL; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; - PATHOBJ(objPtr) = (VOID *) fsPathPtr; - PATHFLAGS(objPtr) = TCLPATH_RELATIVE | TCLPATH_APPENDED; - objPtr->typePtr = &tclFsPathType; - objPtr->bytes = NULL; - objPtr->length = 0; + PATHOBJ(pathPtr) = (VOID *) fsPathPtr; + PATHFLAGS(pathPtr) = TCLPATH_APPENDED; + pathPtr->typePtr = &tclFsPathType; + pathPtr->bytes = NULL; + pathPtr->length = 0; - return objPtr; + return pathPtr; } /* @@ -808,11 +1110,17 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) * * TclFSMakePathRelative -- * - * Like SetFsPathFromAny, but assumes the given object is an - * absolute normalized path. Only for internal use. + * Only for internal use. + * + * Takes a path and a directory, where we _assume_ both path and + * directory are absolute, normalized and that the path lies + * inside the directory. Returns a Tcl_Obj representing filename + * of the path relative to the directory. * * Results: - * Standard Tcl error code. + * NULL on error, otherwise a valid object, typically with + * refCount of zero, which it is assumed the caller will + * increment. * * Side effects: * The old representation may be freed, and new memory allocated. @@ -821,24 +1129,24 @@ TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len) */ Tcl_Obj* -TclFSMakePathRelative(interp, objPtr, cwdPtr) +TclFSMakePathRelative(interp, pathPtr, cwdPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr; /* The object we have. */ + Tcl_Obj *pathPtr; /* The object we have. */ Tcl_Obj *cwdPtr; /* Make it relative to this. */ { int cwdLen, len; CONST char *tempStr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - if (objPtr->typePtr == &tclFsPathType) { - FsPath* fsPathPtr = (FsPath*) PATHOBJ(objPtr); - if (PATHFLAGS(objPtr) != 0 + if (pathPtr->typePtr == &tclFsPathType) { + FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathPtr); + if (PATHFLAGS(pathPtr) != 0 && fsPathPtr->cwdPtr == cwdPtr) { - objPtr = fsPathPtr->normPathPtr; + pathPtr = fsPathPtr->normPathPtr; /* Free old representation */ - if (objPtr->typePtr != NULL) { - if (objPtr->bytes == NULL) { - if (objPtr->typePtr->updateStringProc == NULL) { + if (pathPtr->typePtr != NULL) { + if (pathPtr->bytes == NULL) { + if (pathPtr->typePtr->updateStringProc == NULL) { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "can't find object", @@ -846,17 +1154,17 @@ TclFSMakePathRelative(interp, objPtr, cwdPtr) } return NULL; } - objPtr->typePtr->updateStringProc(objPtr); + pathPtr->typePtr->updateStringProc(pathPtr); } - if ((objPtr->typePtr->freeIntRepProc) != NULL) { - (*objPtr->typePtr->freeIntRepProc)(objPtr); + if ((pathPtr->typePtr->freeIntRepProc) != NULL) { + (*pathPtr->typePtr->freeIntRepProc)(pathPtr); } } fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); /* Circular reference, by design */ - fsPathPtr->translatedPathPtr = objPtr; + fsPathPtr->translatedPathPtr = pathPtr; fsPathPtr->normPathPtr = NULL; fsPathPtr->cwdPtr = cwdPtr; Tcl_IncrRefCount(cwdPtr); @@ -864,11 +1172,11 @@ TclFSMakePathRelative(interp, objPtr, cwdPtr) fsPathPtr->fsRecPtr = NULL; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; - PATHOBJ(objPtr) = (VOID *) fsPathPtr; - PATHFLAGS(objPtr) = 0; - objPtr->typePtr = &tclFsPathType; + PATHOBJ(pathPtr) = (VOID *) fsPathPtr; + PATHFLAGS(pathPtr) = 0; + pathPtr->typePtr = &tclFsPathType; - return objPtr; + return pathPtr; } } /* @@ -908,7 +1216,7 @@ TclFSMakePathRelative(interp, objPtr, cwdPtr) } break; } - tempStr = Tcl_GetStringFromObj(objPtr, &len); + tempStr = Tcl_GetStringFromObj(pathPtr, &len); return Tcl_NewStringObj(tempStr + cwdLen, len - cwdLen); } @@ -931,23 +1239,23 @@ TclFSMakePathRelative(interp, objPtr, cwdPtr) */ int -TclFSMakePathFromNormalized(interp, objPtr, nativeRep) +TclFSMakePathFromNormalized(interp, pathPtr, nativeRep) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr; /* The object to convert. */ + Tcl_Obj *pathPtr; /* The object to convert. */ ClientData nativeRep; /* The native rep for the object, if known * else NULL. */ { FsPath *fsPathPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - if (objPtr->typePtr == &tclFsPathType) { + if (pathPtr->typePtr == &tclFsPathType) { return TCL_OK; } /* Free old representation */ - if (objPtr->typePtr != NULL) { - if (objPtr->bytes == NULL) { - if (objPtr->typePtr->updateStringProc == NULL) { + if (pathPtr->typePtr != NULL) { + if (pathPtr->bytes == NULL) { + if (pathPtr->typePtr->updateStringProc == NULL) { if (interp != NULL) { Tcl_ResetResult(interp); Tcl_AppendResult(interp, "can't find object", @@ -955,25 +1263,26 @@ TclFSMakePathFromNormalized(interp, objPtr, nativeRep) } return TCL_ERROR; } - objPtr->typePtr->updateStringProc(objPtr); + pathPtr->typePtr->updateStringProc(pathPtr); } - if ((objPtr->typePtr->freeIntRepProc) != NULL) { - (*objPtr->typePtr->freeIntRepProc)(objPtr); + if ((pathPtr->typePtr->freeIntRepProc) != NULL) { + (*pathPtr->typePtr->freeIntRepProc)(pathPtr); } } fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); /* It's a pure normalized absolute path */ fsPathPtr->translatedPathPtr = NULL; - fsPathPtr->normPathPtr = objPtr; + /* Circular reference by design */ + fsPathPtr->normPathPtr = pathPtr; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = nativeRep; fsPathPtr->fsRecPtr = NULL; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; - PATHOBJ(objPtr) = (VOID *) fsPathPtr; - PATHFLAGS(objPtr) = 0; - objPtr->typePtr = &tclFsPathType; + PATHOBJ(pathPtr) = (VOID *) fsPathPtr; + PATHFLAGS(pathPtr) = 0; + pathPtr->typePtr = &tclFsPathType; return TCL_OK; } @@ -1009,15 +1318,15 @@ Tcl_FSNewNativePath(fromFilesystem, clientData) Tcl_Filesystem* fromFilesystem; ClientData clientData; { - Tcl_Obj *objPtr; + Tcl_Obj *pathPtr; FsPath *fsPathPtr; FilesystemRecord *fsFromPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - objPtr = TclFSInternalToNormalized(fromFilesystem, clientData, + pathPtr = TclFSInternalToNormalized(fromFilesystem, clientData, &fsFromPtr); - if (objPtr == NULL) { + if (pathPtr == NULL) { return NULL; } @@ -1025,15 +1334,15 @@ Tcl_FSNewNativePath(fromFilesystem, clientData) * Free old representation; shouldn't normally be any, * but best to be safe. */ - if (objPtr->typePtr != NULL) { - if (objPtr->bytes == NULL) { - if (objPtr->typePtr->updateStringProc == NULL) { + if (pathPtr->typePtr != NULL) { + if (pathPtr->bytes == NULL) { + if (pathPtr->typePtr->updateStringProc == NULL) { return NULL; } - objPtr->typePtr->updateStringProc(objPtr); + pathPtr->typePtr->updateStringProc(pathPtr); } - if ((objPtr->typePtr->freeIntRepProc) != NULL) { - (*objPtr->typePtr->freeIntRepProc)(objPtr); + if ((pathPtr->typePtr->freeIntRepProc) != NULL) { + (*pathPtr->typePtr->freeIntRepProc)(pathPtr); } } @@ -1041,18 +1350,18 @@ Tcl_FSNewNativePath(fromFilesystem, clientData) fsPathPtr->translatedPathPtr = NULL; /* Circular reference, by design */ - fsPathPtr->normPathPtr = objPtr; + fsPathPtr->normPathPtr = pathPtr; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = clientData; fsPathPtr->fsRecPtr = fsFromPtr; fsPathPtr->fsRecPtr->fileRefCount++; fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; - PATHOBJ(objPtr) = (VOID *) fsPathPtr; - PATHFLAGS(objPtr) = 0; - objPtr->typePtr = &tclFsPathType; + PATHOBJ(pathPtr) = (VOID *) fsPathPtr; + PATHFLAGS(pathPtr) = 0; + pathPtr->typePtr = &tclFsPathType; - return objPtr; + return pathPtr; } /* @@ -1167,19 +1476,19 @@ Tcl_FSGetTranslatedStringPath(interp, pathPtr) */ Tcl_Obj* -Tcl_FSGetNormalizedPath(interp, pathObjPtr) +Tcl_FSGetNormalizedPath(interp, pathPtr) Tcl_Interp *interp; - Tcl_Obj* pathObjPtr; + Tcl_Obj* pathPtr; { FsPath *fsPathPtr; - if (Tcl_FSConvertToPathType(interp, pathObjPtr) != TCL_OK) { + if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) { return NULL; } - fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + fsPathPtr = (FsPath*) PATHOBJ(pathPtr); - if (PATHFLAGS(pathObjPtr) != 0) { + if (PATHFLAGS(pathPtr) != 0) { /* * This is a special path object which is the result of * something like 'file join' @@ -1195,8 +1504,8 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) if (dir == NULL) { return NULL; } - if (pathObjPtr->bytes == NULL) { - UpdateStringOfFsPath(pathObjPtr); + if (pathPtr->bytes == NULL) { + UpdateStringOfFsPath(pathPtr); } copy = Tcl_DuplicateObj(dir); Tcl_IncrRefCount(copy); @@ -1268,21 +1577,21 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) if (clientData != NULL) { fsPathPtr->nativePathPtr = clientData; } - PATHFLAGS(pathObjPtr) = 0; + PATHFLAGS(pathPtr) = 0; } /* Ensure cwd hasn't changed */ if (fsPathPtr->cwdPtr != NULL) { - if (!TclFSCwdPointerEquals(fsPathPtr->cwdPtr)) { - if (pathObjPtr->bytes == NULL) { - UpdateStringOfFsPath(pathObjPtr); + if (!TclFSCwdPointerEquals(&fsPathPtr->cwdPtr)) { + if (pathPtr->bytes == NULL) { + UpdateStringOfFsPath(pathPtr); } - FreeFsPathInternalRep(pathObjPtr); - pathObjPtr->typePtr = NULL; - if (Tcl_ConvertToType(interp, pathObjPtr, + FreeFsPathInternalRep(pathPtr); + pathPtr->typePtr = NULL; + if (Tcl_ConvertToType(interp, pathPtr, &tclFsPathType) != TCL_OK) { return NULL; } - fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + fsPathPtr = (FsPath*) PATHOBJ(pathPtr); } else if (fsPathPtr->normPathPtr == NULL) { int cwdLen; Tcl_Obj *copy; @@ -1319,7 +1628,7 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) } break; } - Tcl_AppendObjToObj(copy, pathObjPtr); + Tcl_AppendObjToObj(copy, pathPtr); /* * Normalize the combined string, but only starting after * the end of the previously normalized 'dir'. This should @@ -1350,7 +1659,7 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) * action, which might loop back through here. */ if (path[0] != '\0') { - Tcl_PathType type = Tcl_FSGetPathType(pathObjPtr); + Tcl_PathType type = Tcl_FSGetPathType(pathPtr); if (type == TCL_PATH_RELATIVE) { useThisCwd = Tcl_FSGetCwd(interp); @@ -1432,21 +1741,30 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) fsPathPtr->nativePathPtr = (*fsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc)(clientData); } - if (!strcmp(Tcl_GetString(fsPathPtr->normPathPtr), - Tcl_GetString(pathObjPtr))) { - /* - * The path was already normalized. - * Get rid of the duplicate. - */ - Tcl_DecrRefCount(fsPathPtr->normPathPtr); + /* + * Check if path is pure normalized (this can only be the case + * if it is an absolute path). + */ + if (useThisCwd == NULL) { + if (!strcmp(Tcl_GetString(fsPathPtr->normPathPtr), + Tcl_GetString(pathPtr))) { + /* + * The path was already normalized. + * Get rid of the duplicate. + */ + Tcl_DecrRefCount(fsPathPtr->normPathPtr); + /* + * We do *not* increment the refCount for + * this circular reference + */ + fsPathPtr->normPathPtr = pathPtr; + } + } else { /* - * We do *not* increment the refCount for - * this circular reference + * We just need to free an object we allocated above for + * relative paths (this was returned by Tcl_FSJoinToPath + * above), and then of course store the cwd. */ - fsPathPtr->normPathPtr = pathObjPtr; - } - if (useThisCwd != NULL) { - /* This was returned by Tcl_FSJoinToPath above */ Tcl_DecrRefCount(absolutePath); fsPathPtr->cwdPtr = useThisCwd; } @@ -1478,16 +1796,16 @@ Tcl_FSGetNormalizedPath(interp, pathObjPtr) */ ClientData -Tcl_FSGetInternalRep(pathObjPtr, fsPtr) - Tcl_Obj* pathObjPtr; +Tcl_FSGetInternalRep(pathPtr, fsPtr) + Tcl_Obj* pathPtr; Tcl_Filesystem *fsPtr; { FsPath* srcFsPathPtr; - if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) { + if (Tcl_FSConvertToPathType(NULL, pathPtr) != TCL_OK) { return NULL; } - srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr); /* * We will only return the native representation for the caller's @@ -1514,7 +1832,7 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) * call the native filesystem directly. It is at least safer * to allow this sub-optimal routing. */ - Tcl_FSGetFileSystemForPath(pathObjPtr); + Tcl_FSGetFileSystemForPath(pathPtr); /* * If we fail through here, then the path is probably not a @@ -1522,7 +1840,7 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) * use of the empty path "" via a direct call to one of the * objectified interfaces (e.g. from the Tcl testsuite). */ - srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr); if (srcFsPathPtr->fsRecPtr == NULL) { return NULL; } @@ -1536,9 +1854,9 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) * which we do care about. The way we can check for this * is we ask what filesystem this path belongs to. */ - Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathObjPtr); + Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathPtr); if (actualFs == fsPtr) { - return Tcl_FSGetInternalRep(pathObjPtr, fsPtr); + return Tcl_FSGetInternalRep(pathPtr, fsPtr); } return NULL; } @@ -1550,7 +1868,7 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) if (proc == NULL) { return NULL; } - srcFsPathPtr->nativePathPtr = (*proc)(pathObjPtr); + srcFsPathPtr->nativePathPtr = (*proc)(pathPtr); } return srcFsPathPtr->nativePathPtr; @@ -1561,7 +1879,7 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) * * TclFSEnsureEpochOk -- * - * This will ensure the pathObjPtr is up to date and can be + * This will ensure the pathPtr is up to date and can be * converted into a "path" type, and that we are able to generate a * complete normalized path which is used to determine the * filesystem match. @@ -1576,22 +1894,18 @@ Tcl_FSGetInternalRep(pathObjPtr, fsPtr) */ int -TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr) - Tcl_Obj* pathObjPtr; +TclFSEnsureEpochOk(pathPtr, fsPtrPtr) + Tcl_Obj* pathPtr; Tcl_Filesystem **fsPtrPtr; { FsPath* srcFsPathPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - /* - * SHOULD BE ABLE TO IMPROVE EFFICIENCY HERE. - */ - - if (Tcl_FSGetNormalizedPath(NULL, pathObjPtr) == NULL) { - return TCL_ERROR; + if (pathPtr->typePtr != &tclFsPathType) { + return TCL_OK; } - srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr); /* * Check if the filesystem has changed in some way since @@ -1602,15 +1916,15 @@ TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr) * We have to discard the stale representation and * recalculate it */ - if (pathObjPtr->bytes == NULL) { - UpdateStringOfFsPath(pathObjPtr); + if (pathPtr->bytes == NULL) { + UpdateStringOfFsPath(pathPtr); } - FreeFsPathInternalRep(pathObjPtr); - pathObjPtr->typePtr = NULL; - if (SetFsPathFromAny(NULL, pathObjPtr) != TCL_OK) { + FreeFsPathInternalRep(pathPtr); + pathPtr->typePtr = NULL; + if (SetFsPathFromAny(NULL, pathPtr) != TCL_OK) { return TCL_ERROR; } - srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr); } /* Check whether the object is already assigned to a fs */ if (srcFsPathPtr->fsRecPtr != NULL) { @@ -1621,16 +1935,22 @@ TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr) } void -TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData) - Tcl_Obj *pathObjPtr; +TclFSSetPathDetails(pathPtr, fsRecPtr, clientData) + Tcl_Obj *pathPtr; FilesystemRecord *fsRecPtr; ClientData clientData; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - /* We assume pathObjPtr is already of the correct type */ FsPath* srcFsPathPtr; - srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + /* Make sure pathPtr is of the correct type */ + if (pathPtr->typePtr != &tclFsPathType) { + if (SetFsPathFromAny(NULL, pathPtr) != TCL_OK) { + return; + } + } + + srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr); srcFsPathPtr->fsRecPtr = fsRecPtr; srcFsPathPtr->nativePathPtr = clientData; srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; @@ -1718,9 +2038,9 @@ Tcl_FSEqualPaths(firstPtr, secondPtr) */ static int -SetFsPathFromAny(interp, objPtr) +SetFsPathFromAny(interp, pathPtr) Tcl_Interp *interp; /* Used for error reporting if not NULL. */ - Tcl_Obj *objPtr; /* The object to convert. */ + Tcl_Obj *pathPtr; /* The object to convert. */ { int len; FsPath *fsPathPtr; @@ -1728,7 +2048,7 @@ SetFsPathFromAny(interp, objPtr) char *name; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - if (objPtr->typePtr == &tclFsPathType) { + if (pathPtr->typePtr == &tclFsPathType) { return TCL_OK; } @@ -1747,7 +2067,7 @@ SetFsPathFromAny(interp, objPtr) * or MacOS (fCmd.test, fileName.test and cmdAH.test exercise * most of the code). */ - name = Tcl_GetStringFromObj(objPtr,&len); + name = Tcl_GetStringFromObj(pathPtr,&len); /* * Handle tilde substitutions, if needed. @@ -1818,7 +2138,7 @@ SetFsPathFromAny(interp, objPtr) int objc; Tcl_Obj **objv; - Tcl_Obj *parts = TclpNativeSplitPath(objPtr, NULL); + Tcl_Obj *parts = TclpNativeSplitPath(pathPtr, NULL); Tcl_ListObjGetElements(NULL, parts, &objc, &objv); /* Skip '~'. It's replaced by its expansion */ objc--; objv++; @@ -1827,14 +2147,23 @@ SetFsPathFromAny(interp, objPtr) } Tcl_DecrRefCount(parts); } else { - /* Simple case. "rest" is relative path. Just join it. */ + /* + * Simple case. "rest" is relative path. Just join it. + * The "rest" object will be freed when + * Tcl_FSJoinToPath returns (unless something else + * claims a refCount on it). + */ + Tcl_Obj *joined; Tcl_Obj *rest = Tcl_NewStringObj(name+split+1,-1); - transPtr = Tcl_FSJoinToPath(transPtr, 1, &rest); + Tcl_IncrRefCount(transPtr); + joined = Tcl_FSJoinToPath(transPtr, 1, &rest); + Tcl_DecrRefCount(transPtr); + transPtr = joined; } } Tcl_DStringFree(&temp); } else { - transPtr = Tcl_FSJoinToPath(objPtr,0,NULL); + transPtr = Tcl_FSJoinToPath(pathPtr,0,NULL); } #if defined(__CYGWIN__) && defined(__WIN32__) @@ -1866,7 +2195,9 @@ SetFsPathFromAny(interp, objPtr) fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath)); fsPathPtr->translatedPathPtr = transPtr; - Tcl_IncrRefCount(fsPathPtr->translatedPathPtr); + if (transPtr != pathPtr) { + Tcl_IncrRefCount(fsPathPtr->translatedPathPtr); + } fsPathPtr->normPathPtr = NULL; fsPathPtr->cwdPtr = NULL; fsPathPtr->nativePathPtr = NULL; @@ -1876,29 +2207,29 @@ SetFsPathFromAny(interp, objPtr) /* * Free old representation before installing our new one. */ - if (objPtr->typePtr != NULL && objPtr->typePtr->freeIntRepProc != NULL) { - (objPtr->typePtr->freeIntRepProc)(objPtr); + if (pathPtr->typePtr != NULL && pathPtr->typePtr->freeIntRepProc != NULL) { + (pathPtr->typePtr->freeIntRepProc)(pathPtr); } - PATHOBJ(objPtr) = (VOID *) fsPathPtr; - PATHFLAGS(objPtr) = 0; - objPtr->typePtr = &tclFsPathType; + PATHOBJ(pathPtr) = (VOID *) fsPathPtr; + PATHFLAGS(pathPtr) = 0; + pathPtr->typePtr = &tclFsPathType; return TCL_OK; } static void -FreeFsPathInternalRep(pathObjPtr) - Tcl_Obj *pathObjPtr; /* Path object with internal rep to free. */ +FreeFsPathInternalRep(pathPtr) + Tcl_Obj *pathPtr; /* Path object with internal rep to free. */ { - FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr); + FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathPtr); if (fsPathPtr->translatedPathPtr != NULL) { - if (fsPathPtr->translatedPathPtr != pathObjPtr) { + if (fsPathPtr->translatedPathPtr != pathPtr) { Tcl_DecrRefCount(fsPathPtr->translatedPathPtr); } } if (fsPathPtr->normPathPtr != NULL) { - if (fsPathPtr->normPathPtr != pathObjPtr) { + if (fsPathPtr->normPathPtr != pathPtr) { Tcl_DecrRefCount(fsPathPtr->normPathPtr); } fsPathPtr->normPathPtr = NULL; @@ -1926,7 +2257,6 @@ FreeFsPathInternalRep(pathObjPtr) ckfree((char*) fsPathPtr); } - static void DupFsPathInternalRep(srcPtr, copyPtr) Tcl_Obj *srcPtr; /* Path obj with internal rep to copy. */ @@ -2004,15 +2334,15 @@ DupFsPathInternalRep(srcPtr, copyPtr) */ static void -UpdateStringOfFsPath(objPtr) - register Tcl_Obj *objPtr; /* path obj with string rep to update. */ +UpdateStringOfFsPath(pathPtr) + register Tcl_Obj *pathPtr; /* path obj with string rep to update. */ { - FsPath* fsPathPtr = (FsPath*) PATHOBJ(objPtr); + FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathPtr); CONST char *cwdStr; int cwdLen; Tcl_Obj *copy; - if (PATHFLAGS(objPtr) == 0 || fsPathPtr->cwdPtr == NULL) { + if (PATHFLAGS(pathPtr) == 0 || fsPathPtr->cwdPtr == NULL) { Tcl_Panic("Called UpdateStringOfFsPath with invalid object"); } @@ -2055,8 +2385,8 @@ UpdateStringOfFsPath(objPtr) break; } Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr); - objPtr->bytes = Tcl_GetStringFromObj(copy, &cwdLen); - objPtr->length = cwdLen; + pathPtr->bytes = Tcl_GetStringFromObj(copy, &cwdLen); + pathPtr->length = cwdLen; copy->bytes = tclEmptyStringRep; copy->length = 0; Tcl_DecrRefCount(copy); |