Tcl Source Code

Artifact [1c65c2d252]
Login

Artifact 1c65c2d252345bee43961c37aaad45364aed26f6:

Attachment "tclWinFile.diff" to ticket [580053ffff] added by vincentdarley 2002-07-11 20:54:43.
Index: tclWinFile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinFile.c,v
retrieving revision 1.33
diff -u -r1.33 tclWinFile.c
--- tclWinFile.c	21 Jun 2002 14:22:29 -0000	1.33
+++ tclWinFile.c	11 Jul 2002 13:54:22 -0000
@@ -2074,76 +2074,113 @@
     char *path = Tcl_GetStringFromObj(pathPtr, &pathLen);
 
     if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) {
-	Tcl_DString eDs;
-	char *nativePath;
-	int nativeLen;
+	/* We're on Win95, 98 or ME */
+	CONST char *nativePath;
+	char *currentPathEndPosition;
+	Tcl_Obj *temp = NULL;
+	int isDrive = 1;
+	/* This will hold the normalized string */
+	Tcl_DString dsNorm;
+	Tcl_DStringInit(&dsNorm);
+	nativePath = Tcl_UtfToExternalDString(NULL, path, -1, &ds);
 
-	Tcl_UtfToExternalDString(NULL, path, -1, &ds);
-	nativePath = Tcl_DStringValue(&ds);
-	nativeLen = Tcl_DStringLength(&ds);
-
-	/* We're on Windows 95/98 */
-	lastValidPathEnd = nativePath + Tcl_DStringLength(&ds);
-	
+	Tcl_DStringFree(&ds);
+	currentPathEndPosition = path + nextCheckpoint;
 	while (1) {
-	    DWORD res = GetShortPathNameA(nativePath, nativePath, 1+nativeLen);
-	    if (res != 0) {
-		/* We found an ok path */
-		break;
-	    }
-	    /* Undo the null-termination we put in before */
-	    if (lastValidPathEnd != (nativePath + nativeLen)) {
-		*lastValidPathEnd = '/';
-	    }
-	    /* 
-	     * The path doesn't exist.  Back up the path, one component
-	     * (directory/file) at a time, until one does exist. 
-	     */
-	    while (1) {
-		char cur;
-		lastValidPathEnd--;
-		if (lastValidPathEnd == nativePath) {
-		    /* We didn't accept any of the path */
-		    Tcl_DStringFree(&ds);
-		    return nextCheckpoint;
+	    char cur = *currentPathEndPosition;
+	    if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) {
+		/* Reached directory separator, or end of string */
+		nativePath = Tcl_UtfToExternalDString(NULL, path, 
+			    currentPathEndPosition - path, &ds);
+
+		/*
+		 * Now we convert the tail of the current path to its
+		 * 'long form', and append it to 'dsNorm' which holds
+		 * the current normalized path, if the file exists.
+		 */
+		if (isDrive) {
+		    if (GetFileAttributesA(nativePath) 
+			== 0xffffffff) {
+			/* File doesn't exist */
+			Tcl_DStringFree(&ds);
+			break;
+		    }
+		    if (nativePath[0] >= 'a') {
+			((char*)nativePath)[0] -= ('a' - 'A');
+		    }
+		    Tcl_DStringAppend(&dsNorm,nativePath,Tcl_DStringLength(&ds));
+		} else {
+		    WIN32_FIND_DATA fData;
+		    HANDLE handle;
+		    
+		    handle = FindFirstFileA(nativePath, &fData);
+		    if (handle == INVALID_HANDLE_VALUE) {
+			if (GetFileAttributesA(nativePath) 
+			    == 0xffffffff) {
+			    /* File doesn't exist */
+			    Tcl_DStringFree(&ds);
+			    break;
+			}
+			/* This is usually the '/' in 'c:/' at end of string */
+			Tcl_DStringAppend(&dsNorm,"/", 1);
+		    } else {
+			char *nativeName;
+			if (fData.cFileName[0] != '\0') {
+			    nativeName = fData.cFileName;
+			} else {
+			    nativeName = fData.cAlternateFileName;
+			}
+			FindClose(handle);
+			Tcl_DStringAppend(&dsNorm,"/", 1);
+			Tcl_DStringAppend(&dsNorm,nativeName, 
+					  strlen(nativeName));
+		    }
 		}
-		cur = *(lastValidPathEnd);
-		if (cur == '/' || cur == '\\') {
-		    /* Reached directory separator */
+		Tcl_DStringFree(&ds);
+		lastValidPathEnd = currentPathEndPosition;
+		if (cur == 0) {
 		    break;
 		}
+		/* 
+		 * If we get here, we've got past one directory
+		 * delimiter, so we know it is no longer a drive 
+		 */
+		isDrive = 0;
 	    }
-	    /* Temporarily terminate the string */
-	    *lastValidPathEnd = '\0';
+	    currentPathEndPosition++;
 	}
-	/* 
-	 * If we get here, we found a valid path, which we've converted
-	 * to short form, and the valid string ends at or before
-	 * 'lastValidPathEnd' and the invalid string starts at
-	 * 'lastValidPathEnd'.
-	 */
-
-	/* Copy over the valid part of the path and find its length */
-	Tcl_ExternalToUtfDString(NULL, nativePath, -1, &eDs);
-	path = Tcl_DStringValue(&eDs);
-	if (path[1] == ':') {
-	    if (path[0] >= 'a' && path[0] <= 'z') {
-		/* Make uppercase */
-		path[0] -= 32;
+	nextCheckpoint = currentPathEndPosition - path;
+	
+	if (lastValidPathEnd != NULL) {
+	    /* 
+	     * Concatenate the normalized string in dsNorm with the
+	     * tail of the path which we didn't recognise.  The
+	     * string in dsNorm is in the native encoding, so we
+	     * have to convert it to Utf.
+	     */
+	    Tcl_DString dsTemp;
+	    Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&dsNorm), 
+			      Tcl_DStringLength(&dsNorm), &dsTemp);
+	    nextCheckpoint = Tcl_DStringLength(&dsTemp);
+	    if (*lastValidPathEnd != 0) {
+		/* Not the end of the string */
+		int len;
+		char *path;
+		Tcl_Obj *tmpPathPtr;
+		tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp), 
+					      nextCheckpoint);
+		Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1);
+		path = Tcl_GetStringFromObj(tmpPathPtr, &len);
+		Tcl_SetStringObj(pathPtr, path, len);
+		Tcl_DecrRefCount(tmpPathPtr);
+	    } else {
+		/* End of string was reached above */
+		Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&dsTemp),
+				 nextCheckpoint);
 	    }
+	    Tcl_DStringFree(&dsTemp);
 	}
-	nextCheckpoint = Tcl_DStringLength(&eDs);
-	Tcl_SetStringObj(pathPtr, path, Tcl_DStringLength(&eDs));
-	Tcl_DStringFree(&eDs);
-	if (lastValidPathEnd != (nativePath + nativeLen)) {
-	    CONST char *tmp;
-	    *lastValidPathEnd = '/';
-	    /* Now copy over the invalid (i.e. non-existent) part of the path */
-	    tmp = Tcl_ExternalToUtfDString(NULL, lastValidPathEnd, -1, &eDs);
-	    Tcl_AppendToObj(pathPtr, tmp, Tcl_DStringLength(&eDs));
-	    Tcl_DStringFree(&eDs);
-	}
-	Tcl_DStringFree(&ds);
+	Tcl_DStringFree(&dsNorm);
     } else {
 	/* We're on WinNT or 2000 or XP */
 	CONST char *nativePath;