From 249f334f838e0cb58022a749a549e00251e3a0ac Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@Germany>
Date: Wed, 15 Mar 2017 13:06:45 +0100
Subject: [PATCH] ENH: respect '-silent' option for cmake builds

- minor cleanup of wmake sources
---
 wmake/rules/General/transform |   5 +-
 wmake/scripts/cmakeFunctions  |  15 +-
 wmake/scripts/makeFiles       |  10 +-
 wmake/scripts/makeOptions     |   5 +-
 wmake/scripts/makeTargetDir   |   2 +-
 wmake/src/Makefile            |   1 -
 wmake/src/dirToString.c       |  50 ++--
 wmake/src/wmkdep.l            | 535 ++++++++++++++++++++++------------
 wmake/wclean                  |   6 +-
 wmake/wmake                   |  15 +-
 wmake/wmakeCheckPwd           |  52 ++--
 wmake/wmakeFilesAndOptions    |  37 +--
 12 files changed, 452 insertions(+), 281 deletions(-)

diff --git a/wmake/rules/General/transform b/wmake/rules/General/transform
index 165c4a1f4e8..ae247644925 100644
--- a/wmake/rules/General/transform
+++ b/wmake/rules/General/transform
@@ -28,8 +28,7 @@ $(OBJECTS_DIR)/%.dep : %
 	$(call QUIET_MESSAGE,wmkdep,$(<F))
 	$(call VERBOSE_MESSAGE,Making dependency list for source file,$(<F))
 	@$(WM_SCRIPTS)/makeTargetDir $@
-	@$(WMAKE_BIN)/wmkdep -I$(*D) $(LIB_HEADER_DIRS) $< | \
-		sed -e 's,^$(WM_PROJECT_DIR)/,$$(WM_PROJECT_DIR)/,' \
-			-e 's,^$(WM_THIRD_PARTY_DIR)/,$$(WM_THIRD_PARTY_DIR)/,' > $@
+	@$(WMAKE_BIN)/wmkdep -o$@ -I$(*D) $(LIB_HEADER_DIRS) \
+		-eWM_PROJECT_DIR -eWM_THIRD_PARTY_DIR $<
 
 #------------------------------------------------------------------------------
diff --git a/wmake/scripts/cmakeFunctions b/wmake/scripts/cmakeFunctions
index b78d7c34aa1..c64bdb3525c 100644
--- a/wmake/scripts/cmakeFunctions
+++ b/wmake/scripts/cmakeFunctions
@@ -72,6 +72,19 @@ sameDependency()
 }
 
 
+# CMake with output suppressed according to WM_QUIET
+_cmake()
+{
+    echo "cmake..."
+    if [ -n "$WM_QUIET" ]
+    then
+        cmake -DCMAKE_RULE_MESSAGES=OFF $@ >/dev/null
+    else
+        cmake $@
+    fi
+}
+
+
 # CMake into objectsDir with external dependency
 # - use sentinel file(s) to handle paraview/vtk version changes
 cmakeVersioned()
@@ -89,7 +102,7 @@ cmakeVersioned()
 
     mkdir -p $objectsDir && \
     (
-        cd $objectsDir && cmake $sourceDir && make \
+        cd $objectsDir && _cmake $sourceDir && make \
      && echo "$depend" > ${sentinel:-/dev/null}
     )
 }
diff --git a/wmake/scripts/makeFiles b/wmake/scripts/makeFiles
index 09b487219a4..118a97ec1bc 100755
--- a/wmake/scripts/makeFiles
+++ b/wmake/scripts/makeFiles
@@ -31,6 +31,7 @@
 #     Usage : makeFiles
 #
 #------------------------------------------------------------------------------
+dirToString=$WM_DIR/platforms/$WM_ARCH$WM_COMPILER/dirToString
 
 if [ -r Make/files ]
 then
@@ -38,10 +39,15 @@ then
     exit 1
 fi
 
-dirToString=$WM_DIR/platforms/$WM_ARCH$WM_COMPILER/dirToString
+[ -x "$dirToString" ] || {
+    echo "Error: no command $dirToString" 1>&2
+    exit 1
+}
 
 [ -d Make ] || mkdir Make
 rm -f Make/files
+#------------------------------------------------------------------------------
+echo "Creating Make/files"
 
 for dir in $(find . -mindepth 1 -type d -print)
 do
@@ -53,7 +59,7 @@ do
         echo "$(echo $dir | $dirToString -strip)  =  ${dir#./}"
         ;;
     esac
-done >> Make/files
+done > Make/files
 [ -s Make/files ] && echo >> Make/files
 
 for file in $(find . -name "*.[cCylLfF]" -type f -print)
diff --git a/wmake/scripts/makeOptions b/wmake/scripts/makeOptions
index 62f7e88e5ef..5b991ee1dc2 100755
--- a/wmake/scripts/makeOptions
+++ b/wmake/scripts/makeOptions
@@ -39,11 +39,12 @@ then
 fi
 
 [ -d Make ] || mkdir Make
