about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorRory Bradford <roryrjb@gmail.com>2022-11-19 11:11:26 +0000
committerRory Bradford <roryrjb@gmail.com>2022-11-19 11:18:40 +0000
commit0f92f7352d1964a9859868439e8ded2c4de2111e (patch)
tree14c690402fa28c3b465ec00d2fe767054a1a3331
parentfbb7c479de91b197c6c501c2023bf564a6a7610f (diff)
downloadrf-0f92f7352d1964a9859868439e8ded2c4de2111e.tar.gz
Full native win32 support
This will now compile with MSVC using the make.bat batch file. It does
however bring in some additional third party dependencies: ports of
dirent and getopt (something I'd ideally like to work on in the future).

Signed-off-by: Rory Bradford <roryrjb@gmail.com>
-rw-r--r--.gitignore6
-rw-r--r--dirent/.gitignore27
-rw-r--r--dirent/CMakeLists.txt64
-rw-r--r--dirent/CONTRIBUTING.md41
-rw-r--r--dirent/ChangeLog129
-rw-r--r--dirent/LICENSE21
-rw-r--r--dirent/README.md176
-rw-r--r--dirent/distclean.cmake62
-rw-r--r--dirent/examples/cat.c127
-rw-r--r--dirent/examples/dir.c234
-rw-r--r--dirent/examples/du.c199
-rw-r--r--dirent/examples/find.c184
-rw-r--r--dirent/examples/locate.c262
-rw-r--r--dirent/examples/ls.c148
-rw-r--r--dirent/examples/scandir.c152
-rw-r--r--dirent/examples/updatedb.c206
-rw-r--r--dirent/include/dirent.h1212
-rw-r--r--dirent/tests/1/dir/readme.txt3
-rw-r--r--dirent/tests/1/file0
-rw-r--r--dirent/tests/2/Testfile-1.2.3.dat0
-rw-r--r--dirent/tests/2/file.txt1
-rw-r--r--dirent/tests/3/3zero.dat0
-rw-r--r--dirent/tests/3/666.dat0
-rw-r--r--dirent/tests/3/Qwerty-my-aunt.dat0
-rw-r--r--dirent/tests/3/README.txt2
-rw-r--r--dirent/tests/3/aaa.dat0
-rw-r--r--dirent/tests/3/dirent.dat0
-rw-r--r--dirent/tests/3/empty.dat0
-rw-r--r--dirent/tests/3/sane-1.12.0.dat0
-rw-r--r--dirent/tests/3/sane-1.2.30.dat0
-rw-r--r--dirent/tests/3/sane-1.2.4.dat0
-rw-r--r--dirent/tests/3/zebra.dat0
-rw-r--r--dirent/tests/4/asidofilusphosphorus0
-rw-r--r--dirent/tests/4/bubblebob0
-rw-r--r--dirent/tests/4/celsiusfortissimo0
-rw-r--r--dirent/tests/t-compile.c46
-rw-r--r--dirent/tests/t-cplusplus.cpp155
-rw-r--r--dirent/tests/t-dirent.c608
-rw-r--r--dirent/tests/t-scandir.c276
-rw-r--r--dirent/tests/t-strverscmp.c206
-rw-r--r--dirent/tests/t-telldir.c165
-rw-r--r--dirent/tests/t-unicode.c381
-rw-r--r--dirent/tests/t-utf8.c238
-rw-r--r--getopt/.gitignore4
-rw-r--r--getopt/LICENSE165
-rw-r--r--getopt/README.md9
-rw-r--r--getopt/appveyor.yml5
-rw-r--r--getopt/article.md224
-rw-r--r--getopt/getopt.c973
-rw-r--r--getopt/getopt.h136
-rw-r--r--getopt/getopt.sln31
-rw-r--r--getopt/getopt.vcxproj193
-rw-r--r--ignore.c5
-rw-r--r--ignore.h4
-rw-r--r--make.bat8
-rw-r--r--rf.c44
-rw-r--r--rf.h1
57 files changed, 7107 insertions, 26 deletions
diff --git a/.gitignore b/.gitignore
index 9651efe..2029cf6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 /rf
 *.o
-*.1
-*.5
\ No newline at end of file
+*.exe
+*.obj
+*.lib
+*.exp
\ No newline at end of file
diff --git a/dirent/.gitignore b/dirent/.gitignore
new file mode 100644
index 0000000..7def436
--- /dev/null
+++ b/dirent/.gitignore
@@ -0,0 +1,27 @@
+/CMakeCache.txt
+/CMakeFiles
+/CTestTestfile.cmake
+/DartConfiguration.tcl
+/Makefile
+/Testing
+/Win32
+/cmake_install.cmake
+/find
+/locate
+/ls
+/scandir
+/cat
+/dir
+/du
+/t-compile
+/t-dirent
+/t-scandir
+/t-cplusplus
+/t-unicode
+/t-strverscmp
+/t-telldir
+/t-utf8
+/updatedb
+/*.filters
+/*.vcxproj
+/*.dir
diff --git a/dirent/CMakeLists.txt b/dirent/CMakeLists.txt
new file mode 100644
index 0000000..0e002c8
--- /dev/null
+++ b/dirent/CMakeLists.txt
@@ -0,0 +1,64 @@
+cmake_minimum_required(VERSION 2.8.12)
+project(dirent LANGUAGES C CXX)
+
+# User options
+option(DIRENT_BUILD_TESTS "Build bundled tests" ON)
+message(STATUS "Build test and example programs: ${DIRENT_BUILD_TESTS}")
+
+# Initialize C and C++ compilers
+enable_language(C CXX)
+
+# Compile in debug mode by default
+if(NOT CMAKE_BUILD_TYPE)
+    set(CMAKE_BUILD_TYPE Debug
+        CACHE STRING
+        "Type of build: None Debug Release RelWithDebInfo MinSizeRel."
+        FORCE
+    )
+endif(NOT CMAKE_BUILD_TYPE)
+
+# Use the include directory only on Windows
+if(WIN32)
+    include_directories(${CMAKE_SOURCE_DIR}/include)
+endif(WIN32)
+
+# Install dirent.h
+if(WIN32)
+    install(FILES include/dirent.h DESTINATION include)
+endif(WIN32)
+
+# Add distclean target
+add_custom_target(distclean
+    COMMAND ${CMAKE_BUILD_TOOL} clean
+    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/distclean.cmake
+)
+
+# Build example programs
+if(DIRENT_BUILD_TESTS)
+    add_executable(find examples/find.c)
+    add_executable(ls examples/ls.c)
+    add_executable(locate examples/locate.c)
+    add_executable(updatedb examples/updatedb.c)
+    add_executable(scandir examples/scandir.c)
+    add_executable(cat examples/cat.c)
+    add_executable(dir examples/dir.c)
+    add_executable(du examples/du.c)
+
+    # Build test programs
+    include(CTest)
+    add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C ${CMAKE_CFG_INTDIR})
+    function(add_test_executable TEST_NAME)
+        add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${ARGN})
+        add_test(NAME ${TEST_NAME} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND $<TARGET_FILE:${TEST_NAME}>)
+        add_dependencies(check ${TEST_NAME})
+    endfunction(add_test_executable)
+
+    add_test_executable(t-compile tests/t-compile.c)
+    add_test_executable(t-dirent tests/t-dirent.c)
+    add_test_executable(t-scandir tests/t-scandir.c)
+    add_test_executable(t-unicode tests/t-unicode.c)
+    add_test_executable(t-cplusplus tests/t-cplusplus.cpp)
+    add_test_executable(t-telldir tests/t-telldir.c)
+    add_test_executable(t-strverscmp tests/t-strverscmp.c)
+    add_test_executable(t-utf8 tests/t-utf8.c)
+endif(DIRENT_BUILD_TESTS)
diff --git a/dirent/CONTRIBUTING.md b/dirent/CONTRIBUTING.md
new file mode 100644
index 0000000..bff76c3
--- /dev/null
+++ b/dirent/CONTRIBUTING.md
@@ -0,0 +1,41 @@
+# Contributing to Dirent
+
+Dirent is an open source project and we love to receive contributions from our
+community -- you!  There are many ways to contribute, from writing tutorials
+or blog posts, improving the documentation, submitting bug reports and
+feature requests, or writing code which can be incorporated into Dirent.
+
+For example, we are looking for contributions which
+
+1. Improve portability of code developed for Unix/Linux to Microsoft Windows.
+2. Make Dirent easier to use and/or more useful for programmers working on
+   Microsoft Windows platform.
+3. Remove compiler warnings or fix bugs.
+
+## How to Suggest a Feature
+
+We use Github to host code, to track issues and to discuss about Dirent.  If
+you would like to suggest a feature, then open an issue at Github.
+
+## How to Report a Bug
+
+If you have trouble using Dirent, then try to repeat the problem with the
+latest version found at Github.  If the problem remains, then open an issue
+at Github.
+
+## How to Submit a Fix or an Enhancement
+
+If you wish to contribute code, then fork the repo and test the change in your
+private repo first.  If the change works for you and you would like to donate
+the change back to the community, then make a pull request at Github.
+
+Before making a pull request, please consider that:
+
+1. We can only accept contributions which are compatible with [MIT Software
+   License](LICENSE).
+2. By making a pull request, you agree to transfer all copyrights to us.
+3. Our code will be reviewed and edited by us.  In particular, we may
+   reformat your code according to the [Linux Kernel Coding
+   Style](https://www.kernel.org/doc/html/v4.10/process/coding-style.html)
+
+
diff --git a/dirent/ChangeLog b/dirent/ChangeLog
new file mode 100644
index 0000000..d79cea2
--- /dev/null
+++ b/dirent/ChangeLog
@@ -0,0 +1,129 @@
+2018-05-08  Toni Rönkkö
+
+	* Version 1.23.2: fixes bad scandir prototype.
+
+2017-08-27  Toni Rönkkö
+
+	* Version 1.23: support readdir_r and scandir functions.
+
+2017-07-18  Toni Rönkkö
+
+	* Created release branches v1.22 and v1.21 to Git.  Published version
+	1.22 at softagalleria.net.
+
+2016-09-11  Toni Rönkkö
+
+	* Version 1.22: added support for CMake.  Thanks to Paul Fultz II.
+
+2014-09-25  Toni Rönkkö
+
+	* Version 1.21: compiles correctly under Open Watcom.  Thanks to
+	Virgil Banowetz for a patch!
+
+2014-04-07  Toni Rönkkö
+
+	* Version 1.20.1: the zip file from the previous version did not open
+	correctly with Microsoft's compressed folders.  Thanks to Alexandre
+	for info!
+
+2014-03-17  Toni Ronkko
+
+	* Version 1.20: dirent.h compiles correctly in 64-bit architecture.
+	Thanks to Aaron Simmons!
+
+2014-03-03  Toni Ronkko
+
+	* Version 1.13.2: define DT_LNK for compatibility with Unix
+	programs.  Thanks to Joel Bruick for suggestion!
+
+2013-01-27  Toni Ronkko
+
+	* Version 1.13.1: patch from Edward Berner fixes set_errno() on
+	Windows NT 4.0.
+
+	* Revised wcstombs() and mbstowcs() wrappers to make sure that they do
+	not write past their target string.
+
+	* PATH_MAX from windows.h includes zero terminator so there is no
+	need to add one extra byte to variables and structures.
+
+2012-12-12  Toni Ronkko
+
+	* Version 1.13: use the traditional 8+3 file naming scheme if a file
+	name cannot be represented in the default ANSI code page.  Now
+	compiles again with MSVC 6.0.  Thanks to Konstantin Khomoutov for
+	testing.
+
+2012-10-01  Toni Ronkko
+
+	* Version 1.12.1: renamed wide-character DIR structure _wDIR to
+	_WDIR (with capital W) in order to maintain compatibility with MingW.
+
+2012-09-30  Toni Ronkko
+
+	* Version 1.12: define PATH_MAX and NAME_MAX.  Added wide-character
+	variants _wDIR, _wdirent, _wopendir(), _wreaddir(), _wclosedir() and
+	_wrewinddir().  Thanks to Edgar Buerkle and Jan Nijtmans for ideas
+	and code.
+
+	* Now avoiding windows.h.  This allows dirent.h to be integrated
+	more easily into programs using winsock.  Thanks to Fernando
+	Azaldegui.
+
+2011-03-15  Toni Ronkko
+
+	* Version 1.11: defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
+
+2010-08-11  Toni Ronkko
+
+	* Version 1.10: added d_type and d_namlen fields to dirent structure.
+	The former is especially useful for determining whether directory
+	entry represents a file or a directory.  For more information, see
+	http://www.delorie.com/gnu/docs/glibc/libc_270.html
+
+	* Improved conformance to the standards.  For example, errno is now
+	set properly on failure and assert() is never used.  Thanks to Peter
+	Brockam for suggestions.
+
+	* Fixed a bug in rewinddir(): when using relative directory names,
+	change of working directory no longer causes rewinddir() to fail.
+
+2009-12-15  John Cunningham
+
+	* Version 1.9: added rewinddir member function
+
+2008-01-18  Toni Ronkko
+
+	* Version 1.8: Using FindFirstFileA and WIN32_FIND_DATAA to avoid
+	converting string between multi-byte and unicode representations.
+	This makes the code simpler and also allows the code to be compiled
+	under MingW.  Thanks to Azriel Fasten for the suggestion.
+
+2007-03-04  Toni Ronkko
+
+	* Bug fix: due to the strncpy_s() function this file only compiled in
+	Visual Studio 2005.  Using the new string functions only when the
+	compiler version allows.
+
+2006-11-02  Toni Ronkko
+
+	* Major update: removed support for Watcom C, MS-DOS and Turbo C to
+	simplify the file, updated the code to compile cleanly on Visual
+	Studio 2005 with both unicode and multi-byte character strings,
+	removed rewinddir() as it had a bug.
+
+2006-08-20  Toni Ronkko
+
+	* Removed all remarks about MSVC 1.0, which is antiqued now.
+	Simplified comments by removing SGML tags.
+
+2002-05-14  Toni Ronkko
+
+	* Embedded the function definitions directly to the header so that no
+	source modules need to be included in the Visual Studio project.
+	Removed all the dependencies to other projects so that this header
+	file can be used independently.
+
+1998-05-28  Toni Ronkko
+
+	* First version.
diff --git a/dirent/LICENSE b/dirent/LICENSE
new file mode 100644
index 0000000..af04360
--- /dev/null
+++ b/dirent/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 1998-2019 Toni Ronkko
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/dirent/README.md b/dirent/README.md
new file mode 100644
index 0000000..93e21d6
--- /dev/null
+++ b/dirent/README.md
@@ -0,0 +1,176 @@
+# Dirent
+
+Dirent is a programming interface for retrieving information about files and
+directories in C and C++ languages.  This project provides a Dirent interface
+for Microsoft Visual Studio.
+
+
+# Installation
+
+Download the latest Dirent installation package from
+[GitHub](https://github.com/tronkko/dirent/releases) and
+unpack the installation file with 7-zip, for example.  The installation
+package contains ``include/dirent.h`` file as well as a few example and test
+programs.
+
+To make Dirent available to all C/C++ projects in your machine, simply copy
+``include/dirent.h`` file to the system include directory, e.g.
+``C:\Program Files\Microsoft Visual Studio 9.0\VC\include``.  Everything you
+need is included in the single ``dirent.h`` file, and you can start using
+Dirent immediately -- there is no need to add files to your Visual Studio
+project.
+
+Alternatively, if you wish to distribute ``dirent.h`` alongside with your own
+project, then copy ``include/dirent.h`` file to a new sub-directory within
+your project and add that directory to include path on Windows while omitting
+the directory under Linux/UNIX.  This allows your project to be compiled
+against native ``dirent.h`` on Linux/UNIX while substituting the functionality
+on Microsoft Windows.
+
+
+# Example Programs
+
+The installation package contains example programs:
+
+Program  | Purpose
+-------- | -----------------------------------------------------------------
+ls       | List files in a directory, e.g. ls "c:\Program Files"
+find     | Find files in subdirectories, e.g. find "c:\Program Files\CMake"
+updatedb | Build database of files in a drive, e.g. updatedb c:\
+locate   | Locate a file from database, e.g. locate notepad
+scandir  | Printed sorted list of file names in a directory, e.g. scandir .
+du       | Compute disk usage, e.g. du "C:\Program Files"
+cat      | Print a text file to screen, e.g. cat include/dirent.h
+
+In order to build the example programs, first install
+[CMake](https://cmake.org/) to your machine.  Then, open command prompt and
+create a temporary directory ``c:\temp\dirent`` for the build files as
+
+```
+c:\
+mkdir temp
+mkdir temp\dirent
+cd temp\dirent
+```
+
+Generate build files as
+
+```
+cmake d:\dirent
+```
+
+where ``d:\dirent`` is the root directory of the Dirent package containing
+this README.md file.
+
+Once CMake is finished, open Visual Studio, load the generated ``dirent.sln``
+file from the build directory and build the whole solution.
+
+Once the build completes, open command prompt and cd to the Debug directory to
+run the example programs.  For example:
+
+```
+cd c:\temp\dirent\Debug
+.\ls .
+```
+
+Visual Studio project also contains a solution named ``check`` which can be
+used to verify that Dirent API works as expected.  Just build the solution
+from Visual Studio to run the test programs.
+
+
+# UTF-8 Support
+
+By default, file and directory names in the Dirent API are expressed in the
+currently selected windows codepage.  If you wish to use UTF-8 character
+encoding, then replace the main function with \_main function and convert
+wide-character arguments to UTF-8 strings as demonstrated in the snippet
+below.
+
+```
+/* This is your true main function */
+static int
+_main(int argc, wchar_t *argv[])
+{
+	/* ... */
+}
+
+/* Convert arguments to UTF-8 */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+```
+
+For more information on UTF-8 support, please see setlocale in Visual Studio
+[C runtime library reference](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc-160#utf-8-support).
+
+
+# Contributing
+
+We love to receive contributions from you.  See the
+[CONTRIBUTING](CONTRIBUTING.md) file for details.
+
+
+# Copying
+
+Dirent may be freely distributed under the MIT license.  See the
+[LICENSE](LICENSE) file for details.
+
+
+# Alternatives to Dirent
+
+I ported Dirent to Microsoft Windows in 1998 when only a few alternatives
+were available.  However, the situation has changed since then and nowadays
+both [Cygwin](http://www.cygwin.com) and [MingW](http://www.mingw.org)
+allow you to compile a great number of UNIX programs in Microsoft Windows.
+They both provide a full Dirent API as well as many other UNIX APIs.  MingW
+can even be used for commercial applications!
+
diff --git a/dirent/distclean.cmake b/dirent/distclean.cmake
new file mode 100644
index 0000000..60e69ad
--- /dev/null
+++ b/dirent/distclean.cmake
@@ -0,0 +1,62 @@
+# Remove CMake generated temporary files
+set (cmake_generated
+    ${CMAKE_BINARY_DIR}/ALL_BUILD.vcxproj
+    ${CMAKE_BINARY_DIR}/ALL_BUILD.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/CMakeCache.txt
+    ${CMAKE_BINARY_DIR}/CMakeFiles
+    ${CMAKE_BINARY_DIR}/CTestTestfile.cmake
+    ${CMAKE_BINARY_DIR}/Continuous.vcxproj
+    ${CMAKE_BINARY_DIR}/Continuous.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/DartConfiguration.tcl
+    ${CMAKE_BINARY_DIR}/Debug
+    ${CMAKE_BINARY_DIR}/Experimental.vcxproj
+    ${CMAKE_BINARY_DIR}/Experimental.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/INSTALL.vcxproj
+    ${CMAKE_BINARY_DIR}/INSTALL.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/Makefile
+    ${CMAKE_BINARY_DIR}/Nightly.vcxproj
+    ${CMAKE_BINARY_DIR}/Nightly.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/NightlyMemoryCheck.vcxproj
+    ${CMAKE_BINARY_DIR}/NightlyMemoryCheck.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/RUN_TESTS.vcxproj
+    ${CMAKE_BINARY_DIR}/RUN_TESTS.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/Testing
+    ${CMAKE_BINARY_DIR}/Win32
+    ${CMAKE_BINARY_DIR}/ZERO_CHECK.vcxproj
+    ${CMAKE_BINARY_DIR}/ZERO_CHECK.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/check.vcxproj
+    ${CMAKE_BINARY_DIR}/check.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/cmake_install.cmake
+    ${CMAKE_BINARY_DIR}/dirent.sln
+    ${CMAKE_BINARY_DIR}/distclean.vcxproj
+    ${CMAKE_BINARY_DIR}/distclean.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/find
+    ${CMAKE_BINARY_DIR}/find.dir
+    ${CMAKE_BINARY_DIR}/find.vcxproj
+    ${CMAKE_BINARY_DIR}/find.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/locate
+    ${CMAKE_BINARY_DIR}/locate.dir
+    ${CMAKE_BINARY_DIR}/locate.vcxproj
+    ${CMAKE_BINARY_DIR}/locate.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/ls
+    ${CMAKE_BINARY_DIR}/ls.dir
+    ${CMAKE_BINARY_DIR}/ls.vcxproj
+    ${CMAKE_BINARY_DIR}/ls.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/t-compile
+    ${CMAKE_BINARY_DIR}/t-compile.dir
+    ${CMAKE_BINARY_DIR}/t-compile.vcxproj
+    ${CMAKE_BINARY_DIR}/t-compile.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/t-dirent
+    ${CMAKE_BINARY_DIR}/t-dirent.dir
+    ${CMAKE_BINARY_DIR}/t-dirent.vcxproj
+    ${CMAKE_BINARY_DIR}/t-dirent.vcxproj.filters
+    ${CMAKE_BINARY_DIR}/updatedb
+    ${CMAKE_BINARY_DIR}/updatedb.dir
+    ${CMAKE_BINARY_DIR}/updatedb.vcxproj
+    ${CMAKE_BINARY_DIR}/updatedb.vcxproj.filters
+)
+foreach (file ${cmake_generated})
+    if (EXISTS ${file})
+        file (REMOVE_RECURSE ${file})
+    endif()
+endforeach (file)
diff --git a/dirent/examples/cat.c b/dirent/examples/cat.c
new file mode 100644
index 0000000..5346922
--- /dev/null
+++ b/dirent/examples/cat.c
@@ -0,0 +1,127 @@
+/*
+ * Output contents of a file.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a file name argument.  For example, command
+ *
+ *     cat include\dirent.h
+ *
+ * will output the dirent.h to screen.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <locale.h>
+
+static void output_file(const char *fn);
+static int _main(int argc, char *argv[]);
+
+static int
+_main(int argc, char *argv[])
+{
+	/* Require at least one file */
+	if (argc == 1) {
+		fprintf(stderr, "Usage: cat filename\n");
+		return EXIT_FAILURE;
+	}
+
+	/* For each file name argument in command line */
+	int i = 1;
+	while (i < argc) {
+		output_file(argv[i]);
+		i++;
+	}
+	return EXIT_SUCCESS;
+}
+
+/*
+ * Output file to screen
+ */
+static void
+output_file(const char *fn)
+{
+	/* Open file */
+	FILE *fp = fopen(fn, "r");
+	if (!fp) {
+		/* Could not open directory */
+		fprintf(stderr, "Cannot open %s (%s)\n", fn, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Output file to screen */
+	size_t n;
+	do {
+		/* Read some bytes from file */
+		char buffer[4096];
+		n = fread(buffer, 1, 4096, fp);
+
+		/* Output bytes to screen */
+		fwrite(buffer, 1, n, stdout);
+	} while (n != 0);
+
+	/* Close file */
+	fclose(fp);
+}
+
+/* Stub for converting arguments to UTF-8 on Windows */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n + 1);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+
diff --git a/dirent/examples/dir.c b/dirent/examples/dir.c
new file mode 100644
index 0000000..46e38de
--- /dev/null
+++ b/dirent/examples/dir.c
@@ -0,0 +1,234 @@
+/*
+ * List files with date, type and size.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a directory name argument.  For example, command
+ *
+ *     dir "C:\Users\User 1\Documents"
+ *
+ * might output something like
+ *
+ *     Directory of c:\Users\User 1\Documents
+ *
+ *     2021-06-06  20:04       <DIR>               .
+ *     2021-07-20  13:42       <DIR>               ..
+ *     2020-06-21  15:00                       402 desktop.ini
+ *     2020-06-21  15:00       <DIR>               Omat kuvatiedostot
+ *     2020-06-21  15:00       <DIR>               Omat musiikkitiedostot
+ *     2020-06-21  15:00       <DIR>               Omat videotiedostot
+ *     2018-12-21  18:34       <DIR>               Visual Studio 2017
+ *                        3 File(s)       402 bytes
+ *                        7 Dir(s)
+ *
+ * The dir command provided by this file is only an example: the command
+ * does not have any fancy options.
+ *
+ * Copyright (C) 2006-2012 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <locale.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#define ERR_MSG_LEN 256
+
+static void list_directory(const char* dirname);
+static void fail(const char* dirname);
+static int _main(int argc, char *argv[]);
+
+static int
+_main(int argc, char* argv[])
+{
+	/* For each directory in command line */
+	int i = 1;
+	while (i < argc) {
+		list_directory(argv[i]);
+		i++;
+	}
+
+	/* List current working directory if no arguments on command line */
+	if (argc == 1)
+		list_directory(".");
+
+	return EXIT_SUCCESS;
+}
+
+/* List files and file sizes in directory */
+static void
+list_directory(const char* dirname)
+{
+	char path[PATH_MAX + 2];
+	char *p = path;
+	char *end = &path[PATH_MAX];
+
+	/* Copy directory name to path */
+	const char *src = dirname;
+	while (p < end && *src != '\0') {
+		*p++ = *src++;
+	}
+
+	/* Get final character of directory name */
+	char c = (path < p ? p[-1] : ':');
+
+	/* Append directory separator if not already there */
+	if (c != ':' && c != '/' && c != '\\')
+		*p++ = '/';
+
+	/* Print directory name to screen */
+	printf("Directory of %s\n\n", dirname);
+
+	/* Open directory stream */
+	DIR *dir = opendir(dirname);
+	if (!dir) {
+		/* Could not open directory */
+		fprintf(stderr,
+			"Cannot open %s (%s)\n", dirname, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Loop through file names */
+	int filecount = 0;
+	int dircount = 0;
+	long long bytecount = 0;
+	struct dirent *ent;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Append file name to path */
+		char *q = p;
+		src = ent->d_name;
+		while (q < end && *src != '\0') {
+			*q++ = *src++;
+		}
+		*q = '\0';
+
+		/* Get file properties such as size and modification time */
+		struct stat stbuf;
+		if (stat(path, &stbuf) == /*error*/-1) {
+			fail(path);
+		}
+
+		/* Get file type from stat buffer */
+		const char *type;
+		if (S_ISDIR(stbuf.st_mode)) {
+			/* Directory */
+			type = "<DIR>";
+		} else if (S_ISREG(stbuf.st_mode)) {
+			/* Regular file */
+			type = "";
+		} else if (S_ISLNK(stbuf.st_mode)) {
+			/* Link */
+			type = "<LNK>";
+		} else {
+			/* Named pipe, socket, character device or else */
+			type = "<UNK>";
+		}
+
+		/* Get last modification date as a string */
+		struct tm *tp = localtime(&stbuf.st_mtime);
+		char mtime[40];
+		sprintf(mtime, "%04d-%02d-%02d  %02d:%02d",
+			tp->tm_year + 1900,
+			tp->tm_mon + 1,
+			tp->tm_mday,
+			tp->tm_hour,
+			tp->tm_min);
+
+		/* Get file size as a string */
+		char size[40];
+		if (S_ISREG(stbuf.st_mode)) {
+			sprintf(size, "%lld", (long long) stbuf.st_size);
+		} else {
+			size[0] = '\0';
+		}
+
+		/* Output file info */
+		printf("%-20s    %-5s  %12s %s\n",
+			mtime, type, size, ent->d_name);
+
+		/* Compute totals */
+		if (S_ISREG(stbuf.st_mode)) {
+			filecount++;
+			bytecount += (long long) stbuf.st_size;
+		}
+		if (S_ISDIR(stbuf.st_mode)) {
+			dircount++;
+		}
+	}
+
+	/* Output sums */
+	printf("%20d File(s) %12lld bytes\n", filecount, bytecount);
+	printf("%20d Dir(s)\n", dircount);
+}
+
+/* Print error message and exit with error condition */
+static void
+fail(const char* msg)
+{
+	/* Output error message */
+	perror(msg);
+
+	/* Exit the program immediately */
+	exit(EXIT_FAILURE);
+}
+
+/* Stub for converting arguments to UTF-8 on Windows */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n + 1);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+
diff --git a/dirent/examples/du.c b/dirent/examples/du.c
new file mode 100644
index 0000000..a5832c4
--- /dev/null
+++ b/dirent/examples/du.c
@@ -0,0 +1,199 @@
+/*
+ * Compute disk usage of files and sub-directories in bytes.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a directory name argument.  For example, command
+ *
+ *     du "c:\Program Files"
+ *
+ * might produce listing such as
+ *
+ *     5204927     7-Zip
+ *     140046882   CCleaner
+ *     83140342    CMake
+ *     2685264     Internet Explorer
+ *     686314712   LibreOffice
+ *     214025459   Mozilla Firefox
+ *     174753900   VideoLAN
+ *
+ * If you compare this program to a genuine du command in Linux, then be ware
+ * directories themselves consume some space in Linux.  This program, however,
+ * only counts the files and hence the size will always be smaller than that
+ * reported by Linux du.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <locale.h>
+
+static long long list_directory(const char *dirname, int level);
+static int _main(int argc, char *argv[]);
+
+static int
+_main(int argc, char *argv[])
+{
+	/* For each directory in command line */
+	int i = 1;
+	while (i < argc) {
+		list_directory(argv[i], 0);
+		i++;
+	}
+
+	/* List current working directory if no arguments on command line */
+	if (argc == 1)
+		list_directory(".", 0);
+
+	return EXIT_SUCCESS;
+}
+
+/* Find files and subdirectories recursively; list their sizes */
+static long long
+list_directory(const char *dirname, int level)
+{
+	char buffer[PATH_MAX + 2];
+	char *p = buffer;
+	char *end = &buffer[PATH_MAX];
+	
+	/* Copy directory name to buffer */
+	const char *src = dirname;
+	while (p < end && *src != '\0') {
+		*p++ = *src++;
+	}
+	*p = '\0';
+
+	/* Get final character of directory name */
+	char c;
+	if (buffer < p)
+		c = p[-1];
+	else
+		c = ':';
+
+	/* Append directory separator if not already there */
+	if (c != ':' && c != '/' && c != '\\')
+		*p++ = '/';
+
+	/* Open directory stream */
+	DIR *dir = opendir(dirname);
+	if (!dir) {
+		fprintf(stderr,
+			"Cannot open %s (%s)\n", dirname, strerror(errno));
+		return 0LL;
+	}
+
+	/* Compute total disk usage of all files and directories */
+	struct stat stbuf;
+	struct dirent *ent;
+	long long total = 0;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Skip pseudo directories . and .. */
+		if (strcmp(ent->d_name, ".") == 0
+			|| strcmp(ent->d_name, "..") == 0)
+			continue;
+
+		/* Skip links as they consume no space */
+		if (ent->d_type == DT_LNK)
+			continue;
+
+		/* Skip device entries */
+		if (ent->d_type != DT_REG && ent->d_type != DT_DIR)
+			continue;
+
+		/* Append file name to buffer */
+		src = ent->d_name;
+		char *q = p;
+		while (q < end && *src != '\0') {
+			*q++ = *src++;
+		}
+		*q = '\0';
+
+		/* Add file size */
+		long long size = 0;
+		if (ent->d_type == DT_REG) {
+			if (stat(buffer, &stbuf) == /*Error*/-1) {
+				fprintf(stderr, "Cannot access %s\n", buffer);
+				continue;
+			}
+			size += (long long) stbuf.st_size;
+		}
+
+		/* Compute size of subdirectories recursively */
+		if (ent->d_type == DT_DIR)
+			size += list_directory(buffer, level + 1);
+
+		/* Update total size of directory */
+		total += size;
+
+		/* Output file/directory size in bytes */
+		if (level == 0)
+			printf("%-10lld  %s\n", size, ent->d_name);
+	}
+
+	closedir(dir);
+
+	/* Return total size of directory */
+	return total;
+}
+
+/* Stub for converting arguments to UTF-8 on Windows */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n + 1);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+
diff --git a/dirent/examples/find.c b/dirent/examples/find.c
new file mode 100644
index 0000000..3e53d49
--- /dev/null
+++ b/dirent/examples/find.c
@@ -0,0 +1,184 @@
+/*
+ * List files and directories recursively.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a directory name argument.  For example, command
+ *
+ *     find "C:\Program Files"
+ *
+ * will output thousands of file names such as
+ *
+ *     c:\Program Files/7-Zip/7-zip.chm
+ *     c:\Program Files/7-Zip/7-zip.dll
+ *     c:\Program Files/7-Zip/7z.dll
+ *     c:\Program Files/Adobe/Reader 10.0/Reader/logsession.dll
+ *     c:\Program Files/Adobe/Reader 10.0/Reader/LogTransport2.exe
+ *     c:\Program Files/Windows NT/Accessories/wordpad.exe
+ *     c:\Program Files/Windows NT/Accessories/write.wpc
+ *
+ * The find command provided by this file is only an example: the command does
+ * not provide options to restrict the output to certain files as the Linux
+ * version does.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <locale.h>
+
+static int find_directory(const char *dirname);
+static int _main(int argc, char *argv[]);
+
+int
+_main(int argc, char *argv[])
+{
+	/* For each directory in command line */
+	int i = 1;
+	while (i < argc) {
+		if (!find_directory(argv[i]))
+			exit(EXIT_FAILURE);
+		i++;
+	}
+
+	/* List current working directory if no arguments on command line */
+	if (argc == 1)
+		find_directory(".");
+
+	return EXIT_SUCCESS;
+}
+
+/* Find files and subdirectories recursively */
+static int
+find_directory(const char *dirname)
+{
+	char buffer[PATH_MAX + 2];
+	char *p = buffer;
+	char *end = &buffer[PATH_MAX];
+
+	/* Copy directory name to buffer */
+	const char *src = dirname;
+	while (p < end && *src != '\0') {
+		*p++ = *src++;
+	}
+	*p = '\0';
+
+	/* Open directory stream */
+	DIR *dir = opendir(dirname);
+	if (!dir) {
+		/* Could not open directory */
+		fprintf(stderr,
+			"Cannot open %s (%s)\n", dirname, strerror(errno));
+		return /*failure*/ 0;
+	}
+
+	/* Print all files and directories within the directory */
+	struct dirent *ent;
+	while ((ent = readdir(dir)) != NULL) {
+		char *q = p;
+		char c;
+
+		/* Get final character of directory name */
+		if (buffer < q)
+			c = q[-1];
+		else
+			c = ':';
+
+		/* Append directory separator if not already there */
+		if (c != ':' && c != '/' && c != '\\')
+			*q++ = '/';
+
+		/* Append file name */
+		src = ent->d_name;
+		while (q < end && *src != '\0') {
+			*q++ = *src++;
+		}
+		*q = '\0';
+
+		/* Decide what to do with the directory entry */
+		switch (ent->d_type) {
+		case DT_LNK:
+		case DT_REG:
+			/* Output file name with directory */
+			printf("%s\n", buffer);
+			break;
+
+		case DT_DIR:
+			/* Scan sub-directory recursively */
+			if (strcmp(ent->d_name, ".") != 0
+				&&  strcmp(ent->d_name, "..") != 0) {
+				find_directory(buffer);
+			}
+			break;
+
+		default:
+			/* Ignore device entries */
+			/*NOP*/;
+		}
+
+	}
+
+	closedir(dir);
+	return /*success*/ 1;
+}
+
+/* Stub for converting arguments to UTF-8 on Windows */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n + 1);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+
diff --git a/dirent/examples/locate.c b/dirent/examples/locate.c
new file mode 100644
index 0000000..60bea4d
--- /dev/null
+++ b/dirent/examples/locate.c
@@ -0,0 +1,262 @@
+/*
+ * Find file name from locatedb database.
+ *
+ * Compile and run updatedb command first to create locate.db file.  Then,
+ * compile this program with Visual Studio and run the program in console with
+ * a file name argument.  For example, the command
+ *
+ *     locate autoexec
+ *
+ * might output something like
+ *
+ *     c:/AUTOEXEC.BAT
+ *     c:/WINDOWS/repair/autoexec.nt
+ *     c:/WINDOWS/system32/AUTOEXEC.NT
+ *
+ * Be ware that this file uses wide-character API which is not compatible
+ * with Linux or other major Unixes.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#ifdef WIN32
+#	include <io.h>
+#	include <fcntl.h>
+#endif
+#include <dirent.h>
+
+/* File name and location of database file */
+#define DB_LOCATION L"locate.db"
+
+/* Forward-decl */
+static int db_locate(const wchar_t *pattern);
+static int db_match(const wchar_t *fn, const wchar_t *pattern);
+static void db_open(void);
+static void db_close(void);
+static int db_read(wchar_t *buffer, size_t max);
+
+/* Module local variables */
+static FILE *db = NULL;
+
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Prepare for unicode output */
+	_setmode(_fileno(stdout), _O_U16TEXT);
+
+	/* For each pattern in command line */
+	int i = 1;
+	while (i < argc) {
+		int count = 0;
+
+		/* Find files matching pattern */
+		count = db_locate(argv[i]);
+
+		/* Output warning if string is not found */
+		if (count == 0) {
+			wprintf(L"%s not found\n", argv[i]);
+		}
+
+		i++;
+	}
+
+	if (argc < 2) {
+		wprintf(L"Usage: locate pattern\n");
+		exit(EXIT_FAILURE);
+	}
+	return EXIT_SUCCESS;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	printf("locate only works on Microsoft Windows\n");
+	return EXIT_SUCCESS;
+}
+#endif
+
+/* Match pattern against files in locate.db file */
+static int
+db_locate(const wchar_t *pattern)
+{
+	int count = 0;
+
+#ifdef WIN32
+	wchar_t buffer[PATH_MAX + 1];
+
+	/* Open locate.db for read */
+	db_open();
+
+	/* Read one directory and file name at a time from database file */
+	while (db_read(buffer, PATH_MAX + 1)) {
+		/* See if file name in buffer matches the search pattern */
+		if (db_match(buffer, pattern)) {
+			/* Match found => output file name and path */
+			wprintf(L"%s\n", buffer);
+			count++;
+		}
+	}
+
+	db_close();
+#endif
+
+	return count;
+}
+
+/* Match pattern against file name */
+static int
+db_match(const wchar_t *fn, const wchar_t *pattern)
+{
+	int found = 0;
+
+#ifdef WIN32
+	/* Locate zero-terminator from fn */
+	wchar_t *p = wcschr(fn, '\0');
+
+	/* Find base name from buffer */
+	int done = 0;
+	while (fn < p && !done) {
+		switch (p[-1]) {
+		case ':':
+		case '/':
+		case '\\':
+			/* Final path separator found */
+			done = 1;
+			break;
+
+		default:
+			/* No path separator yet */
+			p--;
+		}
+	}
+
+	/* Convert base name to lower case */
+	int i = 0;
+	wchar_t base[PATH_MAX + 1];
+	while (i < PATH_MAX && p[i] != '\0') {
+		base[i] = towlower(p[i]);
+		i++;
+	}
+	base[i] = '\0';
+
+	/* Convert search pattern to lower case */
+	i = 0;
+	wchar_t patt[PATH_MAX + 1];
+	while (i < PATH_MAX && pattern[i] != '\0') {
+		patt[i] = towlower(pattern[i]);
+		i++;
+	}
+	patt[i] = '\0';
+
+	/* See if file name matches pattern */
+	if (wcsstr(base, patt) != NULL) {
+		found = 1;
+	} else {
+		found = 0;
+	}
+#endif
+
+	return found;
+}
+
+/*
+ * Read line from locate.db.  This function is same as fgetws() except
+ * that new-line at the end of line is not included.
+ */
+static int
+db_read(wchar_t *buffer, size_t max)
+{
+	int ok = 0;
+
+#ifdef WIN32
+	size_t i = 0;
+	wchar_t c;
+	int done = 0;
+
+	if (!db) {
+		wprintf(L"Database not open\n");
+		exit(EXIT_SUCCESS);
+	}
+
+	do {
+		/* Read wide-character from stream */
+		c = fgetwc(db);
+
+		/* Determine how to process character */
+		switch (c) {
+		case '\r':
+			/* Ignore, should be handled by run-time libraries */
+			/*NOP*/;
+			break;
+
+		case '\n':
+			/* End of string => return file name */
+			done = 1;
+			ok = 1;
+			break;
+
+		case /*EOF*/WEOF:
+			/* End of file */
+			done = 1;
+			if (i == 0) {
+				/* No data in buffer => return false */
+				ok = 0;
+			} else {
+				/* Data in buffer => return file name */
+				ok = 1;
+			}
+			break;
+
+		default:
+			/* Store character */
+			if (i < max - 1) {
+				buffer[i++] = c;
+			} else {
+				buffer[max - 1] = '\0';
+				wprintf(L"Buffer too small: %s", buffer);
+				exit(EXIT_FAILURE);
+			}
+		}
+	} while (!done);
+
+	/* Zero-terminate buffer */
+	buffer[i] = '\0';
+#endif
+
+	return ok;
+}
+
+/* Open database file locate.db */
+static void
+db_open(void)
+{
+#ifdef WIN32
+	if (db)
+		return;
+
+	/* Open file for writing */
+	errno_t error = _wfopen_s(&db, DB_LOCATION, L"rt, ccs=UNICODE");
+	if (error) {
+		wprintf(L"Cannot open %s\n", DB_LOCATION);
+		exit(EXIT_FAILURE);
+	}
+#endif
+}
+
+/* Close database file */
+static void
+db_close(void)
+{
+	if (!db)
+		return;
+
+	fclose(db);
+	db = NULL;
+}
diff --git a/dirent/examples/ls.c b/dirent/examples/ls.c
new file mode 100644
index 0000000..3fb627e
--- /dev/null
+++ b/dirent/examples/ls.c
@@ -0,0 +1,148 @@
+/*
+ * List contents of a directory.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a directory name argument.  For example, command
+ *
+ *     ls "c:\Program Files"
+ *
+ * might output something like
+ *
+ *     ./
+ *     ../
+ *     7-Zip/
+ *     Internet Explorer/
+ *     Microsoft Visual Studio 9.0/
+ *     Microsoft.NET/
+ *     Mozilla Firefox/
+ *
+ * The ls command provided by this file is only an example: the command does
+ * not have any fancy options like "ls -al" in Linux and the command does not
+ * support file name matching like "ls *.c".
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <locale.h>
+
+static void list_directory(const char *dirname);
+static int _main(int argc, char *argv[]);
+
+static int
+_main(int argc, char *argv[])
+{
+	/* For each directory in command line */
+	int i = 1;
+	while (i < argc) {
+		list_directory(argv[i]);
+		i++;
+	}
+
+	/* List current working directory if no arguments on command line */
+	if (argc == 1)
+		list_directory(".");
+
+	return EXIT_SUCCESS;
+}
+
+/*
+ * List files and directories within a directory.
+ */
+static void
+list_directory(const char *dirname)
+{
+	/* Open directory stream */
+	DIR *dir = opendir(dirname);
+	if (!dir) {
+		/* Could not open directory */
+		fprintf(stderr,
+			"Cannot open %s (%s)\n", dirname, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Print all files and directories within the directory */
+	struct dirent *ent;
+	while ((ent = readdir(dir)) != NULL) {
+		switch (ent->d_type) {
+		case DT_REG:
+			printf("%s\n", ent->d_name);
+			break;
+
+		case DT_DIR:
+			printf("%s/\n", ent->d_name);
+			break;
+
+		case DT_LNK:
+			printf("%s@\n", ent->d_name);
+			break;
+
+		default:
+			printf("%s*\n", ent->d_name);
+		}
+	}
+
+	closedir(dir);
+}
+
+/* Stub for converting arguments to UTF-8 on Windows */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n + 1);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+
diff --git a/dirent/examples/scandir.c b/dirent/examples/scandir.c
new file mode 100644
index 0000000..65dc11f
--- /dev/null
+++ b/dirent/examples/scandir.c
@@ -0,0 +1,152 @@
+/*
+ * List contents of a directory in an alphabetical order.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a directory name argument.  For example, command
+ *
+ *     scandir "c:\Program Files"
+ *
+ * might output something like
+ *
+ *     ./
+ *     ../
+ *     7-Zip/
+ *     Internet Explorer/
+ *     Microsoft Visual Studio 9.0/
+ *     Microsoft.NET/
+ *     Mozilla Firefox/
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <locale.h>
+
+static void list_directory(const char *dirname);
+static int _main(int argc, char *argv[]);
+
+static int
+_main(int argc, char *argv[])
+{
+	/* For each directory in command line */
+	int i = 1;
+	while (i < argc) {
+		list_directory(argv[i]);
+		i++;
+	}
+
+	/* List current working directory if no arguments on command line */
+	if (argc == 1)
+		list_directory(".");
+
+	return EXIT_SUCCESS;
+}
+
+/*
+ * List files and directories within a directory.
+ */
+static void
+list_directory(
+	const char *dirname)
+{
+	/* Scan files in directory */
+	struct dirent **files;
+	int n = scandir(dirname, &files, NULL, alphasort);
+	if (n < 0) {
+		fprintf(stderr,
+			"Cannot open %s (%s)\n", dirname, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	/* Loop through file names */
+	for (int i = 0; i < n; i++) {
+		/* Get pointer to file entry */
+		struct dirent *ent = files[i];
+
+		/* Output file name */
+		switch (ent->d_type) {
+		case DT_REG:
+			printf("%s\n", ent->d_name);
+			break;
+
+		case DT_DIR:
+			printf("%s/\n", ent->d_name);
+			break;
+
+		case DT_LNK:
+			printf("%s@\n", ent->d_name);
+			break;
+
+		default:
+			printf("%s*\n", ent->d_name);
+		}
+	}
+
+	/* Release file names */
+	for (int i = 0; i < n; i++) {
+		free(files[i]);
+	}
+	free(files);
+}
+
+/* Stub for converting arguments to UTF-8 on Windows */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n + 1);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+
diff --git a/dirent/examples/updatedb.c b/dirent/examples/updatedb.c
new file mode 100644
index 0000000..c7ec652
--- /dev/null
+++ b/dirent/examples/updatedb.c
@@ -0,0 +1,206 @@
+/*
+ * Build database of file and directory names.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a directory name argument.  For example, command
+ *
+ *     updatedb C:\
+ *
+ * will produce the file locate.db with one file name per line such as
+ *
+ *     c:\Program Files/7-Zip/7-zip.chm
+ *     c:\Program Files/7-Zip/7-zip.dll
+ *     c:\Program Files/7-Zip/7z.dll
+ *     c:\Program Files/Adobe/Reader 10.0/Reader/logsession.dll
+ *     c:\Program Files/Adobe/Reader 10.0/Reader/LogTransport2.exe
+ *     c:\Program Files/Windows NT/Accessories/wordpad.exe
+ *     c:\Program Files/Windows NT/Accessories/write.wpc
+ *
+ * Be ware that this file uses wide-character API which is not compatible
+ * with Linux or other major Unixes.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#ifdef WIN32
+#	include <io.h>
+#	include <fcntl.h>
+#endif
+#include <dirent.h>
+
+/* File name and location of database file */
+#define DB_LOCATION L"locate.db"
+
+/* Forward-decl */
+static int update_directory(const wchar_t *dirname);
+static void db_open(void);
+static void db_close(void);
+static void db_store(const wchar_t *dirname);
+
+/* Module local variables */
+static FILE *db = NULL;
+
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Prepare for unicode output */
+	_setmode(_fileno(stdout), _O_U16TEXT);
+
+	/* Open locate.db */
+	db_open();
+
+	/* For each directory in command line */
+	int i = 1;
+	while (i < argc) {
+		/* Scan directory for files */
+		int ok = update_directory(argv[i]);
+		if (!ok) {
+			wprintf(L"Cannot open directory %s\n", argv[i]);
+			exit(EXIT_FAILURE);
+		}
+
+		i++;
+	}
+
+	/* Use current working directory if no arguments on command line */
+	if (argc == 1)
+		update_directory(L".");
+
+	db_close();
+	return EXIT_SUCCESS;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	printf("updatedb only works on Microsoft Windows\n");
+	return EXIT_SUCCESS;
+}
+#endif
+
+/* Find files recursively */
+static int
+update_directory(const wchar_t *dirname)
+{
+#ifdef WIN32
+	wchar_t buffer[PATH_MAX + 2];
+	wchar_t *p = buffer;
+	wchar_t *end = &buffer[PATH_MAX];
+
+	/* Copy directory name to buffer */
+	const wchar_t *src = dirname;
+	while (p < end  &&  *src != '\0') {
+		*p++ = *src++;
+	}
+	*p = '\0';
+
+	/* Open directory stream */
+	_WDIR *dir = _wopendir(dirname);
+	if (!dir) {
+		/* Cannot open directory */
+		return /*failure*/ 0;
+	}
+
+	/* Print all files and directories within the directory */
+	struct _wdirent *ent;
+	while ((ent = _wreaddir (dir)) != NULL) {
+		wchar_t *q = p;
+		wchar_t c;
+
+		/* Get final character of directory name */
+		if (buffer < q)
+			c = q[-1];
+		else
+			c = ':';
+
+		/* Append directory separator if not already there */
+		if (c != ':'  &&  c != '/'  &&  c != '\\')
+			*q++ = '/';
+
+		/* Append file name */
+		src = ent->d_name;
+		while (q < end  &&  *src != '\0') {
+			*q++ = *src++;
+		}
+		*q = '\0';
+
+		/* Decide what to do with the directory entry */
+		switch (ent->d_type) {
+		case DT_REG:
+			/* Store file name */
+			db_store(buffer);
+			break;
+
+		case DT_DIR:
+			/* Scan sub-directory recursively */
+			if (wcscmp(ent->d_name, L".") != 0
+				&&  wcscmp(ent->d_name, L"..") != 0) {
+				update_directory(buffer);
+			}
+			break;
+
+		default:
+			/* Do not device entries */
+			/*NOP*/;
+		}
+
+	}
+
+	wclosedir(dir);
+	return /*success*/ 1;
+#else
+	return /*failure*/ 0;
+#endif
+}
+
+/* Store file name to locate.db */
+static void
+db_store(const wchar_t *dirname)
+{
+#ifdef WIN32
+	if (!db) {
+		wprintf(L"Database not open\n");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Output line to file */
+	fwprintf(db, L"%s\n", dirname);
+#endif
+}
+
+/* Open database file locate.db */
+static void
+db_open(void)
+{
+#ifdef WIN32
+	if (db)
+		return;
+
+	/* Open file for writing */
+	errno_t error = _wfopen_s(&db, DB_LOCATION, L"wt, ccs=UNICODE");
+	if (error) {
+		wprintf(L"Cannot open %s\n", DB_LOCATION);
+		exit(EXIT_FAILURE);
+	}
+#endif
+}
+
+/* Close database file */
+static void
+db_close(
+	void)
+{
+	if (!db)
+		return;
+
+	/* Close file */
+	fclose(db);
+	db = NULL;
+}
diff --git a/dirent/include/dirent.h b/dirent/include/dirent.h
new file mode 100644
index 0000000..557485a
--- /dev/null
+++ b/dirent/include/dirent.h
@@ -0,0 +1,1212 @@
+/*
+ * Dirent interface for Microsoft Visual Studio
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#ifndef DIRENT_H
+#define DIRENT_H
+
+/* Hide warnings about unreferenced local functions */
+#if defined(__clang__)
+#	pragma clang diagnostic ignored "-Wunused-function"
+#elif defined(_MSC_VER)
+#	pragma warning(disable:4505)
+#elif defined(__GNUC__)
+#	pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+/*
+ * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
+ * Windows Sockets 2.0.
+ */
+#ifndef WIN32_LEAN_AND_MEAN
+#	define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+
+/* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* Indicates that d_namlen field is available in dirent structure */
+#define _DIRENT_HAVE_D_NAMLEN
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+#	define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat(), general mask */
+#if !defined(S_IFMT)
+#	define S_IFMT _S_IFMT
+#endif
+
+/* Directory bit */
+#if !defined(S_IFDIR)
+#	define S_IFDIR _S_IFDIR
+#endif
+
+/* Character device bit */
+#if !defined(S_IFCHR)
+#	define S_IFCHR _S_IFCHR
+#endif
+
+/* Pipe bit */
+#if !defined(S_IFFIFO)
+#	define S_IFFIFO _S_IFFIFO
+#endif
+
+/* Regular file bit */
+#if !defined(S_IFREG)
+#	define S_IFREG _S_IFREG
+#endif
+
+/* Read permission */
+#if !defined(S_IREAD)
+#	define S_IREAD _S_IREAD
+#endif
+
+/* Write permission */
+#if !defined(S_IWRITE)
+#	define S_IWRITE _S_IWRITE
+#endif
+
+/* Execute permission */
+#if !defined(S_IEXEC)
+#	define S_IEXEC _S_IEXEC
+#endif
+
+/* Pipe */
+#if !defined(S_IFIFO)
+#	define S_IFIFO _S_IFIFO
+#endif
+
+/* Block device */
+#if !defined(S_IFBLK)
+#	define S_IFBLK 0
+#endif
+
+/* Link */
+#if !defined(S_IFLNK)
+#	define S_IFLNK 0
+#endif
+
+/* Socket */
+#if !defined(S_IFSOCK)
+#	define S_IFSOCK 0
+#endif
+
+/* Read user permission */
+#if !defined(S_IRUSR)
+#	define S_IRUSR S_IREAD
+#endif
+
+/* Write user permission */
+#if !defined(S_IWUSR)
+#	define S_IWUSR S_IWRITE
+#endif
+
+/* Execute user permission */
+#if !defined(S_IXUSR)
+#	define S_IXUSR 0
+#endif
+
+/* Read group permission */
+#if !defined(S_IRGRP)
+#	define S_IRGRP 0
+#endif
+
+/* Write group permission */
+#if !defined(S_IWGRP)
+#	define S_IWGRP 0
+#endif
+
+/* Execute group permission */
+#if !defined(S_IXGRP)
+#	define S_IXGRP 0
+#endif
+
+/* Read others permission */
+#if !defined(S_IROTH)
+#	define S_IROTH 0
+#endif
+
+/* Write others permission */
+#if !defined(S_IWOTH)
+#	define S_IWOTH 0
+#endif
+
+/* Execute others permission */
+#if !defined(S_IXOTH)
+#	define S_IXOTH 0
+#endif
+
+/* Maximum length of file name */
+#if !defined(PATH_MAX)
+#	define PATH_MAX MAX_PATH
+#endif
+#if !defined(FILENAME_MAX)
+#	define FILENAME_MAX MAX_PATH
+#endif
+#if !defined(NAME_MAX)
+#	define NAME_MAX FILENAME_MAX
+#endif
+
+/* File type flags for d_type */
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+#define DT_LNK S_IFLNK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+ * File type macros.  Note that block devices, sockets and links cannot be
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+ * only defined for compatibility.  These macros should always return false
+ * on Windows.
+ */
+#if !defined(S_ISFIFO)
+#	define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
+#endif
+#if !defined(S_ISDIR)
+#	define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+#if !defined(S_ISREG)
+#	define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+#if !defined(S_ISLNK)
+#	define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#endif
+#if !defined(S_ISSOCK)
+#	define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#endif
+#if !defined(S_ISCHR)
+#	define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#endif
+#if !defined(S_ISBLK)
+#	define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+#endif
+
+/* Return the exact length of the file name without zero terminator */
+#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
+
+/* Return the maximum size of a file name */
+#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Wide-character version */
+struct _wdirent {
+	/* Always zero */
+	long d_ino;
+
+	/* Position of next file in a directory stream */
+	long d_off;
+
+	/* Structure size */
+	unsigned short d_reclen;
+
+	/* Length of name without \0 */
+	size_t d_namlen;
+
+	/* File type */
+	int d_type;
+
+	/* File name */
+	wchar_t d_name[PATH_MAX+1];
+};
+typedef struct _wdirent _wdirent;
+
+struct _WDIR {
+	/* Current directory entry */
+	struct _wdirent ent;
+
+	/* Private file data */
+	WIN32_FIND_DATAW data;
+
+	/* True if data is valid */
+	int cached;
+
+	/* True if next entry is invalid */
+	int invalid;
+
+	/* Win32 search handle */
+	HANDLE handle;
+
+	/* Initial directory name */
+	wchar_t *patt;
+};
+typedef struct _WDIR _WDIR;
+
+/* Multi-byte character version */
+struct dirent {
+	/* Always zero */
+	long d_ino;
+
+	/* Position of next file in a directory stream */
+	long d_off;
+
+	/* Structure size */
+	unsigned short d_reclen;
+
+	/* Length of name without \0 */
+	size_t d_namlen;
+
+	/* File type */
+	int d_type;
+
+	/* File name */
+	char d_name[PATH_MAX+1];
+};
+typedef struct dirent dirent;
+
+struct DIR {
+	struct dirent ent;
+	struct _WDIR *wdirp;
+};
+typedef struct DIR DIR;
+
+
+/* Dirent functions */
+static DIR *opendir(const char *dirname);
+static _WDIR *_wopendir(const wchar_t *dirname);
+
+static struct dirent *readdir(DIR *dirp);
+static struct _wdirent *_wreaddir(_WDIR *dirp);
+
+static int readdir_r(
+	DIR *dirp, struct dirent *entry, struct dirent **result);
+static int _wreaddir_r(
+	_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
+
+static int closedir(DIR *dirp);
+static int _wclosedir(_WDIR *dirp);
+
+static void rewinddir(DIR *dirp);
+static void _wrewinddir(_WDIR *dirp);
+
+static long telldir(DIR *dirp);
+static long _wtelldir(_WDIR *dirp);
+
+static void seekdir(DIR *dirp, long loc);
+static void _wseekdir(_WDIR *dirp, long loc);
+
+static int scandir(const char *dirname, struct dirent ***namelist,
+	int (*filter)(const struct dirent*),
+	int (*compare)(const struct dirent**, const struct dirent**));
+
+static int alphasort(const struct dirent **a, const struct dirent **b);
+
+static int versionsort(const struct dirent **a, const struct dirent **b);
+
+static int strverscmp(const char *a, const char *b);
+
+/* For compatibility with Symbian */
+#define wdirent _wdirent
+#define WDIR _WDIR
+#define wopendir _wopendir
+#define wreaddir _wreaddir
+#define wclosedir _wclosedir
+#define wrewinddir _wrewinddir
+#define wtelldir _wtelldir
+#define wseekdir _wseekdir
+
+/* Compatibility with older Microsoft compilers and non-Microsoft compilers */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+#	define wcstombs_s dirent_wcstombs_s
+#	define mbstowcs_s dirent_mbstowcs_s
+#endif
+
+/* Optimize dirent_set_errno() away on modern Microsoft compilers */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#	define dirent_set_errno _set_errno
+#endif
+
+
+/* Internal utility functions */
+static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
+static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
+static long dirent_hash(WIN32_FIND_DATAW *datap);
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int dirent_mbstowcs_s(
+	size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords,
+	const char *mbstr, size_t count);
+#endif
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int dirent_wcstombs_s(
+	size_t *pReturnValue, char *mbstr, size_t sizeInBytes,
+	const wchar_t *wcstr, size_t count);
+#endif
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static void dirent_set_errno(int error);
+#endif
+
+
+/*
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+static _WDIR *
+_wopendir(const wchar_t *dirname)
+{
+	wchar_t *p;
+
+	/* Must have directory name */
+	if (dirname == NULL || dirname[0] == '\0') {
+		dirent_set_errno(ENOENT);
+		return NULL;
+	}
+
+	/* Allocate new _WDIR structure */
+	_WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR));
+	if (!dirp)
+		return NULL;
+
+	/* Reset _WDIR structure */
+	dirp->handle = INVALID_HANDLE_VALUE;
+	dirp->patt = NULL;
+	dirp->cached = 0;
+	dirp->invalid = 0;
+
+	/*
+	 * Compute the length of full path plus zero terminator
+	 *
+	 * Note that on WinRT there's no way to convert relative paths
+	 * into absolute paths, so just assume it is an absolute path.
+	 */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+	/* Desktop */
+	DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL);
+#else
+	/* WinRT */
+	size_t n = wcslen(dirname);
+#endif
+
+	/* Allocate room for absolute directory name and search pattern */
+	dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16);
+	if (dirp->patt == NULL)
+		goto exit_closedir;
+
+	/*
+	 * Convert relative directory name to an absolute one.  This
+	 * allows rewinddir() to function correctly even when current
+	 * working directory is changed between opendir() and rewinddir().
+	 *
+	 * Note that on WinRT there's no way to convert relative paths
+	 * into absolute paths, so just assume it is an absolute path.
+	 */
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+	/* Desktop */
+	n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
+	if (n <= 0)
+		goto exit_closedir;
+#else
+	/* WinRT */
+	wcsncpy_s(dirp->patt, n+1, dirname, n);
+#endif
+
+	/* Append search pattern \* to the directory name */
+	p = dirp->patt + n;
+	switch (p[-1]) {
+	case '\\':
+	case '/':
+	case ':':
+		/* Directory ends in path separator, e.g. c:\temp\ */
+		/*NOP*/;
+		break;
+
+	default:
+		/* Directory name doesn't end in path separator */
+		*p++ = '\\';
+	}
+	*p++ = '*';
+	*p = '\0';
+
+	/* Open directory stream and retrieve the first entry */
+	if (!dirent_first(dirp))
+		goto exit_closedir;
+
+	/* Success */
+	return dirp;
+
+	/* Failure */
+exit_closedir:
+	_wclosedir(dirp);
+	return NULL;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns pointer to static directory entry which may be overwritten by
+ * subsequent calls to _wreaddir().
+ */
+static struct _wdirent *
+_wreaddir(_WDIR *dirp)
+{
+	/*
+	 * Read directory entry to buffer.  We can safely ignore the return
+	 * value as entry will be set to NULL in case of error.
+	 */
+	struct _wdirent *entry;
+	(void) _wreaddir_r(dirp, &dirp->ent, &entry);
+
+	/* Return pointer to statically allocated directory entry */
+	return entry;
+}
+
+/*
+ * Read next directory entry.
+ *
+ * Returns zero on success.  If end of directory stream is reached, then sets
+ * result to NULL and returns zero.
+ */
+static int
+_wreaddir_r(
+	_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result)
+{
+	/* Validate directory handle */
+	if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt) {
+		dirent_set_errno(EBADF);
+		*result = NULL;
+		return -1;
+	}
+
+	/* Read next directory entry */
+	WIN32_FIND_DATAW *datap = dirent_next(dirp);
+	if (!datap) {
+		/* Return NULL to indicate end of directory */
+		*result = NULL;
+		return /*OK*/0;
+	}
+
+	/*
+	 * Copy file name as wide-character string.  If the file name is too
+	 * long to fit in to the destination buffer, then truncate file name
+	 * to PATH_MAX characters and zero-terminate the buffer.
+	 */
+	size_t i = 0;
+	while (i < PATH_MAX && datap->cFileName[i] != 0) {
+		entry->d_name[i] = datap->cFileName[i];
+		i++;
+	}
+	entry->d_name[i] = 0;
+
+	/* Length of file name excluding zero terminator */
+	entry->d_namlen = i;
+
+	/* Determine file type */
+	DWORD attr = datap->dwFileAttributes;
+	if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
+		entry->d_type = DT_CHR;
+	else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+		entry->d_type = DT_DIR;
+	else
+		entry->d_type = DT_REG;
+
+	/* Read the next directory entry to cache */
+	datap = dirent_next(dirp);
+	if (datap) {
+		/* Compute 31-bit hash of the next directory entry */
+		entry->d_off = dirent_hash(datap);
+
+		/* Push the next directory entry back to cache */
+		dirp->cached = 1;
+	} else {
+		/* End of directory stream */
+		entry->d_off = (long) ((~0UL) >> 1);
+	}
+
+	/* Reset other fields */
+	entry->d_ino = 0;
+	entry->d_reclen = sizeof(struct _wdirent);
+
+	/* Set result address */
+	*result = entry;
+	return /*OK*/0;
+}
+
+/*
+ * Close directory stream opened by opendir() function.  This invalidates the
+ * DIR structure as well as any directory entry read previously by
+ * _wreaddir().
+ */
+static int
+_wclosedir(_WDIR *dirp)
+{
+	if (!dirp) {
+		dirent_set_errno(EBADF);
+		return /*failure*/-1;
+	}
+
+	/*
+	 * Release search handle if we have one.  Being able to handle
+	 * partially initialized _WDIR structure allows us to use this
+	 * function to handle errors occuring within _wopendir.
+	 */
+	if (dirp->handle != INVALID_HANDLE_VALUE) {
+		FindClose(dirp->handle);
+	}
+
+	/*
+	 * Release search pattern.  Note that we don't need to care if
+	 * dirp->patt is NULL or not: function free is guaranteed to act
+	 * appropriately.
+	 */
+	free(dirp->patt);
+
+	/* Release directory structure */
+	free(dirp);
+	return /*success*/0;
+}
+
+/*
+ * Rewind directory stream such that _wreaddir() returns the very first
+ * file name again.
+ */
+static void _wrewinddir(_WDIR* dirp)
+{
+	/* Check directory pointer */
+	if (!dirp || dirp->handle == INVALID_HANDLE_VALUE || !dirp->patt)
+		return;
+
+	/* Release existing search handle */
+	FindClose(dirp->handle);
+
+	/* Open new search handle */
+	dirent_first(dirp);
+}
+
+/* Get first directory entry */
+static WIN32_FIND_DATAW *
+dirent_first(_WDIR *dirp)
+{
+	/* Open directory and retrieve the first entry */
+	dirp->handle = FindFirstFileExW(
+		dirp->patt, FindExInfoStandard, &dirp->data,
+		FindExSearchNameMatch, NULL, 0);
+	if (dirp->handle == INVALID_HANDLE_VALUE)
+		goto error;
+
+	/* A directory entry is now waiting in memory */
+	dirp->cached = 1;
+	return &dirp->data;
+
+error:
+	/* Failed to open directory: no directory entry in memory */
+	dirp->cached = 0;
+	dirp->invalid = 1;
+
+	/* Set error code */
+	DWORD errorcode = GetLastError();
+	switch (errorcode) {
+	case ERROR_ACCESS_DENIED:
+		/* No read access to directory */
+		dirent_set_errno(EACCES);
+		break;
+
+	case ERROR_DIRECTORY:
+		/* Directory name is invalid */
+		dirent_set_errno(ENOTDIR);
+		break;
+
+	case ERROR_PATH_NOT_FOUND:
+	default:
+		/* Cannot find the file */
+		dirent_set_errno(ENOENT);
+	}
+	return NULL;
+}
+
+/* Get next directory entry */
+static WIN32_FIND_DATAW *
+dirent_next(_WDIR *dirp)
+{
+	/* Return NULL if seek position was invalid */
+	if (dirp->invalid)
+		return NULL;
+
+	/* Is the next directory entry already in cache? */
+	if (dirp->cached) {
+		/* Yes, a valid directory entry found in memory */
+		dirp->cached = 0;
+		return &dirp->data;
+	}
+
+	/* Read the next directory entry from stream */
+	if (FindNextFileW(dirp->handle, &dirp->data) == FALSE) {
+		/* End of directory stream */
+		return NULL;
+	}
+
+	/* Success */
+	return &dirp->data;
+}
+
+/*
+ * Compute 31-bit hash of file name.
+ *
+ * See djb2 at http://www.cse.yorku.ca/~oz/hash.html
+ */
+static long
+dirent_hash(WIN32_FIND_DATAW *datap)
+{
+	unsigned long hash = 5381;
+	unsigned long c;
+	const wchar_t *p = datap->cFileName;
+	const wchar_t *e = p + MAX_PATH;
+	while (p != e && (c = *p++) != 0) {
+		hash = (hash << 5) + hash + c;
+	}
+
+	return (long) (hash & ((~0UL) >> 1));
+}
+
+/* Open directory stream using plain old C-string */
+static DIR *opendir(const char *dirname)
+{
+	/* Must have directory name */
+	if (dirname == NULL || dirname[0] == '\0') {
+		dirent_set_errno(ENOENT);
+		return NULL;
+	}
+
+	/* Allocate memory for DIR structure */
+	struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR));
+	if (!dirp)
+		return NULL;
+
+	/* Convert directory name to wide-character string */
+	wchar_t wname[PATH_MAX + 1];
+	size_t n;
+	int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1);
+	if (error)
+		goto exit_failure;
+
+	/* Open directory stream using wide-character name */
+	dirp->wdirp = _wopendir(wname);
+	if (!dirp->wdirp)
+		goto exit_failure;
+
+	/* Success */
+	return dirp;
+
+	/* Failure */
+exit_failure:
+	free(dirp);
+	return NULL;
+}
+
+/* Read next directory entry */
+static struct dirent *
+readdir(DIR *dirp)
+{
+	/*
+	 * Read directory entry to buffer.  We can safely ignore the return
+	 * value as entry will be set to NULL in case of error.
+	 */
+	struct dirent *entry;
+	(void) readdir_r(dirp, &dirp->ent, &entry);
+
+	/* Return pointer to statically allocated directory entry */
+	return entry;
+}
+
+/*
+ * Read next directory entry into called-allocated buffer.
+ *
+ * Returns zero on success.  If the end of directory stream is reached, then
+ * sets result to NULL and returns zero.
+ */
+static int
+readdir_r(
+	DIR *dirp, struct dirent *entry, struct dirent **result)
+{
+	/* Read next directory entry */
+	WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp);
+	if (!datap) {
+		/* No more directory entries */
+		*result = NULL;
+		return /*OK*/0;
+	}
+
+	/* Attempt to convert file name to multi-byte string */
+	size_t n;
+	int error = wcstombs_s(
+		&n, entry->d_name, PATH_MAX + 1,
+		datap->cFileName, PATH_MAX + 1);
+
+	/*
+	 * If the file name cannot be represented by a multi-byte string, then
+	 * attempt to use old 8+3 file name.  This allows the program to
+	 * access files although file names may seem unfamiliar to the user.
+	 *
+	 * Be ware that the code below cannot come up with a short file name
+	 * unless the file system provides one.  At least VirtualBox shared
+	 * folders fail to do this.
+	 */
+	if (error && datap->cAlternateFileName[0] != '\0') {
+		error = wcstombs_s(
+			&n, entry->d_name, PATH_MAX + 1,
+			datap->cAlternateFileName, PATH_MAX + 1);
+	}
+
+	if (!error) {
+		/* Length of file name excluding zero terminator */
+		entry->d_namlen = n - 1;
+
+		/* Determine file type */
+		DWORD attr = datap->dwFileAttributes;
+		if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
+			entry->d_type = DT_CHR;
+		else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
+			entry->d_type = DT_DIR;
+		else
+			entry->d_type = DT_REG;
+
+		/* Get offset of next file */
+		datap = dirent_next(dirp->wdirp);
+		if (datap) {
+			/* Compute 31-bit hash of the next directory entry */
+			entry->d_off = dirent_hash(datap);
+
+			/* Push the next directory entry back to cache */
+			dirp->wdirp->cached = 1;
+		} else {
+			/* End of directory stream */
+			entry->d_off = (long) ((~0UL) >> 1);
+		}
+
+		/* Reset fields */
+		entry->d_ino = 0;
+		entry->d_reclen = sizeof(struct dirent);
+	} else {
+		/*
+		 * Cannot convert file name to multi-byte string so construct
+		 * an erroneous directory entry and return that.  Note that
+		 * we cannot return NULL as that would stop the processing
+		 * of directory entries completely.
+		 */
+		entry->d_name[0] = '?';
+		entry->d_name[1] = '\0';
+		entry->d_namlen = 1;
+		entry->d_type = DT_UNKNOWN;
+		entry->d_ino = 0;
+		entry->d_off = -1;
+		entry->d_reclen = 0;
+	}
+
+	/* Return pointer to directory entry */
+	*result = entry;
+	return /*OK*/0;
+}
+
+/* Close directory stream */
+static int
+closedir(DIR *dirp)
+{
+	int ok;
+
+	if (!dirp)
+		goto exit_failure;
+
+	/* Close wide-character directory stream */
+	ok = _wclosedir(dirp->wdirp);
+	dirp->wdirp = NULL;
+
+	/* Release multi-byte character version */
+	free(dirp);
+	return ok;
+
+exit_failure:
+	/* Invalid directory stream */
+	dirent_set_errno(EBADF);
+	return /*failure*/-1;
+}
+
+/* Rewind directory stream to beginning */
+static void
+rewinddir(DIR *dirp)
+{
+	if (!dirp)
+		return;
+
+	/* Rewind wide-character string directory stream */
+	_wrewinddir(dirp->wdirp);
+}
+
+/* Get position of directory stream */
+static long
+_wtelldir(_WDIR *dirp)
+{
+	if (!dirp || dirp->handle == INVALID_HANDLE_VALUE) {
+		dirent_set_errno(EBADF);
+		return /*failure*/-1;
+	}
+
+	/* Read next file entry */
+	WIN32_FIND_DATAW *datap = dirent_next(dirp);
+	if (!datap) {
+		/* End of directory stream */
+		return (long) ((~0UL) >> 1);
+	}
+
+	/* Store file entry to cache for readdir() */
+	dirp->cached = 1;
+
+	/* Return the 31-bit hash code to be used as stream position */
+	return dirent_hash(datap);
+}
+
+/* Get position of directory stream */
+static long
+telldir(DIR *dirp)
+{
+	if (!dirp) {
+		dirent_set_errno(EBADF);
+		return -1;
+	}
+
+	return _wtelldir(dirp->wdirp);
+}
+
+/* Seek directory stream to offset */
+static void
+_wseekdir(_WDIR *dirp, long loc)
+{
+	/* Directory must be open */
+	if (!dirp || dirp->handle == INVALID_HANDLE_VALUE)
+		goto exit_failure;
+
+	/* Ensure that seek position is valid */
+	if (loc < 0)
+		goto exit_failure;
+
+	/* Restart directory stream from the beginning */
+	FindClose(dirp->handle);
+	if (!dirent_first(dirp))
+		goto exit_failure;
+
+	/* Reset invalid flag so that we can read from the stream again */
+	dirp->invalid = 0;
+
+	/*
+	 * Read directory entries from the beginning until the hash matches a
+	 * file name.  Be ware that hash code is only 31 bits longs and
+	 * duplicates are possible: the hash code cannot return the position
+	 * with 100.00% accuracy! Moreover, the method is slow for large
+	 * directories.
+	 */
+	long hash;
+	do {
+		/* Read next directory entry */
+		WIN32_FIND_DATAW *datap = dirent_next(dirp);
+		if (!datap) {
+			/*
+			 * End of directory stream was reached before finding
+			 * the requested location.  Perhaps the file in
+			 * question was deleted or moved out of the directory.
+			 */
+			goto exit_failure;
+		}
+
+		/* Does the file name match the hash? */
+		hash = dirent_hash(datap);
+	} while (hash != loc);
+
+	/*
+	 * File name matches the hash!  Push the directory entry back to cache
+	 * from where next readdir() will return it.
+	 */
+	dirp->cached = 1;
+	dirp->invalid = 0;
+	return;
+
+exit_failure:
+	/* Ensure that readdir will return NULL */
+	dirp->invalid = 1;
+}
+
+/* Seek directory stream to offset */
+static void
+seekdir(DIR *dirp, long loc)
+{
+	if (!dirp)
+		return;
+
+	_wseekdir(dirp->wdirp, loc);
+}
+
+/* Scan directory for entries */
+static int
+scandir(
+	const char *dirname, struct dirent ***namelist,
+	int (*filter)(const struct dirent*),
+	int (*compare)(const struct dirent**, const struct dirent**))
+{
+	int result;
+
+	/* Open directory stream */
+	DIR *dir = opendir(dirname);
+	if (!dir) {
+		/* Cannot open directory */
+		return /*Error*/ -1;
+	}
+
+	/* Read directory entries to memory */
+	struct dirent *tmp = NULL;
+	struct dirent **files = NULL;
+	size_t size = 0;
+	size_t allocated = 0;
+	while (1) {
+		/* Allocate room for a temporary directory entry */
+		if (!tmp) {
+			tmp = (struct dirent*) malloc(sizeof(struct dirent));
+			if (!tmp)
+				goto exit_failure;
+		}
+
+		/* Read directory entry to temporary area */
+		struct dirent *entry;
+		if (readdir_r(dir, tmp, &entry) != /*OK*/0)
+			goto exit_failure;
+
+		/* Stop if we already read the last directory entry */
+		if (entry == NULL)
+			goto exit_success;
+
+		/* Determine whether to include the entry in results */
+		if (filter && !filter(tmp))
+			continue;
+
+		/* Enlarge pointer table to make room for another pointer */
+		if (size >= allocated) {
+			/* Compute number of entries in the new table */
+			size_t num_entries = size * 2 + 16;
+
+			/* Allocate new pointer table or enlarge existing */
+			void *p = realloc(files, sizeof(void*) * num_entries);
+			if (!p)
+				goto exit_failure;
+
+			/* Got the memory */
+			files = (dirent**) p;
+			allocated = num_entries;
+		}
+
+		/* Store the temporary entry to ptr table */
+		files[size++] = tmp;
+		tmp = NULL;
+	}
+
+exit_failure:
+	/* Release allocated entries */
+	for (size_t i = 0; i < size; i++) {
+		free(files[i]);
+	}
+
+	/* Release the pointer table */
+	free(files);
+	files = NULL;
+
+	/* Exit with error code */
+	result = /*error*/ -1;
+	goto exit_status;
+
+exit_success:
+	/* Sort directory entries */
+	qsort(files, size, sizeof(void*),
+		(int (*) (const void*, const void*)) compare);
+
+	/* Pass pointer table to caller */
+	if (namelist)
+		*namelist = files;
+
+	/* Return the number of directory entries read */
+	result = (int) size;
+
+exit_status:
+	/* Release temporary directory entry, if we had one */
+	free(tmp);
+
+	/* Close directory stream */
+	closedir(dir);
+	return result;
+}
+
+/* Alphabetical sorting */
+static int
+alphasort(const struct dirent **a, const struct dirent **b)
+{
+	return strcoll((*a)->d_name, (*b)->d_name);
+}
+
+/* Sort versions */
+static int
+versionsort(const struct dirent **a, const struct dirent **b)
+{
+	return strverscmp((*a)->d_name, (*b)->d_name);
+}
+
+/* Compare strings */
+static int
+strverscmp(const char *a, const char *b)
+{
+	size_t i = 0;
+	size_t j;
+
+	/* Find first difference */
+	while (a[i] == b[i]) {
+		if (a[i] == '\0') {
+			/* No difference */
+			return 0;
+		}
+		++i;
+	}
+
+	/* Count backwards and find the leftmost digit */
+	j = i;
+	while (j > 0 && isdigit(a[j-1])) {
+		--j;
+	}
+
+	/* Determine mode of comparison */
+	if (a[j] == '0' || b[j] == '0') {
+		/* Find the next non-zero digit */
+		while (a[j] == '0' && a[j] == b[j]) {
+			j++;
+		}
+
+		/* String with more digits is smaller, e.g 002 < 01 */
+		if (isdigit(a[j])) {
+			if (!isdigit(b[j])) {
+				return -1;
+			}
+		} else if (isdigit(b[j])) {
+			return 1;
+		}
+	} else if (isdigit(a[j]) && isdigit(b[j])) {
+		/* Numeric comparison */
+		size_t k1 = j;
+		size_t k2 = j;
+
+		/* Compute number of digits in each string */
+		while (isdigit(a[k1])) {
+			k1++;
+		}
+		while (isdigit(b[k2])) {
+			k2++;
+		}
+
+		/* Number with more digits is bigger, e.g 999 < 1000 */
+		if (k1 < k2)
+			return -1;
+		else if (k1 > k2)
+			return 1;
+	}
+
+	/* Alphabetical comparison */
+	return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]);
+}
+
+/* Convert multi-byte string to wide character string */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int
+dirent_mbstowcs_s(
+	size_t *pReturnValue, wchar_t *wcstr,
+	size_t sizeInWords, const char *mbstr, size_t count)
+{
+	/* Older Visual Studio or non-Microsoft compiler */
+	size_t n = mbstowcs(wcstr, mbstr, sizeInWords);
+	if (wcstr && n >= count)
+		return /*error*/ 1;
+
+	/* Zero-terminate output buffer */
+	if (wcstr && sizeInWords) {
+		if (n >= sizeInWords)
+			n = sizeInWords - 1;
+		wcstr[n] = 0;
+	}
+
+	/* Length of multi-byte string with zero terminator */
+	if (pReturnValue) {
+		*pReturnValue = n + 1;
+	}
+
+	/* Success */
+	return 0;
+}
+#endif
+
+/* Convert wide-character string to multi-byte string */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static int
+dirent_wcstombs_s(
+	size_t *pReturnValue, char *mbstr,
+	size_t sizeInBytes, const wchar_t *wcstr, size_t count)
+{
+	/* Older Visual Studio or non-Microsoft compiler */
+	size_t n = wcstombs(mbstr, wcstr, sizeInBytes);
+	if (mbstr && n >= count)
+		return /*error*/1;
+
+	/* Zero-terminate output buffer */
+	if (mbstr && sizeInBytes) {
+		if (n >= sizeInBytes) {
+			n = sizeInBytes - 1;
+		}
+		mbstr[n] = '\0';
+	}
+
+	/* Length of resulting multi-bytes string WITH zero-terminator */
+	if (pReturnValue) {
+		*pReturnValue = n + 1;
+	}
+
+	/* Success */
+	return 0;
+}
+#endif
+
+/* Set errno variable */
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+static void
+dirent_set_errno(int error)
+{
+	/* Non-Microsoft compiler or older Microsoft compiler */
+	errno = error;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/
diff --git a/dirent/tests/1/dir/readme.txt b/dirent/tests/1/dir/readme.txt
new file mode 100644
index 0000000..e59af2f
--- /dev/null
+++ b/dirent/tests/1/dir/readme.txt
@@ -0,0 +1,3 @@
+This file ensures that the directory dir will be created accordingly when
+you unzip dirent to your computer.  The directory itself is needed by the
+test program t-dirent.
diff --git a/dirent/tests/1/file b/dirent/tests/1/file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/1/file
diff --git a/dirent/tests/2/Testfile-1.2.3.dat b/dirent/tests/2/Testfile-1.2.3.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/2/Testfile-1.2.3.dat
diff --git a/dirent/tests/2/file.txt b/dirent/tests/2/file.txt
new file mode 100644
index 0000000..d32e004
--- /dev/null
+++ b/dirent/tests/2/file.txt
@@ -0,0 +1 @@
+This dummy file is needed by the test program t-dirent.
diff --git a/dirent/tests/3/3zero.dat b/dirent/tests/3/3zero.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/3zero.dat
diff --git a/dirent/tests/3/666.dat b/dirent/tests/3/666.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/666.dat
diff --git a/dirent/tests/3/Qwerty-my-aunt.dat b/dirent/tests/3/Qwerty-my-aunt.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/Qwerty-my-aunt.dat
diff --git a/dirent/tests/3/README.txt b/dirent/tests/3/README.txt
new file mode 100644
index 0000000..a07591c
--- /dev/null
+++ b/dirent/tests/3/README.txt
@@ -0,0 +1,2 @@
+This directory contains some random files for the t-scandir test program.  The
+files are empty and only the file names matter.
diff --git a/dirent/tests/3/aaa.dat b/dirent/tests/3/aaa.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/aaa.dat
diff --git a/dirent/tests/3/dirent.dat b/dirent/tests/3/dirent.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/dirent.dat
diff --git a/dirent/tests/3/empty.dat b/dirent/tests/3/empty.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/empty.dat
diff --git a/dirent/tests/3/sane-1.12.0.dat b/dirent/tests/3/sane-1.12.0.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/sane-1.12.0.dat
diff --git a/dirent/tests/3/sane-1.2.30.dat b/dirent/tests/3/sane-1.2.30.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/sane-1.2.30.dat
diff --git a/dirent/tests/3/sane-1.2.4.dat b/dirent/tests/3/sane-1.2.4.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/sane-1.2.4.dat
diff --git a/dirent/tests/3/zebra.dat b/dirent/tests/3/zebra.dat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/3/zebra.dat
diff --git a/dirent/tests/4/asidofilusphosphorus b/dirent/tests/4/asidofilusphosphorus
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/4/asidofilusphosphorus
diff --git a/dirent/tests/4/bubblebob b/dirent/tests/4/bubblebob
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/4/bubblebob
diff --git a/dirent/tests/4/celsiusfortissimo b/dirent/tests/4/celsiusfortissimo
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dirent/tests/4/celsiusfortissimo
diff --git a/dirent/tests/t-compile.c b/dirent/tests/t-compile.c
new file mode 100644
index 0000000..90d8e50
--- /dev/null
+++ b/dirent/tests/t-compile.c
@@ -0,0 +1,46 @@
+/*
+ * Test program to make sure that dirent compiles cleanly with winsock.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#include <dirent.h>
+#ifdef WIN32
+#	include <winsock2.h>
+#	include <ws2tcpip.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(int argc, char *argv[])
+{
+	struct dirent *dirp = NULL;
+
+	(void) argc;
+	(void) argv;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+	printf("Has d_type\n");
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+	printf("Has d_namlen\n");
+#endif
+#ifdef _D_EXACT_NAMLEN
+	printf("Has _D_EXACT_NAMLEN\n");
+#endif
+#ifdef _D_ALLOC_NAMLEN
+	printf("Has _D_ALLOC_NAMLEN\n");
+#endif
+#ifdef _D_ALLOC_NAMLEN
+	printf("Has _D_ALLOC_NAMLEN\n");
+#endif
+	printf("Length of d_name with terminator: %d\n",
+		(int) sizeof(dirp->d_name));
+
+	printf("OK\n");
+	return EXIT_SUCCESS;
+}
diff --git a/dirent/tests/t-cplusplus.cpp b/dirent/tests/t-cplusplus.cpp
new file mode 100644
index 0000000..8a8bad4
--- /dev/null
+++ b/dirent/tests/t-cplusplus.cpp
@@ -0,0 +1,155 @@
+/*
+ * Test program to make sure that dirent compiles cleanly with C++
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#include <iostream>
+#include <string.h>
+#include <dirent.h>
+#include <assert.h>
+using namespace std;
+
+/* Filter and sort functions */
+static int only_readme(const struct dirent *entry);
+static void test_retrieval(void);
+static void test_scan(void);
+
+int
+main(int argc, char *argv[])
+{
+	(void) argc;
+	(void) argv;
+
+	test_retrieval();
+	test_scan();
+
+	cout << "OK" << endl;
+	return EXIT_SUCCESS;
+}
+
+/* Test basic directory retrieval */
+static void
+test_retrieval(void)
+{
+	/* Open directory */
+	DIR *dir = opendir("tests/1");
+	if (dir == NULL) {
+		cerr << "Directory tests/1 not found" << endl;
+		abort();
+	}
+
+	/* Read directory entries */
+	struct dirent *ent;
+	int found = 0;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Check each file */
+		if (strcmp(ent->d_name, ".") == 0) {
+			/* Directory itself */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 1);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 1);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 1);
+#endif
+			found += 1;
+		} else if (strcmp(ent->d_name, "..") == 0) {
+			/* Parent directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 2);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 2);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 2);
+#endif
+			found += 2;
+		} else if (strcmp(ent->d_name, "file") == 0) {
+			/* Regular file */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_REG);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 4);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 4);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 4);
+#endif
+			found += 4;
+		} else if (strcmp(ent->d_name, "dir") == 0) {
+			/* Just a directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 3);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 3);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 3);
+#endif
+			found += 8;
+		} else {
+			/* Other file */
+			cerr << "Unexpected file " << ent->d_name << endl;
+			abort();
+		}
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	closedir(dir);
+}
+
+/* Text basic scan with simple filter function */
+static void
+test_scan(void)
+{
+	struct dirent **files;
+
+	/* Read directory entries */
+	int n = scandir("tests/3", &files, only_readme, alphasort);
+	assert(n == 1);
+
+	/* Make sure that the filter works */
+	assert(strcmp(files[0]->d_name, "README.txt") == 0);
+
+	/* Release file names */
+	for (int i = 0; i < n; i++) {
+		free(files[i]);
+	}
+	free(files);
+}
+
+/* Only pass README.txt file */
+static int
+only_readme(const struct dirent *entry)
+{
+	int pass;
+
+	if (strcmp (entry->d_name, "README.txt") == 0) {
+		pass = 1;
+	} else {
+		pass = 0;
+	}
+
+	return pass;
+}
diff --git a/dirent/tests/t-dirent.c b/dirent/tests/t-dirent.c
new file mode 100644
index 0000000..95f151a
--- /dev/null
+++ b/dirent/tests/t-dirent.c
@@ -0,0 +1,608 @@
+/*
+ * A test program to make sure that dirent works correctly.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MSC_VER
+#	include <direct.h>
+#	define chdir(x) _chdir(x)
+#else
+#	include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+static void test_macros(void);
+static void test_retrieval(void);
+static void test_nonexistent(void);
+static void test_isfile(void);
+static void test_zero(void);
+static void test_rewind(void);
+static void test_chdir(void);
+static void test_filename(void);
+static void test_readdir(void);
+static void test_wreaddir(void);
+
+int
+main(int argc, char *argv[])
+{
+	(void) argc;
+	(void) argv;
+
+	/* Execute tests */
+	test_macros();
+	test_retrieval();
+	test_nonexistent();
+	test_isfile();
+	test_zero();
+	test_rewind();
+	test_chdir();
+	test_filename();
+	test_readdir();
+	test_wreaddir();
+
+	printf("OK\n");
+	return EXIT_SUCCESS;
+}
+
+/* Test file type macros */
+static void
+test_macros(void)
+{
+	assert(DTTOIF(DT_REG) == S_IFREG);
+	assert(DTTOIF(DT_DIR) == S_IFDIR);
+	assert(DTTOIF(DT_FIFO) == S_IFIFO);
+	assert(DTTOIF(DT_SOCK) == S_IFSOCK);
+	assert(DTTOIF(DT_CHR) == S_IFCHR);
+	assert(DTTOIF(DT_BLK) == S_IFBLK);
+
+	assert(IFTODT(S_IFREG) == DT_REG);
+	assert(IFTODT(S_IFDIR) == DT_DIR);
+	assert(IFTODT(S_IFIFO) == DT_FIFO);
+	assert(IFTODT(S_IFSOCK) == DT_SOCK);
+	assert(IFTODT(S_IFCHR) == DT_CHR);
+	assert(IFTODT(S_IFBLK) == DT_BLK);
+}
+
+/* Test basic directory retrieval */
+static void
+test_retrieval(void)
+{
+	/* Open directory */
+	DIR *dir = opendir("tests/1");
+	if (dir == NULL) {
+		fprintf(stderr, "Directory tests/1 not found\n");
+		abort();
+	}
+
+	/* Read entries */
+	struct dirent *ent;
+	int found = 0;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Check each file */
+		if (strcmp(ent->d_name, ".") == 0) {
+			/* Directory itself */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 1);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 1);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 1);
+#endif
+			found += 1;
+		} else if (strcmp(ent->d_name, "..") == 0) {
+			/* Parent directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 2);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 2);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 2);
+#endif
+			found += 2;
+		} else if (strcmp(ent->d_name, "file") == 0) {
+			/* Regular file */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_REG);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 4);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 4);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 4);
+#endif
+			found += 4;
+		} else if (strcmp(ent->d_name, "dir") == 0) {
+			/* Just a directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 3);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 3);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 3);
+#endif
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file %s\n", ent->d_name);
+			abort();
+		}
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	closedir(dir);
+}
+
+/* Function opendir() fails if directory doesn't exist */
+static void
+test_nonexistent(void)
+{
+	DIR *dir = opendir("tests/invalid");
+	assert(dir == NULL);
+	assert(errno == ENOENT);
+}
+
+/* Function opendir() fails if pathname is really a file */
+static void
+test_isfile(void)
+{
+	DIR *dir = opendir("tests/1/file");
+	assert(dir == NULL);
+	assert(errno == ENOTDIR);
+}
+
+/* Function opendir() fails if pathname is a zero-length string */
+static void
+test_zero(void)
+{
+	DIR *dir = opendir("");
+	assert(dir == NULL);
+	assert(errno == ENOENT);
+}
+
+/* Test rewind of directory stream */
+static void
+test_rewind(void)
+{
+	/* Open directory */
+	DIR *dir = opendir("tests/1");
+	assert(dir != NULL);
+
+	/* Read entries */
+	int found = 0;
+	struct dirent *ent;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Check each file */
+		if (strcmp(ent->d_name, ".") == 0) {
+			/* Directory itself */
+			found += 1;
+		} else if (strcmp(ent->d_name, "..") == 0) {
+			/* Parent directory */
+			found += 2;
+		} else if (strcmp(ent->d_name, "file") == 0) {
+			/* Regular file */
+			found += 4;
+		} else if (strcmp(ent->d_name, "dir") == 0) {
+			/* Just a directory */
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file %s\n", ent->d_name);
+			abort();
+		}
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	/* Rewind stream and read entries again */
+	rewinddir(dir);
+	found = 0;
+
+	/* Read entries */
+	while ((ent = readdir(dir)) != NULL) {
+		/* Check each file */
+		if (strcmp(ent->d_name, ".") == 0) {
+			/* Directory itself */
+			found += 1;
+		} else if (strcmp(ent->d_name, "..") == 0) {
+			/* Parent directory */
+			found += 2;
+		} else if (strcmp(ent->d_name, "file") == 0) {
+			/* Regular file */
+			found += 4;
+		} else if (strcmp(ent->d_name, "dir") == 0) {
+			/* Just a directory */
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file %s\n", ent->d_name);
+			abort();
+		}
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	closedir(dir);
+}
+
+/* Test rewind with intervening change of working directory */
+static void
+test_chdir(void)
+{
+	/* Open directory */
+	DIR *dir = opendir("tests/1");
+	assert(dir != NULL);
+
+	/* Read entries */
+	struct dirent *ent;
+	int found = 0;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Check each file */
+		if (strcmp(ent->d_name, ".") == 0) {
+			/* Directory itself */
+			found += 1;
+		} else if (strcmp(ent->d_name, "..") == 0) {
+			/* Parent directory */
+			found += 2;
+		} else if (strcmp(ent->d_name, "file") == 0) {
+			/* Regular file */
+			found += 4;
+		} else if (strcmp(ent->d_name, "dir") == 0) {
+			/* Just a directory */
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file %s\n", ent->d_name);
+			abort();
+		}
+
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	/* Change working directory */
+	int errorcode = chdir("tests");
+	assert(errorcode == 0);
+
+	/* Rewind stream and read entries again */
+	rewinddir(dir);
+	found = 0;
+
+	/* Read entries */
+	while ((ent = readdir(dir)) != NULL) {
+		/* Check each file */
+		if (strcmp(ent->d_name, ".") == 0) {
+			/* Directory itself */
+			found += 1;
+		} else if (strcmp(ent->d_name, "..") == 0) {
+			/* Parent directory */
+			found += 2;
+		} else if (strcmp(ent->d_name, "file") == 0) {
+			/* Regular file */
+			found += 4;
+		} else if (strcmp(ent->d_name, "dir") == 0) {
+			/* Just a directory */
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file %s\n", ent->d_name);
+			abort();
+		}
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	/* Restore working directory */
+	errorcode = chdir("..");
+	assert(errorcode == 0);
+
+	closedir(dir);
+}
+
+/* Test long file name */
+static void
+test_filename(void)
+{
+	/* Open directory */
+	DIR *dir = opendir("tests/2");
+	if (dir == NULL) {
+		fprintf(stderr, "Directory tests/2 not found\n");
+		abort();
+	}
+
+	/* Read entries */
+	struct dirent *ent;
+	int found = 0;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Check each file */
+		if (strcmp(ent->d_name, ".") == 0) {
+			/* Directory itself */
+			found += 1;
+		} else if (strcmp(ent->d_name, "..") == 0) {
+			/* Parent directory */
+			found += 2;
+		} else if (strcmp(ent->d_name, "file.txt") == 0) {
+			/* Regular 8+3 filename */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_REG);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 8);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 8);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 8);
+#endif
+			found += 4;
+		} else if (strcmp(ent->d_name, "Testfile-1.2.3.dat") == 0) {
+			/* Long file name with multiple dots */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(ent->d_type == DT_REG);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(ent->d_namlen == 18);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(ent) == 18);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(ent) > 18);
+#endif
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file %s\n", ent->d_name);
+			abort();
+		}
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	closedir(dir);
+}
+
+/* Test basic directory retrieval with readdir_r */
+static void
+test_readdir(void)
+{
+	/* Open directory */
+	DIR *dir = opendir("tests/1");
+	if (dir == NULL) {
+		fprintf(stderr, "Directory tests/1 not found\n");
+		abort();
+	}
+
+	/* Read entries to table */
+	struct dirent ent[10];
+	struct dirent *entry;
+	size_t i = 0;
+	size_t n = 0;
+	while (readdir_r(dir, &ent[n], &entry) == /*OK*/0 && entry != 0) {
+		n++;
+		assert(n <= 4);
+	}
+
+	/* Make sure that we got all the files from directory */
+	assert(n == 4);
+
+	/* Check entries in memory */
+	int found = 0;
+	for (i = 0; i < 4; i++) {
+		entry = &ent[i];
+
+		/* Check each file */
+		if (strcmp(entry->d_name, ".") == 0) {
+			/* Directory itself */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 1);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 1);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 1);
+#endif
+			found += 1;
+		} else if (strcmp(entry->d_name, "..") == 0) {
+			/* Parent directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 2);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 2);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 2);
+#endif
+			found += 2;
+		} else if (strcmp(entry->d_name, "file") == 0) {
+			/* Regular file */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_REG);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 4);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 4);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 4);
+#endif
+			found += 4;
+		} else if (strcmp(entry->d_name, "dir") == 0) {
+			/* Just a directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 3);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 3);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 3);
+#endif
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file %s\n", entry->d_name);
+			abort();
+		}
+
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	closedir(dir);
+}
+
+/* Basic directory retrieval with _wreaddir_r */
+static void
+test_wreaddir(void)
+{
+#ifdef WIN32
+	/* Open directory */
+	_WDIR *dir = _wopendir(L"tests/1");
+	if (dir == NULL) {
+		fprintf(stderr, "Directory tests/1 not found\n");
+		abort();
+	}
+
+	/* Read entries to table */
+	struct _wdirent ent[10];
+	struct _wdirent *entry;
+	size_t i = 0;
+	size_t n = 0;
+	while (_wreaddir_r(dir, &ent[n], &entry) == /*OK*/0 && entry != 0) {
+		n++;
+		assert(n <= 4);
+	}
+
+	/* Make sure that we got all the files from directory */
+	assert(n == 4);
+
+	/* Check entries in memory */
+	int found = 0;
+	for (i = 0; i < 4; i++) {
+		entry = &ent[i];
+
+		/* Check each file */
+		if (wcscmp(entry->d_name, L".") == 0) {
+			/* Directory itself */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 1);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 1);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 1);
+#endif
+			found += 1;
+		} else if (wcscmp(entry->d_name, L"..") == 0) {
+			/* Parent directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 2);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 2);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 2);
+#endif
+			found += 2;
+		} else if (wcscmp(entry->d_name, L"file") == 0) {
+			/* Regular file */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_REG);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 4);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 4);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 4);
+#endif
+			found += 4;
+		} else if (wcscmp(entry->d_name, L"dir") == 0) {
+			/* Just a directory */
+#ifdef _DIRENT_HAVE_D_TYPE
+			assert(entry->d_type == DT_DIR);
+#endif
+#ifdef _DIRENT_HAVE_D_NAMLEN
+			assert(entry->d_namlen == 3);
+#endif
+#ifdef _D_EXACT_NAMLEN
+			assert(_D_EXACT_NAMLEN(entry) == 3);
+#endif
+#ifdef _D_ALLOC_NAMLEN
+			assert(_D_ALLOC_NAMLEN(entry) > 3);
+#endif
+			found += 8;
+		} else {
+			/* Other file */
+			fprintf(stderr, "Unexpected file\n");
+			abort();
+		}
+	}
+
+	/* Make sure that all files were found */
+	assert(found == 0xf);
+
+	_wclosedir(dir);
+#endif
+}
diff --git a/dirent/tests/t-scandir.c b/dirent/tests/t-scandir.c
new file mode 100644
index 0000000..c463f9b
--- /dev/null
+++ b/dirent/tests/t-scandir.c
@@ -0,0 +1,276 @@
+/*
+ * Make sure that scandir function works OK.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+
+/* Silence warning about fopen being insecure (MS Visual Studio) */
+#define _CRT_SECURE_NO_WARNINGS
+
+/* Include prototype for versionsort (Linux) */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <time.h>
+#include <limits.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Filter and sort functions */
+static int only_readme(const struct dirent *entry);
+static int no_directories(const struct dirent *entry);
+static int reverse_alpha(const struct dirent **a, const struct dirent **b);
+
+int
+main(int argc, char *argv[])
+{
+	struct dirent **files;
+	int i;
+	int n;
+
+	(void) argc;
+	(void) argv;
+
+	/* Initialize random number generator */
+	srand((unsigned) time(NULL));
+
+	/* Basic scan with simple filter function */
+	{
+		/* Read directory entries */
+		n = scandir("tests/3", &files, only_readme, alphasort);
+		assert(n == 1);
+
+		/* Make sure that the filter works */
+		assert(strcmp(files[0]->d_name, "README.txt") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Basic scan with default sorting function */
+	{
+		/* Read directory entries in alphabetic order */
+		n = scandir("tests/3", &files, NULL, alphasort);
+		assert(n == 13);
+
+		/* Make sure that we got all the names in the proper order */
+		assert(strcmp(files[0]->d_name, ".") == 0);
+		assert(strcmp(files[1]->d_name, "..") == 0);
+		assert(strcmp(files[2]->d_name, "3zero.dat") == 0);
+		assert(strcmp(files[3]->d_name, "666.dat") == 0);
+		assert(strcmp(files[4]->d_name, "Qwerty-my-aunt.dat") == 0);
+		assert(strcmp(files[5]->d_name, "README.txt") == 0);
+		assert(strcmp(files[6]->d_name, "aaa.dat") == 0);
+		assert(strcmp(files[7]->d_name, "dirent.dat") == 0);
+		assert(strcmp(files[8]->d_name, "empty.dat") == 0);
+		assert(strcmp(files[9]->d_name, "sane-1.12.0.dat") == 0);
+		assert(strcmp(files[10]->d_name, "sane-1.2.30.dat") == 0);
+		assert(strcmp(files[11]->d_name, "sane-1.2.4.dat") == 0);
+		assert(strcmp(files[12]->d_name, "zebra.dat") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Custom filter AND sort function */
+	{
+		/* Read directory entries in alphabetic order */
+		n = scandir("tests/3", &files, no_directories, reverse_alpha);
+		assert(n == 11);
+
+		/* Make sure that we got file names in the reverse order */
+		assert(strcmp(files[0]->d_name, "zebra.dat") == 0);
+		assert(strcmp(files[1]->d_name, "sane-1.2.4.dat") == 0);
+		assert(strcmp(files[2]->d_name, "sane-1.2.30.dat") == 0);
+		assert(strcmp(files[3]->d_name, "sane-1.12.0.dat") == 0);
+		assert(strcmp(files[4]->d_name, "empty.dat") == 0);
+		assert(strcmp(files[5]->d_name, "dirent.dat") == 0);
+		assert(strcmp(files[6]->d_name, "aaa.dat") == 0);
+		assert(strcmp(files[7]->d_name, "README.txt") == 0);
+		assert(strcmp(files[8]->d_name, "Qwerty-my-aunt.dat") == 0);
+		assert(strcmp(files[9]->d_name, "666.dat") == 0);
+		assert(strcmp(files[10]->d_name, "3zero.dat") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Trying to read from non-existent directory leads to an error */
+	{
+		files = NULL;
+		n = scandir("tests/invalid", &files, NULL, alphasort);
+		assert(n == -1);
+		assert(files == NULL);
+		assert(errno == ENOENT);
+	}
+
+	/* Trying to open file as a directory produces ENOTDIR error */
+	{
+		files = NULL;
+		n = scandir("tests/3/666.dat", &files, NULL, alphasort);
+		assert(n == -1);
+		assert(files == NULL);
+		assert(errno == ENOTDIR);
+	}
+
+	/* Sort files using versionsort() */
+	{
+		files = NULL;
+		n = scandir("tests/3", &files, no_directories, versionsort);
+		assert(n == 11);
+
+		/*
+		 * Make sure that we got all the file names in the proper order:
+		 * 1.2.4 < 1.2.30 < 1.12.0
+		 */
+		assert(strcmp(files[0]->d_name, "3zero.dat") == 0);
+		assert(strcmp(files[1]->d_name, "666.dat") == 0);
+		assert(strcmp(files[2]->d_name, "Qwerty-my-aunt.dat") == 0);
+		assert(strcmp(files[3]->d_name, "README.txt") == 0);
+		assert(strcmp(files[4]->d_name, "aaa.dat") == 0);
+		assert(strcmp(files[5]->d_name, "dirent.dat") == 0);
+		assert(strcmp(files[6]->d_name, "empty.dat") == 0);
+		assert(strcmp(files[7]->d_name, "sane-1.2.4.dat") == 0);
+		assert(strcmp(files[8]->d_name, "sane-1.2.30.dat") == 0);
+		assert(strcmp(files[9]->d_name, "sane-1.12.0.dat") == 0);
+		assert(strcmp(files[10]->d_name, "zebra.dat") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Scan large directory */
+	{
+		char dirname[PATH_MAX+1];
+		int i;
+		int ok;
+
+		/* Copy name of temporary directory to variable dirname */
+#ifdef WIN32
+		i = GetTempPathA(PATH_MAX, dirname);
+		assert(i > 0);
+#else
+		strcpy(dirname, "/tmp/");
+		i = strlen(dirname);
+#endif
+
+		/* Append random characters to dirname */
+		for (int j = 0; j < 10; j++) {
+			char c;
+
+			/* Generate random character */
+			c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26];
+
+			/* Append character to dirname */
+			assert(i < PATH_MAX);
+			dirname[i++] = c;
+		}
+
+		/* Terminate directory name */
+		assert(i < PATH_MAX);
+		dirname[i] = '\0';
+
+		/* Create directory */
+#ifdef WIN32
+		ok = CreateDirectoryA(dirname, NULL);
+		assert(ok);
+#else
+		ok = mkdir(dirname, 0700);
+		assert(ok == /*success*/0);
+#endif
+
+		/* Create one thousand files */
+		assert(i + 5 < PATH_MAX);
+		for (int j = 0; j < 1000; j++) {
+			FILE *fp;
+
+			/* Construct file name */
+			dirname[i] = '/';
+			dirname[i+1] = 'z';
+			dirname[i+2] = '0' + ((j / 100) % 10);
+			dirname[i+3] = '0' + ((j / 10) % 10);
+			dirname[i+4] = '0' + (j % 10);
+			dirname[i+5] = '\0';
+
+			/* Create file */
+			fp = fopen(dirname, "w");
+			assert(fp != NULL);
+			fclose(fp);
+
+		}
+
+		/* Cut out the file name part */
+		dirname[i] = '\0';
+
+		/* Scan directory */
+		n = scandir(dirname, &files, no_directories, alphasort);
+		assert(n == 1000);
+
+		/* Make sure that all 1000 files are read back */
+		for (int j = 0; j < n; j++) {
+			char match[100];
+
+			/* Construct file name */
+			match[0] = 'z';
+			match[1] = '0' + ((j / 100) % 10);
+			match[2] = '0' + ((j / 10) % 10);
+			match[3] = '0' + (j % 10);
+			match[4] = '\0';
+
+			/* Make sure that file name matches that on the disk */
+			assert(strcmp(files[j]->d_name, match) == 0);
+
+		}
+
+		/* Release file names */
+		for (int j = 0; j < n; j++) {
+			free(files[j]);
+		}
+		free(files);
+	}
+
+	printf("OK\n");
+	return EXIT_SUCCESS;
+}
+
+/* Only pass README.txt file */
+static int
+only_readme(const struct dirent *entry)
+{
+	return strcmp(entry->d_name, "README.txt") == 0;
+}
+
+/* Filter out directories */
+static int
+no_directories(const struct dirent *entry)
+{
+	return entry->d_type != DT_DIR;
+}
+
+/* Sort in reverse direction */
+static int
+reverse_alpha(const struct dirent **a, const struct dirent **b)
+{
+	return strcoll((*b)->d_name, (*a)->d_name);
+}
diff --git a/dirent/tests/t-strverscmp.c b/dirent/tests/t-strverscmp.c
new file mode 100644
index 0000000..fcb044f
--- /dev/null
+++ b/dirent/tests/t-strverscmp.c
@@ -0,0 +1,206 @@
+/*
+ * Test program to make sure that strverscmp works correctly
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+
+/* Include prototype for strverscmp */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <dirent.h>
+#include <ctype.h>
+
+int
+main(
+	int argc, char *argv[])
+{
+	(void) argc;
+	(void) argv;
+
+	/* Strings without digits are compared as in strcmp() */
+	assert(strverscmp("", "") == 0);
+	assert(strverscmp("abc", "abc") == 0);
+	assert(strverscmp("a", "b") < 0);
+	assert(strverscmp("b", "a") > 0);
+
+	/* Shorter string is smaller, other things being equal */
+	assert(strverscmp("a", "aa") < 0);
+	assert(strverscmp("aa", "a") > 0);
+	assert(strverscmp("abcdef", "abcdefg") < 0);
+	assert(strverscmp("abcdefg", "abcdef") > 0);
+
+	/* Integers with equal length are compared as in strcmp() */
+	assert(strverscmp("0", "0") == 0);
+	assert(strverscmp("000", "000") == 0);
+	assert(strverscmp("1", "2") < 0);
+	assert(strverscmp("2", "1") > 0);
+	assert(strverscmp("001", "100") < 0);
+	assert(strverscmp("100", "001") > 0);
+	assert(strverscmp("2020-07-01", "2020-07-02") < 0);
+	assert(strverscmp("2020-07-02", "2020-07-01") > 0);
+	assert(strverscmp("jan999", "jan999") == 0);
+
+	/* Integers of different length are compared as numbers */
+	assert(strverscmp("jan9", "jan10") < 0);
+	assert(strverscmp("jan10", "jan9") > 0);
+	assert(strverscmp("999", "1000") < 0);
+	assert(strverscmp("1000", "999") > 0);
+	assert(strverscmp("t12-1000", "t12-9999") < 0);
+	assert(strverscmp("t12-9999", "t12-1000") > 0);
+	assert(strverscmp("1000", "10001") < 0);
+	assert(strverscmp("10001", "1000") > 0);
+	assert(strverscmp("1000!", "10001") < 0);
+	assert(strverscmp("10001", "1000!") > 0);
+	assert(strverscmp("1000Z", "10001") < 0);
+	assert(strverscmp("10001", "1000Z") > 0);
+
+	/* If numbers starts with zero, then longer number is smaller */
+	assert(strverscmp("00", "0") < 0);
+	assert(strverscmp("0", "00") > 0);
+	assert(strverscmp("a000", "a00") < 0);
+	assert(strverscmp("a00", "a000") > 0);
+	assert(strverscmp("0000", "000") < 0);
+	assert(strverscmp("000", "0000") > 0);
+	assert(strverscmp("0000", "000!") < 0);
+	assert(strverscmp("000!", "0000") > 0);
+	assert(strverscmp("0000", "000Z") < 0);
+	assert(strverscmp("000Z", "0000") > 0);
+	assert(strverscmp("0000", "000Z") < 0);
+	assert(strverscmp("000Z", "0000") > 0);
+	assert(strverscmp("1.01", "1.0") < 0);
+	assert(strverscmp("1.0", "1.01") > 0);
+	assert(strverscmp("1.01", "1.0!") < 0);
+	assert(strverscmp("1.0!", "1.01") > 0);
+	assert(strverscmp("1.01", "1.0~") < 0);
+	assert(strverscmp("1.0~", "1.01") > 0);
+
+	/* Number having more leading zeros is considered smaller */
+	assert(strverscmp("item-0001", "item-001") < 0);
+	assert(strverscmp("item-001", "item-0001") > 0);
+	assert(strverscmp("item-001", "item-01") < 0);
+	assert(strverscmp("item-01", "item-001") > 0);
+	assert(strverscmp(".0001000", ".001") < 0);
+	assert(strverscmp(".001", ".0001000") > 0);
+	assert(strverscmp(".0001000", ".01") < 0);
+	assert(strverscmp(".01", ".0001000") > 0);
+	assert(strverscmp(".0001000", ".1") < 0);
+	assert(strverscmp(".1", ".0001000") > 0);
+	assert(strverscmp("1.0002", "1.0010000") < 0);
+	assert(strverscmp("1.0010000", "1.0002") > 0);
+
+	/* Number starting with zero is smaller than any number */
+	assert(strverscmp("item-009", "item-1") < 0);
+	assert(strverscmp("item-1", "item-009") > 0);
+	assert(strverscmp("item-099", "item-2") < 0);
+	assert(strverscmp("item-2", "item-099") > 0);
+
+	/* Number vs alphabetical comparison */
+	assert(strverscmp("1.001", "1.00!") < 0);
+	assert(strverscmp("1.00!", "1.001") > 0);
+	assert(strverscmp("1.001", "1.00x") < 0);
+	assert(strverscmp("1.00x", "1.001") > 0);
+	assert(strverscmp("1", "x") < 0);
+	assert(strverscmp("x", "1") > 0);
+	assert(strverscmp("1", "!") > 0);
+	assert(strverscmp("!", "1") < 0);
+
+	/* Handling the end of string */
+	assert(strverscmp("01", "011") < 0);
+	assert(strverscmp("011", "01") > 0);
+	assert(strverscmp("0100", "01000") < 0);
+	assert(strverscmp("01000", "0100") > 0);
+	assert(strverscmp("1", "1!") < 0);
+	assert(strverscmp("1!", "1") > 0);
+	assert(strverscmp("1", "1z") < 0);
+	assert(strverscmp("1z", "1") > 0);
+
+	/* Ordering 000 < 00 < 01 < 010 < 09 < 0 < 1 < 9 < 10 */
+	assert(strverscmp("000", "00") < 0);
+	assert(strverscmp("000", "01") < 0);
+	assert(strverscmp("000", "010") < 0);
+	assert(strverscmp("000", "09") < 0);
+	assert(strverscmp("000", "0") < 0);
+	assert(strverscmp("000", "1") < 0);
+	assert(strverscmp("000", "9") < 0);
+	assert(strverscmp("000", "10") < 0);
+
+	assert(strverscmp("00", "01") < 0);
+	assert(strverscmp("00", "010") < 0);
+	assert(strverscmp("00", "09") < 0);
+	assert(strverscmp("00", "0") < 0);
+	assert(strverscmp("00", "1") < 0);
+	assert(strverscmp("00", "9") < 0);
+	assert(strverscmp("00", "10") < 0);
+
+	assert(strverscmp("01", "010") < 0);
+	assert(strverscmp("01", "09") < 0);
+	assert(strverscmp("01", "0") < 0);
+	assert(strverscmp("01", "1") < 0);
+	assert(strverscmp("01", "9") < 0);
+	assert(strverscmp("01", "10") < 0);
+
+	assert(strverscmp("010", "09") < 0);
+	assert(strverscmp("010", "0") < 0);
+	assert(strverscmp("010", "1") < 0);
+	assert(strverscmp("010", "9") < 0);
+	assert(strverscmp("010", "10") < 0);
+
+	assert(strverscmp("09", "0") < 0);
+	assert(strverscmp("09", "1") < 0);
+	assert(strverscmp("09", "9") < 0);
+	assert(strverscmp("09", "10") < 0);
+
+	assert(strverscmp("0", "1") < 0);
+	assert(strverscmp("0", "9") < 0);
+	assert(strverscmp("0", "10") < 0);
+
+	assert(strverscmp("1", "9") < 0);
+	assert(strverscmp("1", "10") < 0);
+
+	assert(strverscmp("9", "10") < 0);
+
+	/* Compare speed */
+	{
+#define LENGTH 100
+#define REPEAT 1000000
+		char a[LENGTH+1];
+		char b[LENGTH+1];
+		size_t i;
+		size_t j;
+		char letters[] = "01234567890123456789abdefghjkpqrtwxyz-/.";
+		size_t n = strlen(letters);
+
+		/* Repeat test */
+		for(i = 0; i < REPEAT; i++) {
+			int diff1;
+			int diff2;
+
+			/* Generate two random strings of LENGTH characters */
+			for(j = 0; j < LENGTH; j++) {
+				a[j] = letters[rand() % n];
+				b[j] = letters[rand() % n];
+			}
+			a[j] = '\0';
+			b[j] = '\0';
+
+			/* Compare strings in both directions */
+			diff1 = strverscmp(a, b);
+			diff2 = strverscmp(b, a);
+
+			/* Must give identical result in both directions */
+			assert((diff1 < 0 && diff2 > 0)
+				|| (diff1 == 0 && diff2 == 0)
+				|| (diff1 > 0 && diff2 < 0));
+		}
+	}
+
+	printf("OK\n");
+	return EXIT_SUCCESS;
+}
diff --git a/dirent/tests/t-telldir.c b/dirent/tests/t-telldir.c
new file mode 100644
index 0000000..e2a1763
--- /dev/null
+++ b/dirent/tests/t-telldir.c
@@ -0,0 +1,165 @@
+/*
+ * A test program to make sure that dirent works correctly.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+
+/* Silence warning about strcmp being insecure (MS Visual Studio) */
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+static void test_telldir(void);
+
+int
+main(int argc, char *argv[])
+{
+	(void) argc;
+	(void) argv;
+
+	test_telldir();
+
+	return EXIT_SUCCESS;
+}
+
+static void
+test_telldir(void)
+{
+	DIR *dir = opendir("tests/4");
+	if (dir == NULL) {
+		fprintf(stderr, "Directory tests/4 not found\n");
+		abort();
+	}
+
+	/* Get position of first file */
+	long pos1 = telldir(dir);
+	printf("pos1: %lx\n", (long) pos1);
+	assert(pos1 >= 0);
+
+	/* Read first file */
+	struct dirent *ent = readdir(dir);
+	assert(ent != NULL);
+	struct dirent ent1 = *ent;
+	printf("ent1: %s %lx\n", ent->d_name, (long) ent->d_off);
+
+	/* Seek back to the first position */
+	seekdir(dir, pos1);
+
+	/* Re-read the first entry */
+	ent = readdir(dir);
+	assert(ent != NULL);
+	assert(strcmp(ent->d_name, ent1.d_name) == 0);
+
+	/* Get position to second file */
+	long pos2 = telldir(dir);
+	printf("pos2: %lx\n", (long) pos2);
+	assert(pos2 >= 0);
+
+	/* Read second file */
+	ent = readdir(dir);
+	assert(ent != NULL);
+	struct dirent ent2 = *ent;
+	printf("ent2: %s %lx\n", ent->d_name, (long) ent->d_off);
+
+	/* Get position to third file */
+	long pos3 = telldir(dir);
+	printf("pos3: %lx\n", (long) pos3);
+	assert(pos3 >= 0);
+
+	/* Read third file */
+	ent = readdir(dir);
+	assert(ent != NULL);
+	struct dirent ent3 = *ent;
+	printf("ent3: %s %lx\n", ent->d_name, (long) ent->d_off);
+
+	/* Get position to fourth file */
+	long pos4 = telldir(dir);
+	printf("pos4: %lx\n", (long) pos4);
+	assert(pos4 >= 0);
+
+	/* Read fourth file */
+	ent = readdir(dir);
+	assert(ent != NULL);
+	struct dirent ent4 = *ent;
+	printf("ent4: %s %lx\n", ent->d_name, (long) ent->d_off);
+
+	/* Get position to fifth file */
+	long pos5 = telldir(dir);
+	printf("pos5: %lx\n", (long) pos5);
+	assert(pos5 >= 0);
+
+	/* Read fifth file */
+	ent = readdir(dir);
+	assert(ent != NULL);
+	struct dirent ent5 = *ent;
+	printf("ent5: %s %lx\n", ent->d_name, (long) ent->d_off);
+
+	/* Read position at the end of directory stream */
+	long posx = telldir(dir);
+	assert(posx >= 0);
+	printf("posx: %lx\n", (long) posx);
+
+	/* End of directory stream has been reached */
+	ent = readdir(dir);
+	assert(ent == NULL);
+
+	/* Seek back to position just before the end of stream */
+	seekdir(dir, posx);
+
+	/* Function telldir returns the same position when asked again */
+	assert(telldir(dir) == posx);
+	assert(telldir(dir) == posx);
+	assert(telldir(dir) == posx);
+
+	/* Read end of stream again */
+	ent = readdir(dir);
+	assert(ent == NULL);
+
+	/* Seek back to fifth file and read it again */
+	seekdir(dir, pos5);
+	assert(telldir(dir) == pos5);
+	ent = readdir(dir);
+	assert(ent != NULL);
+	assert(strcmp(ent->d_name, ent5.d_name) == 0);
+
+	/* Seek back to second file and read it again */
+	seekdir(dir, pos2);
+	assert(telldir(dir) == pos2);
+	ent = readdir(dir);
+	assert(ent != NULL);
+	assert(strcmp(ent->d_name, ent2.d_name) == 0);
+
+	/* Continue reading from the third file without a seek in between */
+	assert(telldir(dir) == pos3);
+	ent = readdir(dir);
+	assert(ent != NULL);
+	assert(strcmp(ent->d_name, ent3.d_name) == 0);
+
+	/* Read fourth position again */
+	assert(telldir(dir) == pos4);
+	ent = readdir(dir);
+	assert(ent != NULL);
+	assert(strcmp(ent->d_name, ent4.d_name) == 0);
+
+	/* Read fifth position again */
+	assert(telldir(dir) == pos5);
+	ent = readdir(dir);
+	assert(ent != NULL);
+	assert(strcmp(ent->d_name, ent5.d_name) == 0);
+
+	/* Read end of stream again */
+	assert(telldir(dir) == posx);
+	ent = readdir(dir);
+	assert(ent == NULL);
+}
+
diff --git a/dirent/tests/t-unicode.c b/dirent/tests/t-unicode.c
new file mode 100644
index 0000000..8239120
--- /dev/null
+++ b/dirent/tests/t-unicode.c
@@ -0,0 +1,381 @@
+/*
+ * Test program to try unicode file names.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+
+/* Silence warning about fopen being insecure */
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <time.h>
+#include <locale.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+int
+main(int argc, char *argv[])
+{
+#ifdef WIN32
+	wchar_t wpath[MAX_PATH+1];
+	char path[MAX_PATH+1];
+	DWORD i, j, k, x;
+	BOOL ok;
+	HANDLE fh;
+	_WDIR *wdir;
+	struct _wdirent *wentry;
+	DIR *dir;
+	struct dirent *entry;
+	char buffer[100];
+	FILE *fp;
+	int counter = 0;
+
+	/* Initialize random number generator */
+	srand(((int) time(NULL)) * 257 + ((int) GetCurrentProcessId()));
+
+	/* Set current locale */
+	if (argc > 1) {
+		printf("Locale %s\n", argv[1]);
+		setlocale(LC_ALL, argv[1]);
+	} else {
+		setlocale(LC_ALL, "");
+	}
+
+	/****** CREATE FILE WITH UNICODE FILE NAME ******/
+
+	/* Get path to temporary directory (wide-character and ascii) */
+	i = GetTempPathW(MAX_PATH, wpath);
+	assert(i > 0);
+	j = GetTempPathA(MAX_PATH, path);
+	assert(j > 0);
+
+	/* Append random directory name */
+	for (k = 0; k < 10; k++) {
+		/* Generate random character */
+		char c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26];
+
+		/* Append character to paths */
+		assert(i < MAX_PATH  &&  j < MAX_PATH);
+		wpath[i++] = c;
+		path[j++] = c;
+	}
+
+	/* Terminate paths */
+	assert(i < MAX_PATH  &&  j < MAX_PATH);
+	wpath[i] = '\0';
+	path[j] = '\0';
+
+	/* Remember the end of directory name */
+	k = i;
+
+	/* Create directory using unicode */
+	ok = CreateDirectoryW(wpath, NULL);
+	if (!ok) {
+		DWORD e = GetLastError();
+		wprintf(L"Cannot create directory %ls (code %u)\n", wpath, e);
+		abort();
+	}
+
+	/* Overwrite zero terminator with path separator */
+	assert(i < MAX_PATH  &&  j < MAX_PATH);
+	wpath[i++] = '\\';
+
+	/* Append a few unicode characters */
+	assert(i < MAX_PATH);
+	wpath[i++] = 0x6d4b;
+	assert(i < MAX_PATH);
+	wpath[i++] = 0x8bd5;
+
+	/* Terminate string */
+	assert(i < MAX_PATH);
+	wpath[i] = '\0';
+
+	/* Create file with unicode */
+	fh = CreateFileW(
+		wpath,
+		/* Access */ GENERIC_READ | GENERIC_WRITE,
+		/* Share mode */ 0,
+		/* Security attributes */ NULL,
+		/* Creation disposition */ CREATE_NEW,
+		/* Attributes */ FILE_ATTRIBUTE_NORMAL,
+		/* Template files */ NULL
+		);
+	assert(fh != INVALID_HANDLE_VALUE);
+
+	/* Write some data to file */
+	ok = WriteFile(
+		/* File handle */ fh,
+		/* Pointer to data */ "hep\n",
+		/* Number of bytes to write */ 4,
+		/* Number of bytes written */ NULL,
+		/* Overlapped */ NULL
+		);
+	assert(ok);
+
+	/* Close file */
+	ok = CloseHandle(fh);
+	assert(ok);
+
+	/****** MAKE SURE THAT UNICODE FILE CAN BE READ BY _WREADDIR ******/
+
+	/* Zero terminate wide-character path and open directory stream */
+	wpath[k] = '\0';
+	wdir = _wopendir(wpath);
+	if (wdir == NULL) {
+		wprintf(L"Cannot open directory %ls\n", wpath);
+		abort();
+	}
+
+	/* Read through entries */
+	counter = 0;
+	while ((wentry = _wreaddir(wdir)) != NULL) {
+		/* Skip pseudo directories */
+		if (wcscmp(wentry->d_name, L".") == 0) {
+			continue;
+		}
+		if (wcscmp(wentry->d_name, L"..") == 0) {
+			continue;
+		}
+
+		/* Found a file */
+		counter++;
+		assert(wentry->d_type == DT_REG);
+
+		/* Append file name to path */
+		i = k;
+		assert(i < MAX_PATH);
+		wpath[i++] = '\\';
+		x = 0;
+		while (wentry->d_name[x] != '\0') {
+			assert(i < MAX_PATH);
+			wpath[i++] = wentry->d_name[x++];
+		}
+		assert(i < MAX_PATH);
+		wpath[i] = '\0';
+
+		/* Open file for read */
+		fh = CreateFileW(
+			wpath,
+			/* Access */ GENERIC_READ,
+			/* Share mode */ 0,
+			/* Security attributes */ NULL,
+			/* Creation disposition */ OPEN_EXISTING,
+			/* Attributes */ FILE_ATTRIBUTE_NORMAL,
+			/* Template files */ NULL
+			);
+		assert(fh != INVALID_HANDLE_VALUE);
+
+		/* Read data from file */
+		ok = ReadFile(
+			/* File handle */ fh,
+			/* Output buffer */ buffer,
+			/* Max number of bytes to read */ sizeof(buffer) - 1,
+			/* Number of bytes actually read */ &x,
+			/* Overlapped */ NULL
+		);
+		assert(ok);
+
+		/* Make sure that we got the file contents right */
+		assert(x == 4);
+		assert(buffer[0] == 'h');
+		assert(buffer[1] == 'e');
+		assert(buffer[2] == 'p');
+		assert(buffer[3] == '\n');
+
+		/* Close file */
+		ok = CloseHandle(fh);
+		assert(ok);
+	}
+	assert(counter == 1);
+
+	/* Close directory */
+	_wclosedir(wdir);
+
+	/****** MAKE SURE THAT UNICODE FILE NAME CAN BE READ BY READDIR *****/
+
+	/* Zero terminate ascii path and open directory stream */
+	k = j;
+	path[k] = '\0';
+	dir = opendir(path);
+	if (dir == NULL) {
+		fprintf(stderr, "Cannot open directory %s\n", path);
+		abort();
+	}
+
+	/* Read through entries */
+	counter = 0;
+	while ((entry = readdir(dir)) != NULL) {
+		/* Skip pseudo directories */
+		if (strcmp(entry->d_name, ".") == 0) {
+			continue;
+		}
+		if (strcmp(entry->d_name, "..") == 0) {
+			continue;
+		}
+
+		/* Found a file */
+		counter++;
+		assert(entry->d_type == DT_REG);
+
+		/* Append file name to path */
+		j = k;
+		assert(j < MAX_PATH);
+		path[j++] = '\\';
+		x = 0;
+		while (entry->d_name[x] != '\0') {
+			assert(j < MAX_PATH);
+			path[j++] = entry->d_name[x++];
+		}
+		assert(j < MAX_PATH);
+		path[j] = '\0';
+
+		/* Open file for read */
+		fp = fopen(path, "r");
+		if (!fp) {
+			fprintf(stderr, "Cannot open file %s\n", path);
+			abort();
+		}
+
+		/* Read data from file */
+		if (fgets(buffer, sizeof(buffer), fp) == NULL) {
+			fprintf(stderr, "Cannot read file %s\n", path);
+			abort();
+		}
+
+		/* Make sure that we got the file contents right */
+		assert(buffer[0] == 'h');
+		assert(buffer[1] == 'e');
+		assert(buffer[2] == 'p');
+		assert(buffer[3] == '\n');
+		assert(buffer[4] == '\0');
+
+		/* Close file */
+		fclose(fp);
+	}
+	assert(counter == 1);
+
+	/* Close directory */
+	closedir(dir);
+
+	/****** CREATE FILE WITH UTF-8 ******/
+
+	/* Append UTF-8 file name (åäö.txt) to path */
+	j = k;
+	path[j++] = '\\';
+	path[j++] = 0xc3;
+	path[j++] = 0xa5;
+	path[j++] = 0xc3;
+	path[j++] = 0xa4;
+	path[j++] = 0xc3;
+	path[j++] = 0xb6;
+	path[j++] = 0x2e;
+	path[j++] = 0x74;
+	path[j++] = 0x78;
+	path[j++] = 0x74;
+	assert(j < MAX_PATH);
+	path[j] = '\0';
+
+	/*
+	 * Create file.
+	 *
+	 * Be ware that the code below creates a different file depending on
+	 * the current locale!  For example, if the current locale is
+	 * english_us.65001, then the file name will be "åäö.txt" (7
+	 * characters).  However, if the current locale is english_us.1252,
+	 * then the file name will be "ÃċÃĊö.txt" (10 characters).
+	 */
+	printf("Creating %s\n", path);
+	fp = fopen(path, "w");
+	if (!fp) {
+		fprintf(stderr, "Cannot open file %s\n", path);
+		abort();
+	}
+	fputs("hep\n", fp);
+	fclose(fp);
+
+	/* Open directory again */
+	path[k] = '\0';
+	dir = opendir(path);
+	if (dir == NULL) {
+		fprintf(stderr, "Cannot open directory %s\n", path);
+		abort();
+	}
+
+	/* Read through entries */
+	counter = 0;
+	while ((entry = readdir(dir)) != NULL) {
+		/* Skip pseudo directories */
+		if (strcmp(entry->d_name, ".") == 0) {
+			continue;
+		}
+		if (strcmp(entry->d_name, "..") == 0) {
+			continue;
+		}
+
+		/* Found a file */
+		counter++;
+		assert(entry->d_type == DT_REG);
+
+		/* Append file name to path */
+		j = k;
+		assert(j < MAX_PATH);
+		path[j++] = '\\';
+		x = 0;
+		while (entry->d_name[x] != '\0') {
+			assert(j < MAX_PATH);
+			path[j++] = entry->d_name[x++];
+		}
+		assert(j < MAX_PATH);
+		path[j] = '\0';
+
+		/* Print file name for debugging */
+		printf("Opening \"%s\" hex ", path + k + 1);
+		x = 0;
+		while (entry->d_name[x] != '\0') {
+			printf("0x%02x ",
+				(unsigned) (entry->d_name[x++] & 0xff));
+		}
+		printf("\n");
+
+		/* Open file for read */
+		fp = fopen(path, "r");
+		if (!fp) {
+			fprintf(stderr, "Cannot open file %s\n", path);
+			abort();
+		}
+
+		/* Read data from file */
+		if (fgets(buffer, sizeof(buffer), fp) == NULL) {
+			fprintf(stderr, "Cannot read file %s\n", path);
+			abort();
+		}
+
+		/* Make sure that we got the file contents right */
+		assert(buffer[0] == 'h');
+		assert(buffer[1] == 'e');
+		assert(buffer[2] == 'p');
+		assert(buffer[3] == '\n');
+		assert(buffer[4] == '\0');
+
+		/* Close file */
+		fclose(fp);
+	}
+	assert(counter == 2);
+
+	/* Close directory */
+	closedir(dir);
+#else
+	/* Linux */
+	(void) argc;
+	(void) argv;
+#endif
+	return EXIT_SUCCESS;
+}
diff --git a/dirent/tests/t-utf8.c b/dirent/tests/t-utf8.c
new file mode 100644
index 0000000..fdc31fa
--- /dev/null
+++ b/dirent/tests/t-utf8.c
@@ -0,0 +1,238 @@
+/*
+ * Test program to try UTF-8 file names.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+
+/* Silence warning about fopen being insecure */
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <time.h>
+#include <locale.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+int
+main(int argc, char *argv[])
+{
+#ifdef WIN32
+	/*
+	 * Select UTF-8 locale.  This will change the way how C runtime
+	 * functions such as fopen() and mkdir() handle character strings.
+	 * For more information, please see:
+	 * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?view=msvc-160#utf-8-support
+	 */
+	setlocale(LC_ALL, "LC_CTYPE=.utf8");
+
+	/* Initialize random number generator */
+	srand(((int) time(NULL)) * 257 + ((int) GetCurrentProcessId()));
+
+	/* Get path to temporary directory */
+	wchar_t wpath[MAX_PATH+1];
+	DWORD i = GetTempPathW(MAX_PATH, wpath);
+	assert(i > 0);
+
+	/* Ensure that path name ends in directory separator */
+	assert(wpath[i - 1] == '\\');
+
+	/* Append random prefix */
+	DWORD k;
+	for (k = 0; k < 8; k++) {
+		/* Generate random character */
+		char c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26];
+
+		/* Append character to path */
+		assert(i < MAX_PATH);
+		wpath[i++] = c;
+	}
+
+	/* Append a wide character to the path name */
+	wpath[i++] = 0x00c4;
+
+	/* Terminate the path name */
+	assert(i < MAX_PATH);
+	wpath[i] = '\0';
+
+	/* Create directory with unicode name */
+	BOOL ok = CreateDirectoryW(wpath, NULL);
+	if (!ok) {
+		DWORD e = GetLastError();
+		wprintf(L"Cannot create directory %ls (code %u)\n", wpath, e);
+		abort();
+	}
+
+	/* Overwrite zero terminator with path separator */
+	assert(i < MAX_PATH);
+	wpath[i++] = '\\';
+
+	/* Append a few unicode characters */
+	assert(i < MAX_PATH);
+	wpath[i++] = 0x00f6;
+	assert(i < MAX_PATH);
+	wpath[i++] = 0x00e4;
+
+	/* Terminate string */
+	assert(i < MAX_PATH);
+	wpath[i] = '\0';
+
+	/* Create file with unicode name */
+	HANDLE fh = CreateFileW(
+		wpath,
+		/* Access */ GENERIC_READ | GENERIC_WRITE,
+		/* Share mode */ 0,
+		/* Security attributes */ NULL,
+		/* Creation disposition */ CREATE_NEW,
+		/* Attributes */ FILE_ATTRIBUTE_NORMAL,
+		/* Template files */ NULL
+		);
+	assert(fh != INVALID_HANDLE_VALUE);
+
+	/* Write some data to file */
+	ok = WriteFile(
+		/* File handle */ fh,
+		/* Pointer to data */ "hep\n",
+		/* Number of bytes to write */ 4,
+		/* Number of bytes written */ NULL,
+		/* Overlapped */ NULL
+		);
+	assert(ok);
+
+	/* Close file */
+	ok = CloseHandle(fh);
+	assert(ok);
+
+	/* Convert file name to UTF-8 */
+	char path[MAX_PATH+1];
+	int n = WideCharToMultiByte(
+		/* Code page to use in conversion */ CP_UTF8,
+		/* Flags */ 0,
+		/* Pointer to unicode string */ wpath,
+		/* Length of unicode string in characters */ i,
+		/* Pointer to output buffer */ path,
+		/* Size of output buffer in bytes */ MAX_PATH,
+		/* Pointer to default character */ NULL,
+		/* Pointer to boolean variable */ NULL
+	);
+	assert(n > 0);
+
+	/* Zero-terminate path */
+	path[(size_t) n] = '\0';
+
+	/* Make sure that fopen() can open the file with UTF-8 file name */
+	FILE *fp = fopen(path, "r");
+	if (!fp) {
+		fprintf(stderr, "Cannot open file %s\n", path);
+		abort();
+	}
+
+	/* Read data from file */
+	char buffer[100];
+	if (fgets(buffer, sizeof(buffer), fp) == NULL) {
+		fprintf(stderr, "Cannot read file %s\n", path);
+		abort();
+	}
+
+	/* Make sure that we got the file contents right */
+	assert(buffer[0] == 'h');
+	assert(buffer[1] == 'e');
+	assert(buffer[2] == 'p');
+	assert(buffer[3] == '\n');
+	assert(buffer[4] == '\0');
+
+	/* Close file */
+	fclose(fp);
+
+	/* Truncate path name to the last directory separator */
+	i = 0;
+	k = 0;
+	while (path[k] != '\0') {
+		if (path[k] == '\\' || path[k] == '/') {
+			i = k;
+		}
+		k++;
+	}
+	path[i] = '\0';
+
+	/* Ensure that opendir() can open the directory with UTF-8 name */
+	DIR *dir = opendir(path);
+	if (dir == NULL) {
+		fprintf(stderr, "Cannot open directory %s\n", path);
+		abort();
+	}
+
+	/* Read entries */
+	int counter = 0;
+	struct dirent *entry;
+	while ((entry = readdir(dir)) != NULL) {
+		/* Skip pseudo directories */
+		if (strcmp(entry->d_name, ".") == 0) {
+			continue;
+		}
+		if (strcmp(entry->d_name, "..") == 0) {
+			continue;
+		}
+
+		/* Found a file */
+		counter++;
+		assert(entry->d_type == DT_REG);
+
+		/* Append file name to path */
+		k = i;
+		assert(i < MAX_PATH);
+		path[i++] = '\\';
+		DWORD x = 0;
+		while (entry->d_name[x] != '\0') {
+			assert(i < MAX_PATH);
+			path[i++] = entry->d_name[x++];
+		}
+		assert(i < MAX_PATH);
+		path[i] = '\0';
+
+		/* Reset buffer */
+		for (x = 0; x < sizeof(buffer); x++) {
+			buffer[x] = '\0';
+		}
+
+		/* Open file for read */
+		fp = fopen(path, "r");
+		if (!fp) {
+			fprintf(stderr, "Cannot open file %s\n", path);
+			abort();
+		}
+
+		/* Read data from file */
+		if (fgets(buffer, sizeof(buffer), fp) == NULL) {
+			fprintf(stderr, "Cannot read file %s\n", path);
+			abort();
+		}
+
+		/* Make sure that we got the file contents right */
+		assert(buffer[0] == 'h');
+		assert(buffer[1] == 'e');
+		assert(buffer[2] == 'p');
+		assert(buffer[3] == '\n');
+		assert(buffer[4] == '\0');
+
+		/* Close file */
+		fclose(fp);
+	}
+	assert(counter == 1);
+
+	/* Close directory */
+	closedir(dir);
+#else
+	/* Linux */
+	(void) argc;
+	(void) argv;
+#endif
+	return EXIT_SUCCESS;
+}
diff --git a/getopt/.gitignore b/getopt/.gitignore
new file mode 100644
index 0000000..975acee
--- /dev/null
+++ b/getopt/.gitignore
@@ -0,0 +1,4 @@
+Win32/
+x64/
+.vs/
+*.user
\ No newline at end of file
diff --git a/getopt/LICENSE b/getopt/LICENSE
new file mode 100644
index 0000000..153d416
--- /dev/null
+++ b/getopt/LICENSE
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
\ No newline at end of file
diff --git a/getopt/README.md b/getopt/README.md
new file mode 100644
index 0000000..d294ae4
--- /dev/null
+++ b/getopt/README.md
@@ -0,0 +1,9 @@
+getopt port for Visual C++
+==========================
+
+[![Build status](https://ci.appveyor.com/api/projects/status/reb7dt6x7jdn1700/branch/master?svg=true)](https://ci.appveyor.com/project/qmfrederik/getopt/branch/master)
+
+This repository contains a port of getopt which can be used with Visual C++. It is intended to be used with vcpkg.
+
+The Visual C++ port was originally done by Ludvik Jerabek, and described in the [Full getopt Port for Unicode and Multibyte Microsoft Visual C, C++, or MFC Projects](https://www.codeproject.com/Articles/157001/Full-getopt-Port-for-Unicode-and-Multibyte-Microso/)
+article. This repository contains a copy of that code and the article.
\ No newline at end of file
diff --git a/getopt/appveyor.yml b/getopt/appveyor.yml
new file mode 100644
index 0000000..868a0b0
--- /dev/null
+++ b/getopt/appveyor.yml
@@ -0,0 +1,5 @@
+build_script:
+  - msbuild getopt.sln /p:Configuration=Debug /p:Platform=Win32 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+  - msbuild getopt.sln /p:Configuration=Debug /p:Platform=x64 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+  - msbuild getopt.sln /p:Configuration=Release /p:Platform=Win32 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
+  - msbuild getopt.sln /p:Configuration=Release /p:Platform=x64 /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
diff --git a/getopt/article.md b/getopt/article.md
new file mode 100644
index 0000000..68c2c0d
--- /dev/null
+++ b/getopt/article.md
@@ -0,0 +1,224 @@
+Full getopt Port for Unicode and Multibyte Microsoft Visual C, C++, or MFC Projects
+===================================================================================
+
+Ludvik Jerabek, 15 Oct 2012
+
+Originally published at https://www.codeproject.com/Articles/157001/Full-getopt-Port-for-Unicode-and-Multibyte-Microso/
+
+
+Introduction
+------------
+
+This software was written after hours of searching for a robust Microsoft C and C++ implementation of getopt,
+which led to devoid results.
+
+This software is a modification of the Free Software Foundation, Inc. getopt library for parsing command line arguments
+and its purpose is to provide a Microsoft Visual C friendly derivative. The source code provides functionality for both
+Unicode and Multibyte builds and supports `getopt`, `getopt_long`, and `getopt_long_only`. Additionally the code supports the
+`POSIXLY_CORRECT` environment flag. The library uses the `_UNICODE` preprocessor directive when defining the `getopt`, `getopt_long`,
+and `getopt_long_only` functions. These functions are mapped back to `getopt_a`\`getopt_w`, `getopt_long_a`\`getopt_long_w`, and
+`getopt_long_only_a`\`getopt_long_only_w` respectively. This improvement was made to allow a single DLL to be used in both
+multibyte and Unicode projects.
+
+The original GNU code used several header and implementation files containing numerous preprocessor directives specific
+to Linux environments which have been removed. After removing unneeded dependencies, it was condensed into a single
+header and implementation file which can be compiled into a DLL, LIB, or directly included into any Visual C, C++, or MFC
+project. The getopt library can be used by proprietary software, however; certain measures need to be taken to ensure
+proprietary code adheres to the Lesser GNU Public License for non-derivative works. Please refer to the licensing section
+of this article for more details on how this software is licensed.
+
+For the sake of brevity, this article doesn't discuss how to use the `getopt` functions. Anyone new to using the `getopt`
+functions should refer to the GNU tutorial for using getopt.
+
+Licensing
+---------
+
+Since `getopt` is licensed under LGPL, it is free to use in proprietary software under some restrictions.
+When using this library as part of a proprietary software solution, it is important that the library is used as
+a dynamically linked library (DLL) and is not statically linked or directly compiled into proprietary source code.
+Static linkage requires that your software be released GPL. Therefore, by keeping the library separately referenced
+via Dynamic Link Library (DLL), allows the DLL to be modified and updated without changing the proprietary software
+which utilizes the library; under this condition proprietary software is said to "use" the library. Thus, it is not
+considered to be a derivative work and can be distributed freely under any license.
+
+Preprocessor Definitions
+------------------------
+
+Compiling `getopt` as a Dynamic Link Library (DLL) requires the preprocessor definition of `EXPORTS_GETOPT`.
+The definition of `EXPORTS_GETOPT` sets the internal preprocessor definition `_GETOPT_API` to the value `__declspec(dllexport)`.
+Compiling getopt as a Static Library (LIB) or directly including the source and header file within a project requires the
+preprocessor definition of `STATIC_GETOPT`. The definition of `STATIC_GETOPT` clears the value of the internal preprocessor definition
+of `_GETOPT_API`. Compiling software to use _getopt.dll_ requires that no library specific preprocessor definitions be used.
+When no library specific preprocessor definitions are used the value assigned to the internal preprocessor definition `_GETOPT_API` is `__declspec(dllimport)`.
+
+The code segment below demonstrates the logic outlined above:
+
+```c
+#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
+    #error "The preprocessor definitions of EXPORTS_GETOPT 
+        and STATIC_GETOPT can only be used individually"
+#elif defined(STATIC_GETOPT)
+#pragma message("Warning static builds of getopt violate the Lesser GNU Public License")
+    #define _GETOPT_API
+#elif defined(EXPORTS_GETOPT)
+    #pragma message("Exporting getopt library")
+    #define _GETOPT_API __declspec(dllexport)    
+#else
+    #pragma message("Importing getopt library")
+    #define _GETOPT_API __declspec(dllimport)
+#endif
+```
+
+The following code segment located in _getopt.h_ is responsible for mapping the correct version of the `getopt`, `getopt_long`,
+and `getopt_long_only` functions. The `getopt` functions appended with `_a` to denote ANSI characters using the char type and
+Unicode functions are appended with `_w` to denote wide characters using the `wchar_t` type.
+
+```c
+#ifdef _UNICODE
+    #define getopt getopt_w
+    #define getopt_long getopt_long_w
+    #define getopt_long_only getopt_long_only_w
+    #define option option_w
+    #define optarg optarg_w
+#else
+    #define getopt getopt_a
+    #define getopt_long getopt_long_a
+    #define getopt_long_only getopt_long_only_a
+    #define option option_a
+    #define optarg optarg_a
+#endif
+```
+
+Using the Code
+---------------
+
+The code is used identical to GNU `getopt`.
+
+```c
+#include <stdio.h>
+#include <stdlib.h>
+#include "tchar.h"
+#include "getopt.h"
+
+int _tmain(int argc, TCHAR** argv)
+{
+    static int verbose_flag;
+    int c;
+
+    while (1)
+    {        
+        static struct option long_options[] =
+        {
+            {_T("verbose"), ARG_NONE, &verbose_flag, 1},
+            {_T("brief"),   ARG_NONE, &verbose_flag, 0},
+            {_T("add"),     ARG_NONE, 0, _T('a')},
+            {_T("append"),  ARG_NONE, 0, _T('b')},
+            {_T("delete"),  ARG_REQ,  0, _T('d')},
+            {_T("create"),  ARG_REQ,  0, _T('c')},
+            {_T("file"),    ARG_REQ, 0 , _T('f')},
+            { ARG_NULL , ARG_NULL , ARG_NULL , ARG_NULL }
+        };
+
+        int option_index = 0;
+        c = getopt_long(argc, argv, _T("abc:d:f:"), long_options, &option_index);
+
+        // Check for end of operation or error
+        if (c == -1)
+            break;
+
+        // Handle options
+        switch (c)
+        {
+        case 0:
+            /* If this option set a flag, do nothing else now. */
+            if (long_options[option_index].flag != 0)
+                break;
+            _tprintf (_T("option %s"), long_options[option_index].name);
+            if (optarg)
+                _tprintf (_T(" with arg %s"), optarg);
+            _tprintf (_T("\n"));
+            break;
+
+        case _T('a'):
+            _tprintf(_T("option -a\n"));
+            break;
+
+        case _T('b'):
+            _tprintf(_T("option -b\n"));
+            break;
+
+        case _T('c'):
+            _tprintf (_T("option -c with value `%s'\n"), optarg);
+            break;
+
+        case _T('d'):
+            _tprintf (_T("option -d with value `%s'\n"), optarg);
+            break;
+
+        case _T('f'):
+            _tprintf (_T("option -f with value `%s'\n"), optarg);
+            break;
+
+        case '?':
+            /* getopt_long already printed an error message. */
+            break;
+
+        default:
+            abort();
+        }
+    }
+
+    if (verbose_flag)
+        _tprintf (_T("verbose flag is set\n"));
+
+
+    if (optind < argc)
+    {
+        _tprintf (_T("non-option ARGV-elements: "));
+        while (optind < argc) _tprintf (_T("%s "), argv[optind++]);
+        _tprintf (_T("\n"));
+    }
+    return 0;
+}
+```
+ 
+Using this Code with C++ Precompiled Headers
+--------------------------------------------
+
+When using this code statically within a C++ project with precompiled headers, it is necessary to rename `getopt.c`
+to `getopt.cpp` in order to circumvent the following compiler error:
+
+```
+"C1853 - Precompiled header file is from a previous version of the compiler, 
+or the precompiled header is C++ and you are using it from C (or vice versa)."
+```
+
+Additionally precompiled header file must be added as the first include of the `getopt.c` or `getopt.cpp` file.
+For example, if you are using _stdafx.h_ as the precompiled header, the following would be expected:
+
+```
+// File comments removed
+#include "stdafx.h"
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdlib.h>
+#include <stdio.h>
+#include "getopt.h"
+```
+
+History
+-------
+
+- 02/03/2011 - Initial release
+- 02/20/2011 - Fixed L4 compiler warnings
+- 07/05/2011 - Added no_argument, required_argument, optional_argument def
+- 08/05/2011 - Fixed non-argument runtime bug which caused runtime exception
+- 08/09/2011 - Added code to export functions for DLL and LIB
+- 02/15/2012 - Fixed _GETOPT_THROW definition missing in implementation file
+- 08/03/2012 - Created separate functions for char and wchar_t characters so single DLL can do both Unicode and ANSI
+- 10/15/2012 - Modified to match latest GNU features
+- 06/19/2015 - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
+
+License
+-------
+
+This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)
\ No newline at end of file
diff --git a/getopt/getopt.c b/getopt/getopt.c
new file mode 100644
index 0000000..fc7b1a0
--- /dev/null
+++ b/getopt/getopt.c
@@ -0,0 +1,973 @@
+/* Getopt for Microsoft C
+This code is a modification of the Free Software Foundation, Inc.
+Getopt library for parsing command line argument the purpose was
+to provide a Microsoft Visual C friendly derivative. This code
+provides functionality for both Unicode and Multibyte builds.
+
+Date: 02/03/2011 - Ludvik Jerabek - Initial Release
+Version: 1.0
+Comment: Supports getopt, getopt_long, and getopt_long_only
+and POSIXLY_CORRECT environment flag
+License: LGPL
+
+Revisions:
+
+02/03/2011 - Ludvik Jerabek - Initial Release
+02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
+07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
+08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
+08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
+02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
+08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
+10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
+06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
+
+**DISCLAIMER**
+THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
+EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
+APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
+DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
+USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
+PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
+YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
+EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+*/
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdlib.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "getopt.h"
+
+#ifdef __cplusplus
+	#define _GETOPT_THROW throw()
+#else
+	#define _GETOPT_THROW
+#endif
+
+int optind = 1;
+int opterr = 1;
+int optopt = '?';
+enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
+
+//
+//
+//		Ansi structures and functions follow
+// 
+//
+
+static struct _getopt_data_a
+{
+	int optind;
+	int opterr;
+	int optopt;
+	char *optarg;
+	int __initialized;
+	char *__nextchar;
+	enum ENUM_ORDERING __ordering;
+	int __posixly_correct;
+	int __first_nonopt;
+	int __last_nonopt;
+} getopt_data_a;
+char *optarg_a;
+
+static void exchange_a(char **argv, struct _getopt_data_a *d)
+{
+	int bottom = d->__first_nonopt;
+	int middle = d->__last_nonopt;
+	int top = d->optind;
+	char *tem;
+	while (top > middle && middle > bottom)
+	{
+		if (top - middle > middle - bottom)
+		{
+			int len = middle - bottom;
+			register int i;
+			for (i = 0; i < len; i++)
+			{
+				tem = argv[bottom + i];
+				argv[bottom + i] = argv[top - (middle - bottom) + i];
+				argv[top - (middle - bottom) + i] = tem;
+			}
+			top -= len;
+		}
+		else
+		{
+			int len = top - middle;
+			register int i;
+			for (i = 0; i < len; i++)
+			{
+				tem = argv[bottom + i];
+				argv[bottom + i] = argv[middle + i];
+				argv[middle + i] = tem;
+			}
+			bottom += len;
+		}
+	}
+	d->__first_nonopt += (d->optind - d->__last_nonopt);
+	d->__last_nonopt = d->optind;
+}
+static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct)
+{
+	d->__first_nonopt = d->__last_nonopt = d->optind;
+	d->__nextchar = NULL;
+	d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT");
+	if (optstring[0] == '-')
+	{
+		d->__ordering = RETURN_IN_ORDER;
+		++optstring;
+	}
+	else if (optstring[0] == '+')
+	{
+		d->__ordering = REQUIRE_ORDER;
+		++optstring;
+	}
+	else if (d->__posixly_correct)
+		d->__ordering = REQUIRE_ORDER;
+	else
+		d->__ordering = PERMUTE;
+	return optstring;
+}
+int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct)
+{
+	int print_errors = d->opterr;
+	if (argc < 1)
+		return -1;
+	d->optarg = NULL;
+	if (d->optind == 0 || !d->__initialized)
+	{
+		if (d->optind == 0)
+			d->optind = 1;
+		optstring = _getopt_initialize_a (optstring, d, posixly_correct);
+		d->__initialized = 1;
+	}
+	else if (optstring[0] == '-' || optstring[0] == '+')
+		optstring++;
+	if (optstring[0] == ':')
+		print_errors = 0;
+	if (d->__nextchar == NULL || *d->__nextchar == '\0')
+	{
+		if (d->__last_nonopt > d->optind)
+			d->__last_nonopt = d->optind;
+		if (d->__first_nonopt > d->optind)
+			d->__first_nonopt = d->optind;
+		if (d->__ordering == PERMUTE)
+		{
+			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
+				exchange_a ((char **) argv, d);
+			else if (d->__last_nonopt != d->optind)
+				d->__first_nonopt = d->optind;
+			while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
+				d->optind++;
+			d->__last_nonopt = d->optind;
+		}
+		if (d->optind != argc && !strcmp(argv[d->optind], "--"))
+		{
+			d->optind++;
+			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
+				exchange_a((char **) argv, d);
+			else if (d->__first_nonopt == d->__last_nonopt)
+				d->__first_nonopt = d->optind;
+			d->__last_nonopt = argc;
+			d->optind = argc;
+		}
+		if (d->optind == argc)
+		{
+			if (d->__first_nonopt != d->__last_nonopt)
+				d->optind = d->__first_nonopt;
+			return -1;
+		}
+		if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
+		{
+			if (d->__ordering == REQUIRE_ORDER)
+				return -1;
+			d->optarg = argv[d->optind++];
+			return 1;
+		}
+		d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-'));
+	}
+	if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1])))))
+	{
+		char *nameend;
+		unsigned int namelen;
+		const struct option_a *p;
+		const struct option_a *pfound = NULL;
+		struct option_list
+		{
+			const struct option_a *p;
+			struct option_list *next;
+		} *ambig_list = NULL;
+		int exact = 0;
+		int indfound = -1;
+		int option_index;
+		for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++);
+		namelen = (unsigned int)(nameend - d->__nextchar);
+		for (p = longopts, option_index = 0; p->name; p++, option_index++)
+			if (!strncmp(p->name, d->__nextchar, namelen))
+			{
+				if (namelen == (unsigned int)strlen(p->name))
+				{
+					pfound = p;
+					indfound = option_index;
+					exact = 1;
+					break;
+				}
+				else if (pfound == NULL)
+				{
+					pfound = p;
+					indfound = option_index;
+				}
+				else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
+				{
+					struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
+					newp->p = p;
+					newp->next = ambig_list;
+					ambig_list = newp;
+				}
+			}
+			if (ambig_list != NULL && !exact)
+			{
+				if (print_errors)
+				{
+					struct option_list first;
+					first.p = pfound;
+					first.next = ambig_list;
+					ambig_list = &first;
+					fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
+					do
+					{
+						fprintf (stderr, " '--%s'", ambig_list->p->name);
+						ambig_list = ambig_list->next;
+					}
+					while (ambig_list != NULL);
+					fputc ('\n', stderr);
+				}
+				d->__nextchar += strlen(d->__nextchar);
+				d->optind++;
+				d->optopt = 0;
+				return '?';
+			}
+			if (pfound != NULL)
+			{
+				option_index = indfound;
+				d->optind++;
+				if (*nameend)
+				{
+					if (pfound->has_arg)
+						d->optarg = nameend + 1;
+					else
+					{
+						if (print_errors)
+						{
+							if (argv[d->optind - 1][1] == '-')
+							{
+								fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
+							}
+							else
+							{
+								fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
+							}
+						}
+						d->__nextchar += strlen(d->__nextchar);
+						d->optopt = pfound->val;
+						return '?';
+					}
+				}
+				else if (pfound->has_arg == 1)
+				{
+					if (d->optind < argc)
+						d->optarg = argv[d->optind++];
+					else
+					{
+						if (print_errors)
+						{
+							fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
+						}
+						d->__nextchar += strlen(d->__nextchar);
+						d->optopt = pfound->val;
+						return optstring[0] == ':' ? ':' : '?';
+					}
+				}
+				d->__nextchar += strlen(d->__nextchar);
+				if (longind != NULL)
+					*longind = option_index;
+				if (pfound->flag)
+				{
+					*(pfound->flag) = pfound->val;
+					return 0;
+				}
+				return pfound->val;
+			}
+			if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL)
+			{
+				if (print_errors)
+				{
+					if (argv[d->optind][1] == '-')
+					{
+						fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
+					}
+					else
+					{
+						fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
+					}
+				}
+				d->__nextchar = (char *)"";
+				d->optind++;
+				d->optopt = 0;
+				return '?';
+			}
+	}
+	{
+		char c = *d->__nextchar++;
+		char *temp = (char*)strchr(optstring, c);
+		if (*d->__nextchar == '\0')
+			++d->optind;
+		if (temp == NULL || c == ':' || c == ';')
+		{
+			if (print_errors)
+			{
+				fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
+			}
+			d->optopt = c;
+			return '?';
+		}
+		if (temp[0] == 'W' && temp[1] == ';')
+		{
+			char *nameend;
+			const struct option_a *p;
+			const struct option_a *pfound = NULL;
+			int exact = 0;
+			int ambig = 0;
+			int indfound = 0;
+			int option_index;
+			if (longopts == NULL)
+				goto no_longs;
+			if (*d->__nextchar != '\0')
+			{
+				d->optarg = d->__nextchar;
+				d->optind++;
+			}
+			else if (d->optind == argc)
+			{
+				if (print_errors)
+				{
+					fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
+				}
+				d->optopt = c;
+				if (optstring[0] == ':')
+					c = ':';
+				else
+					c = '?';
+				return c;
+			}
+			else
+				d->optarg = argv[d->optind++];
+			for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++);
+			for (p = longopts, option_index = 0; p->name; p++, option_index++)
+				if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar))
+				{
+					if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name))
+					{
+						pfound = p;
+						indfound = option_index;
+						exact = 1;
+						break;
+					}
+					else if (pfound == NULL)
+					{
+						pfound = p;
+						indfound = option_index;
+					}
+					else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
+						ambig = 1;
+				}
+				if (ambig && !exact)
+				{
+					if (print_errors)
+					{
+						fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
+					}
+					d->__nextchar += strlen(d->__nextchar);
+					d->optind++;
+					return '?';
+				}
+				if (pfound != NULL)
+				{
+					option_index = indfound;
+					if (*nameend)
+					{
+						if (pfound->has_arg)
+							d->optarg = nameend + 1;
+						else
+						{
+							if (print_errors)
+							{
+								fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
+							}
+							d->__nextchar += strlen(d->__nextchar);
+							return '?';
+						}
+					}
+					else if (pfound->has_arg == 1)
+					{
+						if (d->optind < argc)
+							d->optarg = argv[d->optind++];
+						else
+						{
+							if (print_errors)
+							{
+								fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
+							}
+							d->__nextchar += strlen(d->__nextchar);
+							return optstring[0] == ':' ? ':' : '?';
+						}
+					}
+					else
+						d->optarg = NULL;
+					d->__nextchar += strlen(d->__nextchar);
+					if (longind != NULL)
+						*longind = option_index;
+					if (pfound->flag)
+					{
+						*(pfound->flag) = pfound->val;
+						return 0;
+					}
+					return pfound->val;
+				}
+no_longs:
+				d->__nextchar = NULL;
+				return 'W';
+		}
+		if (temp[1] == ':')
+		{
+			if (temp[2] == ':')
+			{
+				if (*d->__nextchar != '\0')
+				{
+					d->optarg = d->__nextchar;
+					d->optind++;
+				}
+				else
+					d->optarg = NULL;
+				d->__nextchar = NULL;
+			}
+			else
+			{
+				if (*d->__nextchar != '\0')
+				{
+					d->optarg = d->__nextchar;
+					d->optind++;
+				}
+				else if (d->optind == argc)
+				{
+					if (print_errors)
+					{
+						fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c);
+					}
+					d->optopt = c;
+					if (optstring[0] == ':')
+						c = ':';
+					else
+						c = '?';
+				}
+				else
+					d->optarg = argv[d->optind++];
+				d->__nextchar = NULL;
+			}
+		}
+		return c;
+	}
+}
+int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct)
+{
+	int result;
+	getopt_data_a.optind = optind;
+	getopt_data_a.opterr = opterr;
+	result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct);
+	optind = getopt_data_a.optind;
+	optarg_a = getopt_data_a.optarg;
+	optopt = getopt_data_a.optopt;
+	return result;
+}
+int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW
+{
+	return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0);
+}
+int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
+{
+	return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0);
+}
+int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
+{
+	return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0);
+}
+int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
+{
+	return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0);
+}
+int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
+{
+	return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0);
+}
+
+//
+//
+//	Unicode Structures and Functions
+// 
+//
+
+static struct _getopt_data_w
+{
+	int optind;
+	int opterr;
+	int optopt;
+	wchar_t *optarg;
+	int __initialized;
+	wchar_t *__nextchar;
+	enum ENUM_ORDERING __ordering;
+	int __posixly_correct;
+	int __first_nonopt;
+	int __last_nonopt;
+} getopt_data_w;
+wchar_t *optarg_w;
+
+static void exchange_w(wchar_t **argv, struct _getopt_data_w *d)
+{
+	int bottom = d->__first_nonopt;
+	int middle = d->__last_nonopt;
+	int top = d->optind;
+	wchar_t *tem;
+	while (top > middle && middle > bottom)
+	{
+		if (top - middle > middle - bottom)
+		{
+			int len = middle - bottom;
+			register int i;
+			for (i = 0; i < len; i++)
+			{
+				tem = argv[bottom + i];
+				argv[bottom + i] = argv[top - (middle - bottom) + i];
+				argv[top - (middle - bottom) + i] = tem;
+			}
+			top -= len;
+		}
+		else
+		{
+			int len = top - middle;
+			register int i;
+			for (i = 0; i < len; i++)
+			{
+				tem = argv[bottom + i];
+				argv[bottom + i] = argv[middle + i];
+				argv[middle + i] = tem;
+			}
+			bottom += len;
+		}
+	}
+	d->__first_nonopt += (d->optind - d->__last_nonopt);
+	d->__last_nonopt = d->optind;
+}
+static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct)
+{
+	d->__first_nonopt = d->__last_nonopt = d->optind;
+	d->__nextchar = NULL;
+	d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT");
+	if (optstring[0] == L'-')
+	{
+		d->__ordering = RETURN_IN_ORDER;
+		++optstring;
+	}
+	else if (optstring[0] == L'+')
+	{
+		d->__ordering = REQUIRE_ORDER;
+		++optstring;
+	}
+	else if (d->__posixly_correct)
+		d->__ordering = REQUIRE_ORDER;
+	else
+		d->__ordering = PERMUTE;
+	return optstring;
+}
+int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct)
+{
+	int print_errors = d->opterr;
+	if (argc < 1)
+		return -1;
+	d->optarg = NULL;
+	if (d->optind == 0 || !d->__initialized)
+	{
+		if (d->optind == 0)
+			d->optind = 1;
+		optstring = _getopt_initialize_w (optstring, d, posixly_correct);
+		d->__initialized = 1;
+	}
+	else if (optstring[0] == L'-' || optstring[0] == L'+')
+		optstring++;
+	if (optstring[0] == L':')
+		print_errors = 0;
+	if (d->__nextchar == NULL || *d->__nextchar == L'\0')
+	{
+		if (d->__last_nonopt > d->optind)
+			d->__last_nonopt = d->optind;
+		if (d->__first_nonopt > d->optind)
+			d->__first_nonopt = d->optind;
+		if (d->__ordering == PERMUTE)
+		{
+			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
+				exchange_w((wchar_t **) argv, d);
+			else if (d->__last_nonopt != d->optind)
+				d->__first_nonopt = d->optind;
+			while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
+				d->optind++;
+			d->__last_nonopt = d->optind;
+		}
+		if (d->optind != argc && !wcscmp(argv[d->optind], L"--"))
+		{
+			d->optind++;
+			if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
+				exchange_w((wchar_t **) argv, d);
+			else if (d->__first_nonopt == d->__last_nonopt)
+				d->__first_nonopt = d->optind;
+			d->__last_nonopt = argc;
+			d->optind = argc;
+		}
+		if (d->optind == argc)
+		{
+			if (d->__first_nonopt != d->__last_nonopt)
+				d->optind = d->__first_nonopt;
+			return -1;
+		}
+		if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
+		{
+			if (d->__ordering == REQUIRE_ORDER)
+				return -1;
+			d->optarg = argv[d->optind++];
+			return 1;
+		}
+		d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-'));
+	}
+	if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1])))))
+	{
+		wchar_t *nameend;
+		unsigned int namelen;
+		const struct option_w *p;
+		const struct option_w *pfound = NULL;
+		struct option_list
+		{
+			const struct option_w *p;
+			struct option_list *next;
+		} *ambig_list = NULL;
+		int exact = 0;
+		int indfound = -1;
+		int option_index;
+		for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++);
+		namelen = (unsigned int)(nameend - d->__nextchar);
+		for (p = longopts, option_index = 0; p->name; p++, option_index++)
+			if (!wcsncmp(p->name, d->__nextchar, namelen))
+			{
+				if (namelen == (unsigned int)wcslen(p->name))
+				{
+					pfound = p;
+					indfound = option_index;
+					exact = 1;
+					break;
+				}
+				else if (pfound == NULL)
+				{
+					pfound = p;
+					indfound = option_index;
+				}
+				else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
+				{
+					struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
+					newp->p = p;
+					newp->next = ambig_list;
+					ambig_list = newp;
+				}
+			}
+			if (ambig_list != NULL && !exact)
+			{
+				if (print_errors)
+				{						
+					struct option_list first;
+					first.p = pfound;
+					first.next = ambig_list;
+					ambig_list = &first;
+					fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
+					do
+					{
+						fwprintf (stderr, L" '--%s'", ambig_list->p->name);
+						ambig_list = ambig_list->next;
+					}
+					while (ambig_list != NULL);
+					fputwc (L'\n', stderr);
+				}
+				d->__nextchar += wcslen(d->__nextchar);
+				d->optind++;
+				d->optopt = 0;
+				return L'?';
+			}
+			if (pfound != NULL)
+			{
+				option_index = indfound;
+				d->optind++;
+				if (*nameend)
+				{
+					if (pfound->has_arg)
+						d->optarg = nameend + 1;
+					else
+					{
+						if (print_errors)
+						{
+							if (argv[d->optind - 1][1] == L'-')
+							{
+								fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name);
+							}
+							else
+							{
+								fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name);
+							}
+						}
+						d->__nextchar += wcslen(d->__nextchar);
+						d->optopt = pfound->val;
+						return L'?';
+					}
+				}
+				else if (pfound->has_arg == 1)
+				{
+					if (d->optind < argc)
+						d->optarg = argv[d->optind++];
+					else
+					{
+						if (print_errors)
+						{
+							fwprintf(stderr,L"%s: option '--%s' requires an argument\n",argv[0], pfound->name);
+						}
+						d->__nextchar += wcslen(d->__nextchar);
+						d->optopt = pfound->val;
+						return optstring[0] == L':' ? L':' : L'?';
+					}
+				}
+				d->__nextchar += wcslen(d->__nextchar);
+				if (longind != NULL)
+					*longind = option_index;
+				if (pfound->flag)
+				{
+					*(pfound->flag) = pfound->val;
+					return 0;
+				}
+				return pfound->val;
+			}
+			if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL)
+			{
+				if (print_errors)
+				{
+					if (argv[d->optind][1] == L'-')
+					{
+						fwprintf(stderr, L"%s: unrecognized option '--%s'\n",argv[0], d->__nextchar);
+					}
+					else
+					{
+						fwprintf(stderr, L"%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar);
+					}
+				}
+				d->__nextchar = (wchar_t *)L"";
+				d->optind++;
+				d->optopt = 0;
+				return L'?';
+			}
+	}
+	{
+		wchar_t c = *d->__nextchar++;
+		wchar_t *temp = (wchar_t*)wcschr(optstring, c);
+		if (*d->__nextchar == L'\0')
+			++d->optind;
+		if (temp == NULL || c == L':' || c == L';')
+		{
+			if (print_errors)
+			{
+				fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c);
+			}
+			d->optopt = c;
+			return L'?';
+		}
+		if (temp[0] == L'W' && temp[1] == L';')
+		{
+			wchar_t *nameend;
+			const struct option_w *p;
+			const struct option_w *pfound = NULL;
+			int exact = 0;
+			int ambig = 0;
+			int indfound = 0;
+			int option_index;
+			if (longopts == NULL)
+				goto no_longs;
+			if (*d->__nextchar != L'\0')
+			{
+				d->optarg = d->__nextchar;
+				d->optind++;
+			}
+			else if (d->optind == argc)
+			{
+				if (print_errors)
+				{
+					fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
+				}
+				d->optopt = c;
+				if (optstring[0] == L':')
+					c = L':';
+				else
+					c = L'?';
+				return c;
+			}
+			else
+				d->optarg = argv[d->optind++];
+			for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++);
+			for (p = longopts, option_index = 0; p->name; p++, option_index++)
+				if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
+				{
+					if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name))
+					{
+						pfound = p;
+						indfound = option_index;
+						exact = 1;
+						break;
+					}
+					else if (pfound == NULL)
+					{
+						pfound = p;
+						indfound = option_index;
+					}
+					else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
+						ambig = 1;
+				}
+				if (ambig && !exact)
+				{
+					if (print_errors)
+					{
+						fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n",argv[0], d->optarg);
+					}
+					d->__nextchar += wcslen(d->__nextchar);
+					d->optind++;
+					return L'?';
+				}
+				if (pfound != NULL)
+				{
+					option_index = indfound;
+					if (*nameend)
+					{
+						if (pfound->has_arg)
+							d->optarg = nameend + 1;
+						else
+						{
+							if (print_errors)
+							{
+								fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name);
+							}
+							d->__nextchar += wcslen(d->__nextchar);
+							return L'?';
+						}
+					}
+					else if (pfound->has_arg == 1)
+					{
+						if (d->optind < argc)
+							d->optarg = argv[d->optind++];
+						else
+						{
+							if (print_errors)
+							{
+								fwprintf(stderr, L"%s: option '-W %s' requires an argument\n",argv[0], pfound->name);
+							}
+							d->__nextchar += wcslen(d->__nextchar);
+							return optstring[0] == L':' ? L':' : L'?';
+						}
+					}
+					else
+						d->optarg = NULL;
+					d->__nextchar += wcslen(d->__nextchar);
+					if (longind != NULL)
+						*longind = option_index;
+					if (pfound->flag)
+					{
+						*(pfound->flag) = pfound->val;
+						return 0;
+					}
+					return pfound->val;
+				}
+no_longs:
+				d->__nextchar = NULL;
+				return L'W';
+		}
+		if (temp[1] == L':')
+		{
+			if (temp[2] == L':')
+			{
+				if (*d->__nextchar != L'\0')
+				{
+					d->optarg = d->__nextchar;
+					d->optind++;
+				}
+				else
+					d->optarg = NULL;
+				d->__nextchar = NULL;
+			}
+			else
+			{
+				if (*d->__nextchar != L'\0')
+				{
+					d->optarg = d->__nextchar;
+					d->optind++;
+				}
+				else if (d->optind == argc)
+				{
+					if (print_errors)
+					{
+						fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c);
+					}
+					d->optopt = c;
+					if (optstring[0] == L':')
+						c = L':';
+					else
+						c = L'?';
+				}
+				else
+					d->optarg = argv[d->optind++];
+				d->__nextchar = NULL;
+			}
+		}
+		return c;
+	}
+}
+int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct)
+{
+	int result;
+	getopt_data_w.optind = optind;
+	getopt_data_w.opterr = opterr;
+	result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct);
+	optind = getopt_data_w.optind;
+	optarg_w = getopt_data_w.optarg;
+	optopt = getopt_data_w.optopt;
+	return result;
+}
+int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW
+{
+	return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0);
+}
+int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
+{
+	return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0);
+}
+int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
+{
+	return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0);
+}
+int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
+{
+	return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0);
+}
+int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
+{
+	return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0);
+}
\ No newline at end of file
diff --git a/getopt/getopt.h b/getopt/getopt.h
new file mode 100644
index 0000000..5ed4a46
--- /dev/null
+++ b/getopt/getopt.h
@@ -0,0 +1,136 @@
+/* Getopt for Microsoft C
+This code is a modification of the Free Software Foundation, Inc.
+Getopt library for parsing command line argument the purpose was
+to provide a Microsoft Visual C friendly derivative. This code
+provides functionality for both Unicode and Multibyte builds.
+
+Date: 02/03/2011 - Ludvik Jerabek - Initial Release
+Version: 1.0
+Comment: Supports getopt, getopt_long, and getopt_long_only
+and POSIXLY_CORRECT environment flag
+License: LGPL
+
+Revisions:
+
+02/03/2011 - Ludvik Jerabek - Initial Release
+02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
+07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
+08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
+08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
+02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
+08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
+10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
+06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
+
+**DISCLAIMER**
+THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
+EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
+APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
+DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
+USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
+PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
+YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
+EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+*/
+#ifndef __GETOPT_H_
+	#define __GETOPT_H_
+
+	#ifdef _GETOPT_API
+		#undef _GETOPT_API
+	#endif
+
+	#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
+		#error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually"
+	#elif defined(STATIC_GETOPT)
+		#pragma message("Warning static builds of getopt violate the Lesser GNU Public License")
+		#define _GETOPT_API
+	#elif defined(EXPORTS_GETOPT)
+		#pragma message("Exporting getopt library")
+		#define _GETOPT_API __declspec(dllexport)
+	#else
+		#pragma message("Importing getopt library")
+		#define _GETOPT_API __declspec(dllimport)
+	#endif
+
+	// Change behavior for C\C++
+	#ifdef __cplusplus
+		#define _BEGIN_EXTERN_C extern "C" {
+		#define _END_EXTERN_C }
+		#define _GETOPT_THROW throw()
+	#else
+		#define _BEGIN_EXTERN_C
+		#define _END_EXTERN_C
+		#define _GETOPT_THROW
+	#endif
+
+	// Standard GNU options
+	#define	null_argument		0	/*Argument Null*/
+	#define	no_argument			0	/*Argument Switch Only*/
+	#define required_argument	1	/*Argument Required*/
+	#define optional_argument	2	/*Argument Optional*/	
+
+	// Shorter Options
+	#define ARG_NULL	0	/*Argument Null*/
+	#define ARG_NONE	0	/*Argument Switch Only*/
+	#define ARG_REQ		1	/*Argument Required*/
+	#define ARG_OPT		2	/*Argument Optional*/
+
+	#include <string.h>
+	#include <wchar.h>
+
+_BEGIN_EXTERN_C
+
+	extern _GETOPT_API int optind;
+	extern _GETOPT_API int opterr;
+	extern _GETOPT_API int optopt;
+
+	// Ansi
+	struct option_a
+	{
+		const char* name;
+		int has_arg;
+		int *flag;
+		int val;
+	};
+	extern _GETOPT_API char *optarg_a;
+	extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW;
+	extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
+	extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
+
+	// Unicode
+	struct option_w
+	{
+		const wchar_t* name;
+		int has_arg;
+		int *flag;
+		int val;
+	};
+	extern _GETOPT_API wchar_t *optarg_w;
+	extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW;
+	extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
+	extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;	
+	
+_END_EXTERN_C
+
+	#undef _BEGIN_EXTERN_C
+	#undef _END_EXTERN_C
+	#undef _GETOPT_THROW
+	#undef _GETOPT_API
+
+	#ifdef _UNICODE
+		#define getopt getopt_w
+		#define getopt_long getopt_long_w
+		#define getopt_long_only getopt_long_only_w
+		#define option option_w
+		#define optarg optarg_w
+	#else
+		#define getopt getopt_a
+		#define getopt_long getopt_long_a
+		#define getopt_long_only getopt_long_only_a
+		#define option option_a
+		#define optarg optarg_a
+	#endif
+#endif  // __GETOPT_H_
diff --git a/getopt/getopt.sln b/getopt/getopt.sln
new file mode 100644
index 0000000..45fb7b0
--- /dev/null
+++ b/getopt/getopt.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27705.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", "getopt.vcxproj", "{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Debug|Win32.ActiveCfg = Debug|Win32
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Debug|Win32.Build.0 = Debug|Win32
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Debug|x64.ActiveCfg = Debug|x64
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Debug|x64.Build.0 = Debug|x64
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Release|Win32.ActiveCfg = Release|Win32
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Release|Win32.Build.0 = Release|Win32
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Release|x64.ActiveCfg = Release|x64
+		{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {4E6DE38C-035F-4DBE-9385-C35AC4C787ED}
+	EndGlobalSection
+EndGlobal
diff --git a/getopt/getopt.vcxproj b/getopt/getopt.vcxproj
new file mode 100644
index 0000000..f2cf127
--- /dev/null
+++ b/getopt/getopt.vcxproj
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{4BBAEAA1-9AD1-42D2-B6DC-7F73C4B3D238}</ProjectGuid>
+    <RootNamespace>GetOptTest</RootNamespace>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+    <OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(SolutionDir)$(Platform)\$(Configuration)\</IntDir>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+    <TargetName>getopt</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <PreBuildEvent>
+      <Command>
+      </Command>
+    </PreBuildEvent>
+    <ClCompile>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;EXPORTS_GETOPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)\getopt.dll</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <PreBuildEvent>
+      <Command>
+      </Command>
+    </PreBuildEvent>
+    <ClCompile>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;EXPORTS_GETOPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)\getopt.dll</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <PreBuildEvent>
+      <Command>
+      </Command>
+    </PreBuildEvent>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;EXPORTS_GETOPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MinimalRebuild>true</MinimalRebuild>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)\getopt.dll</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <PreBuildEvent>
+      <Command>
+      </Command>
+    </PreBuildEvent>
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;EXPORTS_GETOPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <OutputFile>$(OutDir)\getopt.dll</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+    </Link>
+    <PostBuildEvent>
+      <Command>
+      </Command>
+    </PostBuildEvent>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="getopt.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="getopt.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/ignore.c b/ignore.c
index 8bff2ce..9640d0b 100644
--- a/ignore.c
+++ b/ignore.c
@@ -7,7 +7,6 @@
 #include <string.h>
 
 #include "ignore.h"
-#include "rf.h"
 
 static int total_size;
 
@@ -19,13 +18,13 @@ struct ignores *init_ignores(char *path) {
 		return NULL;
 	}
 
-	char line[MAX_PATH_LENGTH];
+	char line[MAXPATHLEN];
 	total_size = IGNORE_SIZE;
 	struct ignores *ignores = (struct ignores *)calloc(sizeof(struct ignores), 1);
 	ignores->list = (char **)calloc(sizeof(char *), IGNORE_SIZE);
 	ignores->size = 0;
 
-	while (fgets(line, MAX_PATH_LENGTH, ignore) != NULL) {
+	while (fgets(line, MAXPATHLEN, ignore) != NULL) {
 		/** isspace doesn't necessarily hold true for `\n` for anything
 		 * other than the 'C' locale on some platforms, so we have to do
 		 * an additional check for this
diff --git a/ignore.h b/ignore.h
index 1bc3add..3fcc445 100644
--- a/ignore.h
+++ b/ignore.h
@@ -3,6 +3,10 @@
 
 #define IGNORE_SIZE 100
 
+#ifdef _WIN32
+#define MAXPATHLEN 1024
+#endif
+
 struct ignores {
 	char **list;
 	int size;
diff --git a/make.bat b/make.bat
new file mode 100644
index 0000000..151e0df
--- /dev/null
+++ b/make.bat
@@ -0,0 +1,8 @@
+@echo off
+
+if "%1%" == "clean" (
+	del *.obj *.exe *.lib *.exp *.pdb
+	exit /b
+)
+
+cl /nologo /W3 rf.c ignore.c include\common\strl.c getopt\getopt.c /link /out:rf.exe
\ No newline at end of file
diff --git a/rf.c b/rf.c
index 95dc432..c31feb7 100644
--- a/rf.c
+++ b/rf.c
@@ -4,21 +4,31 @@
 #define _XOPEN_SOURCE 700
 
 #include <ctype.h>
-#include <dirent.h>
+
 #include <errno.h>
-#include <getopt.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <unistd.h>
 
 #ifdef _WIN32
+#include "dirent/include/dirent.h"
+#include "getopt/getopt.h"
+#include <direct.h>
 #include <shlwapi.h>
+#pragma comment(lib, "shlwapi")
+#define RFIGNORE_PATTERN "%s\\%s"
+#define HOME_ENV_VAR "USERPROFILE"
+#define MAXPATHLEN 1024
 #else
+#include <dirent.h>
 #include <fnmatch.h>
+#include <getopt.h>
+#include <sys/param.h>
+#include <unistd.h>
+#define RFIGNORE_PATTERN "%s/%s"
+#define HOME_ENV_VAR "HOME"
 #endif
 
 #include "ignore.h"
@@ -120,8 +130,8 @@ static int recurse_find(char **patterns, int *pattern_count, const char *dirname
 			struct stat entry_stat;
 
 			if (stat(full_path, &entry_stat)) {
+				fprintf(stderr, "%s: ", full_path);
 				perror("stat");
-				exit(EXIT_FAILURE);
 				continue;
 			}
 
@@ -194,16 +204,16 @@ int main(int argc, char **argv) {
 	char cwd[MAXPATHLEN];
 	int unmatched_error = 0;
 
+#ifdef _WIN32
+	if (_getcwd(cwd, MAXPATHLEN) == NULL) {
+#else
 	if (getcwd(cwd, MAXPATHLEN) == NULL) {
+#endif
 		perror("getcwd");
 		exit(EXIT_FAILURE);
 	}
 
-#ifdef _WIN32
-	char *home = getenv("USERPROFILE");
-#else
-	char *home = getenv("HOME");
-#endif
+	char *home = getenv(HOME_ENV_VAR);
 
 	while ((ch = getopt(argc, argv, "d:l:svw")) > -1) {
 		switch (ch) {
@@ -243,17 +253,11 @@ int main(int argc, char **argv) {
 		}
 	}
 
-	char global_ignore_path[(strlen(home) + strlen(".rfignore") + 1)];
-	char local_ignore_path[strlen(cwd) + strlen(".rfignore") + 1];
-
-#ifdef _WIN32
-	const char *pattern = "%s\\%s";
-#else
-	const char *pattern = "%s/%s";
-#endif
+	char global_ignore_path[MAXPATHLEN];
+	char local_ignore_path[MAXPATHLEN];
 
-	snprintf(global_ignore_path, (strlen(pattern) + strlen(home) + strlen(RFIGNORE)), pattern, home, RFIGNORE);
-	snprintf(local_ignore_path, (strlen(pattern) + strlen(cwd) + strlen(RFIGNORE)), pattern, cwd, RFIGNORE);
+	snprintf(global_ignore_path, MAXPATHLEN, RFIGNORE_PATTERN, home, RFIGNORE);
+	snprintf(local_ignore_path, MAXPATHLEN, RFIGNORE_PATTERN, cwd, RFIGNORE);
 
 	global_ignores = init_ignores(global_ignore_path);
 	local_ignores = init_ignores(local_ignore_path);
diff --git a/rf.h b/rf.h
deleted file mode 100644
index 4695fa1..0000000
--- a/rf.h
+++ /dev/null
@@ -1 +0,0 @@
-#define MAX_PATH_LENGTH 1024