summaryrefslogtreecommitdiffstats
path: root/generic/tclPathObj.c
diff options
context:
space:
mode:
authorvincentdarley <vincentdarley>2004-01-21 19:59:32 (GMT)
committervincentdarley <vincentdarley>2004-01-21 19:59:32 (GMT)
commitaa7a81aef5d2a5e07732a9d10432071098bbe532 (patch)
tree0ffe5e984dd325a6bea1e24606e505aa4f37574b /generic/tclPathObj.c
parent255a92739ba23b8db77bffe62d4f6e3ef06d099f (diff)
downloadtcl-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.c752
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);