-
 rm -f Make/options
+#------------------------------------------------------------------------------
+echo "Creating Make/options"
 
 echo 'EXE_INC = \
-    -I$(LIB_SRC)/finiteVolume/lnInclude' >> Make/options
+    -I$(LIB_SRC)/finiteVolume/lnInclude' > Make/options
 echo >> Make/options
 echo 'EXE_LIBS = \
     -lfiniteVolume' >> Make/options
diff --git a/wmake/scripts/makeTargetDir b/wmake/scripts/makeTargetDir
index 94307ce32e2..e7477c55505 100755
--- a/wmake/scripts/makeTargetDir
+++ b/wmake/scripts/makeTargetDir
@@ -28,7 +28,7 @@
 # Description
 #     Makes a directory hierarchy for the given target file
 #
-#     Usage: makeTargetDir <directory>
+#     Usage: makeTargetDir <file>
 #
 #------------------------------------------------------------------------------
 
diff --git a/wmake/src/Makefile b/wmake/src/Makefile
index cc679c9482a..d5ee35fb5b1 100644
--- a/wmake/src/Makefile
+++ b/wmake/src/Makefile
@@ -78,5 +78,4 @@ $(WMAKE_BIN)/wmkdep: wmkdep.l
 	$E flex -o $@.c $(<F) && $(cc) $(cFLAGS) $@.c -o $@
 	@rm -f $@.c 2>/dev/null
 
-
 #------------------------------------------------------------------------------
diff --git a/wmake/src/dirToString.c b/wmake/src/dirToString.c
index 1ce3e9455f7..1655af38549 100644
--- a/wmake/src/dirToString.c
+++ b/wmake/src/dirToString.c
@@ -25,8 +25,8 @@ Application
     dirToString
 
 Description
-    converts a directory path into a string with appropriate capitalisation
-    e.g. dir1/dir2 becomes dir1Dir2
+    Converts a directory path into a camelCase string.
+    e.g. dir1/dir2/dir3 becomes dir1Dir2Dir3
 
 Usage
     echo dirName | dirToString
@@ -45,34 +45,34 @@ Usage
 #include <string.h>
 #include <ctype.h>
 
