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/tclIOUtil.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/tclIOUtil.c')
-rw-r--r-- | generic/tclIOUtil.c | 328 |
1 files changed, 258 insertions, 70 deletions
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index c47e07f..738f182 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.92 2004/01/09 15:22:46 vincentdarley Exp $ + * RCS: @(#) $Id: tclIOUtil.c,v 1.93 2004/01/21 19:59:33 vincentdarley Exp $ */ #include "tclInt.h" @@ -35,13 +35,16 @@ * Prototypes for procedures defined later in this file. */ -static FilesystemRecord* FsGetFirstFilesystem _ANSI_ARGS_((void)); -static void FsThrExitProc _ANSI_ARGS_((ClientData cd)); -static Tcl_Obj* FsListMounts _ANSI_ARGS_((Tcl_Obj *pathPtr, - CONST char *pattern)); -static Tcl_Obj* FsAddMountsToGlobResult _ANSI_ARGS_((Tcl_Obj *result, - Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types)); - +static FilesystemRecord* FsGetFirstFilesystem _ANSI_ARGS_((void)); +static void FsThrExitProc _ANSI_ARGS_((ClientData cd)); +static Tcl_Obj* FsListMounts _ANSI_ARGS_((Tcl_Obj *pathPtr, + CONST char *pattern)); +static Tcl_Obj* FsAddMountsToGlobResult _ANSI_ARGS_((Tcl_Obj *result, + Tcl_Obj *pathPtr, CONST char *pattern, + Tcl_GlobTypeData *types)); +static void FsUpdateCwd _ANSI_ARGS_((Tcl_Obj *cwdObj, + ClientData clientData)); + #ifdef TCL_THREADS static void FsRecacheFilesystemList(void); #endif @@ -297,7 +300,6 @@ TCL_DECLARE_MUTEX(obsoleteFsHookMutex) */ static Tcl_FSFilesystemSeparatorProc NativeFilesystemSeparator; static Tcl_FSFreeInternalRepProc NativeFreeInternalRep; -Tcl_FSDupInternalRepProc TclNativeDupInternalRep; static Tcl_FSCreateInternalRepProc NativeCreateNativeRep; static Tcl_FSFileAttrStringsProc NativeFileAttrStrings; static Tcl_FSFileAttrsGetProc NativeFileAttrsGet; @@ -318,7 +320,6 @@ Tcl_FSInternalToNormalizedProc TclpNativeToNormalized; Tcl_FSStatProc TclpObjStat; Tcl_FSAccessProc TclpObjAccess; Tcl_FSMatchInDirectoryProc TclpMatchInDirectory; -Tcl_FSGetCwdProc TclpObjGetCwd; Tcl_FSChdirProc TclpObjChdir; Tcl_FSLstatProc TclpObjLstat; Tcl_FSCopyFileProc TclpObjCopyFile; @@ -342,7 +343,7 @@ Tcl_FSListVolumesProc TclpObjListVolumes; Tcl_Filesystem tclNativeFilesystem = { "native", sizeof(Tcl_Filesystem), - TCL_FILESYSTEM_VERSION_1, + TCL_FILESYSTEM_VERSION_2, &TclNativePathInFilesystem, &TclNativeDupInternalRep, &NativeFreeInternalRep, @@ -373,7 +374,8 @@ Tcl_Filesystem tclNativeFilesystem = { &TclpObjCopyDirectory, &TclpObjLstat, &TclpDlopen, - &TclpObjGetCwd, + /* Needs a cast since we're using version_2 */ + (Tcl_FSGetCwdProc*)&TclpGetNativeCwd, &TclpObjChdir }; @@ -415,6 +417,7 @@ TCL_DECLARE_MUTEX(filesystemMutex) */ static Tcl_Obj* cwdPathPtr = NULL; static int cwdPathEpoch = 0; +static ClientData cwdClientData = NULL; TCL_DECLARE_MUTEX(cwdMutex) Tcl_ThreadDataKey tclFsDataKey; @@ -454,6 +457,9 @@ FsThrExitProc(cd) if (tsdPtr->cwdPathPtr != NULL) { Tcl_DecrRefCount(tsdPtr->cwdPathPtr); } + if (tsdPtr->cwdClientData != NULL) { + NativeFreeInternalRep(tsdPtr->cwdClientData); + } /* Trash the filesystems cache */ fsRecPtr = tsdPtr->filesystemList; while (fsRecPtr != NULL) { @@ -465,24 +471,53 @@ FsThrExitProc(cd) } } +/* + *---------------------------------------------------------------------- + * + * TclFSCwdPointerEquals -- + * + * Check whether the current working directory is equal to the + * path given. + * + * Results: + * 1 (equal) or 0 (un-equal) as appropriate. + * + * Side effects: + * If the paths are equal, but are not the same object, this + * method will modify the given pathPtrPtr to refer to the same + * object. In this case the object pointed to by pathPtrPtr will + * have its refCount decremented, and it will be adjusted to + * point to the cwd (with a new refCount). + * + *---------------------------------------------------------------------- + */ + int -TclFSCwdPointerEquals(objPtr) - Tcl_Obj* objPtr; +TclFSCwdPointerEquals(pathPtrPtr) + Tcl_Obj** pathPtrPtr; { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); Tcl_MutexLock(&cwdMutex); if (tsdPtr->cwdPathPtr == NULL || tsdPtr->cwdPathEpoch != cwdPathEpoch) { - if (tsdPtr->cwdPathPtr) { + if (tsdPtr->cwdPathPtr != NULL) { Tcl_DecrRefCount(tsdPtr->cwdPathPtr); } + if (tsdPtr->cwdClientData != NULL) { + NativeFreeInternalRep(tsdPtr->cwdClientData); + } if (cwdPathPtr == NULL) { tsdPtr->cwdPathPtr = NULL; } else { tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr); Tcl_IncrRefCount(tsdPtr->cwdPathPtr); } + if (cwdClientData == NULL) { + tsdPtr->cwdClientData = NULL; + } else { + tsdPtr->cwdClientData = TclNativeDupInternalRep(cwdClientData); + } tsdPtr->cwdPathEpoch = cwdPathEpoch; } Tcl_MutexUnlock(&cwdMutex); @@ -492,7 +527,30 @@ TclFSCwdPointerEquals(objPtr) tsdPtr->initialized = 1; } - return (tsdPtr->cwdPathPtr == objPtr); + if (pathPtrPtr == NULL) { + return (tsdPtr->cwdPathPtr == NULL); + } + + if (tsdPtr->cwdPathPtr == *pathPtrPtr) { + return 1; + } else { + int len1, len2; + CONST char *str1, *str2; + str1 = Tcl_GetStringFromObj(tsdPtr->cwdPathPtr, &len1); + str2 = Tcl_GetStringFromObj(*pathPtrPtr, &len2); + if (len1 == len2 && !strcmp(str1,str2)) { + /* + * They are equal, but different objects. Update so they + * will be the same object in the future. + */ + Tcl_DecrRefCount(*pathPtrPtr); + *pathPtrPtr = tsdPtr->cwdPathPtr; + Tcl_IncrRefCount(*pathPtrPtr); + return 1; + } else { + return 0; + } + } } #ifdef TCL_THREADS @@ -568,9 +626,13 @@ FsGetFirstFilesystem(void) { return fsRecPtr; } +/* + * If non-NULL, clientData is owned by us and must be freed later. + */ static void -FsUpdateCwd(cwdObj) +FsUpdateCwd(cwdObj, clientData) Tcl_Obj *cwdObj; + ClientData clientData; { int len; char *str = NULL; @@ -584,12 +646,17 @@ FsUpdateCwd(cwdObj) if (cwdPathPtr != NULL) { Tcl_DecrRefCount(cwdPathPtr); } + if (cwdClientData != NULL) { + NativeFreeInternalRep(cwdClientData); + } if (cwdObj == NULL) { cwdPathPtr = NULL; + cwdClientData = NULL; } else { /* This must be stored as string obj! */ cwdPathPtr = Tcl_NewStringObj(str, len); Tcl_IncrRefCount(cwdPathPtr); + cwdClientData = TclNativeDupInternalRep(clientData); } cwdPathEpoch++; tsdPtr->cwdPathEpoch = cwdPathEpoch; @@ -598,10 +665,15 @@ FsUpdateCwd(cwdObj) if (tsdPtr->cwdPathPtr) { Tcl_DecrRefCount(tsdPtr->cwdPathPtr); } + if (tsdPtr->cwdClientData) { + NativeFreeInternalRep(tsdPtr->cwdClientData); + } if (cwdObj == NULL) { tsdPtr->cwdPathPtr = NULL; + tsdPtr->cwdClientData = NULL; } else { tsdPtr->cwdPathPtr = Tcl_NewStringObj(str, len); + tsdPtr->cwdClientData = clientData; Tcl_IncrRefCount(tsdPtr->cwdPathPtr); } } @@ -641,6 +713,10 @@ TclFinalizeFilesystem() cwdPathPtr = NULL; cwdPathEpoch = 0; } + if (cwdClientData != NULL) { + NativeFreeInternalRep(cwdClientData); + cwdClientData = NULL; + } /* * Remove all filesystems, freeing any allocated memory @@ -922,7 +998,13 @@ Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types) * May be NULL. In particular the directory * flag is very important. */ { - Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); + Tcl_Filesystem *fsPtr; + if (pathPtr != NULL) { + fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); + } else { + fsPtr = NULL; + } + if (fsPtr != NULL) { Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc; if (proc != NULL) { @@ -1024,10 +1106,12 @@ Tcl_FSMatchInDirectory(interp, result, pathPtr, pattern, types) */ static Tcl_Obj* FsAddMountsToGlobResult(result, pathPtr, pattern, types) - Tcl_Obj *result; /* The current list of matching paths */ - Tcl_Obj *pathPtr; /* The directory in question */ - CONST char *pattern; - Tcl_GlobTypeData *types; + Tcl_Obj *result; /* The current list of matching paths */ + Tcl_Obj *pathPtr; /* The directory in question */ + CONST char *pattern; /* Pattern to match against. */ + Tcl_GlobTypeData *types; /* Object containing list of acceptable types. + * May be NULL. In particular the directory + * flag is very important. */ { int mLength, gLength, i; int dir = (types == NULL || (types->type & TCL_GLOB_TYPE_DIR)); @@ -1234,10 +1318,13 @@ Tcl_FSData(fsPtr) */ int TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr) - Tcl_Interp *interp; - Tcl_Obj *pathPtr; - int startAt; - ClientData *clientDataPtr; + Tcl_Interp *interp; /* Used for error messages. */ + Tcl_Obj *pathPtr; /* The path to normalize in place */ + int startAt; /* Start at this char-offset */ + ClientData *clientDataPtr; /* If we generated a complete + * normalized path for a given + * filesystem, we can optionally return + * an fs-specific clientdata here. */ { FilesystemRecord *fsRecPtr, *firstFsRecPtr; /* Ignore this variable */ @@ -1497,7 +1584,8 @@ Tcl_FSEvalFileEx(interp, pathPtr, encodingName) Tcl_Interp *interp; /* Interpreter in which to process file. */ Tcl_Obj *pathPtr; /* Path of file to process. Tilde-substitution * will be performed on this name. */ - CONST char *encodingName; + CONST char *encodingName; /* If non-NULL, then use this encoding + * for the file. */ { int result, length; Tcl_StatBuf statBuf; @@ -1540,7 +1628,7 @@ Tcl_FSEvalFileEx(interp, pathPtr, encodingName) * Else don't touch it (and use the system encoding) * Report error on unknown encoding. */ - if (encodingName) { + if (encodingName != NULL) { if (Tcl_SetChannelOption(interp, chan, "-encoding", encodingName) != TCL_OK) { Tcl_Close(interp,chan); @@ -2307,7 +2395,48 @@ Tcl_FSGetCwd(interp) while ((retVal == NULL) && (fsRecPtr != NULL)) { Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc; if (proc != NULL) { - retVal = (*proc)(interp); + if (fsRecPtr->fsPtr->version != TCL_FILESYSTEM_VERSION_1) { + ClientData retCd; + TclFSGetCwdProc2 *proc2 = (TclFSGetCwdProc2*)proc; + + retCd = (*proc2)(NULL); + if (retCd != NULL) { + Tcl_Obj *norm; + /* Looks like a new current directory */ + retVal = (*fsRecPtr->fsPtr->internalToNormalizedProc)(retCd); + Tcl_IncrRefCount(retVal); + norm = TclFSNormalizeAbsolutePath(interp, retVal, NULL); + if (norm != NULL) { + /* + * We found a cwd, which is now in our global storage. + * We must make a copy. Norm already has a refCount of 1. + * + * Threading issue: note that multiple threads at system + * startup could in principle call this procedure + * simultaneously. They will therefore each set the + * cwdPathPtr independently. That behaviour is a bit + * peculiar, but should be fine. Once we have a cwd, + * we'll always be in the 'else' branch below which + * is simpler. + */ + FsUpdateCwd(norm, retCd); + Tcl_DecrRefCount(norm); + } else { + (*fsRecPtr->fsPtr->freeInternalRepProc)(retCd); + } + Tcl_DecrRefCount(retVal); + retVal = NULL; + goto cdDidNotChange; + } else { + if (interp != NULL) { + Tcl_AppendResult(interp, + "error getting working directory name: ", + Tcl_PosixError(interp), (char *) NULL); + } + } + } else { + retVal = (*proc)(interp); + } } fsRecPtr = fsRecPtr->nextPtr; } @@ -2334,7 +2463,8 @@ Tcl_FSGetCwd(interp) * we'll always be in the 'else' branch below which * is simpler. */ - FsUpdateCwd(norm); + ClientData cd = (ClientData) Tcl_FSGetNativePath(norm); + FsUpdateCwd(norm, TclNativeDupInternalRep(cd)); Tcl_DecrRefCount(norm); } Tcl_DecrRefCount(retVal); @@ -2359,10 +2489,32 @@ Tcl_FSGetCwd(interp) */ if (fsPtr != NULL) { Tcl_FSGetCwdProc *proc = fsPtr->getCwdProc; + ClientData retCd = NULL; if (proc != NULL) { - Tcl_Obj *retVal = (*proc)(interp); + Tcl_Obj *retVal; + if (fsPtr->version != TCL_FILESYSTEM_VERSION_1) { + TclFSGetCwdProc2 *proc2 = (TclFSGetCwdProc2*)proc; + + retCd = (*proc2)(tsdPtr->cwdClientData); + if (retCd == NULL && interp != NULL) { + Tcl_AppendResult(interp, + "error getting working directory name: ", + Tcl_PosixError(interp), (char *) NULL); + } + + if (retCd == tsdPtr->cwdClientData) { + goto cdDidNotChange; + } + + /* Looks like a new current directory */ + retVal = (*fsPtr->internalToNormalizedProc)(retCd); + Tcl_IncrRefCount(retVal); + } else { + retVal = (*proc)(interp); + } if (retVal != NULL) { - Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal, NULL); + Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal, + NULL); /* * Check whether cwd has changed from the value * previously stored in cwdPathPtr. Really 'norm' @@ -2370,6 +2522,9 @@ Tcl_FSGetCwd(interp) */ if (norm == NULL) { /* Do nothing */ + if (retCd != NULL) { + (*fsPtr->freeInternalRepProc)(retCd); + } } else if (Tcl_FSEqualPaths(tsdPtr->cwdPathPtr, norm)) { /* * If the paths were equal, we can be more @@ -2379,19 +2534,23 @@ Tcl_FSGetCwd(interp) * path we just calculated. */ Tcl_DecrRefCount(norm); + if (retCd != NULL) { + (*fsPtr->freeInternalRepProc)(retCd); + } } else { - FsUpdateCwd(norm); + FsUpdateCwd(norm, retCd); Tcl_DecrRefCount(norm); } Tcl_DecrRefCount(retVal); } else { /* The 'cwd' function returned an error; reset the cwd */ - FsUpdateCwd(NULL); + FsUpdateCwd(NULL, NULL); } } } } + cdDidNotChange: if (tsdPtr->cwdPathPtr != NULL) { Tcl_IncrRefCount(tsdPtr->cwdPathPtr); } @@ -2469,11 +2628,13 @@ Tcl_FSChdir(pathPtr) * will have been cached as a result of the * Tcl_FSGetFileSystemForPath call above anyway). */ + ClientData cd; Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr); if (normDirName == NULL) { return TCL_ERROR; } - FsUpdateCwd(normDirName); + cd = (ClientData) Tcl_FSGetNativePath(pathPtr); + FsUpdateCwd(normDirName, TclNativeDupInternalRep(cd)); } } else { Tcl_SetErrno(ENOENT); @@ -3239,10 +3400,13 @@ TclFSInternalToNormalized(fromFilesystem, clientData, fsRecPtrPtr) */ Tcl_PathType -TclGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef) - Tcl_Obj *pathObjPtr; - Tcl_Filesystem **filesystemPtrPtr; - int *driveNameLengthPtr; +TclGetPathType(pathPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef) + Tcl_Obj *pathPtr; /* Path to determine type for */ + Tcl_Filesystem **filesystemPtrPtr; /* If absolute path and this is + * non-NULL, then set to the + * filesystem which claims this + * path */ + int *driveNameLengthPtr; Tcl_Obj **driveNameRef; { FilesystemRecord *fsRecPtr; @@ -3250,7 +3414,7 @@ TclGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef) char *path; Tcl_PathType type = TCL_PATH_RELATIVE; - path = Tcl_GetStringFromObj(pathObjPtr, &pathLen); + path = Tcl_GetStringFromObj(pathPtr, &pathLen); /* * Call each of the "listVolumes" function in succession, checking @@ -3335,7 +3499,7 @@ TclGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef) } if (type != TCL_PATH_ABSOLUTE) { - type = TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, + type = TclpGetNativePathType(pathPtr, driveNameLengthPtr, driveNameRef); if ((type == TCL_PATH_ABSOLUTE) && (filesystemPtrPtr != NULL)) { *filesystemPtrPtr = &tclNativeFilesystem; @@ -3655,7 +3819,8 @@ Tcl_FSRemoveDirectory(pathPtr, recursive, errorPtr) * the cwd is inside the directory, so we * perform a 'cd [file dirname $path]' */ - Tcl_Obj *dirPtr = TclFileDirname(NULL, pathPtr); + Tcl_Obj *dirPtr = TclPathPart(NULL, pathPtr, + TCL_PATH_DIRNAME); Tcl_FSChdir(dirPtr); Tcl_DecrRefCount(dirPtr); } @@ -3690,13 +3855,13 @@ Tcl_FSRemoveDirectory(pathPtr, recursive, errorPtr) */ Tcl_Filesystem* -Tcl_FSGetFileSystemForPath(pathObjPtr) - Tcl_Obj* pathObjPtr; +Tcl_FSGetFileSystemForPath(pathPtr) + Tcl_Obj* pathPtr; { FilesystemRecord *fsRecPtr; Tcl_Filesystem* retVal = NULL; - if (pathObjPtr == NULL) { + if (pathPtr == NULL) { Tcl_Panic("Tcl_FSGetFileSystemForPath called with NULL object"); return NULL; } @@ -3708,7 +3873,7 @@ Tcl_FSGetFileSystemForPath(pathObjPtr) * the ref count on return or not). */ - if (pathObjPtr->refCount == 0) { + if (pathPtr->refCount == 0) { Tcl_Panic("Tcl_FSGetFileSystemForPath called with object with refCount == 0"); return NULL; } @@ -3717,7 +3882,7 @@ Tcl_FSGetFileSystemForPath(pathObjPtr) * Check if the filesystem has changed in some way since * this object's internal representation was calculated. */ - if (TclFSEnsureEpochOk(pathObjPtr, &retVal) != TCL_OK) { + if (TclFSEnsureEpochOk(pathPtr, &retVal) != TCL_OK) { return NULL; } @@ -3732,13 +3897,13 @@ Tcl_FSGetFileSystemForPath(pathObjPtr) Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc; if (proc != NULL) { ClientData clientData = NULL; - int ret = (*proc)(pathObjPtr, &clientData); + int ret = (*proc)(pathPtr, &clientData); if (ret != -1) { /* - * We assume the type of pathObjPtr hasn't been changed + * We assume the type of pathPtr hasn't been changed * by the above call to the pathInFilesystemProc. */ - TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData); + TclFSSetPathDetails(pathPtr, fsRecPtr, clientData); retVal = fsRecPtr->fsPtr; } } @@ -3781,10 +3946,10 @@ Tcl_FSGetFileSystemForPath(pathObjPtr) */ CONST char * -Tcl_FSGetNativePath(pathObjPtr) - Tcl_Obj *pathObjPtr; +Tcl_FSGetNativePath(pathPtr) + Tcl_Obj *pathPtr; { - return (CONST char *)Tcl_FSGetInternalRep(pathObjPtr, &tclNativeFilesystem); + return (CONST char *)Tcl_FSGetInternalRep(pathPtr, &tclNativeFilesystem); } /* @@ -3803,19 +3968,26 @@ Tcl_FSGetNativePath(pathObjPtr) *--------------------------------------------------------------------------- */ static ClientData -NativeCreateNativeRep(pathObjPtr) - Tcl_Obj* pathObjPtr; +NativeCreateNativeRep(pathPtr) + Tcl_Obj* pathPtr; { char *nativePathPtr; Tcl_DString ds; - Tcl_Obj* validPathObjPtr; + Tcl_Obj* validPathPtr; int len; char *str; + ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey); - /* Make sure the normalized path is set */ - validPathObjPtr = Tcl_FSGetNormalizedPath(NULL, pathObjPtr); + if (tsdPtr->cwdClientData != NULL) { + /* The cwd is native */ + validPathPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); + } else { + /* Make sure the normalized path is set */ + validPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr); + Tcl_IncrRefCount(validPathPtr); + } - str = Tcl_GetStringFromObj(validPathObjPtr, &len); + str = Tcl_GetStringFromObj(validPathPtr, &len); #ifdef __WIN32__ Tcl_WinUtfToTChar(str, len, &ds); if (tclWinProcs->useWide) { @@ -3827,6 +3999,7 @@ NativeCreateNativeRep(pathObjPtr) Tcl_UtfToExternalDString(NULL, str, len, &ds); len = Tcl_DStringLength(&ds) + sizeof(char); #endif + Tcl_DecrRefCount(validPathPtr); nativePathPtr = ckalloc((unsigned) len); memcpy((VOID*)nativePathPtr, (VOID*)Tcl_DStringValue(&ds), (size_t) len); @@ -3841,6 +4014,11 @@ NativeCreateNativeRep(pathObjPtr) * * Convert native format to a normalized path object, with refCount * of zero. + * + * Currently assumes all native paths are actually normalized + * already, so if the path given is not normalized this will + * actually just convert to a valid string path, but not + * necessarily a normalized one. * * Results: * A valid normalized path. @@ -3856,12 +4034,14 @@ TclpNativeToNormalized(clientData) { Tcl_DString ds; Tcl_Obj *objPtr; - CONST char *copy; int len; #ifdef __WIN32__ + char *copy; + char *p; Tcl_WinTCharToUtf((CONST char*)clientData, -1, &ds); #else + CONST char *copy; Tcl_ExternalToUtfDString(NULL, (CONST char*)clientData, -1, &ds); #endif @@ -3883,6 +4063,14 @@ TclpNativeToNormalized(clientData) len -= 4; } } + /* + * Ensure we are using forward slashes only. + */ + for (p = copy; *p != '\0'; p++) { + if (*p == '\\') { + *p = '/'; + } + } #endif objPtr = Tcl_NewStringObj(copy,len); @@ -3978,12 +4166,12 @@ NativeFreeInternalRep(clientData) *--------------------------------------------------------------------------- */ Tcl_Obj* -Tcl_FSFileSystemInfo(pathObjPtr) - Tcl_Obj* pathObjPtr; +Tcl_FSFileSystemInfo(pathPtr) + Tcl_Obj* pathPtr; { Tcl_Obj *resPtr; Tcl_FSFilesystemPathTypeProc *proc; - Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathObjPtr); + Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr == NULL) { return NULL; @@ -3996,7 +4184,7 @@ Tcl_FSFileSystemInfo(pathObjPtr) proc = fsPtr->filesystemPathTypeProc; if (proc != NULL) { - Tcl_Obj *typePtr = (*proc)(pathObjPtr); + Tcl_Obj *typePtr = (*proc)(pathPtr); if (typePtr != NULL) { Tcl_ListObjAppendElement(NULL, resPtr, typePtr); } @@ -4024,16 +4212,16 @@ Tcl_FSFileSystemInfo(pathObjPtr) *--------------------------------------------------------------------------- */ Tcl_Obj* -Tcl_FSPathSeparator(pathObjPtr) - Tcl_Obj* pathObjPtr; +Tcl_FSPathSeparator(pathPtr) + Tcl_Obj* pathPtr; { - Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathObjPtr); + Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr); if (fsPtr == NULL) { return NULL; } if (fsPtr->filesystemSeparatorProc != NULL) { - return (*fsPtr->filesystemSeparatorProc)(pathObjPtr); + return (*fsPtr->filesystemSeparatorProc)(pathPtr); } return NULL; @@ -4056,8 +4244,8 @@ Tcl_FSPathSeparator(pathObjPtr) *--------------------------------------------------------------------------- */ static Tcl_Obj* -NativeFilesystemSeparator(pathObjPtr) - Tcl_Obj* pathObjPtr; +NativeFilesystemSeparator(pathPtr) + Tcl_Obj* pathPtr; { char *separator = NULL; /* lint */ switch (tclPlatform) { |