foxygit / doom Log in
commit 533e3726f0fdeb0f679fedd96ab4877f80922456
Author:     Fabian Greffrath <fabian@greffrath.com>
AuthorDate: Tue Nov 22 23:53:48 2016 +0100
Commit:     Simon Howard <fraggle+github@gmail.com>
CommitDate: Tue Nov 22 17:53:48 2016 -0500

    Try multiple capitalizations when searching for WADs.

    Add M_FileCaseExists() that checks if a file exists by trying
    multiple different capitalization formats, and change WAD
    search code to use this when locating WAD files.
---
 src/d_iwad.c | 27 ++++++++++++-------
 src/m_misc.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/m_misc.h |  2 ++
 3 files changed, 106 insertions(+), 10 deletions(-)

diff --git a/src/d_iwad.c b/src/d_iwad.c
index 677debf7..ef67f1c6 100644
--- a/src/d_iwad.c
+++ b/src/d_iwad.c
@@ -459,13 +459,15 @@ static boolean DirIsFile(char *path, char *filename)
 static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
 {
     char *filename;
+    char *probe;

     // As a special case, the "directory" may refer directly to an
     // IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH.

-    if (DirIsFile(dir, iwadname) && M_FileExists(dir))
+    probe = M_FileCaseExists(dir);
+    if (DirIsFile(dir, iwadname) && probe != NULL)
     {
-        return M_StringDuplicate(dir);
+        return probe;
     }

     // Construct the full path to the IWAD if it is located in
@@ -480,9 +482,10 @@ static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
         filename = M_StringJoin(dir, DIR_SEPARATOR_S, iwadname, NULL);
     }

-    if (M_FileExists(filename))
+    probe = M_FileCaseExists(filename);
+    if (probe != NULL)
     {
-        return filename;
+        return probe;
     }

     free(filename);
@@ -709,13 +712,15 @@ static void BuildIWADDirList(void)
 char *D_FindWADByName(char *name)
 {
     char *path;
+    char *probe;
     int i;

     // Absolute path?

-    if (M_FileExists(name))
+    probe = M_FileCaseExists(name);
+    if (probe != NULL)
     {
-        return name;
+        return probe;
     }

     BuildIWADDirList();
@@ -728,18 +733,20 @@ char *D_FindWADByName(char *name)
         // the "directory" may actually refer directly to an IWAD
         // file.

-        if (DirIsFile(iwad_dirs[i], name) && M_FileExists(iwad_dirs[i]))
+        probe = M_FileCaseExists(iwad_dirs[i]);
+        if (DirIsFile(iwad_dirs[i], name) && probe != NULL)
         {
-            return M_StringDuplicate(iwad_dirs[i]);
+            return probe;
         }

         // Construct a string for the full path

         path = M_StringJoin(iwad_dirs[i], DIR_SEPARATOR_S, name, NULL);

-        if (M_FileExists(path))
+        probe = M_FileCaseExists(path);
+        if (probe != NULL)
         {
-            return path;
+            return probe;
         }

         free(path);
diff --git a/src/m_misc.c b/src/m_misc.c
index 53b86dba..7e69da8f 100644
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -83,6 +83,75 @@ boolean M_FileExists(char *filename)
     }
 }

+// Check if a file exists by probing for common case variation of its filename.
+// Returns a newly allocated string that the caller is responsible for freeing.
+
+char *M_FileCaseExists(char *path)
+{
+    char *path_dup, *filename, *ext;
+
+    path_dup = M_StringDuplicate(path);
+
+    // 0: actual path
+    if (M_FileExists(path_dup))
+    {
+        return path_dup;
+    }
+
+    filename = strrchr(path_dup, DIR_SEPARATOR);
+    if (filename != NULL)
+    {
+        filename++;
+    }
+    else
+    {
+        filename = path_dup;
+    }
+
+    // 1: lowercase filename, e.g. doom2.wad
+    M_ForceLowercase(filename);
+
+    if (M_FileExists(path_dup))
+    {
+        return path_dup;
+    }
+
+    // 2: uppercase filename, e.g. DOOM2.WAD
+    M_ForceUppercase(filename);
+
+    if (M_FileExists(path_dup))
+    {
+        return path_dup;
+    }
+
+    // 3. uppercase basename with lowercase extension, e.g. DOOM2.wad
+    ext = strrchr(path_dup, '.');
+    if (ext != NULL && ext > filename)
+    {
+        M_ForceLowercase(ext + 1);
+
+        if (M_FileExists(path_dup))
+        {
+            return path_dup;
+        }
+    }
+
+    // 4. lowercase filename with uppercase first letter, e.g. Doom2.wad
+    if (strlen(filename) > 1)
+    {
+        M_ForceLowercase(filename + 1);
+
+        if (M_FileExists(path_dup))
+        {
+            return path_dup;
+        }
+    }
+
+    // 5. no luck
+    free(path_dup);
+    return NULL;
+}
+
 //
 // Determine the length of an open file.
 //
@@ -250,6 +319,24 @@ void M_ForceUppercase(char *text)
     }
 }

+//---------------------------------------------------------------------------
+//
+// PROC M_ForceLowercase
+//
+// Change string to lowercase.
+//
+//---------------------------------------------------------------------------
+
+void M_ForceLowercase(char *text)
+{
+    char *p;
+
+    for (p = text; *p != '\0'; ++p)
+    {
+        *p = tolower(*p);
+    }
+}
+
 //
 // M_StrCaseStr
 //
diff --git a/src/m_misc.h b/src/m_misc.h
index 844b4859..c6debfd0 100644
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -30,10 +30,12 @@ int M_ReadFile(char *name, byte **buffer);
 void M_MakeDirectory(char *dir);
 char *M_TempFile(char *s);
 boolean M_FileExists(char *file);
+char *M_FileCaseExists(char *file);
 long M_FileLength(FILE *handle);
 boolean M_StrToInt(const char *str, int *result);
 void M_ExtractFileBase(char *path, char *dest);
 void M_ForceUppercase(char *text);
+void M_ForceLowercase(char *text);
 char *M_StrCaseStr(char *haystack, char *needle);
 char *M_StringDuplicate(const char *orig);
 boolean M_StringCopy(char *dest, const char *src, size_t dest_size);