+/* The executable name (for messages), without requiring access to argv[] */
+#define EXENAME  "dirToString"
+
 int main(int argc, char* argv[])
 {
     int c;
-    int nextupper = 0;
 
     if (argc > 1)
     {
-        if (!strncmp(argv[1], "-h", 2))  /* -h, -help */
+        if (!strncmp(argv[1], "-h", 2))
         {
-            fprintf
-            (
-                stderr,
-                "\nUsage: %s [-strip]\n\n",
-                "dirToString"
-            );
+            /* Option: -h, -help */
 
-            fprintf
+            fputs
             (
-                stderr,
+                "\nUsage: " EXENAME
+                " [-strip]\n\n"
                 "  -strip    ignore leading [./] characters.\n\n"
-                "Transform dir1/dir2 to camel-case dir1Dir2\n\n"
+                "Converts a directory path into a camelCase string\n\n",
+                stderr
             );
-
             return 0;
         }
 
-        if (!strcmp(argv[1], "-s") || !strcmp(argv[1], "-strip"))  /* -s, -strip */
+        if (!strcmp(argv[1], "-s") || !strcmp(argv[1], "-strip"))
         {
+            /* Option: -s, -strip */
+
             while ((c=getchar()) != EOF && (c == '.' || c == '/'))
             {
                 /* nop */
@@ -88,23 +88,21 @@ int main(int argc, char* argv[])
     }
 
 
-    while ((c=getchar()) != EOF)
+    int nextUpper = 0;
+    while ((c = getchar()) != EOF)
     {
         if (c == '/')
         {
-            nextupper = 1;
+            nextUpper = 1;
+        }
+        else if (nextUpper)
+        {
+            putchar(toupper(c));
+            nextUpper = 0;
         }
         else
         {
-            if (nextupper)
-            {
-                putchar(toupper(c));
-                nextupper = 0;
-            }
-            else
-            {
-                putchar(c);
-            }
+            putchar(c);
         }
     }
 
diff --git a/wmake/src/wmkdep.l b/wmake/src/wmkdep.l
index 6e198bab4c2..a3a503fb9e9 100644
--- a/wmake/src/wmkdep.l
+++ b/wmake/src/wmkdep.l
@@ -26,18 +26,26 @@ Application
     wmkdep
 
 Description
-    A fast dependency list generator that emulates the behaviour and the
-    output of cpp -M. However, the output contains no duplicates and
-    is approx. 40% faster than cpp.
+    A fast dependency list generator that emulates the behaviour and output
+    of cpp -M. However, the output contains no duplicates and is thus
+    approx. 40% faster than cpp.
+    It also handles missing files somewhat more gracefully.
 
-    The algorithm uses flex to scan for includes and searches the files
-    found.  Each file is entered into a hash table so that files are scanned
-    only once.  This is why this program is faster than cpp.
+    The algorithm uses flex to scan for includes and searches the files found.
+    The files are only visited once (the names of the files visited are hashed),
+    which makes this faster than cpp.
 
 Usage
-    wmkdep [ -Idir ... -Idir ] [ -iheader .. -iheader ] filename
+    wmkdep [-Idir..] [-iheader...] [-eENV...] [-ofile] filename
 
 \*---------------------------------------------------------------------------*/
+/* With cpp:
+ *
+ * cpp -x c++ -std=c++11 -nostdinc -nostdinc++
+ *     -M -DWM_$(WM_PRECISION_OPTION) -DWM_LABEL_SIZE=$(WM_LABEL_SIZE) |
+ * sed -e 's,^$(WM_PROJECT_DIR)/,$$(WM_PROJECT_DIR)/,' \
+ *     -e 's,^$(WM_THIRD_PARTY_DIR)/,$$(WM_THIRD_PARTY_DIR)/,'
+ */
 
 #define FILE_STACK_SIZE 300
 #define HASH_TABLE_SIZE 500
@@ -51,8 +59,7 @@ Usage
 
 /* The executable name (for messages), without requiring access to argv[] */
 #define EXENAME  "wmkdep"
-#undef yywrap        /* sometimes a macro by default */
-#define YY_NO_INPUT  /* no input(), yyinput() required */
+#undef yywrap           /* sometimes a macro by default */
 #pragma GCC diagnostic ignored "-Wunused-function"
 
 void nextFile(const char* fileName);
@@ -60,29 +67,31 @@ void nextFile(const char* fileName);
 /*---------------------------------------------------------------------------*/
 %}
 
-%x CMNT CFNAME SCFNAME JFNAME FFNAME
+%x CMNT CFNAME FFNAME
 %%
 
-"//".*\n                  ;            /* remove c++ style one line comments */
+"//".*\n            ;               /* Remove C++-style comment */
 
-"/*"                      BEGIN(CMNT);    /* start removing c style comment */
-<CMNT>.|\n                ;
-<CMNT>"*/"                BEGIN(INITIAL); /* end removing c style comment */
+"/*"                BEGIN(CMNT);    /* Begin removing C-style comment */
+<CMNT>.|\n          ;
+<CMNT>"*/"          BEGIN(INITIAL); /* End removing C-style comment */
 
-^[ \t]*#[ \t]*include[ \t]+\"   BEGIN(CFNAME);  /* c-file name */
-<CFNAME>[^"\n ]*        { BEGIN(INITIAL); nextFile(yytext); } /*"*/
+^[ \t]*#[ \t]*include[ \t]+\"   BEGIN(CFNAME);  /* C-file name */
+<CFNAME>[^"\n ]*    { BEGIN(INITIAL); nextFile(yytext); } /* "-quoted */
 
-"      "include[ \t]+\'   BEGIN(FFNAME);  /* FORTRAN-file name */
-<FFNAME>[^']*           { BEGIN(INITIAL); nextFile(yytext); } /*'*/
+"      "include[ \t]+\'   BEGIN(FFNAME);        /* FORTRAN-file name */
+<FFNAME>[^']*       { BEGIN(INITIAL); nextFile(yytext); } /* '-quoted */
 
-.|\t|\n                   ;
+.|\t|\n             ;
 
 %%
 
 /*---------------------------------------------------------------------------*/
 
 
-/* char* entry in hash table */
+/*
+ * A char* entry in hash table
+ */
 struct HashEntry
 {
     char* name;
@@ -91,49 +100,173 @@ struct HashEntry
 
 
 /*
- * lookup name in hash table.
+ * Lookup name in hashTable.
  * if found - return 1
- * if not found - insert in table and return 0
+ * if not found - insert in hashTable and return 0
  */
-int lookUp(struct HashEntry** hashTable, const char* p)
+static int lookUp(struct HashEntry* hashTable[HASH_TABLE_SIZE], const char* str)
 {
-    int ii = 0;
-    struct HashEntry* n;
-    struct HashEntry* nn;
-
-    /* hash */
-    const char* pp = p;
-    while (*pp) ii = ii<<1 ^ *pp++;
-    if (ii < 0) ii = -ii;
-    ii %= HASH_TABLE_SIZE;
-
-    /* search */
-    for (n=hashTable[ii]; n; n=n->next)
+    unsigned idx = 0; /* Hash index */
+    {
+        const char* pp = str;
+        while (*pp) idx = idx << 1 ^ *pp++;
+        idx %= HASH_TABLE_SIZE;
+    }
+
+    /* Search for entry */
+    struct HashEntry* entry;
+    for (entry = hashTable[idx]; entry; entry = entry->next)
     {
-        if (strcmp(p, n->name) == 0)
+        if (!strcmp(str, entry->name))
         {
-            /* entry found so return true */
-            return 1;
+            return 1; /* True: entry found */
         }
     }
 
-    /* insert */
-    nn = (struct HashEntry*)malloc(sizeof(struct HashEntry));
-    nn->name = strdup(p);
-    nn->next = hashTable[ii];
-    hashTable[ii] = nn;
+    /* Entry not found - insert a new entry */
+    entry = (struct HashEntry*)malloc(sizeof(struct HashEntry));
+    entry->name = strdup(str);
+    entry->next = hashTable[idx];
+    hashTable[idx] = entry;
 
-    /* entry not found, and therefore added. return false */
-    return 0;
+    return 0;   /* False: entry did not previously exist */
+}
+
+
+/*
+ * Free allocated memory in hashTable.
+ */
+static void free_hashTable(struct HashEntry* hashTable[HASH_TABLE_SIZE])
+{
+    int idx;
+    for (idx = 0; idx < HASH_TABLE_SIZE; ++idx)
+    {
+        struct HashEntry* entry = hashTable[idx];
+        hashTable[idx] = NULL;
+
+        while (entry)
+        {
+            struct HashEntry* next = entry->next;
+            free(entry->name);
+            free(entry);
+
+            entry = next;
+        }
+    }
+}
+
+
+/*
+ * Environment entry - as a linked-list
+ */
+struct KeyValue
+{
+    char* name;
+    char* value;
+    size_t len;
+    struct KeyValue* next;
+};
+
+
+/* List of environ variables to substitute */
+struct KeyValue* envTable = NULL;
+
+/*
+ * Add envTable replacements:
+ *
+ * Eg,
+ *     /openfoam/project/path/directory/xyz
+ *  -> $(WM_PROJECT_DIR)/directory/xyz
+ */
+static void add_env(const char* key)
+{
+    const char *val = getenv(key);
+
+    if (val && *val)
+    {
+        const size_t keyLen = strlen(key);
+        const size_t valLen = strlen(val);
+
+        /* "$(ENV)/" */
+        char *replace = (char*)malloc(keyLen + 5);
+        strcpy(replace, "$(");
+        strcat(replace, key);
+        strcat(replace, ")/");
+
+        /* "/env/value/" */
+        char *orig = (char*)malloc(valLen + 2);
+        strcpy(orig, val);
+        if (val[valLen-1] != '/')
+        {
+            strcat(orig, "/");
+        }
+
+        struct KeyValue* entry =
+            (struct KeyValue*)malloc(sizeof(struct KeyValue));
+
+        entry->name  = replace;
+        entry->value = orig;
+        entry->len   = strlen(orig);
+        entry->next  = envTable;
+        envTable = entry;
+    }
+}
+
+
+/*
+ * Free allocated memory in envTable.
+ */
+static void free_envTable()
+{
+    struct KeyValue* entry = envTable;
+
+    while (entry)
+    {
+        struct KeyValue* next = entry->next;
+        free(entry->name);
+        free(entry->value);
+        free(entry);
+
+        entry = next;
+    }
+}
+
+
+/*
+ * Print fileName to stdout,
+ * with envTable substitutions at the beginning of the path
+ *
+ * Eg,
+ *     /openfoam/project/path/directory/xyz
+ *  -> $(WM_PROJECT_DIR)/directory/xyz
+ */
+static void print_fileName(const char* fileName)
+{
+    const size_t len = strlen(fileName);
+    const char *substr = fileName;
+
+    struct KeyValue* entry = envTable;
+    while (entry)
+    {
+        if (len > entry->len && !strncmp(fileName, entry->value, entry->len))
+        {
+            substr = (fileName + entry->len);
+            fputs(entry->name, stdout);
+            break;
+        }
+        entry = entry->next;
+    }
+
+    fputs(substr, stdout);
+    fputs(" \\\n", stdout);
 }
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 int nDirectories = 0;
-char** directories;
+char** directories = NULL;
 char* sourceFile = NULL;
-char* depFile = NULL;
 
 /* Set of files already visited */
 struct HashEntry* visitedFiles[HASH_TABLE_SIZE];
@@ -150,7 +283,6 @@ const char* bufferPaths[FILE_STACK_SIZE];
 
 int main(int argc, char* argv[])
 {
-    char *basePos, *dotPos;
     int i;
 
     if (argc < 2)
@@ -158,148 +290,211 @@ int main(int argc, char* argv[])
         fputs(EXENAME ": input file not supplied\n", stderr);
         return 1;
     }
-    else if (!strncmp(argv[1], "-h", 2)) /* -h, -help */
-    {
-        fputs
-        (
-            "\nUsage: " EXENAME
-            " [-Idir ... -Idir] [-iheader .. -iheader] filename\n\n"
-            "  -Idir     Directories to be searched for headers.\n"
-            "  -iheader  Headers to be ignored.\n\n"
-            "Dependency list generator, similar to 'cpp -M'\n\n",
-            stderr
-        );
 
-        return 0;
-    }
-
-    sourceFile = strdup(argv[argc-1]);
-
-    if ((basePos = strrchr(sourceFile, '/')) == NULL)
+#if 0
+    for (i = 0; i < argc; ++i)
     {
-        basePos = sourceFile;
-    }
-    else
-    {
-        ++basePos;
-    }
-
-    if
-    (
-        (dotPos = strrchr(sourceFile, '.')) == NULL
-     || (dotPos < basePos)
-    )
-    {
-        fprintf
-        (
-            stderr,
-            EXENAME ": cannot find extension in source file name '%s'\n",
-            sourceFile
-        );
-        return 1;
+        if (i) fputs(" ", stderr);
+        fputs(argv[i], stderr);
     }
+#endif
 
-    /* count number of -I directories */
+    /* Prechecks:
+     * - help
+     * - count number of -I directories
+     */
     nDirectories = 0;
     for (i = 1; i < argc; ++i)
     {
-        if (strncmp(argv[i], "-I", 2) == 0)
+        if (argv[i][0] != '-') continue;
+
+        switch (argv[i][1])
         {
-            if (strlen(argv[i]) > 2)
-            {
+            case 'h':           /* Option: -h, -help */
+                fputs
+                (
+                    "\nUsage: " EXENAME
+                    " [-Idir...] [-iheader...] [-eENV...]"
+                    " [-ofile] filename\n\n"
+                    "  -Idir     Directories to be searched for headers.\n"
+                    "  -iheader  Headers to be ignored.\n"
+                    "  -eENV     Environment variable path substitutions.\n"
+                    "  -ofile    Write output to file.\n"
+                    "\nDependency list generator, similar to 'cpp -M'\n\n",
+                    stderr
+                );
+                return 0;
+                break;
+
+            case 'I':           /* Option: -Idir */
                 ++nDirectories;
-            }
+                break;
+
+            /* Could check other options, warn about unknown options... */
         }
     }
 
-    directories = (char**)malloc(sizeof(char*)*nDirectories);
+    sourceFile = strdup(argv[argc-1]);
 
-    /* build list of -I directories and add -i ignores */
+    /* Verify that it has an extension */
+    {
+        char *base = strrchr(sourceFile, '/');
+        if (!base)
+        {
+            base = sourceFile;
+        }
+        if (!strrchr(base, '.'))
+        {
+            fprintf
+            (
+                stderr,
+                EXENAME ": cannot find extension in source file name '%s'\n",
+                sourceFile
+            );
+            exit(1);
+        }
+    }
+
+    const char *outputFile = NULL;
+
+    /* Build list of -I directories and add -i ignores */
+    directories = (char**)malloc(sizeof(char*)*nDirectories);
     nDirectories = 0;
     for (i = 1; i < argc; ++i)
     {
-        if (strncmp(argv[i], "-I", 2) == 0)
+        const size_t optLen = strlen(argv[i]);
+
+        if (!strncmp(argv[i], "-I", 2))
         {
-            if (strlen(argv[i]) > 2)
+            /* Option: -Idir */
+            if (optLen > 2)
             {
                 directories[nDirectories++] = strdup(argv[i] + 2);
             }
         }
-        else if (strncmp(argv[i], "-i", 2) == 0)
+        else if (!strncmp(argv[i], "-i", 2))
         {
-            if (strlen(argv[i]) > 2)
+            /* Option: -iheader */
+            if (optLen > 2)
             {
                 lookUp(visitedFiles, (argv[i] + 2));
             }
         }
+        else if (!strncmp(argv[i], "-e", 2))
+        {
+            /* Option: -eENV */
+            if (optLen > 2)
+            {
+                add_env(argv[i] + 2);
+            }
+        }
+        else if (!strncmp(argv[i], "-o", 2))
+        {
+            /* Option: -ofile */
+            if (optLen > 2)
+            {
+                outputFile = (argv[i] + 2);
+            }
+        }
     }
 
-    /*
-     * initialise depFile to zero and use strncat rather than strncpy
-     * because there is a bug in the SGI strncat that if 0 preceeds the '.'
-     * it inserts a space
-     */
-    depFile = (char*)malloc(strlen(sourceFile) + 20);
-    depFile[0] = 0;
-    strcat(depFile, "$(OBJECTS_DIR)/");
-    strcat(depFile, sourceFile);
-    strcat(depFile, ".dep");
+    /* Initialize buffer path for currentBuffer */
+    currentBuffer = 0;
+    bufferPaths[currentBuffer] = NULL;
 
-    char *objectFile = strdup(basePos);
-    objectFile[(dotPos - basePos)/sizeof(char)] = 0;
+    /* Start of output */
+    if (outputFile)
+    {
+        FILE *reopened = freopen(outputFile, "w", stdout);
+        if (!reopened)
+        {
+            fprintf
+            (
+                stderr,
+                EXENAME ": could not open file '%s' for output: %s\n",
+                outputFile, strerror(errno)
+            );
 
-    /* printf("$(OBJECTS_DIR)/%s.o: %s\n", objectFile, depFile); */
-    printf("%s: \\\n", depFile);
-    free(objectFile);
+            return 1;
+        }
+    }
 
-    /* Initialize buffer path for currentBuffer */
-    bufferPaths[currentBuffer] = NULL;
+    fputs("$(OBJECTS_DIR)/", stdout);
+    fputs(sourceFile, stdout);
+    fputs(".dep: \\\n", stdout);
 
     nextFile(sourceFile);
     yylex();
 
-    puts("\n");
+    fputs("\n\n", stdout);
 
-    for (i = 0; i < nDirectories; ++i)
+    for (i = nDirectories-1; i >= 0; --i)
     {
         free(directories[i]);
     }
     free(directories);
-
     free(sourceFile);
-    free(depFile);
+
+    free_hashTable(visitedFiles);
+    free_envTable();
+
+    fflush(stdout);
+    fflush(stderr);
 
     return 0;
 }
 
 
 /*
- * Add a directory name to the file name
+ * Open a file for reading and print its qualified name
  */
-char* addDirectoryName(const char* dirName, const char* fileName)
+static FILE* fopen_file(const char* dirName, const char* fileName)
 {
-    char* pathName = (char*)malloc(strlen(dirName) + strlen(fileName) + 2);
-    strcpy(pathName, dirName);
+    FILE *file;
 
-    if (dirName[strlen(dirName)-1] != '/')
+    if (dirName && *dirName)
     {
-        strcat(pathName, "/");
+        const size_t dirLen = strlen(dirName);
+        char* fullName = (char*)malloc(dirLen + strlen(fileName) + 2);
+
+        strcpy(fullName, dirName);
+        if (dirName[dirLen-1] != '/')
+        {
+            strcat(fullName, "/");
+        }
+        strcat(fullName, fileName);
+
+        file = fopen(fullName, "r");
+
+        if (file)
+        {
+            print_fileName(fullName);
+        }
+
+        free(fullName);
     }
+    else
+    {
+        file = fopen(fileName, "r");
 
-    strcat(pathName, fileName);
+        if (file)
+        {
+            print_fileName(fileName);
+        }
+    }
 
-    return pathName;
+    return file;
 }
 
 
 /*
- * open a file and create buffer and put on stack
+ * Open a file and create buffer and put on stack
  */
 void nextFile(const char* fileName)
 {
     if (lookUp(visitedFiles, fileName))
     {
-        return;   /* already existed (did not insert) */
+        return;   /* Already existed (did not insert) */
     }
 
     if (currentBuffer >= FILE_STACK_SIZE)
@@ -311,6 +506,9 @@ void nextFile(const char* fileName)
             "while opening '%s' for file '%s'\n",
             FILE_STACK_SIZE, fileName, sourceFile
         );
+
+        fflush(stdout);
+        fflush(stderr);
         exit(1);
     }
 
@@ -320,47 +518,39 @@ void nextFile(const char* fileName)
     /* Check if the file has same path as the file in the current buffer */
     if (bufferPaths[currentBuffer] != NULL)
     {
-        char* pathName = addDirectoryName(bufferPaths[currentBuffer], fileName);
-
-        if ((newyyin = fopen(pathName, "r")))
+        newyyin = fopen_file(bufferPaths[currentBuffer], fileName);
+        if (newyyin)
         {
-            printf("%s \\\n", pathName);
-
             buffers[currentBuffer++] = YY_CURRENT_BUFFER;
             bufferPaths[currentBuffer] = bufferPaths[currentBuffer-1];
 
             yy_switch_to_buffer(yy_create_buffer(newyyin, YY_BUF_SIZE));
-
-            free(pathName);
-
             return;
         }
-
-        free(pathName);
     }
 
-    if (!(newyyin = fopen(fileName, "r")))
+    newyyin = fopen_file(NULL, fileName);
+    if (newyyin)
+    {
+        buffers[currentBuffer++] = YY_CURRENT_BUFFER;
+        bufferPaths[currentBuffer] = NULL;
+
+        yy_switch_to_buffer(yy_create_buffer(newyyin, YY_BUF_SIZE));
+    }
+    else
     {
         int d;
         for (d=0; d<nDirectories; ++d)
         {
-            char* pathName = addDirectoryName(directories[d], fileName);
-
-            if ((newyyin = fopen(pathName, "r")))
+            newyyin = fopen_file(directories[d], fileName);
+            if (newyyin)
             {
-                printf("%s \\\n", pathName);
-
                 buffers[currentBuffer++] = YY_CURRENT_BUFFER;
                 bufferPaths[currentBuffer] = directories[d];
 
                 yy_switch_to_buffer(yy_create_buffer(newyyin, YY_BUF_SIZE));
-
-                free(pathName);
-
                 return;
             }
-
-            free(pathName);
         }
 
         fprintf
@@ -378,34 +568,9 @@ void nextFile(const char* fileName)
         fflush(stdout);
         fflush(stderr);
 
-        /* only report the first occurance */
+        /* Only report the first occurrence */
         lookUp(visitedFiles, fileName);
     }
-    else
-    {
-        printf("%s \\\n", fileName);
-        fflush(stdout);
-
-        buffers[currentBuffer++] = YY_CURRENT_BUFFER;
-        bufferPaths[currentBuffer] = NULL;
-
-        yy_switch_to_buffer(yy_create_buffer(newyyin, YY_BUF_SIZE));
-    }
-}
-
-
-/*
- * Replace all '.' with '/'
- */
-void dotToSlash(char* fileName)
-{
-    const size_t len = strlen(fileName);
-    size_t i;
-
-    for (i=0; i<len; ++i)
-    {
-        if (fileName[i] == '.') fileName[i] = '/';
-    }
 }
 
 
@@ -415,9 +580,9 @@ void dotToSlash(char* fileName)
 int yywrap()
 {
     /* Close the file for the buffer which has just reached EOF */
-    /* This causes strange problems on some systems
+    /* This causes strange problems on several systems:
     fclose(yyin);
-    yyin = 0;
+    yyin = NULL;
     */
 
     /* Delete the buffer */
@@ -426,22 +591,24 @@ int yywrap()
     /* Set buffer counter to previous buffer */
     currentBuffer--;
 
-    if (currentBuffer >= 0) /* if buffer counter refers to a valid file */
+    if (currentBuffer >= 0)
     {
-        /* reset input buffer to the previous buffer on the stack */
+        /* Buffer counter refers to a valid file */
+
+        /* Reset input buffer to the previous buffer on the stack */
         yy_switch_to_buffer(buffers[currentBuffer]);
 
         /* Return to the normal state for the previous buffer on the stack */
         BEGIN(INITIAL);
 
-        /* return 0 to inform lex to continue reading */
+        /* Return 0 to inform lex to continue reading */
         return 0;
     }
-    else                 /* else there are no more buffers on the stack */
-    {
-        /* return 1 to inform lex finish now that all buffers have been read */
-        return 1;
-    }
+
+    /* No more buffers on the stack:
+     * Return 1 to inform lex to finish now that all buffers have been read
+     */
+    return 1;
 }
 
 
diff --git a/wmake/wclean b/wmake/wclean
index 426dd18a8cc..3becc517460 100755
--- a/wmake/wclean
+++ b/wmake/wclean
@@ -105,7 +105,7 @@ if [ $# -ge 1 ]
 then
     if [ -d "$1" ]
     then
-        dir=$1
+        dir="${1%/}"
     elif [ -f "$1" ]
     then
         dir="${1%/*}"
@@ -115,10 +115,10 @@ then
     fi
 
     # Specified directory name:
-    [ $# -ge 2 ] && dir=$2
+    [ $# -ge 2 ] && dir="${2%/}"
 
     # Specified alternative name for the Make sub-directory:
-    [ $# -ge 3 ] && MakeDir=$3
+    [ $# -ge 3 ] && MakeDir="${3%/}"
 
     if [ -n "$dir" ]
     then
diff --git a/wmake/wmake b/wmake/wmake
index 11dd888968f..bcf6c3fa3ab 100755
--- a/wmake/wmake
+++ b/wmake/wmake
@@ -243,14 +243,15 @@ fi
 # The variables 'targetType' and 'MakeDir' are considered global
 #------------------------------------------------------------------------------
 
-unset dir targetType
+unset targetType
 MakeDir=Make
 
 if [ $# -ge 1 ]
 then
+    unset dir
     if [ -d "$1" ]
     then
-        dir="$1"
+        dir="${1%/}"
     elif [ -f "$1" ]
     then
         dir="${1%/*}"
@@ -260,10 +261,10 @@ then
     fi
 
     # Specified directory name:
-    [ $# -ge 2 ] && dir=$2
+    [ $# -ge 2 ] && dir="${2%/}"
 
     # Specified alternative name for the Make sub-directory:
-    [ $# -ge 3 ] && MakeDir=$3
+    [ $# -ge 3 ] && MakeDir="${3%/}"
 
     if [ -n "$dir" ]
     then
@@ -271,10 +272,14 @@ then
             echo "$Script error: could not change to directory '$dir'" 1>&2
             exit 1
         }
+    elif [ -f "$MakeDir/files" ]
+    then
+        dir="(${PWD##*/})"  # Implicit directory information
     fi
 
     # Print command
-    echo "$Script $targetType${targetType:+ }${dir:-.}"
+    echo "$Script $targetType${targetType:+ }$dir"
+    unset dir
 fi
 
 
diff --git a/wmake/wmakeCheckPwd b/wmake/wmakeCheckPwd
index d21318778b1..5dc76782d55 100755
--- a/wmake/wmakeCheckPwd
+++ b/wmake/wmakeCheckPwd
@@ -29,16 +29,17 @@
 #     wmakeCheckPwd <dir>
 #
 # Description
-#     Check that the current working directory is the directory <dir>
+#     Check that the current working directory is the directory <dir>.
+#     Exit status 0 when the directories are identical
 #
 #-------------------------------------------------------------------------------
 Script=${0##*/}
 
-unset quietOpt
+unset optQuiet
+exec 1>&2 # No stdout, stderr only
 
 usage() {
-    [ "$quietOpt" = true ] && exit 1
-    exec 1>&2
+    [ "$optQuiet" = true ] && exit 1
     while [ "$#" -ge 1 ]; do echo "$1"; shift; done
     cat<<USAGE
 
@@ -57,6 +58,17 @@ USAGE
 }
 
 
+error()
+{
+    if [ "$optQuiet" != true ]
+    then
+        echo "$Script error: $1"
+        shift
+        while [ "$#" -ge 1 ]; do echo "    $1"; shift; done
+    fi
+    exit 1
+}
+
 #------------------------------------------------------------------------------
 # Parse arguments and options
 #------------------------------------------------------------------------------
@@ -68,11 +80,11 @@ do
         usage
         ;;
     -q | -quiet)
-        quietOpt=true
+        optQuiet=true
         shift
         ;;
     -*)
-        usage "unknown option: '$*'"
+        usage "Unknown option: '$1'"
         ;;
     *)
         break
@@ -80,35 +92,21 @@ do
     esac
 done
 
+[ "$#" -eq 1 ] || usage "Incorrect number of arguments"
 
-[ "$#" -eq 1 ] || usage
-
-# Set dirName to <dir>
 dirName="$1"
 
-# Simple check against $PWD
+# Simple lexical check against PWD
 [ "$PWD" = "$dirName" ] && exit 0
 
 # Check existence of <dir>
-[ -d "$dirName" ] || {
-    [ "$quietOpt" = true ] || {
-        echo "$Script error: Directory does not exist $dirName"
-    }
-    exit 1
-}
+[ -d "$dirName" ] || error "Directory does not exist '$dirName'"
 
-# Use /bin/pwd to get the absolute path (could be linked)
-thisDir=$(/bin/pwd)
-target=$(cd $dirName 2>/dev/null && /bin/pwd)
+# Compare absolute paths, without symlinks
+[ "$(cd $dirName 2>/dev/null && pwd -P)" = "$(pwd -P)" ] || \
+    error "Current directory is not '$dirName'"
 
-# Return 0 if this directory is <dir>
-[ "$thisDir" = "$target" ] && exit 0
-
-# This directory is not <dir>
-[ "$quietOpt" = true ] || {
-    echo "$Script error: Current directory is not $dirName"
-}
 
-exit 1
+exit 0 # clean exit
 
 #------------------------------------------------------------------------------
diff --git a/wmake/wmakeFilesAndOptions b/wmake/wmakeFilesAndOptions
index 8519006ef01..7e2f4859cf7 100755
--- a/wmake/wmakeFilesAndOptions
+++ b/wmake/wmakeFilesAndOptions
@@ -59,23 +59,23 @@ do
     -h | -help)   # Provide immediate help
         usage
         ;;
-    -*)
-        usage "unknown option: '$1'"
-        ;;
     *)
-        break
+        # No options/arguments
+        usage "unexpected options/arguments: $*"
         ;;
     esac
 done
 
-# No arguments
-[ "$#" -eq 0 ] || usage "unexpected arguments: '$*'"
-
+if [ -e Make ]
+then
+    echo "$Script error: Make directory already exists" 1>&2
+    exit 1
+fi
 
 #------------------------------------------------------------------------------
 # Check environment variables
 #------------------------------------------------------------------------------
-for check in WM_OPTIONS WM_LINK_LANGUAGE WM_DIR
+for check in WM_DIR WM_ARCH WM_COMPILER
 do
     eval test "\$$check" || {
         echo "$Script error: environment variable \$$check not set" 1>&2
@@ -83,24 +83,9 @@ do
     }
 done
 
-if [ -d Make ]
-then
-    echo "$Script error: Make directory already exists" 1>&2
-    exit 1
-else
-    mkdir Make
-fi
-
-[ -e Make/files ] || {
-    echo "$Script: Creating Make/files"
-    $WM_DIR/scripts/makeFiles
-}
-
-[ -e Make/options ] || {
-    echo "$Script: Creating Make/options"
-    $WM_DIR/scripts/makeOptions
-}
-
+mkdir Make
+[ -e Make/files ]   || $WM_DIR/scripts/makeFiles
+[ -e Make/options ] || $WM_DIR/scripts/makeOptions
 
 exit 0 # clean exit
 
-- 
GitLab