#pragma once // This header provides POSIX-compatible versions of some functions from // WindowsUnicodeToolShim and the Windows API. #include #include #include #include #include // Linux and macOS (and probably other non-Windows systems in general) do not // have separate file system or command line APIs for different text encodings. // On these systems UTF-8 is commonly the system encoding and, if so, argv will // typically be UTF-8 encoded, though it is the calling process's responsibility // to ensure this, as argv is passed verbatim as a sequence of byte strings. // // Filesystems on Unix-like systems are typically encoding-unaware, in which // case the actual encoding used should match the system encoding, or else // manual intervention is required. // // On macOS, HFS+ and APFS filenames are encoded as UTF-16 and UTF-8 // respectively, and the C filesystem API accepts UTF-8 strings. There are some // gotchas relating to Unicode normalization, where HFS+ enforces a specific // form of normalization at the filesystem layer but APFS does not, and using // the C API to access the filesystem may avoid automatic normalization that // higher-level macOS API functions may perform. // // In summary, text encoding is still a hairy problem on every computer system, // though on the major non-Windows systems, assuming UTF-8 encoding is // reasonable. For now, this header simply maps the WindowsUnicodeToolShim // functions to their regular C API counterparts. #define toolMain main #define fopen_utf8 fopen #define fputs_utf8 fputs typedef int errno_t; inline int mkdir_utf8(const char *path) { return mkdir(path, 0777); } // These use long as the offset type, which is 64 bits on 64-bit Linux and macOS // systems, so explicitly 64-bit variants aren't necessary. 32-bit systems are // likely to have a 32-bit long type, but we aren't likely to deal with // multi-gigabyte files, are we? #define _fseeki64 fseek #define _ftelli64 ftell // On Windows this is supposed to call an error handler if the buffer is too // small. I don't think this is likely to happen in Aerofoil's case, but if it // does, this function will crash the program as a precaution. template int sprintf_s ( char (&buffer)[size], const char *format, ... ) { va_list ap; va_start(ap, format); int count = vsnprintf(buffer, size, format, ap); va_end(ap); if (count >= size) exit(1); return count; } inline errno_t fopen_s(FILE **pFile, const char *name, const char *mode) { FILE *f = fopen(name, mode); if (!f) { // Error codes might not match those from Windows, but all are // non-zero, so *detecting* an error will work fine. return errno; } *pFile = f; return 0; } inline void TerminateDirectoryPath(std::string &path) { const size_t length = path.length(); if (length == 0 || path[length - 1] != '/') path.push_back('/'); } void ScanDirectoryForExtension ( std::vector &outPaths, const char *path, const char *ending, bool recursive );