re3/src/skel/crossplatform.cpp

259 lines
6.6 KiB
C++
Raw Permalink Normal View History

2020-04-21 10:28:06 +00:00
#include "common.h"
#include "crossplatform.h"
2020-05-11 17:10:01 +00:00
// Codes compatible with Windows and Linux
#ifndef _WIN32
2020-04-21 10:28:06 +00:00
// 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(&timestamp);
tmToSystemTime(localTm, out);
}
2020-05-11 17:10:01 +00:00
#endif
2020-04-21 10:28:06 +00:00
2020-05-11 02:55:57 +00:00
// Compatible with Linux/POSIX and MinGW on Windows
#ifndef _WIN32
2020-04-21 10:28:06 +00:00
HANDLE FindFirstFile(const char* pathname, WIN32_FIND_DATA* firstfile) {
2020-10-23 01:37:01 +00:00
char pathCopy[MAX_PATH];
strcpy(pathCopy, pathname);
char *folder = strtok(pathCopy, "*");
char *extension = strtok(NULL, "*");
2020-10-22 22:56:32 +00:00
2021-01-29 00:32:21 +00:00
// because I remember like strtok might not return NULL for last delimiter
if (extension && extension - folder == strlen(pathname))
2020-10-23 01:37:01 +00:00
extension = nil;
2020-10-12 17:30:49 +00:00
// Case-sensitivity and backslashes...
2020-10-23 01:37:01 +00:00
// Will be freed at the bottom
2020-10-21 00:11:10 +00:00
char *realFolder = casepath(folder);
if (realFolder) {
2020-10-23 01:37:01 +00:00
folder = realFolder;
2020-10-12 17:30:49 +00:00
}
2020-10-23 01:37:01 +00:00
2020-10-21 00:11:10 +00:00
strncpy(firstfile->folder, folder, sizeof(firstfile->folder));
2020-04-21 10:28:06 +00:00
2020-10-21 00:11:10 +00:00
if (extension)
strncpy(firstfile->extension, extension, sizeof(firstfile->extension));
2020-04-21 10:28:06 +00:00
else
2020-10-21 00:11:10 +00:00
firstfile->extension[0] = '\0';
2020-04-21 10:28:06 +00:00
2020-10-23 01:37:01 +00:00
if (realFolder)
free(realFolder);
2020-04-21 10:28:06 +00:00
HANDLE d;
2020-10-23 01:37:01 +00:00
if ((d = (HANDLE)opendir(firstfile->folder)) == NULL || !FindNextFile(d, firstfile))
2020-04-21 10:28:06 +00:00
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);
2020-05-11 02:55:57 +00:00
while ((file = readdir((DIR*)d)) != NULL) {
2020-04-21 10:28:06 +00:00
// We only want "DT_REG"ular Files, but reportedly some FS and OSes gives DT_UNKNOWN as type.
2020-10-12 17:30:49 +00:00
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)) {
2020-04-21 10:28:06 +00:00
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);
}
2020-05-11 02:55:57 +00:00
#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;
}
2020-05-11 17:10:01 +00:00
// Funcs/features from Windows that we need on other platforms
2020-05-11 02:55:57 +00:00
#ifndef _WIN32
char *strupr(char *s) {
2020-07-26 17:59:58 +00:00
char* tmp = s;
2020-05-11 02:55:57 +00:00
for (;*tmp;++tmp) {
*tmp = toupper((unsigned char) *tmp);
}
return s;
}
char *strlwr(char *s) {
2020-07-26 17:59:58 +00:00
char* tmp = s;
2020-05-11 02:55:57 +00:00
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;
}
2020-07-26 17:59:58 +00:00
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;
}
2020-05-11 02:55:57 +00:00
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
2020-07-26 17:59:58 +00:00
// Returned string should freed manually (if exists)
char* casepath(char const* path, bool checkPathFirst)
2020-05-11 02:55:57 +00:00
{
2020-07-26 17:59:58 +00:00
if (checkPathFirst && access(path, F_OK) != -1) {
// File path is correct
return nil;
}
2020-05-11 02:55:57 +00:00
size_t l = strlen(path);
2020-07-26 17:59:58 +00:00
char* p = (char*)alloca(l + 1);
char* out = (char*)malloc(l + 3); // for extra ./
2020-05-11 02:55:57 +00:00
strcpy(p, path);
2020-07-26 17:59:58 +00:00
// my addon: linux doesn't handle filenames with spaces at the end nicely
p = trim(p);
2020-05-11 02:55:57 +00:00
size_t rl = 0;
2020-07-26 17:59:58 +00:00
DIR* d;
if (p[0] == '/' || p[0] == '\\')
2020-05-11 02:55:57 +00:00
{
d = opendir("/");
}
else
{
d = opendir(".");
2020-07-26 17:59:58 +00:00
out[0] = '.';
out[1] = 0;
2020-05-11 02:55:57 +00:00
rl = 1;
}
2020-07-26 17:59:58 +00:00
2021-01-29 00:32:21 +00:00
bool cantProceed = false; // just convert slashes in what's left in string, don't correct case of letters(because we can't)
2020-07-26 17:59:58 +00:00
bool mayBeTrailingSlash = false;
char* c;
while (c = strsep(&p, "/\\"))
2020-05-11 02:55:57 +00:00
{
2020-07-26 17:59:58 +00:00
// May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid)
if (*c == '\0')
2020-05-11 02:55:57 +00:00
{
2020-07-26 17:59:58 +00:00
mayBeTrailingSlash = true;
continue;
} else {
mayBeTrailingSlash = false;
2020-05-11 02:55:57 +00:00
}
2020-07-26 17:59:58 +00:00
out[rl] = '/';
rl += 1;
out[rl] = 0;
if (cantProceed)
2020-05-11 02:55:57 +00:00
{
2020-07-26 17:59:58 +00:00
strcpy(out + rl, c);
rl += strlen(c);
continue;
2020-05-11 02:55:57 +00:00
}
2020-07-26 17:59:58 +00:00
struct dirent* e;
while (e = readdir(d))
2020-05-11 02:55:57 +00:00
{
if (strcasecmp(c, e->d_name) == 0)
{
2020-07-26 17:59:58 +00:00
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");
2020-05-11 02:55:57 +00:00
closedir(d);
2020-07-26 17:59:58 +00:00
d = opendir(out);
// Either it wasn't a folder, or permission error, I/O error etc.
if (!d) {
cantProceed = true;
}
2020-05-11 02:55:57 +00:00
break;
}
}
2020-07-26 17:59:58 +00:00
2020-05-11 02:55:57 +00:00
if (!e)
{
2020-07-26 17:59:58 +00:00
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);
2020-05-11 02:55:57 +00:00
rl += strlen(c);
2020-07-26 17:59:58 +00:00
cantProceed = true;
2020-05-11 02:55:57 +00:00
}
}
2020-07-26 17:59:58 +00:00
2020-05-11 02:55:57 +00:00
if (d) closedir(d);
2020-07-26 17:59:58 +00:00
if (mayBeTrailingSlash) {
out[rl] = '/'; rl += 1;
out[rl] = '\0';
}
if (rl > l + 2) {
2021-01-29 00:32:21 +00:00
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);
2020-07-26 17:59:58 +00:00
}
return out;
2020-05-11 02:55:57 +00:00
}
#endif