diff options
| author | claude-bot <[email protected]> | 2026-07-13 12:27:07 +0000 |
|---|---|---|
| committer | claude-bot <[email protected]> | 2026-07-13 12:27:07 +0000 |
| commit | 9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686 (patch) | |
| tree | a84756b82513739a2672db3a1f0ec579db6d18ff /src/skel/crossplatform.cpp | |
| download | re3-9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686.tar.gz re3-9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686.zip | |
Snapshot import (no upstream history) into git.ancap.in.ua/claude, per @lzcnt.
Source: https://github.com/Cai1Hsu/re3 branch miami.
Diffstat (limited to 'src/skel/crossplatform.cpp')
| -rw-r--r-- | src/skel/crossplatform.cpp | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp new file mode 100644 index 0000000..68df670 --- /dev/null +++ b/src/skel/crossplatform.cpp @@ -0,0 +1,272 @@ +#include "common.h" +#include "crossplatform.h" + +// Codes compatible with Windows and Linux +#ifndef _WIN32 + +// For internal use +// wMilliseconds is not needed +void tmToSystemTime(const tm *tm, SYSTEMTIME *out) { + out->wYear = tm->tm_year + 1900; + out->wMonth = tm->tm_mon + 1; + out->wDayOfWeek = tm->tm_wday; + out->wDay = tm->tm_mday; + out->wHour = tm->tm_hour; + out->wMinute = tm->tm_min; + out->wSecond = tm->tm_sec; +} + +void GetLocalTime_CP(SYSTEMTIME *out) { + time_t timestamp = time(nil); + tm *localTm = localtime(×tamp); + tmToSystemTime(localTm, out); +} +#endif + +// Compatible with Linux/POSIX and MinGW on Windows +#ifndef _WIN32 +HANDLE FindFirstFile(const char* pathname, WIN32_FIND_DATA* firstfile) { + char pathCopy[MAX_PATH]; + strcpy(pathCopy, pathname); + + char *folder = strtok(pathCopy, "*"); + char *extension = strtok(NULL, "*"); + + // because I remember like strtok might not return NULL for last delimiter + if (extension && extension - folder == strlen(pathname)) + extension = nil; + + // Case-sensitivity and backslashes... + // Will be freed at the bottom + char *realFolder = casepath(folder); + if (realFolder) { + folder = realFolder; + } + + strncpy(firstfile->folder, folder, sizeof(firstfile->folder)); + + if (extension) + strncpy(firstfile->extension, extension, sizeof(firstfile->extension)); + else + firstfile->extension[0] = '\0'; + + if (realFolder) + free(realFolder); + + HANDLE d; + if ((d = (HANDLE)opendir(firstfile->folder)) == NULL || !FindNextFile(d, firstfile)) + return NULL; + + return d; +} + +bool FindNextFile(HANDLE d, WIN32_FIND_DATA* finddata) { + dirent *file; + static struct stat fileStats; + static char path[PATH_MAX], relativepath[NAME_MAX + sizeof(finddata->folder) + 1]; + int extensionLen = strlen(finddata->extension); + while ((file = readdir((DIR*)d)) != NULL) { + + // We only want "DT_REG"ular Files, but reportedly some FS and OSes gives DT_UNKNOWN as type. + if ((file->d_type == DT_UNKNOWN || file->d_type == DT_REG || file->d_type == DT_LNK) && + (extensionLen == 0 || strncasecmp(&file->d_name[strlen(file->d_name) - extensionLen], finddata->extension, extensionLen) == 0)) { + + sprintf(relativepath, "%s/%s", finddata->folder, file->d_name); + realpath(relativepath, path); + stat(path, &fileStats); + strncpy(finddata->cFileName, file->d_name, sizeof(finddata->cFileName)); + finddata->ftLastWriteTime = fileStats.st_mtime; + return true; + } + } + return false; +} + +void GetDateFormat(int unused1, int unused2, SYSTEMTIME* in, int unused3, char* out, int size) { + tm linuxTime; + linuxTime.tm_year = in->wYear - 1900; + linuxTime.tm_mon = in->wMonth - 1; + linuxTime.tm_wday = in->wDayOfWeek; + linuxTime.tm_mday = in->wDay; + linuxTime.tm_hour = in->wHour; + linuxTime.tm_min = in->wMinute; + linuxTime.tm_sec = in->wSecond; + strftime(out, size, nl_langinfo(D_FMT), &linuxTime); +} + +void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) { + tm *ptm = gmtime(writeTime); + tmToSystemTime(ptm, out); +} +#endif + +// Because wchar length differs between platforms. +wchar* +AllocUnicode(const char* src) +{ + wchar *dst = (wchar*)malloc(strlen(src)*2 + 2); + wchar *i = dst; + while((*i++ = (unsigned char)*src++) != '\0'); + return dst; +} + +// Funcs/features from Windows that we need on other platforms +#ifndef _WIN32 +char *strupr(char *s) { + char* tmp = s; + + for (;*tmp;++tmp) { + *tmp = toupper((unsigned char) *tmp); + } + + return s; +} +char *strlwr(char *s) { + char* tmp = s; + + for (;*tmp;++tmp) { + *tmp = tolower((unsigned char) *tmp); + } + + return s; +} + +char *trim(char *s) { + char *ptr; + if (!s) + return NULL; // handle NULL string + if (!*s) + return s; // handle empty string + for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr); + ptr[1] = '\0'; + return s; +} + +FILE* _fcaseopen(char const* filename, char const* mode) +{ + FILE* result; + char* real = casepath(filename); + if (!real) + result = fopen(filename, mode); + else { + result = fopen(real, mode); + free(real); + } + return result; +} + +// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen) +// Returned string should freed manually (if exists) +char* casepath(char const* path, bool checkPathFirst) +{ + if (checkPathFirst && access(path, F_OK) != -1) { + // File path is correct + return nil; + } + + size_t l = strlen(path); + char* p = (char*)alloca(l + 1); + char* out = (char*)malloc(l + 3); // for extra ./ + strcpy(p, path); + + // my addon: linux doesn't handle filenames with spaces at the end nicely + p = trim(p); + + size_t rl = 0; + + DIR* d; + if (p[0] == '/' || p[0] == '\\') + { + d = opendir("/"); + } + else + { + d = opendir("."); + out[0] = '.'; + out[1] = 0; + rl = 1; + } + + bool cantProceed = false; // just convert slashes in what's left in string, don't correct case of letters(because we can't) + bool mayBeTrailingSlash = false; + char* c; + while (c = strsep(&p, "/\\")) + { + // May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid) + if (*c == '\0') + { + mayBeTrailingSlash = true; + continue; + } else { + mayBeTrailingSlash = false; + } + + out[rl] = '/'; + rl += 1; + out[rl] = 0; + + if (cantProceed) + { + strcpy(out + rl, c); + rl += strlen(c); + continue; + } + + struct dirent* e; + while (e = readdir(d)) + { + if (strcasecmp(c, e->d_name) == 0) + { + strcpy(out + rl, e->d_name); + int reportedLen = (int)strlen(e->d_name); + rl += reportedLen; + assert(reportedLen == strlen(c) && "casepath: This is not good at all"); + + closedir(d); + d = opendir(out); + + // Either it wasn't a folder, or permission error, I/O error etc. + if (!d) { + cantProceed = true; + } + + break; + } + } + + if (!e) + { + printf("casepath couldn't find dir/file \"%s\", full path was %s\n", c, path); + // No match, add original name and continue converting further slashes. + strcpy(out + rl, c); + rl += strlen(c); + cantProceed = true; + } + } + + if (d) closedir(d); + if (mayBeTrailingSlash) { + out[rl] = '/'; rl += 1; + out[rl] = '\0'; + } + + if (rl > l + 2) { + printf("\n\ncasepath: Corrected path length is longer then original+2:\n\tOriginal: %s (%zu chars)\n\tCorrected: %s (%zu chars)\n\n", path, l, out, rl); + } + return out; +} +#endif + +#if !defined(_MSC_VER) && !defined(__CWCC__) +char *strdate(char *buf) { + time_t timestamp; + time(×tamp); + tm *localTm = localtime(×tamp); + strftime(buf, 10, "%m/%d/%y", localTm); + return buf; +} + +char *_strdate(char *buf) { + return strdate(buf); +} +#endif |
