#pragma once
#include "util/FFstrbuf.h"
#include "util/FFlist.h"
#ifdef _WIN32
#include <fileapi.h>
#include <handleapi.h>
#include <io.h>
typedef HANDLE FFNativeFD;
#define FF_INVALID_FD INVALID_HANDLE_VALUE
#else
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
typedef int FFNativeFD;
#define FF_INVALID_FD (-1)
#define PROC_FILE_BUFFSIZ 8192
#endif
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
{
#ifndef _WIN32
return unixfd;
#else
return (FFNativeFD) _get_osfhandle(unixfd);
#endif
}
static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* data)
{
#ifndef _WIN32
return write(fd, data, dataSize) != -1;
#else
DWORD written;
return WriteFile(fd, data, (DWORD) dataSize, &written, NULL) && written == dataSize;
#endif
}
static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content)
{
return ffWriteFDData(fd, content->length, content->chars);
}
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer)
{
return ffWriteFileData(fileName, buffer->length, buffer->chars);
}
static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
{
#ifndef _WIN32
return read(fd, data, dataSize);
#else
DWORD bytesRead;
if(!ReadFile(fd, data, (DWORD)dataSize, &bytesRead, NULL))
return -1;
return (ssize_t)bytesRead;
#endif
}
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data);
ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data);
bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer);
bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer);
static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer)
{
ffStrbufClear(buffer);
return ffAppendFileBuffer(fileName, buffer);
}
static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
{
ffStrbufClear(buffer);
return ffAppendFileBufferRelative(dfd, fileName, buffer);
}
typedef enum __attribute__((__packed__)) FFPathType
{
FF_PATHTYPE_FILE = 1 << 0,
FF_PATHTYPE_DIRECTORY = 1 << 1,
FF_PATHTYPE_ANY = FF_PATHTYPE_FILE | FF_PATHTYPE_DIRECTORY,
FF_PATHTYPE_FORCE_UNSIGNED = UINT8_MAX,
} FFPathType;
static inline bool ffPathExists(const char* path, FFPathType pathType)
{
#ifdef _WIN32
DWORD attr = GetFileAttributesA(path);
if(attr == INVALID_FILE_ATTRIBUTES)
return false;
if(pathType & FF_PATHTYPE_FILE && !(attr & FILE_ATTRIBUTE_DIRECTORY))
return true;
if(pathType & FF_PATHTYPE_DIRECTORY && (attr & FILE_ATTRIBUTE_DIRECTORY))
return true;
#else
if (pathType == FF_PATHTYPE_ANY)
{
return access(path, F_OK) == 0;
}
else
{
struct stat fileStat;
if(stat(path, &fileStat) != 0)
return false;
unsigned int mode = fileStat.st_mode & S_IFMT;
if(pathType & FF_PATHTYPE_FILE && mode != S_IFDIR)
return true;
if(pathType & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR)
return true;
}
#endif
return false;
}
bool ffPathExpandEnv(const char* in, FFstrbuf* out);
#define FF_IO_TERM_RESP_WAIT_MS 100
FF_C_SCANF(3, 4)
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);
bool ffSuppressIO(bool suppress);
static inline void ffUnsuppressIO(bool* suppressed)
{
if (!*suppressed) return;
ffSuppressIO(false);
*suppressed = false;
}
#define FF_SUPPRESS_IO() bool __attribute__((__cleanup__(ffUnsuppressIO), __unused__)) io_suppressed__ = ffSuppressIO(true)
void ffListFilesRecursively(const char* path, bool pretty);
static inline bool wrapClose(FFNativeFD* pfd)
{
assert(pfd);
#ifndef WIN32
if (*pfd < 0)
return false;
close(*pfd);
#else
if (*pfd == NULL || *pfd == INVALID_HANDLE_VALUE)
return false;
CloseHandle(*pfd);
#endif
return true;
}
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
static inline bool wrapFclose(FILE** pfile)
{
assert(pfile);
if (!*pfile)
return false;
fclose(*pfile);
return true;
}
#define FF_AUTO_CLOSE_FILE __attribute__((__cleanup__(wrapFclose)))
#ifndef _WIN32
static inline bool wrapClosedir(DIR** pdir)
{
assert(pdir);
if (!*pdir)
return false;
closedir(*pdir);
return true;
}
#else
static inline bool wrapClosedir(HANDLE* pdir)
{
assert(pdir);
if (!*pdir)
return false;
FindClose(*pdir);
return true;
}
#endif
#define FF_AUTO_CLOSE_DIR __attribute__((__cleanup__(wrapClosedir)))
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result)
{
FF_LIST_FOR_EACH(FFstrbuf, dir, *configDirs)
{
ffStrbufClear(result);
ffStrbufAppend(result, dir);
ffStrbufAppendS(result, fileSubpath);
if (ffPathExists(result->chars, FF_PATHTYPE_FILE))
return true;
}
return false;
}
#ifdef _WIN32
HANDLE openat(HANDLE dfd, const char* fileName, bool directory);
#endif