diff --git a/cbp/Module.cbp b/cbp/Module.cbp
index 17a72800..b6d1bed5 100644
--- a/cbp/Module.cbp
+++ b/cbp/Module.cbp
@@ -541,6 +541,8 @@
+
+
diff --git a/include/tinydir.h b/include/tinydir.h
new file mode 100644
index 00000000..d8197003
--- /dev/null
+++ b/include/tinydir.h
@@ -0,0 +1,815 @@
+/*
+Copyright (c) 2013-2018, tinydir authors:
+- Cong Xu
+- Lautis Sun
+- Baudouin Feildel
+- Andargor
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef TINYDIR_H
+#define TINYDIR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if ((defined _UNICODE) && !(defined UNICODE))
+#define UNICODE
+#endif
+
+#if ((defined UNICODE) && !(defined _UNICODE))
+#define _UNICODE
+#endif
+
+#include
+#include
+#include
+#ifdef _MSC_VER
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include
+# include
+# pragma warning(push)
+# pragma warning (disable : 4996)
+#else
+# include
+# include
+# include
+# include
+#endif
+#ifdef __MINGW32__
+# include
+#endif
+
+
+/* types */
+
+/* Windows UNICODE wide character support */
+#if defined _MSC_VER || defined __MINGW32__
+# define _tinydir_char_t TCHAR
+# define TINYDIR_STRING(s) _TEXT(s)
+# define _tinydir_strlen _tcslen
+# define _tinydir_strcpy _tcscpy
+# define _tinydir_strcat _tcscat
+# define _tinydir_strcmp _tcscmp
+# define _tinydir_strrchr _tcsrchr
+# define _tinydir_strncmp _tcsncmp
+#else
+# define _tinydir_char_t char
+# define TINYDIR_STRING(s) s
+# define _tinydir_strlen strlen
+# define _tinydir_strcpy strcpy
+# define _tinydir_strcat strcat
+# define _tinydir_strcmp strcmp
+# define _tinydir_strrchr strrchr
+# define _tinydir_strncmp strncmp
+#endif
+
+#if (defined _MSC_VER || defined __MINGW32__)
+# include
+# define _TINYDIR_PATH_MAX MAX_PATH
+#elif defined __linux__
+# include
+# ifdef PATH_MAX
+# define _TINYDIR_PATH_MAX PATH_MAX
+# endif
+#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
+# include
+# if defined(BSD)
+# include
+# ifdef PATH_MAX
+# define _TINYDIR_PATH_MAX PATH_MAX
+# endif
+# endif
+#endif
+
+#ifndef _TINYDIR_PATH_MAX
+#define _TINYDIR_PATH_MAX 4096
+#endif
+
+#ifdef _MSC_VER
+/* extra chars for the "\\*" mask */
+# define _TINYDIR_PATH_EXTRA 2
+#else
+# define _TINYDIR_PATH_EXTRA 0
+#endif
+
+#define _TINYDIR_FILENAME_MAX 256
+
+#if (defined _MSC_VER || defined __MINGW32__)
+#define _TINYDIR_DRIVE_MAX 3
+#endif
+
+#ifdef _MSC_VER
+# define _TINYDIR_FUNC static __inline
+#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
+# define _TINYDIR_FUNC static __inline__
+#else
+# define _TINYDIR_FUNC static inline
+#endif
+
+/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
+#ifdef TINYDIR_USE_READDIR_R
+
+/* readdir_r is a POSIX-only function, and may not be available under various
+ * environments/settings, e.g. MinGW. Use readdir fallback */
+#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
+ _POSIX_SOURCE
+# define _TINYDIR_HAS_READDIR_R
+#endif
+#if _POSIX_C_SOURCE >= 200112L
+# define _TINYDIR_HAS_FPATHCONF
+# include
+#endif
+#if _BSD_SOURCE || _SVID_SOURCE || \
+ (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
+# define _TINYDIR_HAS_DIRFD
+# include
+#endif
+#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
+ defined _PC_NAME_MAX
+# define _TINYDIR_USE_FPATHCONF
+#endif
+#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
+ !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
+# define _TINYDIR_USE_READDIR
+#endif
+
+/* Use readdir by default */
+#else
+# define _TINYDIR_USE_READDIR
+#endif
+
+/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
+#ifndef _MSC_VER
+#if (defined __MINGW32__) && (defined _UNICODE)
+#define _TINYDIR_DIR _WDIR
+#define _tinydir_dirent _wdirent
+#define _tinydir_opendir _wopendir
+#define _tinydir_readdir _wreaddir
+#define _tinydir_closedir _wclosedir
+#else
+#define _TINYDIR_DIR DIR
+#define _tinydir_dirent dirent
+#define _tinydir_opendir opendir
+#define _tinydir_readdir readdir
+#define _tinydir_closedir closedir
+#endif
+#endif
+
+/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
+#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
+#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
+#else
+#error "Either define both alloc and free or none of them!"
+#endif
+
+#if !defined(_TINYDIR_MALLOC)
+ #define _TINYDIR_MALLOC(_size) malloc(_size)
+ #define _TINYDIR_FREE(_ptr) free(_ptr)
+#endif /* !defined(_TINYDIR_MALLOC) */
+
+typedef struct tinydir_file
+{
+ _tinydir_char_t path[_TINYDIR_PATH_MAX];
+ _tinydir_char_t name[_TINYDIR_FILENAME_MAX];
+ _tinydir_char_t *extension;
+ int is_dir;
+ int is_reg;
+
+#ifndef _MSC_VER
+#ifdef __MINGW32__
+ struct _stat _s;
+#else
+ struct stat _s;
+#endif
+#endif
+} tinydir_file;
+
+typedef struct tinydir_dir
+{
+ _tinydir_char_t path[_TINYDIR_PATH_MAX];
+ int has_next;
+ size_t n_files;
+
+ tinydir_file *_files;
+#ifdef _MSC_VER
+ HANDLE _h;
+ WIN32_FIND_DATA _f;
+#else
+ _TINYDIR_DIR *_d;
+ struct _tinydir_dirent *_e;
+#ifndef _TINYDIR_USE_READDIR
+ struct _tinydir_dirent *_ep;
+#endif
+#endif
+} tinydir_dir;
+
+
+/* declarations */
+
+_TINYDIR_FUNC
+int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
+_TINYDIR_FUNC
+int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
+_TINYDIR_FUNC
+void tinydir_close(tinydir_dir *dir);
+
+_TINYDIR_FUNC
+int tinydir_next(tinydir_dir *dir);
+_TINYDIR_FUNC
+int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
+_TINYDIR_FUNC
+int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
+_TINYDIR_FUNC
+int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
+
+_TINYDIR_FUNC
+int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
+_TINYDIR_FUNC
+void _tinydir_get_ext(tinydir_file *file);
+_TINYDIR_FUNC
+int _tinydir_file_cmp(const void *a, const void *b);
+#ifndef _MSC_VER
+#ifndef _TINYDIR_USE_READDIR
+_TINYDIR_FUNC
+size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
+#endif
+#endif
+
+
+/* definitions*/
+
+_TINYDIR_FUNC
+int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
+{
+#ifndef _MSC_VER
+#ifndef _TINYDIR_USE_READDIR
+ int error;
+ int size; /* using int size */
+#endif
+#else
+ _tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
+#endif
+ _tinydir_char_t *pathp;
+
+ if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ /* initialise dir */
+ dir->_files = NULL;
+#ifdef _MSC_VER
+ dir->_h = INVALID_HANDLE_VALUE;
+#else
+ dir->_d = NULL;
+#ifndef _TINYDIR_USE_READDIR
+ dir->_ep = NULL;
+#endif
+#endif
+ tinydir_close(dir);
+
+ _tinydir_strcpy(dir->path, path);
+ /* Remove trailing slashes */
+ pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
+ while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
+ {
+ *pathp = TINYDIR_STRING('\0');
+ pathp++;
+ }
+#ifdef _MSC_VER
+ _tinydir_strcpy(path_buf, dir->path);
+ _tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
+#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
+ dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
+#else
+ dir->_h = FindFirstFile(path_buf, &dir->_f);
+#endif
+ if (dir->_h == INVALID_HANDLE_VALUE)
+ {
+ errno = ENOENT;
+#else
+ dir->_d = _tinydir_opendir(path);
+ if (dir->_d == NULL)
+ {
+#endif
+ goto bail;
+ }
+
+ /* read first file */
+ dir->has_next = 1;
+#ifndef _MSC_VER
+#ifdef _TINYDIR_USE_READDIR
+ dir->_e = _tinydir_readdir(dir->_d);
+#else
+ /* allocate dirent buffer for readdir_r */
+ size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
+ if (size == -1) return -1;
+ dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
+ if (dir->_ep == NULL) return -1;
+
+ error = readdir_r(dir->_d, dir->_ep, &dir->_e);
+ if (error != 0) return -1;
+#endif
+ if (dir->_e == NULL)
+ {
+ dir->has_next = 0;
+ }
+#endif
+
+ return 0;
+
+bail:
+ tinydir_close(dir);
+ return -1;
+}
+
+_TINYDIR_FUNC
+int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
+{
+ /* Count the number of files first, to pre-allocate the files array */
+ size_t n_files = 0;
+ if (tinydir_open(dir, path) == -1)
+ {
+ return -1;
+ }
+ while (dir->has_next)
+ {
+ n_files++;
+ if (tinydir_next(dir) == -1)
+ {
+ goto bail;
+ }
+ }
+ tinydir_close(dir);
+
+ if (n_files == 0 || tinydir_open(dir, path) == -1)
+ {
+ return -1;
+ }
+
+ dir->n_files = 0;
+ dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
+ if (dir->_files == NULL)
+ {
+ goto bail;
+ }
+ while (dir->has_next)
+ {
+ tinydir_file *p_file;
+ dir->n_files++;
+
+ p_file = &dir->_files[dir->n_files - 1];
+ if (tinydir_readfile(dir, p_file) == -1)
+ {
+ goto bail;
+ }
+
+ if (tinydir_next(dir) == -1)
+ {
+ goto bail;
+ }
+
+ /* Just in case the number of files has changed between the first and
+ second reads, terminate without writing into unallocated memory */
+ if (dir->n_files == n_files)
+ {
+ break;
+ }
+ }
+
+ qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
+
+ return 0;
+
+bail:
+ tinydir_close(dir);
+ return -1;
+}
+
+_TINYDIR_FUNC
+void tinydir_close(tinydir_dir *dir)
+{
+ if (dir == NULL)
+ {
+ return;
+ }
+
+ memset(dir->path, 0, sizeof(dir->path));
+ dir->has_next = 0;
+ dir->n_files = 0;
+ _TINYDIR_FREE(dir->_files);
+ dir->_files = NULL;
+#ifdef _MSC_VER
+ if (dir->_h != INVALID_HANDLE_VALUE)
+ {
+ FindClose(dir->_h);
+ }
+ dir->_h = INVALID_HANDLE_VALUE;
+#else
+ if (dir->_d)
+ {
+ _tinydir_closedir(dir->_d);
+ }
+ dir->_d = NULL;
+ dir->_e = NULL;
+#ifndef _TINYDIR_USE_READDIR
+ _TINYDIR_FREE(dir->_ep);
+ dir->_ep = NULL;
+#endif
+#endif
+}
+
+_TINYDIR_FUNC
+int tinydir_next(tinydir_dir *dir)
+{
+ if (dir == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!dir->has_next)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+#ifdef _MSC_VER
+ if (FindNextFile(dir->_h, &dir->_f) == 0)
+#else
+#ifdef _TINYDIR_USE_READDIR
+ dir->_e = _tinydir_readdir(dir->_d);
+#else
+ if (dir->_ep == NULL)
+ {
+ return -1;
+ }
+ if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
+ {
+ return -1;
+ }
+#endif
+ if (dir->_e == NULL)
+#endif
+ {
+ dir->has_next = 0;
+#ifdef _MSC_VER
+ if (GetLastError() != ERROR_SUCCESS &&
+ GetLastError() != ERROR_NO_MORE_FILES)
+ {
+ tinydir_close(dir);
+ errno = EIO;
+ return -1;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+_TINYDIR_FUNC
+int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
+{
+ const _tinydir_char_t *filename;
+ if (dir == NULL || file == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+#ifdef _MSC_VER
+ if (dir->_h == INVALID_HANDLE_VALUE)
+#else
+ if (dir->_e == NULL)
+#endif
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ filename =
+#ifdef _MSC_VER
+ dir->_f.cFileName;
+#else
+ dir->_e->d_name;
+#endif
+ if (_tinydir_strlen(dir->path) +
+ _tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >=
+ _TINYDIR_PATH_MAX)
+ {
+ /* the path for the file will be too long */
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ _tinydir_strcpy(file->path, dir->path);
+ _tinydir_strcat(file->path, TINYDIR_STRING("/"));
+ _tinydir_strcpy(file->name, filename);
+ _tinydir_strcat(file->path, filename);
+#ifndef _MSC_VER
+#ifdef __MINGW32__
+ if (_tstat(
+#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \
+ || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \
+ || ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L))
+ if (lstat(
+#else
+ if (stat(
+#endif
+ file->path, &file->_s) == -1)
+ {
+ return -1;
+ }
+#endif
+ _tinydir_get_ext(file);
+
+ file->is_dir =
+#ifdef _MSC_VER
+ !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+#else
+ S_ISDIR(file->_s.st_mode);
+#endif
+ file->is_reg =
+#ifdef _MSC_VER
+ !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
+ (
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
+#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
+#endif
+#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
+#endif
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
+ !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
+#else
+ S_ISREG(file->_s.st_mode);
+#endif
+
+ return 0;
+}
+
+_TINYDIR_FUNC
+int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
+{
+ if (dir == NULL || file == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (i >= dir->n_files)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ memcpy(file, &dir->_files[i], sizeof(tinydir_file));
+ _tinydir_get_ext(file);
+
+ return 0;
+}
+
+_TINYDIR_FUNC
+int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
+{
+ _tinydir_char_t path[_TINYDIR_PATH_MAX];
+ if (dir == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (i >= dir->n_files || !dir->_files[i].is_dir)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ _tinydir_strcpy(path, dir->_files[i].path);
+ tinydir_close(dir);
+ if (tinydir_open_sorted(dir, path) == -1)
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Open a single file given its path */
+_TINYDIR_FUNC
+int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
+{
+ tinydir_dir dir;
+ int result = 0;
+ int found = 0;
+ _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
+ _tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
+ _tinydir_char_t *dir_name;
+ _tinydir_char_t *base_name;
+#if (defined _MSC_VER || defined __MINGW32__)
+ _tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
+ _tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
+#endif
+
+ if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ /* Get the parent path */
+#if (defined _MSC_VER || defined __MINGW32__)
+#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
+ errno = _tsplitpath_s(
+ path,
+ drive_buf, _TINYDIR_DRIVE_MAX,
+ dir_name_buf, _TINYDIR_FILENAME_MAX,
+ file_name_buf, _TINYDIR_FILENAME_MAX,
+ ext_buf, _TINYDIR_FILENAME_MAX);
+#else
+ _tsplitpath(
+ path,
+ drive_buf,
+ dir_name_buf,
+ file_name_buf,
+ ext_buf);
+#endif
+
+if (errno)
+{
+ return -1;
+}
+
+/* _splitpath_s not work fine with only filename and widechar support */
+#ifdef _UNICODE
+ if (drive_buf[0] == L'\xFEFE')
+ drive_buf[0] = '\0';
+ if (dir_name_buf[0] == L'\xFEFE')
+ dir_name_buf[0] = '\0';
+#endif
+
+ /* Emulate the behavior of dirname by returning "." for dir name if it's
+ empty */
+ if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
+ {
+ _tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
+ }
+ /* Concatenate the drive letter and dir name to form full dir name */
+ _tinydir_strcat(drive_buf, dir_name_buf);
+ dir_name = drive_buf;
+ /* Concatenate the file name and extension to form base name */
+ _tinydir_strcat(file_name_buf, ext_buf);
+ base_name = file_name_buf;
+#else
+ _tinydir_strcpy(dir_name_buf, path);
+ dir_name = dirname(dir_name_buf);
+ _tinydir_strcpy(file_name_buf, path);
+ base_name =basename(file_name_buf);
+#endif
+
+ /* Open the parent directory */
+ if (tinydir_open(&dir, dir_name) == -1)
+ {
+ return -1;
+ }
+
+ /* Read through the parent directory and look for the file */
+ while (dir.has_next)
+ {
+ if (tinydir_readfile(&dir, file) == -1)
+ {
+ result = -1;
+ goto bail;
+ }
+ if (_tinydir_strcmp(file->name, base_name) == 0)
+ {
+ /* File found */
+ found = 1;
+ break;
+ }
+ tinydir_next(&dir);
+ }
+ if (!found)
+ {
+ result = -1;
+ errno = ENOENT;
+ }
+
+bail:
+ tinydir_close(&dir);
+ return result;
+}
+
+_TINYDIR_FUNC
+void _tinydir_get_ext(tinydir_file *file)
+{
+ _tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
+ if (period == NULL)
+ {
+ file->extension = &(file->name[_tinydir_strlen(file->name)]);
+ }
+ else
+ {
+ file->extension = period + 1;
+ }
+}
+
+_TINYDIR_FUNC
+int _tinydir_file_cmp(const void *a, const void *b)
+{
+ const tinydir_file *fa = (const tinydir_file *)a;
+ const tinydir_file *fb = (const tinydir_file *)b;
+ if (fa->is_dir != fb->is_dir)
+ {
+ return -(fa->is_dir - fb->is_dir);
+ }
+ return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
+}
+
+#ifndef _MSC_VER
+#ifndef _TINYDIR_USE_READDIR
+/*
+The following authored by Ben Hutchings
+from https://womble.decadent.org.uk/readdir_r-advisory.html
+*/
+/* Calculate the required buffer size (in bytes) for directory *
+* entries read from the given directory handle. Return -1 if this *
+* this cannot be done. *
+* *
+* This code does not trust values of NAME_MAX that are less than *
+* 255, since some systems (including at least HP-UX) incorrectly *
+* define it to be a smaller value. */
+_TINYDIR_FUNC
+size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
+{
+ long name_max;
+ size_t name_end;
+ /* parameter may be unused */
+ (void)dirp;
+
+#if defined _TINYDIR_USE_FPATHCONF
+ name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
+ if (name_max == -1)
+#if defined(NAME_MAX)
+ name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
+#else
+ return (size_t)(-1);
+#endif
+#elif defined(NAME_MAX)
+ name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
+#else
+#error "buffer size for readdir_r cannot be determined"
+#endif
+ name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
+ return (name_end > sizeof(struct _tinydir_dirent) ?
+ name_end : sizeof(struct _tinydir_dirent));
+}
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+# if defined (_MSC_VER)
+# pragma warning(pop)
+# endif
+
+#endif
diff --git a/source/Library/System.cpp b/source/Library/System.cpp
index 0ac8080d..1a8ce5ee 100644
--- a/source/Library/System.cpp
+++ b/source/Library/System.cpp
@@ -14,9 +14,9 @@
namespace SqMod {
// ------------------------------------------------------------------------------------------------
+extern void Register_SysDir(HSQUIRRELVM vm);
extern void Register_SysEnv(HSQUIRRELVM vm);
extern void Register_SysPath(HSQUIRRELVM vm);
-
// ------------------------------------------------------------------------------------------------
static SQInteger SqSysExec(HSQUIRRELVM vm)
{
@@ -99,6 +99,7 @@ static SQInteger SqSysExec(HSQUIRRELVM vm)
// ================================================================================================
void Register_System(HSQUIRRELVM vm)
{
+ Register_SysDir(vm);
Register_SysEnv(vm);
Register_SysPath(vm);
diff --git a/source/Library/System/Dir.cpp b/source/Library/System/Dir.cpp
new file mode 100644
index 00000000..989b385b
--- /dev/null
+++ b/source/Library/System/Dir.cpp
@@ -0,0 +1,126 @@
+// ------------------------------------------------------------------------------------------------
+#include "Library/System/Dir.hpp"
+
+// ------------------------------------------------------------------------------------------------
+namespace SqMod {
+
+// ------------------------------------------------------------------------------------------------
+SQMODE_DECL_TYPENAME(TypenameD, _SC("SqSysDir"))
+SQMODE_DECL_TYPENAME(TypenameF, _SC("SqSysFile"))
+
+// ------------------------------------------------------------------------------------------------
+LightObj SysDir::ReadFile() const
+{
+ Validate("read current file");
+ // Create a file instance
+ std::unique_ptr< SysFile > mem = std::make_unique< SysFile >();
+ // Turn it into a script object
+ LightObj obj(mem.get());
+ // Will hold the raw object pointer
+ SysFile * ptr = nullptr;
+ // Release it if it was taken over by the script engine
+ if (obj.IsNull())
+ {
+ STHROWF("Failed to create a SqSysFile object.");
+ }
+ else
+ {
+ ptr = mem.release();
+ }
+ // The file handle where it will be opened
+ tinydir_file * handle = ptr->GetOrMake();
+ // Attempt to read the current file
+ if (tinydir_readfile(mHandle.get(), handle) == -1)
+ {
+ STHROWF("Failed to read current file.");
+ }
+ // Return the resulted object
+ return obj;
+}
+// ------------------------------------------------------------------------------------------------
+LightObj SysDir::ReadFileAt(SQInteger i) const
+{
+ Validate("read scanned file");
+ // Make sure the specified directory index is valid
+ if (i < 0)
+ {
+ STHROWF("File index (" PRINT_INT_FMT " < 0) our of bounds.", i);
+ }
+ if (static_cast< size_t >(i) >= mHandle->n_files)
+ {
+ STHROWF("File index (" PRINT_INT_FMT " >= " PRINT_SZ_FMT ") our of bounds.", i, mHandle->n_files);
+ }
+ // Create a file instance
+ std::unique_ptr< SysFile > mem = std::make_unique< SysFile >();
+ // Turn it into a script object
+ LightObj obj(mem.get());
+ // Will hold the raw object pointer
+ SysFile * ptr = nullptr;
+ // Release it if it was taken over by the script engine
+ if (obj.IsNull())
+ {
+ STHROWF("Failed to create a SqSysFile object.");
+ }
+ else
+ {
+ ptr = mem.release();
+ }
+ // The file handle where it will be opened
+ tinydir_file * handle = ptr->GetOrMake();
+ // Attempt to read the current file
+ if (tinydir_readfile_n(mHandle.get(), handle, i) == -1)
+ {
+ STHROWF("Failed to read file at index (" PRINT_INT_FMT ")", i);
+ }
+ // Return the resulted object
+ return obj;
+}
+
+// ================================================================================================
+void Register_SysDir(HSQUIRRELVM vm)
+{
+ RootTable(vm).Bind(TypenameD::Str,
+ Class< SysDir, NoCopy< SysDir > >(vm, TypenameD::Str)
+ // Constructors
+ .Ctor()
+ .Ctor< StackStrF & >()
+ .Ctor< bool, StackStrF & >()
+ // Meta-methods
+ .SquirrelFunc(_SC("_typename"), &TypenameD::Fn)
+ .Func(_SC("_tostring"), &SysDir::ToString)
+ // Member Properties
+ .Prop(_SC("IsValid"), &SysDir::IsValid)
+ .Prop(_SC("Path"), &SysDir::GetPath)
+ .Prop(_SC("HasNext"), &SysDir::HasNext)
+ .Prop(_SC("FileCount"), &SysDir::FileCount)
+ // Member Methods
+ .FmtFunc(_SC("Open"), &SysDir::Open)
+ .FmtFunc(_SC("OpenSorted"), &SysDir::OpenSorted)
+ .Func(_SC("OpenSubDir"), &SysDir::OpenSubDir)
+ .Func(_SC("Next"), &SysDir::Next)
+ .Func(_SC("Close"), &SysDir::Close)
+ .Func(_SC("ReadFile"), &SysDir::ReadFile)
+ .Func(_SC("ReadFileAt"), &SysDir::ReadFileAt)
+ );
+ RootTable(vm).Bind(TypenameF::Str,
+ Class< SysFile, NoCopy< SysFile > >(vm, TypenameF::Str)
+ // Constructors
+ .Ctor()
+ .Ctor< StackStrF & >()
+ // Meta-methods
+ .SquirrelFunc(_SC("_typename"), &TypenameF::Fn)
+ .Func(_SC("_tostring"), &SysFile::ToString)
+ // Member Properties
+ .Prop(_SC("IsValid"), &SysFile::IsValid)
+ .Prop(_SC("IsDir"), &SysFile::IsDir)
+ .Prop(_SC("IsReg"), &SysFile::IsReg)
+ .Prop(_SC("Path"), &SysFile::GetPath)
+ .Prop(_SC("Name"), &SysFile::GetName)
+ .Prop(_SC("Extension"), &SysFile::GetExtension)
+ // Member Methods
+ .FmtFunc(_SC("Open"), &SysFile::Open)
+ );
+
+}
+
+} // Namespace:: SqMod
diff --git a/source/Library/System/Dir.hpp b/source/Library/System/Dir.hpp
new file mode 100644
index 00000000..ae5d156d
--- /dev/null
+++ b/source/Library/System/Dir.hpp
@@ -0,0 +1,587 @@
+#ifndef _LIBRARY_SYSDIR_HPP_
+#define _LIBRARY_SYSDIR_HPP_
+
+// ------------------------------------------------------------------------------------------------
+#include "Base/Shared.hpp"
+
+// ------------------------------------------------------------------------------------------------
+#include
+
+// ------------------------------------------------------------------------------------------------
+#include
+
+// ------------------------------------------------------------------------------------------------
+namespace SqMod {
+
+// ------------------------------------------------------------------------------------------------
+typedef std::unique_ptr< tinydir_dir > TinyDir;
+typedef std::unique_ptr< tinydir_file > TinyFile;
+
+/* ------------------------------------------------------------------------------------------------
+ * This class represents file-system directories in a platform-independent manner.
+*/
+class SysDir
+{
+ // --------------------------------------------------------------------------------------------
+ TinyDir mHandle; /* Handle to the managed directory. */
+
+public:
+
+ /* --------------------------------------------------------------------------------------------
+ * Make sure a valid handle is being managed before attempting to use it.
+ */
+ void Validate() const
+ {
+ if (!mHandle)
+ {
+ STHROWF("Invalid directory handle. Please open a directory first.");
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Make sure a valid handle is being managed before attempting to use it.
+ */
+ void Validate(CSStr action) const
+ {
+ if (!mHandle)
+ {
+ STHROWF("Cannot %s. Invalid directory handle.", action);
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Defaults to a null handle.
+ */
+ SysDir()
+ : mHandle()
+ {
+ /*...*/
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Opens the directory at the specified path.
+ */
+ SysDir(StackStrF & path)
+ : SysDir(false, path)
+ {
+ /*...*/
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Construct from an existing file handle.
+ */
+ explicit SysDir(tinydir_dir * handle)
+ : mHandle(handle)
+ {
+ /*...*/
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Opens the directory at the specified path.
+ */
+ SysDir(bool sorted, StackStrF & path)
+ : SysDir()
+ {
+ // Should we open this in sorted mode?
+ if (sorted)
+ {
+ OpenSorted(path);
+ }
+ else
+ {
+ Open(path);
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Copy constructor (disabled).
+ */
+ SysDir(const SysDir &) = delete;
+
+ /* --------------------------------------------------------------------------------------------
+ * Move constructor.
+ */
+ SysDir(SysDir && o)
+ : mHandle(std::forward< TinyDir >(o.mHandle))
+ {
+ /*...*/
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Destructor.
+ */
+ ~SysDir()
+ {
+ // Is there handle being managed?
+ if (mHandle)
+ {
+ tinydir_close(mHandle.get()); // Close it!
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Copy assignment operator (disabled).
+ */
+ SysDir & operator = (const SysDir &) = delete;
+
+ /* --------------------------------------------------------------------------------------------
+ * Move assignment operator.
+ */
+ SysDir & operator = (SysDir && o)
+ {
+ // Avoid self assignment
+ if (this != &o)
+ {
+ // Is there handle being managed?
+ if (mHandle)
+ {
+ tinydir_close(mHandle.get()); // Close it!
+ }
+ // Take ownership of the new handle
+ mHandle = std::move(o.mHandle);
+ }
+ return *this;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the raw managed handle.
+ */
+ tinydir_dir * Get() const
+ {
+ return mHandle.get();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the raw managed handle and make one if it doesn't exist already.
+ */
+ tinydir_dir * GetOrMake()
+ {
+ // Do we have a handle already?
+ if (!mHandle)
+ {
+ mHandle = std::make_unique< tinydir_dir >(); // Make one
+ }
+ // Return it like we promised
+ return mHandle.get();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Take ownership of the managed handle.
+ */
+ tinydir_dir * Release()
+ {
+ return mHandle.release();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Release the managed handle.
+ */
+ void Reset()
+ {
+ mHandle.reset();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Used by the script engine to convert an instance of this type to a string.
+ */
+ CSStr ToString() const
+ {
+ return mHandle ? mHandle->path : _SC("");
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Check for the presence of a handle.
+ */
+ bool IsValid() const
+ {
+ return !!mHandle;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Open a handle to the directory at the specified path.
+ */
+ void Open(StackStrF & path)
+ {
+ // Get the string from the script
+ if ((SQ_FAILED(path.Proc(true))))
+ {
+ STHROWF("Unable to extract the specified path.");
+ }
+ // Allocate handle memory, if necessary
+ if (!mHandle)
+ {
+ mHandle = std::make_unique< tinydir_dir >();
+ }
+ // If there was a handle open, we close it
+ // If we just allocated one, we initialize it (win, either way)
+ tinydir_close(mHandle.get());
+ // Attempt to open the specified directory
+ if (tinydir_open(mHandle.get(), path.mPtr) == -1)
+ {
+ // Don't keep a bad handle
+ mHandle.reset();
+ // Now we can throw the exception
+ STHROWLASTF("Failed to open directory: %s", path.mPtr);
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Open a handle to the directory at the specified path.
+ */
+ void OpenSorted(StackStrF & path)
+ {
+ // Get the string from the script
+ if ((SQ_FAILED(path.Proc(true))))
+ {
+ STHROWF("Unable to extract the specified path.");
+ }
+ // Allocate handle memory, if necessary
+ if (!mHandle)
+ {
+ mHandle = std::make_unique< tinydir_dir >();
+ }
+ // If there was a handle open, we close it
+ // If we just allocated one, we initialize it (win, either way)
+ tinydir_close(mHandle.get());
+ // Attempt to open the specified directory
+ if (tinydir_open_sorted(mHandle.get(), path.mPtr) == -1)
+ {
+ // Don't keep a bad handle
+ mHandle.reset();
+ // Now we can throw the exception
+ STHROWLASTF("Failed to open directory: %s", path.mPtr);
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Open a handle to the directory at the specified path.
+ */
+ SysDir & OpenSubDir(SQInteger i)
+ {
+ Validate("open sub directory");
+ // Discard current error number
+ errno = 0;
+ // Make sure the specified directory index is valid
+ if (i < 0)
+ {
+ STHROWF("Directory index (" PRINT_INT_FMT " < 0) our of bounds.", i);
+ }
+ if (static_cast< size_t >(i) >= mHandle->n_files)
+ {
+ STHROWF("Directory index (" PRINT_INT_FMT " >= " PRINT_SZ_FMT ") our of bounds.", i, mHandle->n_files);
+ }
+ // Make sure there is a directory at the specified index
+ else if (!mHandle->_files[i].is_dir)
+ {
+ STHROWF("The specified index (" PRINT_INT_FMT ") is not a directory.", i);
+ }
+ // Attempt to open the specified sub-directory
+ if (tinydir_open_subdir_n(mHandle.get(), static_cast< size_t >(i)) == -1)
+ {
+ // Don't keep a bad handle
+ mHandle.reset();
+ // Now we can throw the exception
+ STHROWLASTF("Failed to open sub directory (" PRINT_INT_FMT ").", i);
+ }
+ // Return self to allow chaining
+ return *this;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Advance to the next element in the opened directory.
+ */
+ void Next()
+ {
+ Validate("advance to next element");
+ // See if there is a next element
+ if (!mHandle->has_next)
+ {
+ STHROWF("Nothing left to advance to.");
+ }
+ // Discard current error number
+ errno = 0;
+ // Perform the requested action
+ if (tinydir_next(mHandle.get()) == -1)
+ {
+ // This particular error number means the directory was closed
+ if (errno == EIO) mHandle.reset();
+ // Now the exception can be thrown
+ STHROWLASTF("Failed to advance to the next element");
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Close the currently associated directory handle.
+ */
+ void Close()
+ {
+ Validate("close directory");
+ // Perform the requested action
+ tinydir_close(mHandle.get());
+ // Release any associated memory
+ mHandle.reset();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the opened path.
+ */
+ CSStr GetPath() const
+ {
+ Validate("obtain path");
+ // Return the requested information
+ return mHandle->path;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * See if there's a next element in the opened directory.
+ */
+ bool HasNext() const
+ {
+ Validate("check for next");
+ // Return the requested information
+ return static_cast< bool >(mHandle->has_next);
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the number of files in the opened directory (only when opened in sorted mode).
+ */
+ SQInteger FileCount() const
+ {
+ Validate("obtain file count");
+ // Return the requested information
+ return static_cast< SQInteger >(mHandle->n_files);
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Open current file from the specified directory.
+ */
+ LightObj ReadFile() const;
+ /* --------------------------------------------------------------------------------------------
+ * Open current file from the specified directory.
+ */
+ LightObj ReadFileAt(SQInteger i) const;
+};
+
+/* ------------------------------------------------------------------------------------------------
+ * This class represents file-system files in a platform-independent manner.
+*/
+class SysFile
+{
+ // --------------------------------------------------------------------------------------------
+ TinyFile mHandle; /* Handle to the managed file. */
+
+public:
+ /* --------------------------------------------------------------------------------------------
+ * Make sure a valid handle is being managed before attempting to use it.
+ */
+ void Validate() const
+ {
+ if (!mHandle)
+ {
+ STHROWF("Invalid file handle. Please open a file first.");
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Make sure a valid handle is being managed before attempting to use it.
+ */
+ void Validate(CSStr action) const
+ {
+ if (!mHandle)
+ {
+ STHROWF("Cannot %s. Invalid file handle.", action);
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Defaults to a null handle.
+ */
+ SysFile()
+ : mHandle()
+ {
+ /*...*/
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Opens the file at the specified path.
+ */
+ SysFile(StackStrF & path)
+ : SysFile()
+ {
+ Open(path);
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Copy constructor (disabled).
+ */
+ SysFile(const SysFile &) = delete;
+
+ /* --------------------------------------------------------------------------------------------
+ * Move constructor.
+ */
+ SysFile(SysFile && o)
+ : mHandle(std::forward< TinyFile >(o.mHandle))
+ {
+ /*...*/
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Copy assignment operator (disabled).
+ */
+ SysFile & operator = (const SysFile &) = delete;
+
+ /* --------------------------------------------------------------------------------------------
+ * Move assignment operator.
+ */
+ SysFile & operator = (SysFile && o)
+ {
+ // Avoid self assignment
+ if (this != &o)
+ {
+ // Take ownership of the new handle
+ mHandle = std::move(o.mHandle);
+ }
+ return *this;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the raw managed handle.
+ */
+ tinydir_file * Get() const
+ {
+ return mHandle.get();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the raw managed handle and make one if it doesn't exist already.
+ */
+ tinydir_file * GetOrMake()
+ {
+ // Do we have a handle already?
+ if (!mHandle)
+ {
+ mHandle = std::make_unique< tinydir_file >(); // Make one
+ }
+ // Return it like we promised
+ return mHandle.get();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Take ownership of the managed handle.
+ */
+ tinydir_file * Release()
+ {
+ return mHandle.release();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Release the managed handle.
+ */
+ void Reset()
+ {
+ mHandle.reset();
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Used by the script engine to convert an instance of this type to a string.
+ */
+ CSStr ToString() const
+ {
+ return mHandle ? mHandle->path : _SC("");
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Check for the presence of a handle.
+ */
+ bool IsValid() const
+ {
+ return !!mHandle;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Open a handle to the file at the specified path.
+ */
+ void Open(StackStrF & path)
+ {
+ // Get the string from the script
+ if ((SQ_FAILED(path.Proc(true))))
+ {
+ STHROWF("Unable to extract the specified path.");
+ }
+ // Allocate the handle memory
+ mHandle = std::make_unique< tinydir_file >();
+ // Discard current error number
+ errno = 0;
+ // Attempt to open the specified file
+ if (tinydir_file_open(mHandle.get(), path.mPtr) == -1)
+ {
+ // Don't keep a bad handle
+ mHandle.reset();
+ // Now we can throw the exception
+ if (errno != 0)
+ {
+ STHROWF("Failed to open file: %s [%s]", path.mPtr, strerror(errno));
+ }
+ else
+ {
+ STHROWLASTF("Failed to open file: %s", path.mPtr);
+ }
+ }
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Check if the opened element is a directory.
+ */
+ bool IsDir() const
+ {
+ Validate("check type");
+ // Return the requested information
+ return static_cast< bool >(mHandle->is_dir);
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Check if the opened element is a regular file.
+ */
+ bool IsReg() const
+ {
+ Validate("check type");
+ // Return the requested information
+ return static_cast< bool >(mHandle->is_reg);
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the path of the opened file.
+ */
+ CSStr GetPath() const
+ {
+ Validate("retrieve path");
+ // Return the requested information
+ return mHandle->path;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the name of the opened file.
+ */
+ CSStr GetName() const
+ {
+ Validate("retrieve name");
+ // Return the requested information
+ return mHandle->name;
+ }
+
+ /* --------------------------------------------------------------------------------------------
+ * Retrieve the extension of the opened file.
+ */
+ CSStr GetExtension() const
+ {
+ Validate("retrieve extension");
+ // Return the requested information
+ return mHandle->extension != nullptr ? mHandle->extension : _SC("");
+ }
+};
+
+
+
+} // Namespace:: SqMod
+
+#endif // _LIBRARY_SYSDIR_HPP_
diff --git a/source/Makefile b/source/Makefile
index 6995350f..b234296b 100644
--- a/source/Makefile
+++ b/source/Makefile
@@ -82,6 +82,7 @@ PP_OBJECTS= "$(SQ_OBJDIR)/external/Squirrel/Lib/sqstdaux.$(SQ_OEXT)" \
"$(SQ_OBJDIR)/source/Library/Numeric/Random.$(SQ_OEXT)" \
"$(SQ_OBJDIR)/source/Library/String.$(SQ_OEXT)" \
"$(SQ_OBJDIR)/source/Library/System.$(SQ_OEXT)" \
+ "$(SQ_OBJDIR)/source/Library/System/Dir.$(SQ_OEXT)" \
"$(SQ_OBJDIR)/source/Library/System/Environment.$(SQ_OEXT)" \
"$(SQ_OBJDIR)/source/Library/System/Path.$(SQ_OEXT)" \
"$(SQ_OBJDIR)/source/Library/Utils.$(SQ_OEXT)" \
@@ -181,6 +182,7 @@ build:
$(SQ_PP_COMPILER) $(SQ_C_OPTIONS) $(SQ_PP_OPTIONS) $(SQ_DEFINES) $(SQ_INCLUDES) -c "$(SQ_SRCDIR)/Library/Numeric/Random.cpp" -o "$(SQ_OBJDIR)/source/Library/Numeric/Random.$(SQ_OEXT)"
$(SQ_PP_COMPILER) $(SQ_C_OPTIONS) $(SQ_PP_OPTIONS) $(SQ_DEFINES) $(SQ_INCLUDES) -c "$(SQ_SRCDIR)/Library/String.cpp" -o "$(SQ_OBJDIR)/source/Library/String.$(SQ_OEXT)"
$(SQ_PP_COMPILER) $(SQ_C_OPTIONS) $(SQ_PP_OPTIONS) $(SQ_DEFINES) $(SQ_INCLUDES) -c "$(SQ_SRCDIR)/Library/System.cpp" -o "$(SQ_OBJDIR)/source/Library/System.$(SQ_OEXT)"
+ $(SQ_PP_COMPILER) $(SQ_C_OPTIONS) $(SQ_PP_OPTIONS) $(SQ_DEFINES) $(SQ_INCLUDES) -c "$(SQ_SRCDIR)/Library/System/Dir.cpp" -o "$(SQ_OBJDIR)/source/Library/System/Dir.$(SQ_OEXT)"
$(SQ_PP_COMPILER) $(SQ_C_OPTIONS) $(SQ_PP_OPTIONS) $(SQ_DEFINES) $(SQ_INCLUDES) -c "$(SQ_SRCDIR)/Library/System/Environment.cpp" -o "$(SQ_OBJDIR)/source/Library/System/Environment.$(SQ_OEXT)"
$(SQ_PP_COMPILER) $(SQ_C_OPTIONS) $(SQ_PP_OPTIONS) $(SQ_DEFINES) $(SQ_INCLUDES) -c "$(SQ_SRCDIR)/Library/System/Path.cpp" -o "$(SQ_OBJDIR)/source/Library/System/Path.$(SQ_OEXT)"
$(SQ_PP_COMPILER) $(SQ_C_OPTIONS) $(SQ_PP_OPTIONS) $(SQ_DEFINES) $(SQ_INCLUDES) -c "$(SQ_SRCDIR)/Library/Utils.cpp" -o "$(SQ_OBJDIR)/source/Library/Utils.$(SQ_OEXT)"