diff options
author | vincentdarley <vincentdarley> | 2003-10-06 09:49:19 (GMT) |
---|---|---|
committer | vincentdarley <vincentdarley> | 2003-10-06 09:49:19 (GMT) |
commit | 667a4aad934603ef865cba2b5b15f4c5687dc0c4 (patch) | |
tree | 65328a9bee43268f3dc141a59f2f3d9a446710fd /generic/tclIOUtil.c | |
parent | ce5f8d3fdff40fbd42079a7d4c6acf2671e42c62 (diff) | |
download | tcl-667a4aad934603ef865cba2b5b15f4c5687dc0c4.zip tcl-667a4aad934603ef865cba2b5b15f4c5687dc0c4.tar.gz tcl-667a4aad934603ef865cba2b5b15f4c5687dc0c4.tar.bz2 |
filesystem bug fixes: volumerelative normalization, file join inconsistency
Diffstat (limited to 'generic/tclIOUtil.c')
-rw-r--r-- | generic/tclIOUtil.c | 92 |
1 files changed, 58 insertions, 34 deletions
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index c59348a..8de62f1 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -17,7 +17,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIOUtil.c,v 1.77.2.9 2003/10/03 17:45:37 vincentdarley Exp $ + * RCS: @(#) $Id: tclIOUtil.c,v 1.77.2.10 2003/10/06 09:49:20 vincentdarley Exp $ */ #include "tclInt.h" @@ -4515,25 +4515,34 @@ Tcl_FSJoinPath(listObj, elements) } } - if (elements == 2) { - /* - * This is a special case where we can be much more - * efficient - */ - Tcl_Obj *base; + res = Tcl_NewObj(); + + for (i = 0; i < elements; i++) { + Tcl_Obj *elt; + int driveNameLength; + Tcl_PathType type; + char *strElt; + int strEltLen; + int length; + char *ptr; + Tcl_Obj *driveName = NULL; + + Tcl_ListObjIndex(NULL, listObj, i, &elt); - Tcl_ListObjIndex(NULL, listObj, 0, &base); /* - * There is only any value in doing this if the first object is - * of path type, otherwise we'll never actually get any - * efficiency benefit elsewhere in the code (from re-using the - * normalized representation of the base object). + * This is a special case where we can be much more + * efficient, where we are joining a single relative path + * onto an object that is already of path type. The + * 'TclNewFSPathObj' call below creates an object which + * can be normalized more efficiently. Currently we only + * use the special case when we have exactly two elements, + * but we could expand that in the future. */ - if (base->typePtr == &tclFsPathType - && !(base->bytes != NULL && base->bytes[0] == '\0')) { + if ((i == (elements-2)) && (i == 0) && (elt->typePtr == &tclFsPathType) + && !(elt->bytes != NULL && (elt->bytes[0] == '\0'))) { Tcl_Obj *tail; Tcl_PathType type; - Tcl_ListObjIndex(NULL, listObj, 1, &tail); + Tcl_ListObjIndex(NULL, listObj, i+1, &tail); type = GetPathType(tail, NULL, NULL, NULL); if (type == TCL_PATH_RELATIVE) { CONST char *str; @@ -4545,10 +4554,22 @@ Tcl_FSJoinPath(listObj, elements) * '/'. There's no need to return a special path * object, when the base itself is just fine! */ - return base; + Tcl_DecrRefCount(res); + return elt; } - if (str[0] != '.') { - return TclNewFSPathObj(base, str, len); + /* + * If it doesn't begin with '.' and is a mac or unix + * path or it a windows path without backslashes, then we + * can be very efficient here. (In fact even a windows + * path with backslashes can be joined efficiently, but + * the path object would not have forward slashes only, + * and this would therefore contradict our 'file join' + * documentation). + */ + if (str[0] != '.' && ((tclPlatform != TCL_PLATFORM_WINDOWS) + || (strchr(str, '\\') == NULL))) { + Tcl_DecrRefCount(res); + return TclNewFSPathObj(elt, str, len); } /* * Otherwise we don't have an easy join, and @@ -4556,24 +4577,27 @@ Tcl_FSJoinPath(listObj, elements) * things */ } else { - return tail; + if (tclPlatform == TCL_PLATFORM_UNIX) { + Tcl_DecrRefCount(res); + return tail; + } else { + CONST char *str; + int len; + str = Tcl_GetStringFromObj(tail,&len); + if (tclPlatform == TCL_PLATFORM_WINDOWS) { + if (strchr(str, '\\') == NULL) { + Tcl_DecrRefCount(res); + return tail; + } + } else if (tclPlatform == TCL_PLATFORM_MAC) { + if (strchr(str, '/') == NULL) { + Tcl_DecrRefCount(res); + return tail; + } + } + } } } - } - - res = Tcl_NewObj(); - - for (i = 0; i < elements; i++) { - Tcl_Obj *elt; - int driveNameLength; - Tcl_PathType type; - char *strElt; - int strEltLen; - int length; - char *ptr; - Tcl_Obj *driveName = NULL; - - Tcl_ListObjIndex(NULL, listObj, i, &elt); strElt = Tcl_GetStringFromObj(elt, &strEltLen); type = GetPathType(elt, &fsPtr, &driveNameLength, &driveName); if (type != TCL_PATH_RELATIVE) { |