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;