mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-27 23:30:47 +01:00
Chore: run clang-format
```bash find . -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" \) ! -path "src/3rdparty/*" -print0 | xargs -0 clang-format -i ```
This commit is contained in:
@@ -3,8 +3,7 @@
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/FFlist.h"
|
||||
|
||||
typedef struct FFPlatformSysinfo
|
||||
{
|
||||
typedef struct FFPlatformSysinfo {
|
||||
FFstrbuf name;
|
||||
FFstrbuf release;
|
||||
FFstrbuf version;
|
||||
@@ -12,8 +11,7 @@ typedef struct FFPlatformSysinfo
|
||||
uint32_t pageSize;
|
||||
} FFPlatformSysinfo;
|
||||
|
||||
typedef struct FFPlatform
|
||||
{
|
||||
typedef struct FFPlatform {
|
||||
FFstrbuf homeDir; // Trailing slash included
|
||||
FFstrbuf cacheDir; // Trailing slash included
|
||||
FFlist configDirs; // List of FFstrbuf, trailing slash included
|
||||
@@ -22,11 +20,11 @@ typedef struct FFPlatform
|
||||
FFstrbuf cwd; // Trailing slash included
|
||||
|
||||
uint32_t pid;
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
uint32_t uid;
|
||||
#else
|
||||
#else
|
||||
FFstrbuf sid;
|
||||
#endif
|
||||
#endif
|
||||
FFstrbuf userName;
|
||||
FFstrbuf fullUserName;
|
||||
FFstrbuf hostName;
|
||||
|
||||
+12
-12
@@ -1,37 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <sal.h>
|
||||
# include <sal.h>
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__warn_unused_result__)
|
||||
#define FF_C_NODISCARD __attribute__((__warn_unused_result__))
|
||||
# define FF_C_NODISCARD __attribute__((__warn_unused_result__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define FF_C_NODISCARD _Check_return_
|
||||
# define FF_C_NODISCARD _Check_return_
|
||||
#else
|
||||
#define FF_C_NODISCARD
|
||||
# define FF_C_NODISCARD
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__format__)
|
||||
#define FF_C_PRINTF(formatStrIndex, argsStartIndex) __attribute__((__format__ (printf, formatStrIndex, argsStartIndex)))
|
||||
# define FF_C_PRINTF(formatStrIndex, argsStartIndex) __attribute__((__format__(printf, formatStrIndex, argsStartIndex)))
|
||||
#else
|
||||
#define FF_C_PRINTF(formatStrIndex, argsStartIndex)
|
||||
# define FF_C_PRINTF(formatStrIndex, argsStartIndex)
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__format__)
|
||||
#define FF_C_SCANF(formatStrIndex, argsStartIndex) __attribute__((__format__ (scanf, formatStrIndex, argsStartIndex)))
|
||||
# define FF_C_SCANF(formatStrIndex, argsStartIndex) __attribute__((__format__(scanf, formatStrIndex, argsStartIndex)))
|
||||
#else
|
||||
#define FF_C_SCANF(formatStrIndex, argsStartIndex)
|
||||
# define FF_C_SCANF(formatStrIndex, argsStartIndex)
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__nonnull__)
|
||||
#define FF_C_NONNULL(argIndex, ...) __attribute__((__nonnull__(argIndex, ##__VA_ARGS__)))
|
||||
# define FF_C_NONNULL(argIndex, ...) __attribute__((__nonnull__(argIndex, ##__VA_ARGS__)))
|
||||
#else
|
||||
#define FF_C_NONNULL(argIndex, ...)
|
||||
# define FF_C_NONNULL(argIndex, ...)
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__returns_nonnull__)
|
||||
#define FF_C_RETURNS_NONNULL __attribute__((__returns_nonnull__))
|
||||
# define FF_C_RETURNS_NONNULL __attribute__((__returns_nonnull__))
|
||||
#else
|
||||
#define FF_C_RETURNS_NONNULL
|
||||
# define FF_C_RETURNS_NONNULL
|
||||
#endif
|
||||
|
||||
+38
-50
@@ -9,8 +9,7 @@
|
||||
|
||||
#define FF_LIST_DEFAULT_ALLOC 16
|
||||
|
||||
typedef struct FFlist
|
||||
{
|
||||
typedef struct FFlist {
|
||||
uint8_t* data;
|
||||
uint32_t elementSize;
|
||||
uint32_t length;
|
||||
@@ -24,8 +23,7 @@ bool ffListShift(FFlist* list, void* result);
|
||||
// Removes the last element, and copy its value to `*result`
|
||||
bool ffListPop(FFlist* list, void* result);
|
||||
|
||||
static inline void ffListInit(FFlist* list, uint32_t elementSize)
|
||||
{
|
||||
static inline void ffListInit(FFlist* list, uint32_t elementSize) {
|
||||
assert(elementSize > 0);
|
||||
list->elementSize = elementSize;
|
||||
list->capacity = 0;
|
||||
@@ -33,112 +31,102 @@ static inline void ffListInit(FFlist* list, uint32_t elementSize)
|
||||
list->data = NULL;
|
||||
}
|
||||
|
||||
static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity)
|
||||
{
|
||||
static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) {
|
||||
ffListInit(list, elementSize);
|
||||
list->capacity = capacity;
|
||||
list->data = __builtin_expect(capacity == 0, 0) ? NULL : (uint8_t*) malloc((size_t)list->capacity * list->elementSize);
|
||||
list->data = __builtin_expect(capacity == 0, 0) ? NULL : (uint8_t*) malloc((size_t) list->capacity * list->elementSize);
|
||||
}
|
||||
|
||||
static inline FFlist ffListCreate(uint32_t elementSize)
|
||||
{
|
||||
static inline FFlist ffListCreate(uint32_t elementSize) {
|
||||
FFlist result;
|
||||
ffListInit(&result, elementSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void* ffListGet(const FFlist* list, uint32_t index)
|
||||
{
|
||||
static inline void* ffListGet(const FFlist* list, uint32_t index) {
|
||||
assert(list->capacity > index);
|
||||
return list->data + (index * list->elementSize);
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*))
|
||||
{
|
||||
for(uint32_t i = 0; i < list->length; i++)
|
||||
{
|
||||
if(compFunc(ffListGet(list, i), compElement))
|
||||
FF_C_NODISCARD static inline uint32_t ffListFirstIndexComp(const FFlist* list, void* compElement, bool (*compFunc)(const void*, const void*)) {
|
||||
for (uint32_t i = 0; i < list->length; i++) {
|
||||
if (compFunc(ffListGet(list, i), compElement)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return list->length;
|
||||
}
|
||||
|
||||
static inline bool ffListContains(const FFlist* list, void* compElement, bool(*compFunc)(const void*, const void*))
|
||||
{
|
||||
static inline bool ffListContains(const FFlist* list, void* compElement, bool (*compFunc)(const void*, const void*)) {
|
||||
return ffListFirstIndexComp(list, compElement, compFunc) != list->length;
|
||||
}
|
||||
|
||||
static inline void ffListSort(FFlist* list, int(*compar)(const void*, const void*))
|
||||
{
|
||||
static inline void ffListSort(FFlist* list, int (*compar)(const void*, const void*)) {
|
||||
qsort(list->data, list->length, list->elementSize, compar);
|
||||
}
|
||||
|
||||
// Move the contents of `src` into `list`, and left `src` empty
|
||||
static inline void ffListInitMove(FFlist* list, FFlist* src)
|
||||
{
|
||||
if (src)
|
||||
{
|
||||
static inline void ffListInitMove(FFlist* list, FFlist* src) {
|
||||
if (src) {
|
||||
list->elementSize = src->elementSize;
|
||||
list->capacity = src->capacity;
|
||||
list->length = src->length;
|
||||
list->data = src->data;
|
||||
ffListInit(src, list->elementSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffListInit(list, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ffListDestroy(FFlist* list)
|
||||
{
|
||||
if (!list->data) return;
|
||||
static inline void ffListDestroy(FFlist* list) {
|
||||
if (!list->data) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Avoid free-after-use. These 3 assignments are cheap so don't remove them
|
||||
// Avoid free-after-use. These 3 assignments are cheap so don't remove them
|
||||
list->capacity = list->length = 0;
|
||||
free(list->data);
|
||||
list->data = NULL;
|
||||
}
|
||||
|
||||
static inline void ffListClear(FFlist* list)
|
||||
{
|
||||
static inline void ffListClear(FFlist* list) {
|
||||
list->length = 0;
|
||||
}
|
||||
|
||||
static inline void ffListReserve(FFlist* list, uint32_t newCapacity)
|
||||
{
|
||||
if (__builtin_expect(newCapacity <= list->capacity, false))
|
||||
static inline void ffListReserve(FFlist* list, uint32_t newCapacity) {
|
||||
if (__builtin_expect(newCapacity <= list->capacity, false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
list->data = (uint8_t*) realloc(list->data, (size_t) newCapacity * list->elementSize);
|
||||
list->capacity = newCapacity;
|
||||
}
|
||||
|
||||
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
|
||||
assert(sizeof(itemType) == (listVar).elementSize); \
|
||||
for(itemType* itemVarName = (itemType*)(listVar).data; \
|
||||
itemVarName - (itemType*)(listVar).data < (intptr_t)(listVar).length; \
|
||||
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
|
||||
assert(sizeof(itemType) == (listVar).elementSize); \
|
||||
for (itemType* itemVarName = (itemType*) (listVar).data; \
|
||||
itemVarName - (itemType*) (listVar).data < (intptr_t) (listVar).length; \
|
||||
++itemVarName)
|
||||
|
||||
#define FF_LIST_AUTO_DESTROY FFlist __attribute__((__cleanup__(ffListDestroy)))
|
||||
|
||||
#define FF_LIST_GET(itemType, listVar, index) \
|
||||
({ \
|
||||
#define FF_LIST_GET(itemType, listVar, index) \
|
||||
({ \
|
||||
assert(sizeof(itemType) == (listVar).elementSize); \
|
||||
assert((listVar).capacity > (index)); \
|
||||
(itemType*)(listVar).data + (index); \
|
||||
assert((listVar).capacity > (index)); \
|
||||
(itemType*) (listVar).data + (index); \
|
||||
})
|
||||
|
||||
#define FF_LIST_ADD(itemType, listVar) \
|
||||
({ \
|
||||
#define FF_LIST_ADD(itemType, listVar) \
|
||||
({ \
|
||||
assert(sizeof(itemType) == (listVar).elementSize); \
|
||||
(itemType*) ffListAdd(&(listVar)); \
|
||||
(itemType*) ffListAdd(&(listVar)); \
|
||||
})
|
||||
|
||||
#define FF_LIST_FIRST(itemType, listVar) FF_LIST_GET(itemType, listVar, 0)
|
||||
#define FF_LIST_LAST(itemType, listVar) \
|
||||
({ \
|
||||
assert((listVar).length > 0); \
|
||||
#define FF_LIST_LAST(itemType, listVar) \
|
||||
({ \
|
||||
assert((listVar).length > 0); \
|
||||
FF_LIST_GET(itemType, listVar, ((listVar).length - 1)); \
|
||||
})
|
||||
|
||||
+128
-192
@@ -11,23 +11,22 @@
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef FF_USE_SYSTEM_YYJSON
|
||||
#include <yyjson.h>
|
||||
# include <yyjson.h>
|
||||
#else
|
||||
#include "3rdparty/yyjson/yyjson.h"
|
||||
# include "3rdparty/yyjson/yyjson.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// #include <shlwapi.h>
|
||||
__stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch);
|
||||
#define strcasestr StrStrIA
|
||||
// #include <shlwapi.h>
|
||||
__stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch);
|
||||
# define strcasestr StrStrIA
|
||||
#endif
|
||||
|
||||
#define FASTFETCH_STRBUF_DEFAULT_ALLOC 32
|
||||
|
||||
// static string (allocated == 0), chars points to a string literal
|
||||
// dynamic string (allocated > 0), chars points to a heap allocated buffer
|
||||
typedef struct FFstrbuf
|
||||
{
|
||||
typedef struct FFstrbuf {
|
||||
uint32_t allocated;
|
||||
uint32_t length;
|
||||
char* chars;
|
||||
@@ -47,8 +46,9 @@ static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* _
|
||||
void ffStrbufAppendC(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c);
|
||||
void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value);
|
||||
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int));
|
||||
FF_C_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
|
||||
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transformFunc)(int));
|
||||
FF_C_PRINTF(2, 3)
|
||||
void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
|
||||
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments);
|
||||
const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until);
|
||||
|
||||
@@ -61,7 +61,8 @@ void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c);
|
||||
// NOTE: Unlike ffStrbufAppend*, ffStrbufSet* functions may NOT reserve extra space
|
||||
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value);
|
||||
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value);
|
||||
FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
|
||||
FF_C_PRINTF(2, 3)
|
||||
void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
|
||||
|
||||
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
|
||||
@@ -126,16 +127,14 @@ void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf
|
||||
*
|
||||
* @return true if a line has been read, false if the end of the buffer has been reached.
|
||||
*/
|
||||
static inline bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer) {
|
||||
return ffStrbufGetdelim(lineptr, n, '\n', buffer);
|
||||
}
|
||||
/**
|
||||
* @brief Restore the end of a line that was modified by ffStrbufGetline.
|
||||
* @warning This function should be called before breaking an ffStrbufGetline loop if `buffer` will be used later.
|
||||
*/
|
||||
static inline void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
{
|
||||
static inline void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer) {
|
||||
ffStrbufGetdelimRestore(lineptr, n, '\n', buffer);
|
||||
}
|
||||
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf);
|
||||
@@ -152,60 +151,51 @@ void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
|
||||
// if `precision < 0`, let yyjson decide the precision
|
||||
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros);
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInitA(&strbuf, allocate);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict src)
|
||||
{
|
||||
if (src->allocated == 0) // static string
|
||||
static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict src) {
|
||||
if (src->allocated == 0) { // static string
|
||||
*strbuf = *src;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufInitA(strbuf, src->allocated);
|
||||
ffStrbufAppend(strbuf, src);
|
||||
}
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateCopy(const FFstrbuf* src)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateCopy(const FFstrbuf* src) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInitCopy(&strbuf, src);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
// Move the content of `src` into `strbuf`, and left `src` empty
|
||||
static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src)
|
||||
{
|
||||
if (src)
|
||||
{
|
||||
static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src) {
|
||||
if (src) {
|
||||
*strbuf = *src;
|
||||
ffStrbufInit(src);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
ffStrbufInit(strbuf);
|
||||
}
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateMove(FFstrbuf* src)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateMove(FFstrbuf* src) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInitMove(&strbuf, src);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateVF(const char* format, va_list arguments)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateVF(const char* format, va_list arguments) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInitVF(&strbuf, format, arguments);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
FF_C_PRINTF(2, 3)
|
||||
static inline void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...)
|
||||
{
|
||||
static inline void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...) {
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
ffStrbufInitVF(strbuf, format, arguments);
|
||||
@@ -213,8 +203,7 @@ static inline void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...)
|
||||
}
|
||||
|
||||
FF_C_PRINTF(1, 2)
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateF(const char* format, ...)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateF(const char* format, ...) {
|
||||
FFstrbuf strbuf;
|
||||
|
||||
va_list arguments;
|
||||
@@ -225,50 +214,46 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateF(const char* format, ...)
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr)
|
||||
{
|
||||
static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr) {
|
||||
ffStrbufInitMoveNS(strbuf, (uint32_t) strlen(heapStr), heapStr);
|
||||
}
|
||||
|
||||
// Despite the name, this function resets strbuf to the initial/unallocated state
|
||||
static inline void ffStrbufDestroy(FFstrbuf* strbuf)
|
||||
{
|
||||
if(strbuf->allocated > 0)
|
||||
static inline void ffStrbufDestroy(FFstrbuf* strbuf) {
|
||||
if (strbuf->allocated > 0) {
|
||||
free(strbuf->chars);
|
||||
}
|
||||
|
||||
ffStrbufInit(strbuf);
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf)
|
||||
{
|
||||
FF_C_NODISCARD static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf) {
|
||||
assert(strbuf != NULL);
|
||||
if(strbuf->allocated == 0)
|
||||
if (strbuf->allocated == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return strbuf->allocated - strbuf->length - 1; // - 1 for the null byte
|
||||
}
|
||||
|
||||
static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf)
|
||||
{
|
||||
static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf) {
|
||||
strbuf->length = (uint32_t) strlen(strbuf->chars);
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value)
|
||||
{
|
||||
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value) {
|
||||
assert(strbuf != NULL);
|
||||
|
||||
if (value == NULL)
|
||||
if (value == NULL) {
|
||||
ffStrbufClear(strbuf);
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetNS(strbuf, (uint32_t) strlen(value), value);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
|
||||
{
|
||||
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
|
||||
assert(strbuf != NULL);
|
||||
|
||||
if (yyjson_is_str(jsonVal))
|
||||
{
|
||||
if (yyjson_is_str(jsonVal)) {
|
||||
ffStrbufSetNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
|
||||
return true;
|
||||
}
|
||||
@@ -277,354 +262,305 @@ static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value)
|
||||
{
|
||||
if(value == NULL)
|
||||
static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value) {
|
||||
if (value == NULL) {
|
||||
return;
|
||||
}
|
||||
ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufAppendJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
|
||||
{
|
||||
if (yyjson_is_str(jsonVal))
|
||||
{
|
||||
static inline bool ffStrbufAppendJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
|
||||
if (yyjson_is_str(jsonVal)) {
|
||||
ffStrbufAppendNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void ffStrbufInit(FFstrbuf* strbuf)
|
||||
{
|
||||
static inline void ffStrbufInit(FFstrbuf* strbuf) {
|
||||
extern char* CHAR_NULL_PTR;
|
||||
strbuf->allocated = strbuf->length = 0;
|
||||
strbuf->chars = CHAR_NULL_PTR;
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreate(void)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreate(void) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInit(&strbuf);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitStatic(FFstrbuf* strbuf, const char* str)
|
||||
{
|
||||
static inline void ffStrbufInitStatic(FFstrbuf* strbuf, const char* str) {
|
||||
ffStrbufInit(strbuf);
|
||||
if (!str) return;
|
||||
if (!str) {
|
||||
return;
|
||||
}
|
||||
|
||||
strbuf->allocated = 0;
|
||||
strbuf->length = (uint32_t) strlen(str);
|
||||
strbuf->chars = (char*) str;
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateStatic(const char* str)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateStatic(const char* str) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInitStatic(&strbuf, str);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value)
|
||||
{
|
||||
if(strbuf->allocated > 0)
|
||||
static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value) {
|
||||
if (strbuf->allocated > 0) {
|
||||
free(strbuf->chars);
|
||||
}
|
||||
|
||||
if(value != NULL)
|
||||
if (value != NULL) {
|
||||
ffStrbufInitStatic(strbuf, value);
|
||||
else
|
||||
} else {
|
||||
ffStrbufInit(strbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str)
|
||||
{
|
||||
static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str) {
|
||||
ffStrbufInit(strbuf);
|
||||
ffStrbufAppendNS(strbuf, length, str);
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateNS(uint32_t length, const char* str)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateNS(uint32_t length, const char* str) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInitNS(&strbuf, length, str);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline bool ffStrbufInitJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
|
||||
{
|
||||
static inline bool ffStrbufInitJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
|
||||
ffStrbufInit(strbuf);
|
||||
return ffStrbufAppendJsonVal(strbuf, jsonVal);
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str)
|
||||
{
|
||||
static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) {
|
||||
ffStrbufInit(strbuf);
|
||||
ffStrbufAppendS(strbuf, str);
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateS(const char* str)
|
||||
{
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateS(const char* str) {
|
||||
FFstrbuf strbuf;
|
||||
ffStrbufInitS(&strbuf, str);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value)
|
||||
{
|
||||
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value) {
|
||||
assert(value != strbuf);
|
||||
if(value == NULL)
|
||||
if (value == NULL) {
|
||||
return;
|
||||
}
|
||||
ffStrbufAppendNS(strbuf, value->length, value->chars);
|
||||
}
|
||||
|
||||
static inline void ffStrbufPrepend(FFstrbuf* strbuf, FFstrbuf* value)
|
||||
{
|
||||
if(value == NULL)
|
||||
static inline void ffStrbufPrepend(FFstrbuf* strbuf, FFstrbuf* value) {
|
||||
if (value == NULL) {
|
||||
return;
|
||||
}
|
||||
ffStrbufPrependNS(strbuf, value->length, value->chars);
|
||||
}
|
||||
|
||||
static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value)
|
||||
{
|
||||
if(value == NULL)
|
||||
static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) {
|
||||
if (value == NULL) {
|
||||
return;
|
||||
}
|
||||
ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
|
||||
uint32_t length = strbuf->length > comp->length ? comp->length : strbuf->length;
|
||||
return memcmp(strbuf->chars, comp->chars, length + 1);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEqual(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
|
||||
return ffStrbufComp(strbuf, comp) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp) {
|
||||
return strcmp(strbuf->chars, comp);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEqualS(const FFstrbuf* strbuf, const char* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufEqualS(const FFstrbuf* strbuf, const char* comp) {
|
||||
return ffStrbufCompS(strbuf, comp) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp) {
|
||||
return strcasecmp(strbuf->chars, comp);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufIgnCaseEqualS(const FFstrbuf* strbuf, const char* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufIgnCaseEqualS(const FFstrbuf* strbuf, const char* comp) {
|
||||
return ffStrbufIgnCaseCompS(strbuf, comp) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
|
||||
return ffStrbufIgnCaseCompS(strbuf, comp->chars);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufIgnCaseEqual(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufIgnCaseEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
|
||||
return ffStrbufIgnCaseComp(strbuf, comp) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainC(const FFstrbuf* strbuf, char c)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainC(const FFstrbuf* strbuf, char c) {
|
||||
return memchr(strbuf->chars, c, strbuf->length) != NULL;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainS(const FFstrbuf* strbuf, const char* str)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainS(const FFstrbuf* strbuf, const char* str) {
|
||||
return strstr(strbuf->chars, str) != NULL;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufContain(const FFstrbuf* strbuf, const FFstrbuf* str)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufContain(const FFstrbuf* strbuf, const FFstrbuf* str) {
|
||||
return ffStrbufContainS(strbuf, str->chars);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainIgnCaseS(const FFstrbuf* strbuf, const char* str)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainIgnCaseS(const FFstrbuf* strbuf, const char* str) {
|
||||
return strcasestr(strbuf->chars, str) != NULL;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* str)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* str) {
|
||||
return ffStrbufContainIgnCaseS(strbuf, str->chars);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c)
|
||||
{
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) {
|
||||
return ffStrbufNextIndexC(strbuf, 0, c);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched)
|
||||
{
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched) {
|
||||
return ffStrbufNextIndexS(strbuf, 0, searched->chars);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str)
|
||||
{
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str) {
|
||||
return ffStrbufNextIndexS(strbuf, 0, str);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c)
|
||||
{
|
||||
if(strbuf->length == 0)
|
||||
static inline FF_C_NODISCARD uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c) {
|
||||
if (strbuf->length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ffStrbufPreviousIndexC(strbuf, strbuf->length - 1, c);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSubstrBeforeFirstC(FFstrbuf* strbuf, char c)
|
||||
{
|
||||
static inline bool ffStrbufSubstrBeforeFirstC(FFstrbuf* strbuf, char c) {
|
||||
return ffStrbufSubstrBefore(strbuf, ffStrbufFirstIndexC(strbuf, c));
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c)
|
||||
{
|
||||
static inline bool ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c) {
|
||||
return ffStrbufSubstrBefore(strbuf, ffStrbufLastIndexC(strbuf, c));
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithC(const FFstrbuf* strbuf, char c)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithC(const FFstrbuf* strbuf, char c) {
|
||||
return strbuf->chars[0] == c;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, const char* start, uint32_t length)
|
||||
{
|
||||
if (length > strbuf->length)
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, const char* start, uint32_t length) {
|
||||
if (length > strbuf->length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(strbuf->chars, start, length) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start) {
|
||||
return ffStrbufStartsWithSN(strbuf, start, (uint32_t) strlen(start));
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWith(const FFstrbuf* strbuf, const FFstrbuf* start)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWith(const FFstrbuf* strbuf, const FFstrbuf* start) {
|
||||
return ffStrbufStartsWithSN(strbuf, start->chars, start->length);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t length, const char* start)
|
||||
{
|
||||
if(length > strbuf->length)
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t length, const char* start) {
|
||||
if (length > strbuf->length) {
|
||||
return false;
|
||||
}
|
||||
return strncasecmp(strbuf->chars, start, length) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) {
|
||||
return ffStrbufStartsWithIgnCaseNS(strbuf, (uint32_t) strlen(start), start);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) {
|
||||
return ffStrbufStartsWithIgnCaseNS(strbuf, start->length, start->chars);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c)
|
||||
{
|
||||
return strbuf->length == 0 ? false :
|
||||
strbuf->chars[strbuf->length - 1] == c;
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) {
|
||||
return strbuf->length == 0 ? false : strbuf->chars[strbuf->length - 1] == c;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end)
|
||||
{
|
||||
if(endLength > strbuf->length)
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
|
||||
if (endLength > strbuf->length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return memcmp(strbuf->chars + strbuf->length - endLength, end, endLength) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) {
|
||||
return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int))
|
||||
{
|
||||
return strbuf->length == 0 ? false :
|
||||
fn(strbuf->chars[strbuf->length - 1]);
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int)) {
|
||||
return strbuf->length == 0 ? false : fn(strbuf->chars[strbuf->length - 1]);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end) {
|
||||
return ffStrbufEndsWithNS(strbuf, end->length, end->chars);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end)
|
||||
{
|
||||
if(endLength > strbuf->length)
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
|
||||
if (endLength > strbuf->length) {
|
||||
return false;
|
||||
}
|
||||
return strcasecmp(strbuf->chars + strbuf->length - endLength, end) == 0;
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end) {
|
||||
return ffStrbufEndsWithIgnCaseNS(strbuf, (uint32_t) strlen(end), end);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* end)
|
||||
{
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* end) {
|
||||
return ffStrbufEndsWithIgnCaseNS(strbuf, end->length, end->chars);
|
||||
}
|
||||
|
||||
static inline void ffStrbufTrim(FFstrbuf* strbuf, char c)
|
||||
{
|
||||
static inline void ffStrbufTrim(FFstrbuf* strbuf, char c) {
|
||||
ffStrbufTrimRight(strbuf, c);
|
||||
ffStrbufTrimLeft(strbuf, c);
|
||||
}
|
||||
|
||||
static inline void ffStrbufTrimSpace(FFstrbuf* strbuf)
|
||||
{
|
||||
static inline void ffStrbufTrimSpace(FFstrbuf* strbuf) {
|
||||
ffStrbufTrimRightSpace(strbuf);
|
||||
ffStrbufTrimLeftSpace(strbuf);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufMatchSeparatedS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufMatchSeparatedS(const FFstrbuf* strbuf, const char* comp, char separator) {
|
||||
return ffStrbufMatchSeparatedNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufMatchSeparated(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufMatchSeparated(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator) {
|
||||
return ffStrbufMatchSeparatedNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufMatchSeparatedIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufMatchSeparatedIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator) {
|
||||
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufMatchSeparatedIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufMatchSeparatedIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator) {
|
||||
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContainS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufSeparatedContainS(const FFstrbuf* strbuf, const char* comp, char separator) {
|
||||
return ffStrbufSeparatedContainNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContain(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufSeparatedContain(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator) {
|
||||
return ffStrbufSeparatedContainNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContainIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufSeparatedContainIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator) {
|
||||
return ffStrbufSeparatedContainIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
|
||||
{
|
||||
static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator) {
|
||||
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,184 +1,183 @@
|
||||
#include "cf_helpers.h"
|
||||
|
||||
const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result)
|
||||
{
|
||||
if(CFGetTypeID(cf) == CFNumberGetTypeID())
|
||||
{
|
||||
if(!CFNumberGetValue((CFNumberRef)cf, kCFNumberSInt64Type, result))
|
||||
const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result) {
|
||||
if (CFGetTypeID(cf) == CFNumberGetTypeID()) {
|
||||
if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt64Type, result)) {
|
||||
return "Number type is not SInt64";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else if(CFGetTypeID(cf) == CFDataGetTypeID())
|
||||
{
|
||||
if(CFDataGetLength((CFDataRef)cf) != sizeof(int64_t))
|
||||
} else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
|
||||
if (CFDataGetLength((CFDataRef) cf) != sizeof(int64_t)) {
|
||||
return "Data length is not sizeof(int64_t)";
|
||||
CFDataGetBytes((CFDataRef)cf, CFRangeMake(0, sizeof(int64_t)), (uint8_t*)result);
|
||||
}
|
||||
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(int64_t)), (uint8_t*) result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "TypeID is neither 'CFNumber' nor 'CFData'";
|
||||
}
|
||||
|
||||
const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result)
|
||||
{
|
||||
if(CFGetTypeID(cf) == CFNumberGetTypeID())
|
||||
{
|
||||
if(!CFNumberGetValue((CFNumberRef)cf, kCFNumberSInt32Type, result))
|
||||
const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result) {
|
||||
if (CFGetTypeID(cf) == CFNumberGetTypeID()) {
|
||||
if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt32Type, result)) {
|
||||
return "Number type is not SInt32";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else if(CFGetTypeID(cf) == CFDataGetTypeID())
|
||||
{
|
||||
if(CFDataGetLength((CFDataRef)cf) != sizeof(int))
|
||||
} else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
|
||||
if (CFDataGetLength((CFDataRef) cf) != sizeof(int)) {
|
||||
return "Data length is not sizeof(int)";
|
||||
CFDataGetBytes((CFDataRef)cf, CFRangeMake(0, sizeof(int)), (uint8_t*)result);
|
||||
}
|
||||
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(int)), (uint8_t*) result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "TypeID is neither 'CFNumber' nor 'CFData'";
|
||||
}
|
||||
|
||||
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
|
||||
{
|
||||
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
|
||||
ffStrbufClear(result);
|
||||
if (!cf)
|
||||
if (!cf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CFGetTypeID(cf) == CFStringGetTypeID())
|
||||
{
|
||||
CFStringRef cfStr = (CFStringRef)cf;
|
||||
if (CFGetTypeID(cf) == CFStringGetTypeID()) {
|
||||
CFStringRef cfStr = (CFStringRef) cf;
|
||||
|
||||
const char* cstr = CFStringGetCStringPtr(cfStr, kCFStringEncodingUTF8);
|
||||
if (cstr)
|
||||
if (cstr) {
|
||||
ffStrbufSetS(result, cstr);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint32_t length = (uint32_t) CFStringGetLength(cfStr);
|
||||
if (length == 0)
|
||||
if (length == 0) {
|
||||
return NULL;
|
||||
}
|
||||
ffStrbufEnsureFixedLengthFree(result, (uint32_t) CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8));
|
||||
if(!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8))
|
||||
if (!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) {
|
||||
return "CFStringGetCString() failed";
|
||||
}
|
||||
// CFStringGetCString ensures the buffer is NUL terminated
|
||||
// https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring
|
||||
result->length = (uint32_t) strnlen(result->chars, (uint32_t)result->allocated);
|
||||
result->length = (uint32_t) strnlen(result->chars, (uint32_t) result->allocated);
|
||||
}
|
||||
}
|
||||
else if (CFGetTypeID(cf) == CFDataGetTypeID())
|
||||
{
|
||||
CFDataRef cfData = (CFDataRef)cf;
|
||||
uint32_t length = (uint32_t)CFDataGetLength(cfData);
|
||||
if (length == 0)
|
||||
} else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
|
||||
CFDataRef cfData = (CFDataRef) cf;
|
||||
uint32_t length = (uint32_t) CFDataGetLength(cfData);
|
||||
if (length == 0) {
|
||||
return NULL;
|
||||
}
|
||||
ffStrbufEnsureFixedLengthFree(result, length + 1);
|
||||
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars);
|
||||
result->length = (uint32_t)strnlen(result->chars, length);
|
||||
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*) result->chars);
|
||||
result->length = (uint32_t) strnlen(result->chars, length);
|
||||
result->chars[result->length] = '\0';
|
||||
}
|
||||
else
|
||||
} else {
|
||||
return "TypeID is neither 'CFString' nor 'CFData'";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result)
|
||||
{
|
||||
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result) {
|
||||
ffStrbufClear(result);
|
||||
if (!cf)
|
||||
if (!cf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CFGetTypeID(cf) == CFDataGetTypeID())
|
||||
{
|
||||
CFDataRef cfData = (CFDataRef)cf;
|
||||
uint32_t length = (uint32_t)CFDataGetLength(cfData);
|
||||
if (length == 0)
|
||||
if (CFGetTypeID(cf) == CFDataGetTypeID()) {
|
||||
CFDataRef cfData = (CFDataRef) cf;
|
||||
uint32_t length = (uint32_t) CFDataGetLength(cfData);
|
||||
if (length == 0) {
|
||||
return NULL;
|
||||
}
|
||||
ffStrbufEnsureFixedLengthFree(result, length + 1);
|
||||
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars);
|
||||
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*) result->chars);
|
||||
result->length = length;
|
||||
result->chars[result->length] = '\0';
|
||||
}
|
||||
else
|
||||
} else {
|
||||
return "TypeID is not 'CFData'";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result)
|
||||
{
|
||||
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
|
||||
if(cf == NULL)
|
||||
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
return ffCfStrGetString(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result)
|
||||
{
|
||||
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
|
||||
if(cf == NULL)
|
||||
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
return ffCfDataGetDataAsString(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result)
|
||||
{
|
||||
CFBooleanRef cf = (CFBooleanRef)CFDictionaryGetValue(dict, key);
|
||||
if(cf == NULL)
|
||||
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) {
|
||||
CFBooleanRef cf = (CFBooleanRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
if(CFGetTypeID(cf) != CFBooleanGetTypeID())
|
||||
if (CFGetTypeID(cf) != CFBooleanGetTypeID()) {
|
||||
return "TypeID is not 'CFBoolean'";
|
||||
}
|
||||
|
||||
*result = CFBooleanGetValue(cf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result)
|
||||
{
|
||||
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
|
||||
if(cf == NULL)
|
||||
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
return ffCfNumGetInt(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result)
|
||||
{
|
||||
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
|
||||
if(cf == NULL)
|
||||
const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
return ffCfNumGetInt64(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length)
|
||||
{
|
||||
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
|
||||
if(cf == NULL)
|
||||
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
if(CFGetTypeID(cf) != CFDataGetTypeID())
|
||||
if (CFGetTypeID(cf) != CFDataGetTypeID()) {
|
||||
return "TypeID is not 'CFData'";
|
||||
}
|
||||
|
||||
CFIndex trueLength = CFDataGetLength((CFDataRef)cf);
|
||||
CFIndex trueLength = CFDataGetLength((CFDataRef) cf);
|
||||
|
||||
if(trueLength < offset + size)
|
||||
if (trueLength < offset + size) {
|
||||
return "Data length is less than offset + size";
|
||||
}
|
||||
|
||||
if(length)
|
||||
if (length) {
|
||||
*length = (uint32_t) trueLength;
|
||||
}
|
||||
|
||||
CFDataGetBytes((CFDataRef)cf, CFRangeMake(offset, size), result);
|
||||
CFDataGetBytes((CFDataRef) cf, CFRangeMake(offset, size), result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result)
|
||||
{
|
||||
CFDictionaryRef cf = (CFDictionaryRef)CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL || CFGetTypeID(cf) != CFDictionaryGetTypeID())
|
||||
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result) {
|
||||
CFDictionaryRef cf = (CFDictionaryRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL || CFGetTypeID(cf) != CFDictionaryGetTypeID()) {
|
||||
return "TypeID is not 'CFDictionary'";
|
||||
}
|
||||
|
||||
*result = cf;
|
||||
return NULL;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
//Return error info if failed, NULL otherwise
|
||||
// Return error info if failed, NULL otherwise
|
||||
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result);
|
||||
const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result);
|
||||
const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result);
|
||||
@@ -17,24 +17,23 @@ const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offs
|
||||
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
|
||||
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result);
|
||||
|
||||
static inline CFNumberRef ffCfCreateInt(int value)
|
||||
{
|
||||
static inline CFNumberRef ffCfCreateInt(int value) {
|
||||
return CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value);
|
||||
}
|
||||
|
||||
static inline void cfReleaseWrapper(void* type)
|
||||
{
|
||||
static inline void cfReleaseWrapper(void* type) {
|
||||
assert(type);
|
||||
if (*(CFTypeRef*) type)
|
||||
if (*(CFTypeRef*) type) {
|
||||
CFRelease(*(CFTypeRef*) type);
|
||||
}
|
||||
}
|
||||
|
||||
#define FF_CFTYPE_AUTO_RELEASE __attribute__((__cleanup__(cfReleaseWrapper)))
|
||||
|
||||
static inline void wrapIoObjectRelease(io_object_t* service)
|
||||
{
|
||||
static inline void wrapIoObjectRelease(io_object_t* service) {
|
||||
assert(service);
|
||||
if (*service)
|
||||
if (*service) {
|
||||
IOObjectRelease(*service);
|
||||
}
|
||||
}
|
||||
#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease)))
|
||||
|
||||
+263
-246
@@ -60,66 +60,64 @@ typedef struct
|
||||
SmcBytes_t bytes;
|
||||
} SmcVal_t;
|
||||
|
||||
static uint32_t smcStrtoul(const char *str, int size, int base)
|
||||
{
|
||||
static uint32_t smcStrtoul(const char* str, int size, int base) {
|
||||
uint32_t total = 0;
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (base == 16)
|
||||
total += (uint32_t)(str[i] << (size - 1 - i) * 8);
|
||||
else
|
||||
total += (uint32_t)((unsigned char)(str[i]) << (size - 1 - i) * 8);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (base == 16) {
|
||||
total += (uint32_t) (str[i] << (size - 1 - i) * 8);
|
||||
} else {
|
||||
total += (uint32_t) ((unsigned char) (str[i]) << (size - 1 - i) * 8);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static void smcUltostr(char *str, uint32_t val)
|
||||
{
|
||||
str[0] = (char)(val >> 24);
|
||||
str[1] = (char)(val >> 16);
|
||||
str[2] = (char)(val >> 8);
|
||||
str[3] = (char)val;
|
||||
static void smcUltostr(char* str, uint32_t val) {
|
||||
str[0] = (char) (val >> 24);
|
||||
str[1] = (char) (val >> 16);
|
||||
str[2] = (char) (val >> 8);
|
||||
str[3] = (char) val;
|
||||
str[4] = '\0';
|
||||
}
|
||||
|
||||
static const char *smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t *inputStructure, SmcKeyData_t *outputStructure)
|
||||
{
|
||||
static const char* smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t* inputStructure, SmcKeyData_t* outputStructure) {
|
||||
size_t size = sizeof(SmcKeyData_t);
|
||||
|
||||
if (IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size) != kIOReturnSuccess)
|
||||
if (IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size) != kIOReturnSuccess) {
|
||||
return "IOConnectCallStructMethod(conn) failed";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Provides key info, using a cache to dramatically improve the energy impact of smcFanControl
|
||||
static const char *smcGetKeyInfo(io_connect_t conn, const uint32_t key, SmcKeyData_keyInfo_t *key_info)
|
||||
{
|
||||
static const char* smcGetKeyInfo(io_connect_t conn, const uint32_t key, SmcKeyData_keyInfo_t* key_info) {
|
||||
SmcKeyData_t inputStructure = {0};
|
||||
SmcKeyData_t outputStructure = {0};
|
||||
|
||||
inputStructure.key = key;
|
||||
inputStructure.data8 = kSmcCmdReadKeyInfo;
|
||||
|
||||
const char *error = smcCall(conn, kKernelIndexSmc, &inputStructure, &outputStructure);
|
||||
if (error)
|
||||
const char* error = smcCall(conn, kKernelIndexSmc, &inputStructure, &outputStructure);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
*key_info = outputStructure.keyInfo;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcVal_t *val)
|
||||
{
|
||||
static const char* smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcVal_t* val) {
|
||||
SmcKeyData_t inputStructure = {0};
|
||||
SmcKeyData_t outputStructure = {0};
|
||||
|
||||
inputStructure.key = smcStrtoul(key, 4, 16);
|
||||
strcpy(val->key, key);
|
||||
|
||||
const char *error = smcGetKeyInfo(conn, inputStructure.key, &outputStructure.keyInfo);
|
||||
if (error)
|
||||
const char* error = smcGetKeyInfo(conn, inputStructure.key, &outputStructure.keyInfo);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
val->dataSize = outputStructure.keyInfo.dataSize;
|
||||
smcUltostr(val->dataType, outputStructure.keyInfo.dataType);
|
||||
@@ -127,132 +125,147 @@ static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV
|
||||
inputStructure.data8 = kSmcCmdReadBytes;
|
||||
|
||||
error = smcCall(conn, kKernelIndexSmc, &inputStructure, &outputStructure);
|
||||
if (error)
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *smcOpen(io_connect_t *conn)
|
||||
{
|
||||
static const char* smcOpen(io_connect_t* conn) {
|
||||
FF_IOOBJECT_AUTO_RELEASE io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC"));
|
||||
if (!device)
|
||||
if (!device) {
|
||||
return "No SMC device found";
|
||||
}
|
||||
|
||||
if (IOServiceOpen(device, mach_task_self(), 0, conn) != kIOReturnSuccess)
|
||||
if (IOServiceOpen(device, mach_task_self(), 0, conn) != kIOReturnSuccess) {
|
||||
return "IOServiceOpen() failed";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, double *value)
|
||||
{
|
||||
static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, double* value) {
|
||||
SmcVal_t val = {0};
|
||||
const char* error = smcReadSmcVal(conn, key, &val);
|
||||
if (error != NULL)
|
||||
if (error != NULL) {
|
||||
return error;
|
||||
if (val.dataSize == 0)
|
||||
}
|
||||
if (val.dataSize == 0) {
|
||||
return "Empty SMC result";
|
||||
}
|
||||
|
||||
switch (val.dataType[0])
|
||||
{
|
||||
switch (val.dataType[0]) {
|
||||
case 'u': // unsigned integer types
|
||||
if (val.dataType[1] == 'i')
|
||||
{
|
||||
switch (val.dataSize)
|
||||
{
|
||||
case 1: *value = *(uint8_t *)(val.bytes); break;
|
||||
case 2: *value = ntohs(*(uint16_t *)(val.bytes)); break;
|
||||
case 4: *value = ntohl(*(uint32_t *)(val.bytes)); break;
|
||||
case 8: *value = (double) ntohll(*(uint64_t *)(val.bytes)); break;
|
||||
if (val.dataType[1] == 'i') {
|
||||
switch (val.dataSize) {
|
||||
case 1:
|
||||
*value = *(uint8_t*) (val.bytes);
|
||||
break;
|
||||
case 2:
|
||||
*value = ntohs(*(uint16_t*) (val.bytes));
|
||||
break;
|
||||
case 4:
|
||||
*value = ntohl(*(uint32_t*) (val.bytes));
|
||||
break;
|
||||
case 8:
|
||||
*value = (double) ntohll(*(uint64_t*) (val.bytes));
|
||||
break;
|
||||
default:
|
||||
return "Unsupported SMC unsigned integer data size";
|
||||
}
|
||||
}
|
||||
else
|
||||
} else {
|
||||
return "Unsupported SMC unsigned data type";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f': // floating point types
|
||||
if (ffStrEquals(val.dataType, "flt ") && val.dataSize == 4)
|
||||
*value = *(float *)(val.bytes);
|
||||
else if (val.dataType[1] == 'p' && val.dataSize == 2) // fixed point types
|
||||
if (ffStrEquals(val.dataType, "flt ") && val.dataSize == 4) {
|
||||
*value = *(float*) (val.bytes);
|
||||
} else if (val.dataType[1] == 'p' && val.dataSize == 2) // fixed point types
|
||||
{
|
||||
if (ffStrEquals(val.dataType, "fp1f"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 32768.0;
|
||||
else if (ffStrEquals(val.dataType, "fp4c"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0;
|
||||
else if (ffStrEquals(val.dataType, "fp5b"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0;
|
||||
else if (ffStrEquals(val.dataType, "fp6a"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0;
|
||||
else if (ffStrEquals(val.dataType, "fp79"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 512.0;
|
||||
else if (ffStrEquals(val.dataType, "fp88"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 256.0;
|
||||
else if (ffStrEquals(val.dataType, "fpa6"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 64.0;
|
||||
else if (ffStrEquals(val.dataType, "fpc4"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 16.0;
|
||||
else if (ffStrEquals(val.dataType, "fpe2"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 4.0;
|
||||
else
|
||||
if (ffStrEquals(val.dataType, "fp1f")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 32768.0;
|
||||
} else if (ffStrEquals(val.dataType, "fp4c")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 4096.0;
|
||||
} else if (ffStrEquals(val.dataType, "fp5b")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 2048.0;
|
||||
} else if (ffStrEquals(val.dataType, "fp6a")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 1024.0;
|
||||
} else if (ffStrEquals(val.dataType, "fp79")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 512.0;
|
||||
} else if (ffStrEquals(val.dataType, "fp88")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 256.0;
|
||||
} else if (ffStrEquals(val.dataType, "fpa6")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 64.0;
|
||||
} else if (ffStrEquals(val.dataType, "fpc4")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 16.0;
|
||||
} else if (ffStrEquals(val.dataType, "fpe2")) {
|
||||
*value = ntohs(*(uint16_t*) (val.bytes)) / 4.0;
|
||||
} else {
|
||||
return "Unsupported SMC floating point data type";
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
return "Unsupported SMC floating point data type";
|
||||
}
|
||||
break;
|
||||
|
||||
case 's': // signed integer types
|
||||
if (val.dataType[1] == 'i')
|
||||
{
|
||||
switch (val.dataSize)
|
||||
{
|
||||
case 1: *value = *(int8_t *)(val.bytes); break;
|
||||
case 2: *value = ntohs(*(int16_t *)(val.bytes)); break;
|
||||
case 4: *value = ntohl(*(int32_t *)(val.bytes)); break;
|
||||
case 8: *value = (double)ntohll(*(int64_t *)(val.bytes)); break;
|
||||
default: return "Unsupported SMC signed integer data size";
|
||||
if (val.dataType[1] == 'i') {
|
||||
switch (val.dataSize) {
|
||||
case 1:
|
||||
*value = *(int8_t*) (val.bytes);
|
||||
break;
|
||||
case 2:
|
||||
*value = ntohs(*(int16_t*) (val.bytes));
|
||||
break;
|
||||
case 4:
|
||||
*value = ntohl(*(int32_t*) (val.bytes));
|
||||
break;
|
||||
case 8:
|
||||
*value = (double) ntohll(*(int64_t*) (val.bytes));
|
||||
break;
|
||||
default:
|
||||
return "Unsupported SMC signed integer data size";
|
||||
}
|
||||
}
|
||||
else if (val.dataType[1] == 'p' && val.dataSize == 2) // signed fixed point types
|
||||
} else if (val.dataType[1] == 'p' && val.dataSize == 2) // signed fixed point types
|
||||
{
|
||||
if (ffStrEquals(val.dataType, "sp1e"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 16384.0;
|
||||
else if (ffStrEquals(val.dataType, "sp3c"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 4096.0;
|
||||
else if (ffStrEquals(val.dataType, "sp4b"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 2048.0;
|
||||
else if (ffStrEquals(val.dataType, "sp5a"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 1024.0;
|
||||
else if (ffStrEquals(val.dataType, "sp69"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 512.0;
|
||||
else if (ffStrEquals(val.dataType, "sp78"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 256.0;
|
||||
else if (ffStrEquals(val.dataType, "sp87"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 128.0;
|
||||
else if (ffStrEquals(val.dataType, "sp96"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 64.0;
|
||||
else if (ffStrEquals(val.dataType, "spb4"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 16.0;
|
||||
else if (ffStrEquals(val.dataType, "spf0"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 1.0;
|
||||
else
|
||||
if (ffStrEquals(val.dataType, "sp1e")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 16384.0;
|
||||
} else if (ffStrEquals(val.dataType, "sp3c")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 4096.0;
|
||||
} else if (ffStrEquals(val.dataType, "sp4b")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 2048.0;
|
||||
} else if (ffStrEquals(val.dataType, "sp5a")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 1024.0;
|
||||
} else if (ffStrEquals(val.dataType, "sp69")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 512.0;
|
||||
} else if (ffStrEquals(val.dataType, "sp78")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 256.0;
|
||||
} else if (ffStrEquals(val.dataType, "sp87")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 128.0;
|
||||
} else if (ffStrEquals(val.dataType, "sp96")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 64.0;
|
||||
} else if (ffStrEquals(val.dataType, "spb4")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 16.0;
|
||||
} else if (ffStrEquals(val.dataType, "spf0")) {
|
||||
*value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 1.0;
|
||||
} else {
|
||||
return "Unsupported SMC signed integer data type";
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
return "Unsupported SMC signed data type";
|
||||
}
|
||||
break;
|
||||
|
||||
case '{': // special types like pwm
|
||||
if (ffStrEquals(val.dataType, "{pwm") && val.dataSize == 2)
|
||||
{
|
||||
*value = (double)ntohs(*(uint16_t *)(val.bytes)) * 100 / 65536.0;
|
||||
}
|
||||
else
|
||||
if (ffStrEquals(val.dataType, "{pwm") && val.dataSize == 2) {
|
||||
*value = (double) ntohs(*(uint16_t*) (val.bytes)) * 100 / 65536.0;
|
||||
} else {
|
||||
return "Unsupported SMC special data type";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -261,187 +274,191 @@ static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool detectTemp(io_connect_t conn, const char* sensor, double* sum)
|
||||
{
|
||||
static bool detectTemp(io_connect_t conn, const char* sensor, double* sum) {
|
||||
double temp = 0;
|
||||
const char* error = smcReadValue(conn, sensor, &temp);
|
||||
if (error) return false;
|
||||
if (error) {
|
||||
return false;
|
||||
}
|
||||
// https://github.com/exelban/stats/blob/14e29c4d60229c363cca9c9d25c30c87b7870830/Modules/Sensors/readers.swift#L124
|
||||
if (temp < 10 || temp > 120) return false;
|
||||
if (temp < 10 || temp > 120) {
|
||||
return false;
|
||||
}
|
||||
*sum += temp;
|
||||
return true;
|
||||
}
|
||||
|
||||
static io_connect_t conn;
|
||||
|
||||
const char* ffDetectSmcSpecificTemp(const char* sensor, double* result)
|
||||
{
|
||||
if (!conn)
|
||||
{
|
||||
if (smcOpen(&conn) != NULL)
|
||||
const char* ffDetectSmcSpecificTemp(const char* sensor, double* result) {
|
||||
if (!conn) {
|
||||
if (smcOpen(&conn) != NULL) {
|
||||
conn = (io_connect_t) -1;
|
||||
}
|
||||
}
|
||||
if (conn == (io_connect_t) -1)
|
||||
if (conn == (io_connect_t) -1) {
|
||||
return "Could not open SMC connection";
|
||||
}
|
||||
|
||||
if (!detectTemp(conn, sensor, result))
|
||||
if (!detectTemp(conn, sensor, result)) {
|
||||
return "Could not read SMC temperature";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectSmcTemps(enum FFTempType type, double* result)
|
||||
{
|
||||
if (!conn)
|
||||
{
|
||||
if (smcOpen(&conn) != NULL)
|
||||
const char* ffDetectSmcTemps(enum FFTempType type, double* result) {
|
||||
if (!conn) {
|
||||
if (smcOpen(&conn) != NULL) {
|
||||
conn = (io_connect_t) -1;
|
||||
}
|
||||
}
|
||||
if (conn == (io_connect_t) -1)
|
||||
if (conn == (io_connect_t) -1) {
|
||||
return "Could not open SMC connection";
|
||||
}
|
||||
|
||||
uint32_t count = 0;
|
||||
*result = 0;
|
||||
|
||||
// https://github.com/exelban/stats/blob/master/Modules/Sensors/values.swift
|
||||
switch (type)
|
||||
{
|
||||
case FF_TEMP_CPU_X64:
|
||||
count += detectTemp(conn, "TC0D", result); // CPU diode
|
||||
count += detectTemp(conn, "TC0E", result); // CPU diode virtual
|
||||
count += detectTemp(conn, "TC0F", result); // CPU diode filtered
|
||||
count += detectTemp(conn, "TC0P", result); // CPU proximity
|
||||
break;
|
||||
switch (type) {
|
||||
case FF_TEMP_CPU_X64:
|
||||
count += detectTemp(conn, "TC0D", result); // CPU diode
|
||||
count += detectTemp(conn, "TC0E", result); // CPU diode virtual
|
||||
count += detectTemp(conn, "TC0F", result); // CPU diode filtered
|
||||
count += detectTemp(conn, "TC0P", result); // CPU proximity
|
||||
break;
|
||||
|
||||
case FF_TEMP_CPU_M1X:
|
||||
count += detectTemp(conn, "Tp09", result); // CPU efficient core 1
|
||||
count += detectTemp(conn, "Tp0T", result); // CPU efficient core 2
|
||||
case FF_TEMP_CPU_M1X:
|
||||
count += detectTemp(conn, "Tp09", result); // CPU efficient core 1
|
||||
count += detectTemp(conn, "Tp0T", result); // CPU efficient core 2
|
||||
|
||||
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tp0H", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tp0L", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tp0P", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tp0X", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tp0b", result); // CPU performance core 8
|
||||
break;
|
||||
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tp0H", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tp0L", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tp0P", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tp0X", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tp0b", result); // CPU performance core 8
|
||||
break;
|
||||
|
||||
case FF_TEMP_CPU_M2X:
|
||||
count += detectTemp(conn, "Tp1h", result); // CPU efficiency core 1
|
||||
count += detectTemp(conn, "Tp1t", result); // CPU efficiency core 2
|
||||
count += detectTemp(conn, "Tp1p", result); // CPU efficiency core 3
|
||||
count += detectTemp(conn, "Tp1l", result); // CPU efficiency core 4
|
||||
case FF_TEMP_CPU_M2X:
|
||||
count += detectTemp(conn, "Tp1h", result); // CPU efficiency core 1
|
||||
count += detectTemp(conn, "Tp1t", result); // CPU efficiency core 2
|
||||
count += detectTemp(conn, "Tp1p", result); // CPU efficiency core 3
|
||||
count += detectTemp(conn, "Tp1l", result); // CPU efficiency core 4
|
||||
|
||||
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tp09", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tp0X", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tp0b", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tp0f", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tp0j", result); // CPU performance core 8
|
||||
break;
|
||||
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tp09", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tp0X", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tp0b", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tp0f", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tp0j", result); // CPU performance core 8
|
||||
break;
|
||||
|
||||
case FF_TEMP_CPU_M3X:
|
||||
count += detectTemp(conn, "Te05", result); // CPU efficiency core 1
|
||||
count += detectTemp(conn, "Te0L", result); // CPU efficiency core 2
|
||||
count += detectTemp(conn, "Te0P", result); // CPU efficiency core 3
|
||||
count += detectTemp(conn, "Te0S", result); // CPU efficiency core 4
|
||||
count += detectTemp(conn, "Tf04", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tf09", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tf0A", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tf0B", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tf0D", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tf0E", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tf44", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tf49", result); // CPU performance core 8
|
||||
count += detectTemp(conn, "Tf4A", result); // CPU performance core 9
|
||||
count += detectTemp(conn, "Tf4B", result); // CPU performance core 10
|
||||
count += detectTemp(conn, "Tf4D", result); // CPU performance core 11
|
||||
count += detectTemp(conn, "Tf4E", result); // CPU performance core 12
|
||||
break;
|
||||
case FF_TEMP_CPU_M3X:
|
||||
count += detectTemp(conn, "Te05", result); // CPU efficiency core 1
|
||||
count += detectTemp(conn, "Te0L", result); // CPU efficiency core 2
|
||||
count += detectTemp(conn, "Te0P", result); // CPU efficiency core 3
|
||||
count += detectTemp(conn, "Te0S", result); // CPU efficiency core 4
|
||||
count += detectTemp(conn, "Tf04", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tf09", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tf0A", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tf0B", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tf0D", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tf0E", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tf44", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tf49", result); // CPU performance core 8
|
||||
count += detectTemp(conn, "Tf4A", result); // CPU performance core 9
|
||||
count += detectTemp(conn, "Tf4B", result); // CPU performance core 10
|
||||
count += detectTemp(conn, "Tf4D", result); // CPU performance core 11
|
||||
count += detectTemp(conn, "Tf4E", result); // CPU performance core 12
|
||||
break;
|
||||
|
||||
case FF_TEMP_CPU_M4X:
|
||||
count += detectTemp(conn, "Te05", result); // CPU efficiency core 1
|
||||
count += detectTemp(conn, "Te0S", result); // CPU efficiency core 2
|
||||
count += detectTemp(conn, "Te09", result); // CPU efficiency core 3
|
||||
count += detectTemp(conn, "Te0H", result); // CPU efficiency core 4
|
||||
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tp09", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tp0V", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tp0Y", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tp0b", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tp0e", result); // CPU performance core 8
|
||||
break;
|
||||
case FF_TEMP_CPU_M4X:
|
||||
count += detectTemp(conn, "Te05", result); // CPU efficiency core 1
|
||||
count += detectTemp(conn, "Te0S", result); // CPU efficiency core 2
|
||||
count += detectTemp(conn, "Te09", result); // CPU efficiency core 3
|
||||
count += detectTemp(conn, "Te0H", result); // CPU efficiency core 4
|
||||
count += detectTemp(conn, "Tp01", result); // CPU performance core 1
|
||||
count += detectTemp(conn, "Tp05", result); // CPU performance core 2
|
||||
count += detectTemp(conn, "Tp09", result); // CPU performance core 3
|
||||
count += detectTemp(conn, "Tp0D", result); // CPU performance core 4
|
||||
count += detectTemp(conn, "Tp0V", result); // CPU performance core 5
|
||||
count += detectTemp(conn, "Tp0Y", result); // CPU performance core 6
|
||||
count += detectTemp(conn, "Tp0b", result); // CPU performance core 7
|
||||
count += detectTemp(conn, "Tp0e", result); // CPU performance core 8
|
||||
break;
|
||||
|
||||
case FF_TEMP_GPU_INTEL:
|
||||
count += detectTemp(conn, "TCGC", result); // GPU Intel Graphics
|
||||
goto gpu_unknown;
|
||||
case FF_TEMP_GPU_INTEL:
|
||||
count += detectTemp(conn, "TCGC", result); // GPU Intel Graphics
|
||||
goto gpu_unknown;
|
||||
|
||||
case FF_TEMP_GPU_AMD:
|
||||
count += detectTemp(conn, "TGDD", result); // GPU AMD Radeon
|
||||
goto gpu_unknown;
|
||||
case FF_TEMP_GPU_AMD:
|
||||
count += detectTemp(conn, "TGDD", result); // GPU AMD Radeon
|
||||
goto gpu_unknown;
|
||||
|
||||
case FF_TEMP_GPU_UNKNOWN: // Nvidia?
|
||||
gpu_unknown:
|
||||
count += detectTemp(conn, "TG0D", result); // GPU diode
|
||||
count += detectTemp(conn, "TG0P", result); // GPU proximity
|
||||
break;
|
||||
case FF_TEMP_GPU_UNKNOWN: // Nvidia?
|
||||
gpu_unknown:
|
||||
count += detectTemp(conn, "TG0D", result); // GPU diode
|
||||
count += detectTemp(conn, "TG0P", result); // GPU proximity
|
||||
break;
|
||||
|
||||
case FF_TEMP_GPU_M1X:
|
||||
count += detectTemp(conn, "Tg05", result); // GPU 1
|
||||
count += detectTemp(conn, "Tg0D", result); // GPU 2
|
||||
count += detectTemp(conn, "Tg0L", result); // GPU 3
|
||||
count += detectTemp(conn, "Tg0T", result); // GPU 4
|
||||
break;
|
||||
case FF_TEMP_GPU_M1X:
|
||||
count += detectTemp(conn, "Tg05", result); // GPU 1
|
||||
count += detectTemp(conn, "Tg0D", result); // GPU 2
|
||||
count += detectTemp(conn, "Tg0L", result); // GPU 3
|
||||
count += detectTemp(conn, "Tg0T", result); // GPU 4
|
||||
break;
|
||||
|
||||
case FF_TEMP_GPU_M2X:
|
||||
count += detectTemp(conn, "Tg0f", result); // GPU 1
|
||||
count += detectTemp(conn, "Tg0j", result); // GPU 2
|
||||
break;
|
||||
case FF_TEMP_GPU_M2X:
|
||||
count += detectTemp(conn, "Tg0f", result); // GPU 1
|
||||
count += detectTemp(conn, "Tg0j", result); // GPU 2
|
||||
break;
|
||||
|
||||
case FF_TEMP_GPU_M3X:
|
||||
count += detectTemp(conn, "Tf14", result); // GPU 1
|
||||
count += detectTemp(conn, "Tf18", result); // GPU 2
|
||||
count += detectTemp(conn, "Tf19", result); // GPU 3
|
||||
count += detectTemp(conn, "Tf1A", result); // GPU 4
|
||||
count += detectTemp(conn, "Tf24", result); // GPU 5
|
||||
count += detectTemp(conn, "Tf28", result); // GPU 6
|
||||
count += detectTemp(conn, "Tf29", result); // GPU 7
|
||||
count += detectTemp(conn, "Tf2A", result); // GPU 8
|
||||
break;
|
||||
case FF_TEMP_GPU_M3X:
|
||||
count += detectTemp(conn, "Tf14", result); // GPU 1
|
||||
count += detectTemp(conn, "Tf18", result); // GPU 2
|
||||
count += detectTemp(conn, "Tf19", result); // GPU 3
|
||||
count += detectTemp(conn, "Tf1A", result); // GPU 4
|
||||
count += detectTemp(conn, "Tf24", result); // GPU 5
|
||||
count += detectTemp(conn, "Tf28", result); // GPU 6
|
||||
count += detectTemp(conn, "Tf29", result); // GPU 7
|
||||
count += detectTemp(conn, "Tf2A", result); // GPU 8
|
||||
break;
|
||||
|
||||
case FF_TEMP_GPU_M4X:
|
||||
count += detectTemp(conn, "Tg0G", result); // GPU 1 (Basic)
|
||||
count += detectTemp(conn, "Tg0H", result); // GPU 2 (Basic)
|
||||
count += detectTemp(conn, "Tg1U", result); // GPU 1 (Pro / Max)
|
||||
count += detectTemp(conn, "Tg1k", result); // GPU 2 (Pro / Max)
|
||||
count += detectTemp(conn, "Tg0K", result); // GPU 3
|
||||
count += detectTemp(conn, "Tg0L", result); // GPU 4
|
||||
count += detectTemp(conn, "Tg0d", result); // GPU 5
|
||||
count += detectTemp(conn, "Tg0e", result); // GPU 6
|
||||
count += detectTemp(conn, "Tg0j", result); // GPU 7
|
||||
count += detectTemp(conn, "Tg0k", result); // GPU 8
|
||||
break;
|
||||
case FF_TEMP_GPU_M4X:
|
||||
count += detectTemp(conn, "Tg0G", result); // GPU 1 (Basic)
|
||||
count += detectTemp(conn, "Tg0H", result); // GPU 2 (Basic)
|
||||
count += detectTemp(conn, "Tg1U", result); // GPU 1 (Pro / Max)
|
||||
count += detectTemp(conn, "Tg1k", result); // GPU 2 (Pro / Max)
|
||||
count += detectTemp(conn, "Tg0K", result); // GPU 3
|
||||
count += detectTemp(conn, "Tg0L", result); // GPU 4
|
||||
count += detectTemp(conn, "Tg0d", result); // GPU 5
|
||||
count += detectTemp(conn, "Tg0e", result); // GPU 6
|
||||
count += detectTemp(conn, "Tg0j", result); // GPU 7
|
||||
count += detectTemp(conn, "Tg0k", result); // GPU 8
|
||||
break;
|
||||
|
||||
case FF_TEMP_BATTERY:
|
||||
count += detectTemp(conn, "TB1T", result); // Battery
|
||||
count += detectTemp(conn, "TB2T", result); // Battery
|
||||
break;
|
||||
case FF_TEMP_BATTERY:
|
||||
count += detectTemp(conn, "TB1T", result); // Battery
|
||||
count += detectTemp(conn, "TB2T", result); // Battery
|
||||
break;
|
||||
|
||||
case FF_TEMP_MEMORY:
|
||||
count += detectTemp(conn, "Tm02", result); // Memory 1
|
||||
count += detectTemp(conn, "Tm06", result); // Memory 2
|
||||
count += detectTemp(conn, "Tm08", result); // Memory 3
|
||||
count += detectTemp(conn, "Tm09", result); // Memory 4
|
||||
break;
|
||||
case FF_TEMP_MEMORY:
|
||||
count += detectTemp(conn, "Tm02", result); // Memory 1
|
||||
count += detectTemp(conn, "Tm06", result); // Memory 2
|
||||
count += detectTemp(conn, "Tm08", result); // Memory 3
|
||||
count += detectTemp(conn, "Tm09", result); // Memory 4
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
if (count == 0) {
|
||||
return "No temperatures detected";
|
||||
}
|
||||
|
||||
*result /= count;
|
||||
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
typedef struct FFTempValue
|
||||
{
|
||||
typedef struct FFTempValue {
|
||||
FFstrbuf name;
|
||||
FFstrbuf deviceClass;
|
||||
double value;
|
||||
} FFTempValue;
|
||||
|
||||
enum FFTempType
|
||||
{
|
||||
enum FFTempType {
|
||||
FF_TEMP_CPU_X64,
|
||||
FF_TEMP_CPU_M1X,
|
||||
FF_TEMP_CPU_M2X,
|
||||
|
||||
+18
-19
@@ -5,14 +5,12 @@
|
||||
// For ffRegReadValue(s)
|
||||
// If length is 0, data will be allocated with malloc() and must be freed by the caller
|
||||
// Otherwise, data must point to a buffer of at least length bytes, and the actual length of the data will be written to length.
|
||||
typedef struct FFArgBuffer
|
||||
{
|
||||
typedef struct FFArgBuffer {
|
||||
void* data;
|
||||
uint32_t length;
|
||||
} FFArgBuffer;
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFArgType
|
||||
{
|
||||
typedef enum __attribute__((__packed__)) FFArgType {
|
||||
FF_ARG_TYPE_NULL = 0,
|
||||
FF_ARG_TYPE_UINT,
|
||||
FF_ARG_TYPE_UINT64,
|
||||
@@ -28,18 +26,19 @@ typedef enum __attribute__((__packed__)) FFArgType
|
||||
FF_ARG_TYPE_BUFFER,
|
||||
} FFArgType;
|
||||
|
||||
#define FF_ARG(variable, var_name) { _Generic((variable), \
|
||||
uint32_t: FF_ARG_TYPE_UINT, \
|
||||
uint64_t: FF_ARG_TYPE_UINT64, \
|
||||
uint16_t: FF_ARG_TYPE_UINT16, \
|
||||
uint8_t: FF_ARG_TYPE_UINT8, \
|
||||
int32_t: FF_ARG_TYPE_INT, \
|
||||
char*: FF_ARG_TYPE_STRING, \
|
||||
const char*: FF_ARG_TYPE_STRING, \
|
||||
FFstrbuf: FF_ARG_TYPE_STRBUF, \
|
||||
float: FF_ARG_TYPE_FLOAT, \
|
||||
double: FF_ARG_TYPE_DOUBLE, \
|
||||
FFlist: FF_ARG_TYPE_LIST, \
|
||||
bool: FF_ARG_TYPE_BOOL, \
|
||||
FFArgBuffer: FF_ARG_TYPE_BUFFER \
|
||||
), _Generic((variable), char*: (variable), const char*: (variable), default: &(variable) ), (var_name) }
|
||||
#define FF_ARG(variable, var_name) {_Generic((variable), \
|
||||
uint32_t: FF_ARG_TYPE_UINT, \
|
||||
uint64_t: FF_ARG_TYPE_UINT64, \
|
||||
uint16_t: FF_ARG_TYPE_UINT16, \
|
||||
uint8_t: FF_ARG_TYPE_UINT8, \
|
||||
int32_t: FF_ARG_TYPE_INT, \
|
||||
char*: FF_ARG_TYPE_STRING, \
|
||||
const char*: FF_ARG_TYPE_STRING, \
|
||||
FFstrbuf: FF_ARG_TYPE_STRBUF, \
|
||||
float: FF_ARG_TYPE_FLOAT, \
|
||||
double: FF_ARG_TYPE_DOUBLE, \
|
||||
FFlist: FF_ARG_TYPE_LIST, \
|
||||
bool: FF_ARG_TYPE_BOOL, \
|
||||
FFArgBuffer: FF_ARG_TYPE_BUFFER), \
|
||||
_Generic((variable), char*: (variable), const char*: (variable), default: &(variable)), \
|
||||
(var_name)}
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __has_builtin
|
||||
#if !__cplusplus && FF_SUPPORTS_COUNT_OF
|
||||
#define ARRAY_SIZE(x) _Countof(x)
|
||||
#elif __has_builtin(__is_array)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(__is_array(__typeof__(x)), "Must be an array"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
#elif __has_builtin(__builtin_types_compatible_p)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(!__builtin_types_compatible_p(__typeof__(x), __typeof__(&*(x))), "Must not be a pointer"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
#endif
|
||||
# if !__cplusplus && FF_SUPPORTS_COUNT_OF
|
||||
# define ARRAY_SIZE(x) _Countof(x)
|
||||
# elif __has_builtin(__is_array)
|
||||
# define ARRAY_SIZE(x) ({ static_assert(__is_array(__typeof__(x)), "Must be an array"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
# elif __has_builtin(__builtin_types_compatible_p)
|
||||
# define ARRAY_SIZE(x) ({ static_assert(!__builtin_types_compatible_p(__typeof__(x), __typeof__(&*(x))), "Must not be a pointer"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
# endif
|
||||
#endif
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) ((uint32_t) (sizeof(x) / sizeof(*(x))))
|
||||
# define ARRAY_SIZE(x) ((uint32_t) (sizeof(x) / sizeof(*(x))))
|
||||
#endif
|
||||
|
||||
+4
-6
@@ -2,9 +2,8 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffBase64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output);
|
||||
static inline FFstrbuf ffBase64EncodeStrbuf(const FFstrbuf* in)
|
||||
{
|
||||
void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output);
|
||||
static inline FFstrbuf ffBase64EncodeStrbuf(const FFstrbuf* in) {
|
||||
FFstrbuf out = ffStrbufCreateA(10 + in->length * 4 / 3);
|
||||
ffBase64EncodeRaw(in->length, in->chars, &out.length, out.chars);
|
||||
assert(out.length < out.allocated);
|
||||
@@ -12,9 +11,8 @@ static inline FFstrbuf ffBase64EncodeStrbuf(const FFstrbuf* in)
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ffBase64DecodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output);
|
||||
static inline FFstrbuf ffBase64DecodeStrbuf(const FFstrbuf* in)
|
||||
{
|
||||
bool ffBase64DecodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output);
|
||||
static inline FFstrbuf ffBase64DecodeStrbuf(const FFstrbuf* in) {
|
||||
FFstrbuf out = ffStrbufCreateA(10 + in->length * 3 / 4);
|
||||
ffBase64DecodeRaw(in->length, in->chars, &out.length, out.chars);
|
||||
assert(out.length < out.allocated);
|
||||
|
||||
+8
-11
@@ -1,13 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include <dbus/dbus.h>
|
||||
# include <dbus/dbus.h>
|
||||
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/library.h"
|
||||
# include "common/FFstrbuf.h"
|
||||
# include "common/library.h"
|
||||
|
||||
typedef struct FFDBusLibrary
|
||||
{
|
||||
typedef struct FFDBusLibrary {
|
||||
FF_LIBRARY_SYMBOL(dbus_bus_get)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_new_method_call)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_append_args)
|
||||
@@ -22,13 +21,12 @@ typedef struct FFDBusLibrary
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_unref)
|
||||
} FFDBusLibrary;
|
||||
|
||||
typedef struct FFDBusData
|
||||
{
|
||||
typedef struct FFDBusData {
|
||||
const FFDBusLibrary* lib;
|
||||
DBusConnection* connection;
|
||||
} FFDBusData;
|
||||
|
||||
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); //Returns an error message or NULL on success
|
||||
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); // Returns an error message or NULL on success
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result);
|
||||
@@ -39,11 +37,10 @@ bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
|
||||
void ffDBusDestroyData(FFDBusData* data);
|
||||
|
||||
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface)
|
||||
{
|
||||
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface) {
|
||||
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL);
|
||||
}
|
||||
|
||||
#define FF_DBUS_AUTO_DESTROY_DATA __attribute__((__cleanup__(ffDBusDestroyData)))
|
||||
# define FF_DBUS_AUTO_DESTROY_DATA __attribute__((__cleanup__(ffDBusDestroyData)))
|
||||
|
||||
#endif // FF_HAVE_DBUS
|
||||
|
||||
+13
-11
@@ -3,27 +3,29 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/time.h"
|
||||
|
||||
static inline const char* ffFindFileName(const char* file)
|
||||
{
|
||||
static inline const char* ffFindFileName(const char* file) {
|
||||
const char* lastSlash = __builtin_strrchr(file, '/');
|
||||
#ifdef _WIN32
|
||||
if (lastSlash == NULL)
|
||||
#ifdef _WIN32
|
||||
if (lastSlash == NULL) {
|
||||
lastSlash = __builtin_strrchr(file, '\\');
|
||||
#endif
|
||||
if (lastSlash != NULL)
|
||||
}
|
||||
#endif
|
||||
if (lastSlash != NULL) {
|
||||
return lastSlash + 1;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define FF_DEBUG_PRINT(file_, line_, format_, ...) \
|
||||
do { \
|
||||
if (instance.config.display.debugMode) \
|
||||
# define FF_DEBUG_PRINT(file_, line_, format_, ...) \
|
||||
do { \
|
||||
if (instance.config.display.debugMode) \
|
||||
fprintf(stderr, "[%s%4d, %s] " format_ "\n", ffFindFileName(file_), line_, ffTimeToTimeStr(ffTimeGetNow()), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define FF_DEBUG_PRINT(file_, line_, format_, ...) \
|
||||
do { } while (0)
|
||||
# define FF_DEBUG_PRINT(file_, line_, format_, ...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define FF_DEBUG(format, ...) FF_DEBUG_PRINT(__FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
+7
-9
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFDataResultDocType
|
||||
{
|
||||
typedef enum __attribute__((__packed__)) FFDataResultDocType {
|
||||
FF_RESULT_DOC_TYPE_DEFAULT = 0,
|
||||
FF_RESULT_DOC_TYPE_JSON,
|
||||
FF_RESULT_DOC_TYPE_CONFIG,
|
||||
@@ -12,13 +11,12 @@ typedef enum __attribute__((__packed__)) FFDataResultDocType
|
||||
|
||||
// FFdata aggregates configuration, generation parameters, and output state used by fastfetch.
|
||||
// It holds the parsed configuration document, a mutable JSON document for results, and related metadata.
|
||||
typedef struct FFdata
|
||||
{
|
||||
yyjson_doc* configDoc; // Parsed JSON configuration document
|
||||
yyjson_mut_doc* resultDoc; // Mutable JSON document for storing results
|
||||
FFstrbuf structure; // Custom output structure from command line
|
||||
FFstrbuf structureDisabled; // Disabled modules in the output structure from command line
|
||||
FFstrbuf genConfigPath; // Path to generate configuration file
|
||||
typedef struct FFdata {
|
||||
yyjson_doc* configDoc; // Parsed JSON configuration document
|
||||
yyjson_mut_doc* resultDoc; // Mutable JSON document for storing results
|
||||
FFstrbuf structure; // Custom output structure from command line
|
||||
FFstrbuf structureDisabled; // Disabled modules in the output structure from command line
|
||||
FFstrbuf genConfigPath; // Path to generate configuration file
|
||||
FFDataResultDocType docType; // Type of result document
|
||||
bool configLoaded;
|
||||
} FFdata;
|
||||
|
||||
+2
-4
@@ -3,8 +3,7 @@
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/FFlist.h"
|
||||
|
||||
typedef struct FFfont
|
||||
{
|
||||
typedef struct FFfont {
|
||||
FFstrbuf pretty;
|
||||
FFstrbuf name;
|
||||
FFstrbuf size;
|
||||
@@ -21,7 +20,6 @@ void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName);
|
||||
void ffFontDestroy(FFfont* font);
|
||||
|
||||
static inline void ffFontInitCopy(FFfont* font, const char* name)
|
||||
{
|
||||
static inline void ffFontInitCopy(FFfont* font, const char* name) {
|
||||
ffFontInitValues(font, name, NULL);
|
||||
}
|
||||
|
||||
+1
-2
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "common/argType.h"
|
||||
|
||||
typedef struct FFformatarg
|
||||
{
|
||||
typedef struct FFformatarg {
|
||||
FFArgType type;
|
||||
const void* value;
|
||||
const char* name; // argument name, must start with an alphabet
|
||||
|
||||
@@ -5,20 +5,22 @@ extern "C" {
|
||||
#include <File.h>
|
||||
#include <AppFileInfo.h>
|
||||
|
||||
bool ffGetFileVersion(const char* filePath, FFstrbuf* version)
|
||||
{
|
||||
bool ffGetFileVersion(const char* filePath, FFstrbuf* version) {
|
||||
BFile f(filePath, B_READ_ONLY);
|
||||
if (f.InitCheck() != B_OK)
|
||||
if (f.InitCheck() != B_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BAppFileInfo fileInfo(&f);
|
||||
if (f.InitCheck() != B_OK)
|
||||
if (f.InitCheck() != B_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
version_info info;
|
||||
if (fileInfo.GetVersionInfo(&info, B_SYSTEM_VERSION_KIND) != B_OK)
|
||||
if (fileInfo.GetVersionInfo(&info, B_SYSTEM_VERSION_KIND) != B_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufSetF(version, "%d.%d.%d", (int)info.major, (int)info.middle, (int)info.minor);
|
||||
ffStrbufSetF(version, "%d.%d.%d", (int) info.major, (int) info.middle, (int) info.minor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "common/io.h"
|
||||
#include "detection/version/version.h"
|
||||
|
||||
void ffPlatformInit(FFPlatform* platform)
|
||||
{
|
||||
void ffPlatformInit(FFPlatform* platform) {
|
||||
ffStrbufInit(&platform->homeDir);
|
||||
ffStrbufInit(&platform->cacheDir);
|
||||
ffListInit(&platform->configDirs, sizeof(FFstrbuf));
|
||||
@@ -17,9 +16,9 @@ void ffPlatformInit(FFPlatform* platform)
|
||||
ffStrbufInit(&platform->hostName);
|
||||
ffStrbufInit(&platform->userShell);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
ffStrbufInit(&platform->sid);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
FFPlatformSysinfo* info = &platform->sysinfo;
|
||||
|
||||
@@ -30,24 +29,27 @@ void ffPlatformInit(FFPlatform* platform)
|
||||
|
||||
ffPlatformInitImpl(platform);
|
||||
|
||||
if(info->name.length == 0)
|
||||
if (info->name.length == 0) {
|
||||
ffStrbufSetStatic(&info->name, ffVersionResult.sysName);
|
||||
}
|
||||
|
||||
if(info->architecture.length == 0)
|
||||
if (info->architecture.length == 0) {
|
||||
ffStrbufSetStatic(&info->architecture, ffVersionResult.architecture);
|
||||
}
|
||||
}
|
||||
|
||||
void ffPlatformDestroy(FFPlatform* platform)
|
||||
{
|
||||
void ffPlatformDestroy(FFPlatform* platform) {
|
||||
ffStrbufDestroy(&platform->homeDir);
|
||||
ffStrbufDestroy(&platform->cacheDir);
|
||||
|
||||
FF_LIST_FOR_EACH(FFstrbuf, dir, platform->configDirs)
|
||||
FF_LIST_FOR_EACH (FFstrbuf, dir, platform->configDirs) {
|
||||
ffStrbufDestroy(dir);
|
||||
}
|
||||
ffListDestroy(&platform->configDirs);
|
||||
|
||||
FF_LIST_FOR_EACH(FFstrbuf, dir, platform->dataDirs)
|
||||
FF_LIST_FOR_EACH (FFstrbuf, dir, platform->dataDirs) {
|
||||
ffStrbufDestroy(dir);
|
||||
}
|
||||
ffListDestroy(&platform->dataDirs);
|
||||
ffStrbufDestroy(&platform->exePath);
|
||||
ffStrbufDestroy(&platform->cwd);
|
||||
@@ -57,9 +59,9 @@ void ffPlatformDestroy(FFPlatform* platform)
|
||||
ffStrbufDestroy(&platform->userShell);
|
||||
ffStrbufDestroy(&platform->fullUserName);
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
ffStrbufDestroy(&platform->sid);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
FFPlatformSysinfo* info = &platform->sysinfo;
|
||||
ffStrbufDestroy(&info->architecture);
|
||||
@@ -68,23 +70,24 @@ void ffPlatformDestroy(FFPlatform* platform)
|
||||
ffStrbufDestroy(&info->version);
|
||||
}
|
||||
|
||||
void ffPlatformPathAddAbsolute(FFlist* dirs, const char* path)
|
||||
{
|
||||
if (!ffPathExists(path, FF_PATHTYPE_DIRECTORY))
|
||||
void ffPlatformPathAddAbsolute(FFlist* dirs, const char* path) {
|
||||
if (!ffPathExists(path, FF_PATHTYPE_DIRECTORY)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateS(path);
|
||||
ffStrbufEnsureEndsWithC(&buffer, '/');
|
||||
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
|
||||
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual)) {
|
||||
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void ffPlatformPathAddHome(FFlist* dirs, const FFPlatform* platform, const char* suffix)
|
||||
{
|
||||
void ffPlatformPathAddHome(FFlist* dirs, const FFPlatform* platform, const char* suffix) {
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateA(64);
|
||||
ffStrbufAppend(&buffer, &platform->homeDir);
|
||||
ffStrbufAppendS(&buffer, suffix);
|
||||
ffStrbufEnsureEndsWithC(&buffer, '/');
|
||||
if (ffPathExists(buffer.chars, FF_PATHTYPE_DIRECTORY) && !ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
|
||||
if (ffPathExists(buffer.chars, FF_PATHTYPE_DIRECTORY) && !ffListContains(dirs, &buffer, (void*) ffStrbufEqual)) {
|
||||
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
|
||||
}
|
||||
}
|
||||
|
||||
+159
-181
@@ -12,167 +12,161 @@
|
||||
#include <paths.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#include <sys/sysctl.h>
|
||||
# include <mach-o/dyld.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#include <kvm.h>
|
||||
#include "common/path.h"
|
||||
# include <sys/sysctl.h>
|
||||
# include <kvm.h>
|
||||
# include "common/path.h"
|
||||
#elif defined(__HAIKU__)
|
||||
#include <image.h>
|
||||
#include <OS.h>
|
||||
# include <image.h>
|
||||
# include <OS.h>
|
||||
#endif
|
||||
|
||||
static void getExePath(FFPlatform* platform)
|
||||
{
|
||||
static void getExePath(FFPlatform* platform) {
|
||||
char exePath[PATH_MAX];
|
||||
#if defined(__linux__) || defined (__GNU__)
|
||||
ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
|
||||
if (exePathLen >= 0)
|
||||
exePath[exePathLen] = '\0';
|
||||
#elif defined(__APPLE__)
|
||||
uint32_t exePathLen = sizeof(exePath);
|
||||
if (_NSGetExecutablePath(exePath, &exePathLen) == 0)
|
||||
exePathLen = (uint32_t) strlen(exePath);
|
||||
else
|
||||
exePathLen = 0;
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
size_t exePathLen = sizeof(exePath);
|
||||
if(sysctl(
|
||||
(int[]){CTL_KERN,
|
||||
#ifdef __FreeBSD__
|
||||
KERN_PROC, KERN_PROC_PATHNAME, (pid_t) platform->pid
|
||||
#else
|
||||
KERN_PROC_ARGS, platform->pid, KERN_PROC_PATHNAME
|
||||
#endif
|
||||
}, 4,
|
||||
exePath, &exePathLen,
|
||||
NULL, 0
|
||||
) < 0)
|
||||
exePathLen = 0;
|
||||
else
|
||||
exePathLen--; // remove terminating NUL
|
||||
#elif defined(__OpenBSD__)
|
||||
// OpenBSD doesn't have a reliable way to get the executable path.
|
||||
// Current implementation uses argv[0], which can be easily spoofed.
|
||||
// See #2195
|
||||
size_t exePathLen = 0;
|
||||
kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
if (kd)
|
||||
{
|
||||
int kpCount;
|
||||
struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount);
|
||||
if (kp && kpCount == 1)
|
||||
{
|
||||
char** argv = kvm_getargv(kd, kp, 0);
|
||||
if (argv && argv[0])
|
||||
{
|
||||
char* arg0 = argv[0];
|
||||
if (arg0[0])
|
||||
#if defined(__linux__) || defined(__GNU__)
|
||||
ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
|
||||
if (exePathLen >= 0) {
|
||||
exePath[exePathLen] = '\0';
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
uint32_t exePathLen = sizeof(exePath);
|
||||
if (_NSGetExecutablePath(exePath, &exePathLen) == 0) {
|
||||
exePathLen = (uint32_t) strlen(exePath);
|
||||
} else {
|
||||
exePathLen = 0;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
size_t exePathLen = sizeof(exePath);
|
||||
if (sysctl(
|
||||
(int[]) {CTL_KERN,
|
||||
# ifdef __FreeBSD__
|
||||
KERN_PROC,
|
||||
KERN_PROC_PATHNAME,
|
||||
(pid_t) platform->pid
|
||||
# else
|
||||
KERN_PROC_ARGS,
|
||||
platform->pid,
|
||||
KERN_PROC_PATHNAME
|
||||
# endif
|
||||
},
|
||||
4,
|
||||
exePath,
|
||||
&exePathLen,
|
||||
NULL,
|
||||
0) < 0)
|
||||
exePathLen = 0;
|
||||
else {
|
||||
exePathLen--; // remove terminating NUL
|
||||
}
|
||||
#elif defined(__OpenBSD__)
|
||||
// OpenBSD doesn't have a reliable way to get the executable path.
|
||||
// Current implementation uses argv[0], which can be easily spoofed.
|
||||
// See #2195
|
||||
size_t exePathLen = 0;
|
||||
kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
if (kd) {
|
||||
int kpCount;
|
||||
struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount);
|
||||
if (kp && kpCount == 1) {
|
||||
char** argv = kvm_getargv(kd, kp, 0);
|
||||
if (argv && argv[0]) {
|
||||
char* arg0 = argv[0];
|
||||
if (arg0[0]) {
|
||||
if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative)
|
||||
{
|
||||
if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative)
|
||||
{
|
||||
exePathLen = strlen(arg0);
|
||||
if (exePathLen < ARRAY_SIZE(exePath))
|
||||
{
|
||||
memcpy(exePath, arg0, exePathLen);
|
||||
exePath[exePathLen] = '\0';
|
||||
}
|
||||
else
|
||||
exePathLen = 0;
|
||||
exePathLen = strlen(arg0);
|
||||
if (exePathLen < ARRAY_SIZE(exePath)) {
|
||||
memcpy(exePath, arg0, exePathLen);
|
||||
exePath[exePathLen] = '\0';
|
||||
} else {
|
||||
exePathLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate();
|
||||
if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath))
|
||||
{
|
||||
memcpy(exePath, tmpPath.chars, tmpPath.length + 1);
|
||||
exePathLen = tmpPath.length;
|
||||
}
|
||||
} else {
|
||||
FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate();
|
||||
if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath)) {
|
||||
memcpy(exePath, tmpPath.chars, tmpPath.length + 1);
|
||||
exePathLen = tmpPath.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (exePathLen > 0)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode))
|
||||
{
|
||||
int cntp;
|
||||
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp);
|
||||
if (kf)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cntp; i++)
|
||||
{
|
||||
if (kf[i].fd_fd == KERN_FILE_TEXT)
|
||||
{
|
||||
// KERN_FILE_TEXT is the executable file, not a shared library, and should be unique in the list.
|
||||
if (st.st_dev != (dev_t)kf[i].va_fsid || st.st_ino != (ino_t)kf[i].va_fileid)
|
||||
i = -1;
|
||||
break;
|
||||
if (exePathLen > 0) {
|
||||
struct stat st;
|
||||
if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||
int cntp;
|
||||
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp);
|
||||
if (kf) {
|
||||
int i;
|
||||
for (i = 0; i < cntp; i++) {
|
||||
if (kf[i].fd_fd == KERN_FILE_TEXT) {
|
||||
// KERN_FILE_TEXT is the executable file, not a shared library, and should be unique in the list.
|
||||
if (st.st_dev != (dev_t) kf[i].va_fsid || st.st_ino != (ino_t) kf[i].va_fileid) {
|
||||
i = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i < 0)
|
||||
exePathLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can't get the list of open files, we can't verify that the file is actually the executable
|
||||
// Assume it is
|
||||
if (i < 0) {
|
||||
exePathLen = 0;
|
||||
}
|
||||
} else {
|
||||
// If we can't get the list of open files, we can't verify that the file is actually the executable
|
||||
// Assume it is
|
||||
}
|
||||
else
|
||||
exePathLen = 0;
|
||||
} else {
|
||||
exePathLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kvm_close(kd);
|
||||
}
|
||||
#elif defined(__sun)
|
||||
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
|
||||
if (exePathLen >= 0)
|
||||
exePath[exePathLen] = '\0';
|
||||
#elif defined(__HAIKU__)
|
||||
size_t exePathLen = 0;
|
||||
image_info info;
|
||||
int32 cookie = 0;
|
||||
kvm_close(kd);
|
||||
}
|
||||
#elif defined(__sun)
|
||||
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
|
||||
if (exePathLen >= 0) {
|
||||
exePath[exePathLen] = '\0';
|
||||
}
|
||||
#elif defined(__HAIKU__)
|
||||
size_t exePathLen = 0;
|
||||
image_info info;
|
||||
int32 cookie = 0;
|
||||
|
||||
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
|
||||
if (info.type == B_APP_IMAGE) {
|
||||
exePathLen = strlcpy(exePath, info.name, sizeof(exePath));
|
||||
break;
|
||||
}
|
||||
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
|
||||
if (info.type == B_APP_IMAGE) {
|
||||
exePathLen = strlcpy(exePath, info.name, sizeof(exePath));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (exePathLen > 0)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
if (exePathLen > 0) {
|
||||
ffStrbufEnsureFree(&platform->exePath, PATH_MAX);
|
||||
if (realpath(exePath, platform->exePath.chars))
|
||||
if (realpath(exePath, platform->exePath.chars)) {
|
||||
ffStrbufRecalculateLength(&platform->exePath);
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetNS(&platform->exePath, (uint32_t) exePathLen, exePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void platformPathAddEnv(FFlist* dirs, const char* env)
|
||||
{
|
||||
static void platformPathAddEnv(FFlist* dirs, const char* env) {
|
||||
const char* envValue = getenv(env);
|
||||
if(!ffStrSet(envValue))
|
||||
if (!ffStrSet(envValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY value = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&value, envValue);
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while (startIndex < value.length)
|
||||
{
|
||||
while (startIndex < value.length) {
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&value, startIndex, ':');
|
||||
value.chars[colonIndex] = '\0';
|
||||
|
||||
if(!ffStrSet(value.chars + startIndex))
|
||||
{
|
||||
if (!ffStrSet(value.chars + startIndex)) {
|
||||
startIndex = colonIndex + 1;
|
||||
continue;
|
||||
}
|
||||
@@ -183,61 +177,53 @@ static void platformPathAddEnv(FFlist* dirs, const char* env)
|
||||
}
|
||||
}
|
||||
|
||||
static void getHomeDir(FFPlatform* platform, const struct passwd* pwd)
|
||||
{
|
||||
static void getHomeDir(FFPlatform* platform, const struct passwd* pwd) {
|
||||
const char* home = pwd ? pwd->pw_dir : getenv("HOME");
|
||||
ffStrbufAppendS(&platform->homeDir, home);
|
||||
ffStrbufEnsureEndsWithC(&platform->homeDir, '/');
|
||||
}
|
||||
|
||||
static void getCacheDir(FFPlatform* platform)
|
||||
{
|
||||
static void getCacheDir(FFPlatform* platform) {
|
||||
const char* cache = getenv("XDG_CACHE_HOME");
|
||||
if(ffStrSet(cache))
|
||||
{
|
||||
if (ffStrSet(cache)) {
|
||||
ffStrbufAppendS(&platform->cacheDir, cache);
|
||||
ffStrbufEnsureEndsWithC(&platform->cacheDir, '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppend(&platform->cacheDir, &platform->homeDir);
|
||||
ffStrbufAppendS(&platform->cacheDir, ".cache/");
|
||||
}
|
||||
}
|
||||
|
||||
static void getConfigDirs(FFPlatform* platform)
|
||||
{
|
||||
static void getConfigDirs(FFPlatform* platform) {
|
||||
// Always make sure `${XDG_CONFIG_HOME:-$HOME/.config}` is the first entry
|
||||
platformPathAddEnv(&platform->configDirs, "XDG_CONFIG_HOME");
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, ".config/");
|
||||
|
||||
#if defined(__APPLE__)
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "Library/Preferences/");
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "Library/Application Support/");
|
||||
#endif
|
||||
#if defined(__HAIKU__)
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "config/settings/");
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "Library/Preferences/");
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "Library/Application Support/");
|
||||
#endif
|
||||
#if defined(__HAIKU__)
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "config/settings/");
|
||||
#endif
|
||||
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "");
|
||||
platformPathAddEnv(&platform->configDirs, "XDG_CONFIG_DIRS");
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC "/xdg/");
|
||||
#endif
|
||||
#if !defined(__APPLE__)
|
||||
ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC "/xdg/");
|
||||
#endif
|
||||
|
||||
ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC "/");
|
||||
ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_INSTALL_SYSCONF "/");
|
||||
}
|
||||
|
||||
static void getDataDirs(FFPlatform* platform)
|
||||
{
|
||||
static void getDataDirs(FFPlatform* platform) {
|
||||
platformPathAddEnv(&platform->dataDirs, "XDG_DATA_HOME");
|
||||
ffPlatformPathAddHome(&platform->dataDirs, platform, ".local/share/");
|
||||
|
||||
// Add ${currentExePath}/../share
|
||||
if (platform->exePath.length > 0)
|
||||
{
|
||||
if (platform->exePath.length > 0) {
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&platform->exePath);
|
||||
ffStrbufSubstrBeforeLastC(&path, '/');
|
||||
ffStrbufSubstrBeforeLastC(&path, '/');
|
||||
@@ -245,9 +231,9 @@ static void getDataDirs(FFPlatform* platform)
|
||||
ffPlatformPathAddAbsolute(&platform->dataDirs, path.chars);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
ffPlatformPathAddHome(&platform->dataDirs, platform, "Library/Application Support/");
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
ffPlatformPathAddHome(&platform->dataDirs, platform, "Library/Application Support/");
|
||||
#endif
|
||||
|
||||
ffPlatformPathAddHome(&platform->dataDirs, platform, "");
|
||||
platformPathAddEnv(&platform->dataDirs, "XDG_DATA_DIRS");
|
||||
@@ -258,74 +244,66 @@ static void getDataDirs(FFPlatform* platform)
|
||||
ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR "/share/");
|
||||
}
|
||||
|
||||
static void getUserName(FFPlatform* platform, const struct passwd* pwd)
|
||||
{
|
||||
if (pwd)
|
||||
{
|
||||
static void getUserName(FFPlatform* platform, const struct passwd* pwd) {
|
||||
if (pwd) {
|
||||
ffStrbufSetS(&platform->userName, pwd->pw_name);
|
||||
ffStrbufSetS(&platform->fullUserName, pwd->pw_gecos);
|
||||
ffStrbufTrimSpace(&platform->fullUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufSetS(&platform->userName, getenv("USER"));
|
||||
}
|
||||
}
|
||||
|
||||
static void getHostName(FFPlatform* platform, const struct utsname* uts)
|
||||
{
|
||||
static void getHostName(FFPlatform* platform, const struct utsname* uts) {
|
||||
ffStrbufAppendS(&platform->hostName, uts->nodename);
|
||||
}
|
||||
|
||||
static void getUserShell(FFPlatform* platform, const struct passwd* pwd)
|
||||
{
|
||||
static void getUserShell(FFPlatform* platform, const struct passwd* pwd) {
|
||||
const char* shell = getenv("SHELL");
|
||||
if(!ffStrSet(shell) && pwd)
|
||||
if (!ffStrSet(shell) && pwd) {
|
||||
shell = pwd->pw_shell;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&platform->userShell, shell);
|
||||
}
|
||||
|
||||
static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
|
||||
{
|
||||
static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts) {
|
||||
ffStrbufAppendS(&info->name, uts->sysname);
|
||||
ffStrbufAppendS(&info->release, uts->release);
|
||||
ffStrbufAppendS(&info->version, uts->version);
|
||||
#ifdef __HAIKU__
|
||||
#ifdef __HAIKU__
|
||||
/* historical reason */
|
||||
if (ffStrEquals(uts->machine, "BePC"))
|
||||
if (ffStrEquals(uts->machine, "BePC")) {
|
||||
ffStrbufSetStatic(&info->architecture, "i386");
|
||||
else
|
||||
#endif
|
||||
ffStrbufAppendS(&info->architecture, uts->machine);
|
||||
} else
|
||||
#endif
|
||||
ffStrbufAppendS(&info->architecture, uts->machine);
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
size_t length = sizeof(info->pageSize);
|
||||
sysctl((int[]){ CTL_HW, HW_PAGESIZE }, 2, &info->pageSize, &length, NULL, 0);
|
||||
#else
|
||||
sysctl((int[]) {CTL_HW, HW_PAGESIZE}, 2, &info->pageSize, &length, NULL, 0);
|
||||
#else
|
||||
info->pageSize = (uint32_t) sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static void getCwd(FFPlatform* platform)
|
||||
{
|
||||
static void getCwd(FFPlatform* platform) {
|
||||
char cwd[PATH_MAX];
|
||||
if (getcwd(cwd, sizeof(cwd)) != NULL)
|
||||
{
|
||||
if (getcwd(cwd, sizeof(cwd)) != NULL) {
|
||||
ffStrbufSetS(&platform->cwd, cwd);
|
||||
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
|
||||
}
|
||||
}
|
||||
|
||||
void ffPlatformInitImpl(FFPlatform* platform)
|
||||
{
|
||||
void ffPlatformInitImpl(FFPlatform* platform) {
|
||||
platform->pid = (uint32_t) getpid();
|
||||
platform->uid = getuid();
|
||||
struct passwd* pwd = getpwuid(platform->uid);
|
||||
|
||||
struct utsname uts;
|
||||
if(uname(&uts) < 0)
|
||||
if (uname(&uts) < 0) {
|
||||
memset(&uts, 0, sizeof(uts));
|
||||
}
|
||||
|
||||
getExePath(platform);
|
||||
getCwd(platform);
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
#define SECURITY_WIN32 1 // For secext.h
|
||||
#include <secext.h>
|
||||
|
||||
static void getExePath(FFPlatform* platform)
|
||||
{
|
||||
static void getExePath(FFPlatform* platform) {
|
||||
wchar_t exePathW[MAX_PATH];
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(
|
||||
@@ -26,19 +25,17 @@ static void getExePath(FFPlatform* platform)
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
if (hPath != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (hPath != INVALID_HANDLE_VALUE) {
|
||||
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_NORMALIZED);
|
||||
if (len > 0 && len < MAX_PATH)
|
||||
{
|
||||
if (len > 0 && len < MAX_PATH) {
|
||||
ffStrbufSetNWS(&platform->exePath, len, exePathW);
|
||||
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
|
||||
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\")) {
|
||||
ffStrbufSubstrAfter(&platform->exePath, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (platform->exePath.length == 0)
|
||||
{
|
||||
if (platform->exePath.length == 0) {
|
||||
PCUNICODE_STRING imagePathName = &ffGetPeb()->ProcessParameters->ImagePathName;
|
||||
ffStrbufSetNWS(&platform->exePath, imagePathName->Length / sizeof(wchar_t), imagePathName->Buffer);
|
||||
}
|
||||
@@ -46,17 +43,13 @@ static void getExePath(FFPlatform* platform)
|
||||
ffStrbufReplaceAllC(&platform->exePath, '\\', '/');
|
||||
}
|
||||
|
||||
static void getHomeDir(FFPlatform* platform)
|
||||
{
|
||||
static void getHomeDir(FFPlatform* platform) {
|
||||
PWSTR pPath = NULL;
|
||||
if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DEFAULT, NULL, &pPath)))
|
||||
{
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DEFAULT, NULL, &pPath))) {
|
||||
ffStrbufSetWS(&platform->homeDir, pPath);
|
||||
ffStrbufReplaceAllC(&platform->homeDir, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&platform->homeDir, '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufSetS(&platform->homeDir, getenv("USERPROFILE"));
|
||||
ffStrbufReplaceAllC(&platform->homeDir, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&platform->homeDir, '/');
|
||||
@@ -64,61 +57,54 @@ static void getHomeDir(FFPlatform* platform)
|
||||
CoTaskMemFree(pPath);
|
||||
}
|
||||
|
||||
static void getCacheDir(FFPlatform* platform)
|
||||
{
|
||||
static void getCacheDir(FFPlatform* platform) {
|
||||
PWSTR pPath = NULL;
|
||||
if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, &pPath)))
|
||||
{
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, &pPath))) {
|
||||
ffStrbufSetWS(&platform->cacheDir, pPath);
|
||||
ffStrbufReplaceAllC(&platform->cacheDir, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&platform->cacheDir, '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppend(&platform->cacheDir, &platform->homeDir);
|
||||
ffStrbufAppendS(&platform->cacheDir, "AppData/Local/");
|
||||
}
|
||||
CoTaskMemFree(pPath);
|
||||
}
|
||||
|
||||
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId)
|
||||
{
|
||||
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId) {
|
||||
PWSTR pPath = NULL;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath)))
|
||||
{
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath))) {
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateWS(pPath);
|
||||
CoTaskMemFree(pPath);
|
||||
ffStrbufReplaceAllC(&buffer, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&buffer, '/');
|
||||
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
|
||||
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual)) {
|
||||
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* suffix)
|
||||
{
|
||||
static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* suffix) {
|
||||
const char* value = getenv(env);
|
||||
if(!ffStrSet(value))
|
||||
if (!ffStrSet(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&buffer, value);
|
||||
ffStrbufReplaceAllC(&buffer, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&buffer, '/');
|
||||
if (suffix)
|
||||
{
|
||||
if (suffix) {
|
||||
ffStrbufAppendS(&buffer, suffix);
|
||||
ffStrbufEnsureEndsWithC(&buffer, '/');
|
||||
}
|
||||
|
||||
if (ffPathExists(buffer.chars, FF_PATHTYPE_DIRECTORY) && !ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
|
||||
if (ffPathExists(buffer.chars, FF_PATHTYPE_DIRECTORY) && !ffListContains(dirs, &buffer, (void*) ffStrbufEqual)) {
|
||||
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void getConfigDirs(FFPlatform* platform)
|
||||
{
|
||||
if(getenv("MSYSTEM"))
|
||||
{
|
||||
static void getConfigDirs(FFPlatform* platform) {
|
||||
if (getenv("MSYSTEM")) {
|
||||
// We are in MSYS2 / Git Bash
|
||||
platformPathAddEnvSuffix(&platform->configDirs, "HOME", ".config/");
|
||||
platformPathAddEnvSuffix(&platform->configDirs, "HOME", NULL);
|
||||
@@ -132,10 +118,8 @@ static void getConfigDirs(FFPlatform* platform)
|
||||
ffPlatformPathAddHome(&platform->configDirs, platform, "");
|
||||
}
|
||||
|
||||
static void getDataDirs(FFPlatform* platform)
|
||||
{
|
||||
if(getenv("MSYSTEM") && getenv("HOME"))
|
||||
{
|
||||
static void getDataDirs(FFPlatform* platform) {
|
||||
if (getenv("MSYSTEM") && getenv("HOME")) {
|
||||
// We are in MSYS2 / Git Bash
|
||||
platformPathAddEnvSuffix(&platform->dataDirs, "HOME", ".local/share/");
|
||||
platformPathAddEnvSuffix(&platform->dataDirs, "HOME", NULL);
|
||||
@@ -148,75 +132,77 @@ static void getDataDirs(FFPlatform* platform)
|
||||
ffPlatformPathAddHome(&platform->dataDirs, platform, "");
|
||||
}
|
||||
|
||||
static void getUserName(FFPlatform* platform)
|
||||
{
|
||||
static void getUserName(FFPlatform* platform) {
|
||||
wchar_t buffer[256];
|
||||
DWORD size = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameExW(NameDisplay, buffer, &size))
|
||||
if (GetUserNameExW(NameDisplay, buffer, &size)) {
|
||||
ffStrbufSetWS(&platform->fullUserName, buffer);
|
||||
}
|
||||
|
||||
size = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameW(buffer, &size)) // GetUserNameExW(10002)?
|
||||
if (GetUserNameW(buffer, &size)) { // GetUserNameExW(10002)?
|
||||
ffStrbufSetWS(&platform->userName, buffer);
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
|
||||
}
|
||||
|
||||
alignas(TOKEN_USER) char buf[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_USER)];
|
||||
if (NT_SUCCESS(NtQueryInformationToken(NtCurrentProcessToken(), TokenUser, buf, sizeof(buf), &size)))
|
||||
{
|
||||
if (NT_SUCCESS(NtQueryInformationToken(NtCurrentProcessToken(), TokenUser, buf, sizeof(buf), &size))) {
|
||||
TOKEN_USER* tokenUser = (TOKEN_USER*) buf;
|
||||
UNICODE_STRING sidString = { .Buffer = buffer, .Length = 0, .MaximumLength = sizeof(buffer) };
|
||||
if (NT_SUCCESS(RtlConvertSidToUnicodeString(&sidString, tokenUser->User.Sid, FALSE)))
|
||||
UNICODE_STRING sidString = {.Buffer = buffer, .Length = 0, .MaximumLength = sizeof(buffer)};
|
||||
if (NT_SUCCESS(RtlConvertSidToUnicodeString(&sidString, tokenUser->User.Sid, FALSE))) {
|
||||
ffStrbufSetNWS(&platform->sid, sidString.Length / sizeof(wchar_t), sidString.Buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getHostName(FFPlatform* platform)
|
||||
{
|
||||
static void getHostName(FFPlatform* platform) {
|
||||
wchar_t buffer[256];
|
||||
DWORD len = ARRAY_SIZE(buffer);
|
||||
if (GetComputerNameExW(ComputerNameDnsHostname, buffer, &len) && len > 0)
|
||||
if (GetComputerNameExW(ComputerNameDnsHostname, buffer, &len) && len > 0) {
|
||||
ffStrbufSetNWS(&platform->hostName, len, buffer);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
len = ARRAY_SIZE(buffer);
|
||||
if (GetComputerNameExW(ComputerNameNetBIOS, buffer, &len) && len > 0)
|
||||
if (GetComputerNameExW(ComputerNameNetBIOS, buffer, &len) && len > 0) {
|
||||
ffStrbufSetNWS(&platform->hostName, len, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getUserShell(FFPlatform* platform)
|
||||
{
|
||||
static void getUserShell(FFPlatform* platform) {
|
||||
// Works in MSYS2
|
||||
const char* userShell = getenv("SHELL");
|
||||
if (userShell)
|
||||
{
|
||||
if (userShell) {
|
||||
ffStrbufAppendS(&platform->userShell, userShell);
|
||||
ffStrbufReplaceAllC(&platform->userShell, '\\', '/');
|
||||
}
|
||||
}
|
||||
|
||||
static const char* detectWine(void)
|
||||
{
|
||||
const char * __cdecl wine_get_version(void);
|
||||
static const char* detectWine(void) {
|
||||
const char* __cdecl wine_get_version(void);
|
||||
void* hntdll = ffLibraryGetModule(L"ntdll.dll");
|
||||
if (!hntdll) return NULL;
|
||||
if (!hntdll) {
|
||||
return NULL;
|
||||
}
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
|
||||
if (!ffwine_get_version) return NULL;
|
||||
if (!ffwine_get_version) {
|
||||
return NULL;
|
||||
}
|
||||
return ffwine_get_version();
|
||||
}
|
||||
|
||||
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
|
||||
{
|
||||
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info) {
|
||||
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL))
|
||||
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t ubr = 0;
|
||||
ffRegReadValues(hKey, 2, (FFRegValueArg[]) {
|
||||
FF_ARG(ubr, L"UBR"),
|
||||
FF_ARG(info->version, L"BuildLabEx"),
|
||||
}, NULL);
|
||||
FF_ARG(ubr, L"UBR"),
|
||||
FF_ARG(info->version, L"BuildLabEx"),
|
||||
},
|
||||
NULL);
|
||||
|
||||
PPEB_FULL peb = ffGetPeb();
|
||||
|
||||
@@ -228,87 +214,82 @@ static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
|
||||
(unsigned) ubr);
|
||||
|
||||
const char* wineVersion = detectWine();
|
||||
if (wineVersion)
|
||||
if (wineVersion) {
|
||||
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
|
||||
else
|
||||
} else {
|
||||
ffStrbufSetStatic(&info->name, "WIN32_NT");
|
||||
}
|
||||
}
|
||||
|
||||
static void getSystemPageSize(FFPlatformSysinfo* info)
|
||||
{
|
||||
static void getSystemPageSize(FFPlatformSysinfo* info) {
|
||||
SYSTEM_BASIC_INFORMATION sbi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL)))
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL))) {
|
||||
info->pageSize = sbi.PhysicalPageSize;
|
||||
else
|
||||
} else {
|
||||
info->pageSize = 4096;
|
||||
}
|
||||
}
|
||||
|
||||
static void getSystemArchitecture(FFPlatformSysinfo* info)
|
||||
{
|
||||
static void getSystemArchitecture(FFPlatformSysinfo* info) {
|
||||
SYSTEM_PROCESSOR_INFORMATION spi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorInformation, &spi, sizeof(spi), NULL)))
|
||||
{
|
||||
switch (spi.ProcessorArchitecture)
|
||||
{
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
ffStrbufSetStatic(&info->architecture, "x86_64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
ffStrbufSetStatic(&info->architecture, "ia64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
switch (spi.ProcessorLevel)
|
||||
{
|
||||
case 4:
|
||||
ffStrbufSetStatic(&info->architecture, "i486");
|
||||
break;
|
||||
case 5:
|
||||
ffStrbufSetStatic(&info->architecture, "i586");
|
||||
break;
|
||||
case 6:
|
||||
ffStrbufSetStatic(&info->architecture, "i686");
|
||||
break;
|
||||
default:
|
||||
ffStrbufSetStatic(&info->architecture, "i386");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM64:
|
||||
ffStrbufSetStatic(&info->architecture, "aarch64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM:
|
||||
ffStrbufSetStatic(&info->architecture, "arm");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_PPC:
|
||||
ffStrbufSetStatic(&info->architecture, "ppc");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_MIPS:
|
||||
ffStrbufSetStatic(&info->architecture, "mips");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||||
ffStrbufSetStatic(&info->architecture, "alpha");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA64:
|
||||
ffStrbufSetStatic(&info->architecture, "alpha64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_UNKNOWN:
|
||||
default:
|
||||
ffStrbufSetStatic(&info->architecture, "unknown");
|
||||
break;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorInformation, &spi, sizeof(spi), NULL))) {
|
||||
switch (spi.ProcessorArchitecture) {
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
ffStrbufSetStatic(&info->architecture, "x86_64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
ffStrbufSetStatic(&info->architecture, "ia64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
switch (spi.ProcessorLevel) {
|
||||
case 4:
|
||||
ffStrbufSetStatic(&info->architecture, "i486");
|
||||
break;
|
||||
case 5:
|
||||
ffStrbufSetStatic(&info->architecture, "i586");
|
||||
break;
|
||||
case 6:
|
||||
ffStrbufSetStatic(&info->architecture, "i686");
|
||||
break;
|
||||
default:
|
||||
ffStrbufSetStatic(&info->architecture, "i386");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM64:
|
||||
ffStrbufSetStatic(&info->architecture, "aarch64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM:
|
||||
ffStrbufSetStatic(&info->architecture, "arm");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_PPC:
|
||||
ffStrbufSetStatic(&info->architecture, "ppc");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_MIPS:
|
||||
ffStrbufSetStatic(&info->architecture, "mips");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||||
ffStrbufSetStatic(&info->architecture, "alpha");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA64:
|
||||
ffStrbufSetStatic(&info->architecture, "alpha64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_UNKNOWN:
|
||||
default:
|
||||
ffStrbufSetStatic(&info->architecture, "unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getCwd(FFPlatform* platform)
|
||||
{
|
||||
static void getCwd(FFPlatform* platform) {
|
||||
PCURDIR cwd = &ffGetPeb()->ProcessParameters->CurrentDirectory;
|
||||
ffStrbufSetNWS(&platform->cwd, cwd->DosPath.Length / sizeof(WCHAR), cwd->DosPath.Buffer);
|
||||
ffStrbufReplaceAllC(&platform->cwd, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
|
||||
}
|
||||
|
||||
void ffPlatformInitImpl(FFPlatform* platform)
|
||||
{
|
||||
void ffPlatformInitImpl(FFPlatform* platform) {
|
||||
platform->pid = (uint32_t) (uintptr_t) ffGetTeb()->ClientId.UniqueProcess;
|
||||
getExePath(platform);
|
||||
getCwd(platform);
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void* ffListAdd(FFlist* list)
|
||||
{
|
||||
if(list->length == list->capacity)
|
||||
void* ffListAdd(FFlist* list) {
|
||||
if (list->length == list->capacity) {
|
||||
ffListReserve(list, list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2);
|
||||
}
|
||||
|
||||
++list->length;
|
||||
return ffListGet(list, list->length - 1);
|
||||
}
|
||||
|
||||
bool ffListShift(FFlist* list, void* result)
|
||||
{
|
||||
if(list->length == 0)
|
||||
bool ffListShift(FFlist* list, void* result) {
|
||||
if (list->length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(result, list->data, list->elementSize);
|
||||
memmove(list->data, list->data + list->elementSize, (size_t) list->elementSize * (list->length - 1));
|
||||
@@ -23,10 +23,10 @@ bool ffListShift(FFlist* list, void* result)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffListPop(FFlist* list, void* result)
|
||||
{
|
||||
if(list->length == 0)
|
||||
bool ffListPop(FFlist* list, void* result) {
|
||||
if (list->length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(result, ffListGet(list, list->length - 1), list->elementSize);
|
||||
--list->length;
|
||||
|
||||
+287
-322
File diff suppressed because it is too large
Load Diff
+45
-47
@@ -1,14 +1,12 @@
|
||||
#include "common/base64.h"
|
||||
|
||||
// https://github.com/kostya/benchmarks/blob/master/base64/test-nolib.c#L145
|
||||
void ffBase64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
|
||||
{
|
||||
void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output) {
|
||||
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
char *out = output;
|
||||
const char *ends = str + (size - size % 3);
|
||||
while (str != ends)
|
||||
{
|
||||
uint32_t n = __builtin_bswap32(*(uint32_t *)str);
|
||||
char* out = output;
|
||||
const char* ends = str + (size - size % 3);
|
||||
while (str != ends) {
|
||||
uint32_t n = __builtin_bswap32(*(uint32_t*) str);
|
||||
*out++ = chars[(n >> 26) & 63];
|
||||
*out++ = chars[(n >> 20) & 63];
|
||||
*out++ = chars[(n >> 14) & 63];
|
||||
@@ -16,94 +14,94 @@ void ffBase64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char
|
||||
str += 3;
|
||||
}
|
||||
|
||||
if (size % 3 == 1)
|
||||
{
|
||||
uint64_t n = (uint64_t)*str << 16;
|
||||
if (size % 3 == 1) {
|
||||
uint64_t n = (uint64_t) *str << 16;
|
||||
*out++ = chars[(n >> 18) & 63];
|
||||
*out++ = chars[(n >> 12) & 63];
|
||||
*out++ = '=';
|
||||
*out++ = '=';
|
||||
}
|
||||
else if (size % 3 == 2)
|
||||
{
|
||||
uint64_t n = (uint64_t)*str++ << 16;
|
||||
n |= (uint64_t)*str << 8;
|
||||
} else if (size % 3 == 2) {
|
||||
uint64_t n = (uint64_t) *str++ << 16;
|
||||
n |= (uint64_t) *str << 8;
|
||||
*out++ = chars[(n >> 18) & 63];
|
||||
*out++ = chars[(n >> 12) & 63];
|
||||
*out++ = chars[(n >> 6) & 63];
|
||||
*out++ = '=';
|
||||
}
|
||||
*out = '\0';
|
||||
*out_size = (uint32_t)(out - output);
|
||||
*out_size = (uint32_t) (out - output);
|
||||
}
|
||||
|
||||
static uint8_t decode_table[256];
|
||||
|
||||
void init_decode_table()
|
||||
{
|
||||
void init_decode_table() {
|
||||
uint8_t ch = 0;
|
||||
do
|
||||
{
|
||||
do {
|
||||
int32_t code = -1;
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
code = ch - 0x41;
|
||||
if (ch >= 'a' && ch <= 'z')
|
||||
}
|
||||
if (ch >= 'a' && ch <= 'z') {
|
||||
code = ch - 0x47;
|
||||
if (ch >= '0' && ch <= '9')
|
||||
}
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
code = ch + 0x04;
|
||||
if (ch == '+' || ch == '-')
|
||||
}
|
||||
if (ch == '+' || ch == '-') {
|
||||
code = 0x3E;
|
||||
if (ch == '/' || ch == '_')
|
||||
}
|
||||
if (ch == '/' || ch == '_') {
|
||||
code = 0x3F;
|
||||
}
|
||||
decode_table[ch] = (uint8_t) code;
|
||||
} while (ch++ < 0xFF);
|
||||
}
|
||||
|
||||
#define next_char(x) uint8_t x = decode_table[(uint8_t) *str++];
|
||||
|
||||
bool ffBase64DecodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
|
||||
{
|
||||
if (*(uint64_t*) decode_table == 0)
|
||||
bool ffBase64DecodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output) {
|
||||
if (*(uint64_t*) decode_table == 0) {
|
||||
init_decode_table();
|
||||
}
|
||||
|
||||
char *out = output;
|
||||
while (size > 0 && (str[size - 1] == '\n' || str[size - 1] == '\r' || str[size - 1] == '='))
|
||||
char* out = output;
|
||||
while (size > 0 && (str[size - 1] == '\n' || str[size - 1] == '\r' || str[size - 1] == '=')) {
|
||||
size--;
|
||||
}
|
||||
|
||||
const char *ends = str + size - 4;
|
||||
while (true)
|
||||
{
|
||||
if (str > ends)
|
||||
const char* ends = str + size - 4;
|
||||
while (true) {
|
||||
if (str > ends) {
|
||||
break;
|
||||
while (*str == '\n' || *str == '\r')
|
||||
}
|
||||
while (*str == '\n' || *str == '\r') {
|
||||
str++;
|
||||
}
|
||||
|
||||
if (str > ends)
|
||||
if (str > ends) {
|
||||
break;
|
||||
}
|
||||
next_char(a);
|
||||
next_char(b);
|
||||
next_char(c);
|
||||
next_char(d);
|
||||
|
||||
*out++ = (char)(a << 2 | b >> 4);
|
||||
*out++ = (char)(b << 4 | c >> 2);
|
||||
*out++ = (char)(c << 6 | d >> 0);
|
||||
*out++ = (char) (a << 2 | b >> 4);
|
||||
*out++ = (char) (b << 4 | c >> 2);
|
||||
*out++ = (char) (c << 6 | d >> 0);
|
||||
}
|
||||
|
||||
uint8_t mod = (uint8_t) (ends - str + 4) % 4;
|
||||
if (mod == 2)
|
||||
{
|
||||
if (mod == 2) {
|
||||
next_char(a);
|
||||
next_char(b);
|
||||
*out++ = (char)(a << 2 | b >> 4);
|
||||
}
|
||||
else if (mod == 3)
|
||||
{
|
||||
*out++ = (char) (a << 2 | b >> 4);
|
||||
} else if (mod == 3) {
|
||||
next_char(a);
|
||||
next_char(b);
|
||||
next_char(c);
|
||||
*out++ = (char)(a << 2 | b >> 4);
|
||||
*out++ = (char)(b << 4 | c >> 2);
|
||||
*out++ = (char) (a << 2 | b >> 4);
|
||||
*out++ = (char) (b << 4 | c >> 2);
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
/**
|
||||
* Helper function to read data from a file at a specific offset
|
||||
*/
|
||||
static inline bool readData(FILE *objFile, void *buf, size_t size, off_t offset)
|
||||
{
|
||||
static inline bool readData(FILE* objFile, void* buf, size_t size, off_t offset) {
|
||||
fseek(objFile, offset, SEEK_SET);
|
||||
return fread(buf, 1, size, objFile) == size;
|
||||
}
|
||||
@@ -36,23 +35,29 @@ static inline bool readData(FILE *objFile, void *buf, size_t size, off_t offset)
|
||||
*
|
||||
* @return true to continue processing, false to stop
|
||||
*/
|
||||
static bool handleMachSection(FILE *objFile, const char *name, off_t offset, size_t size, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
if (!ffStrEquals(name, "__cstring")) return true;
|
||||
static bool handleMachSection(FILE* objFile, const char* name, off_t offset, size_t size, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
|
||||
if (!ffStrEquals(name, "__cstring")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE char* data = (char*) malloc(size);
|
||||
if (!readData(objFile, data, size, offset))
|
||||
if (!readData(objFile, data, size, offset)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t off = 0; off < size; ++off)
|
||||
{
|
||||
for (size_t off = 0; off < size; ++off) {
|
||||
const char* p = (const char*) data + off;
|
||||
if (*p == '\0') continue;
|
||||
if (*p == '\0') {
|
||||
continue;
|
||||
}
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
if (len < minLength) continue;
|
||||
if (*p >= ' ' && *p <= '~') // Ignore control characters
|
||||
{
|
||||
if (!cb(p, len, userdata)) return false;
|
||||
if (len < minLength) {
|
||||
continue;
|
||||
}
|
||||
if (*p >= ' ' && *p <= '~') { // Ignore control characters
|
||||
if (!cb(p, len, userdata)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
off += len;
|
||||
}
|
||||
@@ -75,25 +80,23 @@ static bool handleMachSection(FILE *objFile, const char *name, off_t offset, siz
|
||||
*
|
||||
* @return NULL on success, error message on failure
|
||||
*/
|
||||
static const char* dumpMachHeader(FILE *objFile, off_t offset, bool is_64, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
static const char* dumpMachHeader(FILE* objFile, off_t offset, bool is_64, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
|
||||
uint32_t ncmds;
|
||||
off_t loadCommandsOffset = offset;
|
||||
|
||||
if (is_64)
|
||||
{
|
||||
if (is_64) {
|
||||
struct mach_header_64 header;
|
||||
if (!readData(objFile, &header, sizeof(header), offset))
|
||||
if (!readData(objFile, &header, sizeof(header), offset)) {
|
||||
return "read mach header failed";
|
||||
}
|
||||
|
||||
ncmds = header.ncmds;
|
||||
loadCommandsOffset += sizeof(header);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
struct mach_header header;
|
||||
if (!readData(objFile, &header, sizeof(header), offset))
|
||||
if (!readData(objFile, &header, sizeof(header), offset)) {
|
||||
return "read mach header failed";
|
||||
}
|
||||
|
||||
ncmds = header.ncmds;
|
||||
loadCommandsOffset += sizeof(header);
|
||||
@@ -101,45 +104,50 @@ static const char* dumpMachHeader(FILE *objFile, off_t offset, bool is_64, bool
|
||||
|
||||
off_t commandOffset = loadCommandsOffset;
|
||||
struct load_command cmd = {};
|
||||
for (uint32_t i = 0U; i < ncmds; i++, commandOffset += cmd.cmdsize)
|
||||
{
|
||||
if (!readData(objFile, &cmd, sizeof(cmd), commandOffset))
|
||||
for (uint32_t i = 0U; i < ncmds; i++, commandOffset += cmd.cmdsize) {
|
||||
if (!readData(objFile, &cmd, sizeof(cmd), commandOffset)) {
|
||||
continue;
|
||||
|
||||
if (cmd.cmd == LC_SEGMENT_64)
|
||||
{
|
||||
struct segment_command_64 segment;
|
||||
if (!readData(objFile, &segment, sizeof(segment), commandOffset))
|
||||
continue;
|
||||
|
||||
if (!ffStrEquals(segment.segname, "__TEXT")) continue;
|
||||
|
||||
for (uint32_t j = 0U; j < segment.nsects; j++)
|
||||
{
|
||||
struct section_64 section;
|
||||
if (!readData(objFile, §ion, sizeof(section), (off_t) ((size_t) commandOffset + sizeof(segment) + j * sizeof(section))))
|
||||
continue;
|
||||
|
||||
if (!handleMachSection(objFile, section.sectname, section.offset, section.size, cb, userdata, minLength))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (cmd.cmd == LC_SEGMENT)
|
||||
{
|
||||
struct segment_command segment;
|
||||
if (!readData(objFile, &segment, sizeof(segment), commandOffset))
|
||||
|
||||
if (cmd.cmd == LC_SEGMENT_64) {
|
||||
struct segment_command_64 segment;
|
||||
if (!readData(objFile, &segment, sizeof(segment), commandOffset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ffStrEquals(segment.segname, "__TEXT")) continue;
|
||||
if (!ffStrEquals(segment.segname, "__TEXT")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < segment.nsects; j++)
|
||||
{
|
||||
struct section section;
|
||||
if (!readData(objFile, §ion, sizeof(section), (off_t) ((size_t) commandOffset + sizeof(segment) + j * sizeof(section))))
|
||||
for (uint32_t j = 0U; j < segment.nsects; j++) {
|
||||
struct section_64 section;
|
||||
if (!readData(objFile, §ion, sizeof(section), (off_t) ((size_t) commandOffset + sizeof(segment) + j * sizeof(section)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!handleMachSection(objFile, section.sectname, section.offset, section.size, cb, userdata, minLength))
|
||||
if (!handleMachSection(objFile, section.sectname, section.offset, section.size, cb, userdata, minLength)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else if (cmd.cmd == LC_SEGMENT) {
|
||||
struct segment_command segment;
|
||||
if (!readData(objFile, &segment, sizeof(segment), commandOffset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ffStrEquals(segment.segname, "__TEXT")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < segment.nsects; j++) {
|
||||
struct section section;
|
||||
if (!readData(objFile, §ion, sizeof(section), (off_t) ((size_t) commandOffset + sizeof(segment) + j * sizeof(section)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!handleMachSection(objFile, section.sectname, section.offset, section.size, cb, userdata, minLength)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,47 +171,49 @@ static const char* dumpMachHeader(FILE *objFile, off_t offset, bool is_64, bool
|
||||
*
|
||||
* @return NULL on success, error message on failure
|
||||
*/
|
||||
static const char* dumpFatHeader(FILE *objFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
static const char* dumpFatHeader(FILE* objFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
|
||||
struct fat_header header;
|
||||
if (!readData(objFile, &header, sizeof(header), 0))
|
||||
if (!readData(objFile, &header, sizeof(header), 0)) {
|
||||
return "read fat header failed";
|
||||
}
|
||||
|
||||
bool needSwap = header.magic == FAT_CIGAM || header.magic == FAT_CIGAM_64;
|
||||
|
||||
if (needSwap) swap_fat_header(&header, NX_UnknownByteOrder);
|
||||
if (needSwap) {
|
||||
swap_fat_header(&header, NX_UnknownByteOrder);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0U; i < header.nfat_arch; i++)
|
||||
{
|
||||
for (uint32_t i = 0U; i < header.nfat_arch; i++) {
|
||||
off_t machHeaderOffset = 0;
|
||||
if (header.magic == FAT_MAGIC)
|
||||
{
|
||||
if (header.magic == FAT_MAGIC) {
|
||||
struct fat_arch arch;
|
||||
if (!readData(objFile, &arch, sizeof(arch), (off_t) (sizeof(header) + i * sizeof(arch))))
|
||||
if (!readData(objFile, &arch, sizeof(arch), (off_t) (sizeof(header) + i * sizeof(arch)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (needSwap)
|
||||
if (needSwap) {
|
||||
swap_fat_arch(&arch, 1, NX_UnknownByteOrder);
|
||||
machHeaderOffset = (off_t)arch.offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
machHeaderOffset = (off_t) arch.offset;
|
||||
} else {
|
||||
struct fat_arch_64 arch;
|
||||
if (!readData(objFile, &arch, sizeof(arch), (off_t) (sizeof(header) + i * sizeof(arch))))
|
||||
if (!readData(objFile, &arch, sizeof(arch), (off_t) (sizeof(header) + i * sizeof(arch)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (needSwap)
|
||||
if (needSwap) {
|
||||
swap_fat_arch_64(&arch, 1, NX_UnknownByteOrder);
|
||||
}
|
||||
|
||||
machHeaderOffset = (off_t)arch.offset;
|
||||
machHeaderOffset = (off_t) arch.offset;
|
||||
}
|
||||
|
||||
uint32_t magic;
|
||||
if (!readData(objFile, &magic, sizeof(magic), machHeaderOffset))
|
||||
if (!readData(objFile, &magic, sizeof(magic), machHeaderOffset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (magic == MH_MAGIC_64 || magic == MH_MAGIC)
|
||||
{
|
||||
if (magic == MH_MAGIC_64 || magic == MH_MAGIC) {
|
||||
dumpMachHeader(objFile, machHeaderOffset, magic == MH_MAGIC_64, cb, userdata, minLength);
|
||||
return NULL;
|
||||
}
|
||||
@@ -219,26 +229,29 @@ static const char* dumpFatHeader(FILE *objFile, bool (*cb)(const char *str, uint
|
||||
* It locates the __cstring section in the __TEXT segment which contains
|
||||
* the string literals used in the program.
|
||||
*/
|
||||
const char *ffBinaryExtractStrings(const char *machoFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
FF_AUTO_CLOSE_FILE FILE *objFile = fopen(machoFile, "rb");
|
||||
if (objFile == NULL)
|
||||
const char* ffBinaryExtractStrings(const char* machoFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
|
||||
FF_AUTO_CLOSE_FILE FILE* objFile = fopen(machoFile, "rb");
|
||||
if (objFile == NULL) {
|
||||
return "File could not be opened";
|
||||
}
|
||||
|
||||
// Read the magic number to determine the type of binary
|
||||
uint32_t magic;
|
||||
if (!readData(objFile, &magic, sizeof(magic), 0))
|
||||
if (!readData(objFile, &magic, sizeof(magic), 0)) {
|
||||
return "read magic number failed";
|
||||
}
|
||||
|
||||
// Check for supported formats
|
||||
// MH_CIGAM and MH_CIGAM_64 seem to be no longer used, as `swap_mach_header` is marked as deprecated.
|
||||
// However FAT_CIGAM and FAT_CIGAM_64 are still used (/usr/bin/vim).
|
||||
if (magic != MH_MAGIC && magic != MH_MAGIC_64 && magic != FAT_CIGAM && magic != FAT_CIGAM_64 && magic != FAT_MAGIC && magic != FAT_MAGIC_64)
|
||||
if (magic != MH_MAGIC && magic != MH_MAGIC_64 && magic != FAT_CIGAM && magic != FAT_CIGAM_64 && magic != FAT_MAGIC && magic != FAT_MAGIC_64) {
|
||||
return "Unsupported format or big endian mach-o file";
|
||||
}
|
||||
|
||||
// Process either a fat binary or a regular Mach-O binary
|
||||
if (magic == FAT_MAGIC || magic == FAT_MAGIC_64 || magic == FAT_CIGAM || magic == FAT_CIGAM_64)
|
||||
if (magic == FAT_MAGIC || magic == FAT_MAGIC_64 || magic == FAT_CIGAM || magic == FAT_CIGAM_64) {
|
||||
return dumpFatHeader(objFile, cb, userdata, minLength);
|
||||
else
|
||||
} else {
|
||||
return dumpMachHeader(objFile, 0, magic == MH_MAGIC_64, cb, userdata, minLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
#if defined(FF_HAVE_ELF) || defined(__sun) || (defined(__FreeBSD__) && !defined(__DragonFly__)) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
|
||||
#include "common/io.h"
|
||||
#include "common/library.h"
|
||||
#include "common/stringUtils.h"
|
||||
# include "common/io.h"
|
||||
# include "common/library.h"
|
||||
# include "common/stringUtils.h"
|
||||
|
||||
#include <libelf.h> // #1254
|
||||
#include <fcntl.h>
|
||||
# include <libelf.h> // #1254
|
||||
# include <fcntl.h>
|
||||
|
||||
/**
|
||||
* Structure to hold dynamically loaded libelf function pointers
|
||||
@@ -36,15 +36,15 @@ struct FFElfData {
|
||||
*
|
||||
* The function supports both 32-bit and 64-bit ELF formats.
|
||||
*/
|
||||
const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength)
|
||||
{
|
||||
const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
|
||||
// Initialize libelf if not already done
|
||||
if (!elfData.inited)
|
||||
{
|
||||
if (!elfData.inited) {
|
||||
elfData.inited = true;
|
||||
FF_LIBRARY_LOAD_MESSAGE(libelf, "libelf" FF_LIBRARY_EXTENSION, 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_version)
|
||||
if (elfData.ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed";
|
||||
if (elfData.ffelf_version(EV_CURRENT) == EV_NONE) {
|
||||
return "elf_version() failed";
|
||||
}
|
||||
|
||||
// Load all required libelf functions
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_begin)
|
||||
@@ -59,56 +59,69 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
libelf = NULL;
|
||||
}
|
||||
|
||||
if (elfData.ffelf_end == NULL)
|
||||
if (elfData.ffelf_end == NULL) {
|
||||
return "load libelf failed";
|
||||
}
|
||||
|
||||
// Open the ELF file
|
||||
FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "open() failed";
|
||||
if (fd < 0) {
|
||||
return "open() failed";
|
||||
}
|
||||
|
||||
Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, NULL);
|
||||
if (elf == NULL) return "elf_begin() failed";
|
||||
if (elf == NULL) {
|
||||
return "elf_begin() failed";
|
||||
}
|
||||
|
||||
// Get the section header string table index
|
||||
size_t shstrndx = 0;
|
||||
if (elfData.ffelf_getshdrstrndx(elf, &shstrndx) < 0)
|
||||
{
|
||||
if (elfData.ffelf_getshdrstrndx(elf, &shstrndx) < 0) {
|
||||
elfData.ffelf_end(elf);
|
||||
return "elf_getshdrstrndx() failed";
|
||||
}
|
||||
|
||||
// Iterate through all sections, looking for .rodata which contains string literals
|
||||
Elf_Scn* scn = NULL;
|
||||
while ((scn = elfData.ffelf_nextscn(elf, scn)) != NULL)
|
||||
{
|
||||
while ((scn = elfData.ffelf_nextscn(elf, scn)) != NULL) {
|
||||
// Try 64-bit section header first, then 32-bit if that fails
|
||||
Elf64_Shdr* shdr64 = elfData.ffelf64_getshdr(scn);
|
||||
Elf32_Shdr* shdr32 = NULL;
|
||||
if (shdr64 == NULL)
|
||||
{
|
||||
if (shdr64 == NULL) {
|
||||
shdr32 = elfData.ffelf32_getshdr(scn);
|
||||
if (shdr32 == NULL) continue;
|
||||
if (shdr32 == NULL) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the section name and check if it's .rodata
|
||||
const char* name = elfData.ffelf_strptr(elf, shstrndx, shdr64 ? shdr64->sh_name : shdr32->sh_name);
|
||||
if (name == NULL || !ffStrEquals(name, ".rodata")) continue;
|
||||
if (name == NULL || !ffStrEquals(name, ".rodata")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the section data
|
||||
Elf_Data* data = elfData.ffelf_getdata(scn, NULL);
|
||||
if (data == NULL) continue;
|
||||
if (data == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Scan the section for string literals
|
||||
for (size_t off = 0; off < data->d_size; ++off)
|
||||
{
|
||||
for (size_t off = 0; off < data->d_size; ++off) {
|
||||
const char* p = (const char*) data->d_buf + off;
|
||||
if (*p == '\0') continue;
|
||||
if (*p == '\0') {
|
||||
continue;
|
||||
}
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
if (len < minLength) continue;
|
||||
if (len < minLength) {
|
||||
continue;
|
||||
}
|
||||
// Only process printable ASCII characters
|
||||
if (*p >= ' ' && *p <= '~') // Ignore control characters
|
||||
{
|
||||
if (!cb(p, len, userdata)) break;
|
||||
if (!cb(p, len, userdata)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
off += len;
|
||||
}
|
||||
@@ -125,8 +138,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
/**
|
||||
* Fallback implementation when libelf is not available
|
||||
*/
|
||||
const char* ffBinaryExtractStrings(const char* file, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength)
|
||||
{
|
||||
const char* ffBinaryExtractStrings(const char* file, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
|
||||
FF_UNUSED(file, cb, userdata, minLength);
|
||||
return "Fastfetch was built without libelf support";
|
||||
}
|
||||
|
||||
@@ -14,48 +14,51 @@
|
||||
* (which typically contains string literals), and scans it for valid strings.
|
||||
* Each string found is passed to the callback function for processing.
|
||||
*/
|
||||
const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileA(peFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
const char* ffBinaryExtractStrings(const char* peFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
|
||||
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileA(peFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
return "CreateFileA() failed";
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hSection = NULL;
|
||||
if (!NT_SUCCESS(NtCreateSection(&hSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, hFile)))
|
||||
if (!NT_SUCCESS(NtCreateSection(&hSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, hFile))) {
|
||||
return "NtCreateSection() failed";
|
||||
}
|
||||
|
||||
PVOID base = NULL;
|
||||
SIZE_T viewSize = 0;
|
||||
if (!NT_SUCCESS(NtMapViewOfSection(hSection, NtCurrentProcess(), &base, 0, 0, NULL, &viewSize, ViewUnmap, 0, PAGE_READONLY)))
|
||||
if (!NT_SUCCESS(NtMapViewOfSection(hSection, NtCurrentProcess(), &base, 0, 0, NULL, &viewSize, ViewUnmap, 0, PAGE_READONLY))) {
|
||||
return "NtMapViewOfSection() failed";
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader(base);
|
||||
if (!ntHeaders)
|
||||
{
|
||||
if (!ntHeaders) {
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), base);
|
||||
return "RtlImageNtHeader() failed";
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
|
||||
for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section)
|
||||
{
|
||||
for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section) {
|
||||
// Look for initialized data sections with the name ".rdata" which typically contains string literals
|
||||
if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) && ffStrEquals((const char*) section->Name, ".rdata"))
|
||||
{
|
||||
uint8_t *data = (uint8_t *) base + section->PointerToRawData;
|
||||
if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) && ffStrEquals((const char*) section->Name, ".rdata")) {
|
||||
uint8_t* data = (uint8_t*) base + section->PointerToRawData;
|
||||
|
||||
// Scan the section for string literals
|
||||
for (size_t off = 0; off < section->SizeOfRawData; ++off)
|
||||
{
|
||||
for (size_t off = 0; off < section->SizeOfRawData; ++off) {
|
||||
const char* p = (const char*) data + off;
|
||||
if (*p == '\0') continue;
|
||||
if (*p == '\0') {
|
||||
continue;
|
||||
}
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
if (len < minLength) continue;
|
||||
if (len < minLength) {
|
||||
continue;
|
||||
}
|
||||
// Only process printable ASCII characters
|
||||
if (*p >= ' ' && *p <= '~') // Ignore control characters
|
||||
{
|
||||
if (!cb(p, len, userdata)) break;
|
||||
if (!cb(p, len, userdata)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
off += len;
|
||||
}
|
||||
|
||||
@@ -10,16 +10,17 @@
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value)
|
||||
{
|
||||
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
|
||||
if (value && !*value) value = NULL;
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
bool ffParseModuleOptions(const char* key, const char* value) {
|
||||
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) {
|
||||
return false;
|
||||
}
|
||||
if (value && !*value) {
|
||||
value = NULL;
|
||||
}
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules) {
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
const char* subKey = ffOptionTestPrefix(key, baseInfo->name);
|
||||
if (subKey != NULL)
|
||||
{
|
||||
if (subKey != NULL) {
|
||||
if (subKey[0] == '\0' || subKey[0] == '-') // Key is exactly the module name or has a leading '-'
|
||||
{
|
||||
fprintf(stderr, "Error: unknown module key %s\n", key);
|
||||
@@ -31,32 +32,25 @@ bool ffParseModuleOptions(const char* key, const char* value)
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY jsonKey = ffStrbufCreate();
|
||||
bool flag = false;
|
||||
for (const char* p = subKey; *p; ++p)
|
||||
{
|
||||
if (*p == '-')
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
for (const char* p = subKey; *p; ++p) {
|
||||
if (*p == '-') {
|
||||
if (flag) {
|
||||
fprintf(stderr, "Error: invalid double `-` in module key %s\n", key);
|
||||
exit(477);
|
||||
}
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p))
|
||||
{
|
||||
} else {
|
||||
if (!isalpha((unsigned char) *p) && !isdigit((unsigned char) *p)) {
|
||||
fprintf(stderr, "Error: invalid character `%c` in module key %s\n", *p, key);
|
||||
exit(477);
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (flag) {
|
||||
flag = false;
|
||||
ffStrbufAppendC(&jsonKey, (char) toupper((unsigned char) *p));
|
||||
}
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendC(&jsonKey, *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Error: Unsupported module option: %s\n", key);
|
||||
@@ -69,53 +63,49 @@ bool ffParseModuleOptions(const char* key, const char* value)
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrepareCommandOption(FFdata* data)
|
||||
{
|
||||
void ffPrepareCommandOption(FFdata* data) {
|
||||
char* moduleType = NULL;
|
||||
size_t moduleLen = 0;
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
|
||||
{
|
||||
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) \
|
||||
&& ffStrEqualsIgnCase(moduleType, moduleNameConstant) \
|
||||
&& !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) {
|
||||
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) && ffStrEqualsIgnCase(moduleType, moduleNameConstant) && !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
|
||||
|
||||
switch (moduleType[0])
|
||||
{
|
||||
case 'C': case 'c':
|
||||
switch (moduleType[0]) {
|
||||
case 'C':
|
||||
case 'c':
|
||||
FF_IF_MODULE_MATCH(FF_CPUUSAGE_MODULE_NAME)
|
||||
ffPrepareCPUUsage();
|
||||
ffPrepareCPUUsage();
|
||||
break;
|
||||
|
||||
case 'D': case 'd':
|
||||
FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME)
|
||||
{
|
||||
case 'D':
|
||||
case 'd':
|
||||
FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME) {
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N': case 'n':
|
||||
FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME)
|
||||
{
|
||||
case 'N':
|
||||
case 'n':
|
||||
FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME) {
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P': case 'p':
|
||||
FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME)
|
||||
{
|
||||
case 'P':
|
||||
case 'p':
|
||||
FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME) {
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'W': case 'w':
|
||||
FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME)
|
||||
{
|
||||
case 'W':
|
||||
case 'w':
|
||||
FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME) {
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
ffPrepareWeather(&options);
|
||||
@@ -123,70 +113,65 @@ void ffPrepareCommandOption(FFdata* data)
|
||||
break;
|
||||
}
|
||||
|
||||
#undef FF_IF_MODULE_MATCH
|
||||
#undef FF_IF_MODULE_MATCH
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonConfig(FFdata* data, FFModuleBaseInfo* baseInfo, void* options)
|
||||
{
|
||||
static void genJsonConfig(FFdata* data, FFModuleBaseInfo* baseInfo, void* options) {
|
||||
yyjson_mut_doc* doc = data->resultDoc;
|
||||
|
||||
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
|
||||
if (!modules)
|
||||
if (!modules) {
|
||||
modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules");
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
|
||||
ffStrbufLowerCase(&type);
|
||||
|
||||
if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL)
|
||||
{
|
||||
if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL) {
|
||||
yyjson_mut_val* module = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
|
||||
|
||||
if (baseInfo->generateJsonConfig)
|
||||
if (baseInfo->generateJsonConfig) {
|
||||
baseInfo->generateJsonConfig(options, doc, module);
|
||||
}
|
||||
|
||||
if (yyjson_mut_obj_size(module) > 1)
|
||||
if (yyjson_mut_obj_size(module) > 1) {
|
||||
yyjson_mut_arr_add_val(modules, module);
|
||||
else
|
||||
} else {
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonResult(FFdata* data, FFModuleBaseInfo* baseInfo, void* options)
|
||||
{
|
||||
static void genJsonResult(FFdata* data, FFModuleBaseInfo* baseInfo, void* options) {
|
||||
yyjson_mut_doc* doc = data->resultDoc;
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
if (baseInfo->generateJsonResult) {
|
||||
baseInfo->generateJsonResult(options, doc, module);
|
||||
else
|
||||
} else {
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
}
|
||||
}
|
||||
|
||||
static void parseStructureCommand(
|
||||
FFdata* data,
|
||||
const char* line,
|
||||
void (*fn)(FFdata*, FFModuleBaseInfo* baseInfo, void* options)
|
||||
)
|
||||
{
|
||||
if(ffCharIsEnglishAlphabet(line[0]))
|
||||
{
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(line[0]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
void (*fn)(FFdata*, FFModuleBaseInfo* baseInfo, void* options)) {
|
||||
if (ffCharIsEnglishAlphabet(line[0])) {
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(line[0]) - 'A']; *modules; ++modules) {
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name))
|
||||
{
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name)) {
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (__builtin_expect(data->resultDoc != NULL, false))
|
||||
if (__builtin_expect(data->resultDoc != NULL, false)) {
|
||||
fn(data, baseInfo, optionBuf);
|
||||
else
|
||||
} else {
|
||||
baseInfo->printModule(optionBuf);
|
||||
}
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return;
|
||||
}
|
||||
@@ -196,61 +181,62 @@ static void parseStructureCommand(
|
||||
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
|
||||
}
|
||||
|
||||
void ffPrintCommandOption(FFdata* data)
|
||||
{
|
||||
//Parse the structure and call the modules
|
||||
void ffPrintCommandOption(FFdata* data) {
|
||||
// Parse the structure and call the modules
|
||||
int32_t thres = instance.config.display.stat;
|
||||
|
||||
char* moduleType = NULL;
|
||||
size_t moduleLen = 0;
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
|
||||
{
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':'))
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) {
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double ms = 0;
|
||||
if(thres >= 0)
|
||||
if (thres >= 0) {
|
||||
ms = ffTimeGetTick();
|
||||
}
|
||||
|
||||
parseStructureCommand(data, moduleType, genJsonResult);
|
||||
|
||||
if(thres >= 0)
|
||||
{
|
||||
if (thres >= 0) {
|
||||
ms = ffTimeGetTick() - ms;
|
||||
|
||||
if (data->resultDoc)
|
||||
{
|
||||
if (data->resultDoc) {
|
||||
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(data->resultDoc->root);
|
||||
yyjson_mut_obj_add_real(data->resultDoc, moduleJson, "stat", ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
char str[64];
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
if (thres > 0) {
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW
|
||||
: FF_COLOR_FG_RED),
|
||||
ms);
|
||||
}
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!data->resultDoc && !instance.config.display.noBuffer) fflush(stdout);
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
if (!data->resultDoc && !instance.config.display.noBuffer) {
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data)
|
||||
{
|
||||
//If we don't have a custom structure, use the default one
|
||||
if(data->structure.length == 0)
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data) {
|
||||
// If we don't have a custom structure, use the default one
|
||||
if (data->structure.length == 0) {
|
||||
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
|
||||
}
|
||||
|
||||
char* moduleType = NULL;
|
||||
size_t moduleLen = 0;
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
|
||||
{
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':'))
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) {
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
parseStructureCommand(data, moduleType, genJsonConfig);
|
||||
}
|
||||
|
||||
+70
-83
@@ -2,11 +2,10 @@
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
|
||||
#include "common/thread.h"
|
||||
#include "common/stringUtils.h"
|
||||
# include "common/thread.h"
|
||||
# include "common/stringUtils.h"
|
||||
|
||||
static bool loadLibSymbols(FFDBusLibrary* lib)
|
||||
{
|
||||
static bool loadLibSymbols(FFDBusLibrary* lib) {
|
||||
FF_LIBRARY_LOAD(dbus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4);
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_bus_get, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_new_method_call, false)
|
||||
@@ -24,14 +23,12 @@ static bool loadLibSymbols(FFDBusLibrary* lib)
|
||||
return true;
|
||||
}
|
||||
|
||||
static const FFDBusLibrary* loadLib(void)
|
||||
{
|
||||
static const FFDBusLibrary* loadLib(void) {
|
||||
static FFDBusLibrary lib;
|
||||
static bool loaded = false;
|
||||
static bool loadSuccess = false;
|
||||
|
||||
if(!loaded)
|
||||
{
|
||||
if (!loaded) {
|
||||
loaded = true;
|
||||
loadSuccess = loadLibSymbols(&lib);
|
||||
}
|
||||
@@ -39,199 +36,189 @@ static const FFDBusLibrary* loadLib(void)
|
||||
return loadSuccess ? &lib : NULL;
|
||||
}
|
||||
|
||||
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data)
|
||||
{
|
||||
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data) {
|
||||
data->lib = loadLib();
|
||||
if(data->lib == NULL)
|
||||
if (data->lib == NULL) {
|
||||
return "Failed to load DBus library";
|
||||
}
|
||||
|
||||
data->connection = data->lib->ffdbus_bus_get(busType, NULL);
|
||||
if(data->connection == NULL)
|
||||
if (data->connection == NULL) {
|
||||
return "Failed to connect to DBus";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDBusDestroyData(FFDBusData* data)
|
||||
{
|
||||
if (data->connection != NULL)
|
||||
{
|
||||
void ffDBusDestroyData(FFDBusData* data) {
|
||||
if (data->connection != NULL) {
|
||||
data->lib->ffdbus_connection_unref(data->connection);
|
||||
data->connection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
|
||||
{
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result) {
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_STRING || argType == DBUS_TYPE_OBJECT_PATH)
|
||||
{
|
||||
if (argType == DBUS_TYPE_STRING || argType == DBUS_TYPE_OBJECT_PATH) {
|
||||
const char* value = NULL;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
|
||||
if(!ffStrSet(value))
|
||||
if (!ffStrSet(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(result, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argType == DBUS_TYPE_BYTE)
|
||||
{
|
||||
if (argType == DBUS_TYPE_BYTE) {
|
||||
uint8_t value;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
ffStrbufAppendC(result, (char) value);
|
||||
return false; // Don't append a comma
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY)
|
||||
if (argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
|
||||
if(argType == DBUS_TYPE_VARIANT)
|
||||
if (argType == DBUS_TYPE_VARIANT) {
|
||||
return ffDBusGetString(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
//At this point we have an array
|
||||
// At this point we have an array
|
||||
|
||||
bool foundAValue = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(ffDBusGetString(dbus, &subIter, result))
|
||||
{
|
||||
while (true) {
|
||||
if (ffDBusGetString(dbus, &subIter, result)) {
|
||||
foundAValue = true;
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
|
||||
if(!dbus->lib->ffdbus_message_iter_next(&subIter))
|
||||
if (!dbus->lib->ffdbus_message_iter_next(&subIter)) {
|
||||
break;
|
||||
else
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundAValue)
|
||||
if (foundAValue) {
|
||||
ffStrbufSubstrBefore(result, result->length - 2);
|
||||
}
|
||||
|
||||
return foundAValue;
|
||||
}
|
||||
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result)
|
||||
{
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result) {
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_BOOLEAN)
|
||||
{
|
||||
if (argType == DBUS_TYPE_BOOLEAN) {
|
||||
dbus_bool_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value != 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT)
|
||||
if (argType != DBUS_TYPE_VARIANT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
return ffDBusGetBool(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result)
|
||||
{
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) {
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_BYTE)
|
||||
{
|
||||
if (argType == DBUS_TYPE_BYTE) {
|
||||
uint8_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT16)
|
||||
{
|
||||
if (argType == DBUS_TYPE_UINT16) {
|
||||
uint16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT32)
|
||||
{
|
||||
if (argType == DBUS_TYPE_UINT32) {
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT)
|
||||
if (argType != DBUS_TYPE_VARIANT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
return ffDBusGetUint(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result)
|
||||
{
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_INT16)
|
||||
{
|
||||
if (argType == DBUS_TYPE_INT16) {
|
||||
int16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_INT32)
|
||||
{
|
||||
if (argType == DBUS_TYPE_INT32) {
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_BYTE)
|
||||
{
|
||||
if (argType == DBUS_TYPE_BYTE) {
|
||||
uint8_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT16)
|
||||
{
|
||||
if (argType == DBUS_TYPE_UINT16) {
|
||||
uint16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = (int16_t) value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT32)
|
||||
{
|
||||
if (argType == DBUS_TYPE_UINT32) {
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT)
|
||||
if (argType != DBUS_TYPE_VARIANT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
return ffDBusGetInt(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2)
|
||||
{
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2) {
|
||||
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
|
||||
if(message == NULL)
|
||||
if (message == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (arg1)
|
||||
{
|
||||
if (arg2)
|
||||
if (arg1) {
|
||||
if (arg2) {
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID);
|
||||
else
|
||||
} else {
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
|
||||
@@ -241,15 +228,17 @@ DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const c
|
||||
return reply;
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property)
|
||||
{
|
||||
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property) {
|
||||
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
|
||||
if(message == NULL)
|
||||
if (message == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus->lib->ffdbus_message_append_args(message,
|
||||
DBUS_TYPE_STRING, &interface,
|
||||
DBUS_TYPE_STRING, &property,
|
||||
DBUS_TYPE_STRING,
|
||||
&interface,
|
||||
DBUS_TYPE_STRING,
|
||||
&property,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
|
||||
@@ -259,15 +248,14 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char
|
||||
return reply;
|
||||
}
|
||||
|
||||
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result)
|
||||
{
|
||||
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result) {
|
||||
DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
|
||||
if(reply == NULL)
|
||||
if (reply == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) {
|
||||
dbus->lib->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
@@ -279,15 +267,14 @@ bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char*
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result)
|
||||
{
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result) {
|
||||
DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
|
||||
if(reply == NULL)
|
||||
if (reply == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) {
|
||||
dbus->lib->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
@@ -299,4 +286,4 @@ bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* ob
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif //FF_HAVE_DBUS
|
||||
#endif // FF_HAVE_DBUS
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
const char* ffDebugWin32Error(DWORD errorCode)
|
||||
{
|
||||
const char* ffDebugWin32Error(DWORD errorCode) {
|
||||
static char buffer[256];
|
||||
|
||||
DWORD len = FormatMessageA(
|
||||
@@ -28,23 +27,22 @@ const char* ffDebugWin32Error(DWORD errorCode)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* ffDebugNtStatus(NTSTATUS status)
|
||||
{
|
||||
const char* ffDebugNtStatus(NTSTATUS status) {
|
||||
return ffDebugWin32Error(RtlNtStatusToDosError(status));
|
||||
}
|
||||
|
||||
static inline DWORD HRESULTToWin32Error(HRESULT hr)
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
static inline DWORD HRESULTToWin32Error(HRESULT hr) {
|
||||
if (SUCCEEDED(hr)) {
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32) {
|
||||
return HRESULT_CODE(hr);
|
||||
}
|
||||
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
const char* ffDebugHResult(HRESULT hr)
|
||||
{
|
||||
const char* ffDebugHResult(HRESULT hr) {
|
||||
return ffDebugWin32Error(HRESULTToWin32Error(hr));
|
||||
}
|
||||
|
||||
+38
-33
@@ -1,25 +1,27 @@
|
||||
#include "common/duration.h"
|
||||
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result) {
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
|
||||
bool spaceBeforeUnit = options->durationSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
|
||||
|
||||
if (totalSeconds < 60)
|
||||
{
|
||||
if (totalSeconds < 60) {
|
||||
ffStrbufAppendUInt(result, totalSeconds);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (spaceBeforeUnit) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
ffStrbufAppendS(result, options->durationAbbreviation ? "sec" : "second");
|
||||
if (totalSeconds != 1)
|
||||
if (totalSeconds != 1) {
|
||||
ffStrbufAppendC(result, 's');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t seconds = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
if (seconds >= 30)
|
||||
if (seconds >= 30) {
|
||||
totalSeconds++;
|
||||
}
|
||||
|
||||
uint32_t minutes = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
@@ -27,56 +29,59 @@ void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result)
|
||||
totalSeconds /= 24;
|
||||
uint32_t days = (uint32_t) totalSeconds;
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
if (days > 0) {
|
||||
ffStrbufAppendUInt(result, days);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
{
|
||||
if (spaceBeforeUnit) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
if (options->durationAbbreviation) {
|
||||
ffStrbufAppendC(result, 'd');
|
||||
|
||||
if (hours > 0 || minutes > 0)
|
||||
if (hours > 0 || minutes > 0) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
ffStrbufAppendS(result, days == 1 ? "day" : "days");
|
||||
|
||||
if (days >= 100)
|
||||
if (days >= 100) {
|
||||
ffStrbufAppendS(result, "(!)");
|
||||
}
|
||||
|
||||
if (hours > 0 || minutes > 0)
|
||||
if (hours > 0 || minutes > 0) {
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hours > 0)
|
||||
{
|
||||
if (hours > 0) {
|
||||
ffStrbufAppendUInt(result, hours);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
{
|
||||
if (spaceBeforeUnit) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
if (options->durationAbbreviation) {
|
||||
ffStrbufAppendC(result, 'h');
|
||||
|
||||
if (minutes > 0)
|
||||
if (minutes > 0) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
ffStrbufAppendS(result, hours == 1 ? "hour" : "hours");
|
||||
|
||||
if (minutes > 0)
|
||||
if (minutes > 0) {
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minutes > 0)
|
||||
{
|
||||
if (minutes > 0) {
|
||||
ffStrbufAppendUInt(result, minutes);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
if (spaceBeforeUnit) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
if (options->durationAbbreviation) {
|
||||
ffStrbufAppendC(result, 'm');
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendS(result, minutes == 1 ? "min" : "mins");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +1,39 @@
|
||||
#include "common/edidHelper.h"
|
||||
|
||||
void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height)
|
||||
{
|
||||
void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height) {
|
||||
const int dtd = 54;
|
||||
*width = (((uint32_t) edid[dtd + 4] >> 4) << 8) | edid[dtd + 2];
|
||||
*height = (((uint32_t) edid[dtd + 7] >> 4) << 8) | edid[dtd + 5];
|
||||
}
|
||||
|
||||
void ffEdidGetPreferredResolutionAndRefreshRate(const uint8_t edid[128], uint32_t* width, uint32_t* height, double* refreshRate)
|
||||
{
|
||||
for (uint32_t i = 0x36; i < 0x7E; i += 0x12)
|
||||
{ // read through descriptor blocks...
|
||||
if (edid[i] != 0x00 && edid[i + 1] != 0x00)
|
||||
{ // a dtd
|
||||
uint32_t hactive = edid[i+2] + (uint32_t) ((edid[i + 4] & 0xf0) << 4);
|
||||
uint32_t hblank = edid[i+3] + (uint32_t) ((edid[i + 4] & 0x0f) << 8);
|
||||
uint32_t vactive = edid[i+5] + (uint32_t) ((edid[i + 7] & 0xf0) << 4);
|
||||
uint32_t vblank = edid[i+6] + (uint32_t) ((edid[i + 7] & 0x0f) << 8);
|
||||
uint32_t pixclk = ((uint32_t) edid[i+1] << 8) | (edid[i]);
|
||||
void ffEdidGetPreferredResolutionAndRefreshRate(const uint8_t edid[128], uint32_t* width, uint32_t* height, double* refreshRate) {
|
||||
for (uint32_t i = 0x36; i < 0x7E; i += 0x12) { // read through descriptor blocks...
|
||||
if (edid[i] != 0x00 && edid[i + 1] != 0x00) { // a dtd
|
||||
uint32_t hactive = edid[i + 2] + (uint32_t) ((edid[i + 4] & 0xf0) << 4);
|
||||
uint32_t hblank = edid[i + 3] + (uint32_t) ((edid[i + 4] & 0x0f) << 8);
|
||||
uint32_t vactive = edid[i + 5] + (uint32_t) ((edid[i + 7] & 0xf0) << 4);
|
||||
uint32_t vblank = edid[i + 6] + (uint32_t) ((edid[i + 7] & 0x0f) << 8);
|
||||
uint32_t pixclk = ((uint32_t) edid[i + 1] << 8) | (edid[i]);
|
||||
*width = hactive;
|
||||
*height = vactive;
|
||||
*refreshRate = (double)pixclk * 10000 / (double)(hactive+hblank) / (double)(vactive+vblank);
|
||||
*refreshRate = (double) pixclk * 10000 / (double) (hactive + hblank) / (double) (vactive + vblank);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ffEdidGetVendorAndModel(const uint8_t edid[128], FFstrbuf* result)
|
||||
{
|
||||
void ffEdidGetVendorAndModel(const uint8_t edid[128], FFstrbuf* result) {
|
||||
// https://github.com/jinksong/read_edid/blob/master/parse-edid/parse-edid.c
|
||||
ffStrbufAppendF(result, "%c%c%c%04X",
|
||||
(char) (((uint32_t)edid[8] >> 2 & 0x1f) + 'A' - 1),
|
||||
(char) (((((uint32_t)edid[8] & 0x3) << 3) | (((uint32_t)edid[9] & 0xe0) >> 5)) + 'A' - 1),
|
||||
(char) (((uint32_t)edid[9] & 0x1f) + 'A' - 1),
|
||||
(uint32_t) (edid[10] + (uint32_t) (edid[11] << 8))
|
||||
);
|
||||
ffStrbufAppendF(result, "%c%c%c%04X", (char) (((uint32_t) edid[8] >> 2 & 0x1f) + 'A' - 1), (char) (((((uint32_t) edid[8] & 0x3) << 3) | (((uint32_t) edid[9] & 0xe0) >> 5)) + 'A' - 1), (char) (((uint32_t) edid[9] & 0x1f) + 'A' - 1), (uint32_t) (edid[10] + (uint32_t) (edid[11] << 8)));
|
||||
}
|
||||
|
||||
bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name)
|
||||
{
|
||||
bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name) {
|
||||
// https://github.com/jinksong/read_edid/blob/master/parse-edid/parse-edid.c
|
||||
for (uint32_t i = 0x36; i < 0x7E; i += 0x12)
|
||||
{ // read through descriptor blocks...
|
||||
if (edid[i] == 0x00)
|
||||
{ // not a timing descriptor
|
||||
if (edid[i + 3] == 0xfc)
|
||||
{ // Model Name tag
|
||||
for (uint32_t j = 0; j < 13; j++)
|
||||
{
|
||||
if (edid[i + 5 + j] == 0x0a)
|
||||
{
|
||||
for (uint32_t i = 0x36; i < 0x7E; i += 0x12) { // read through descriptor blocks...
|
||||
if (edid[i] == 0x00) { // not a timing descriptor
|
||||
if (edid[i + 3] == 0xfc) { // Model Name tag
|
||||
for (uint32_t j = 0; j < 13; j++) {
|
||||
if (edid[i + 5 + j] == 0x0a) {
|
||||
ffStrbufAppendNS(name, j, (const char*) &edid[i + 5]);
|
||||
return true;
|
||||
}
|
||||
@@ -63,8 +47,7 @@ bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name)
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height)
|
||||
{
|
||||
void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height) {
|
||||
// Detailed Timing Descriptors
|
||||
uint32_t dw = (((uint32_t) edid[68] & 0xF0) << 4) + edid[66];
|
||||
uint32_t dh = (((uint32_t) edid[68] & 0x0F) << 8) + edid[67];
|
||||
@@ -74,53 +57,54 @@ void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* h
|
||||
uint32_t bh = edid[22] * 10;
|
||||
|
||||
// Some monitors report invalid data in DTD. See #1406
|
||||
if (abs((int)dw - (int)bw) < 10 && abs((int)dh - (int)bh) < 10)
|
||||
{
|
||||
if (abs((int) dw - (int) bw) < 10 && abs((int) dh - (int) bh) < 10) {
|
||||
*width = dw;
|
||||
*height = dh;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
*width = bw;
|
||||
*height = bh;
|
||||
}
|
||||
}
|
||||
|
||||
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week)
|
||||
{
|
||||
if (edid[17] > 0 && edid[17] < 0xFF)
|
||||
{
|
||||
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week) {
|
||||
if (edid[17] > 0 && edid[17] < 0xFF) {
|
||||
*year = (uint16_t) (edid[17] + 1990);
|
||||
*week = (uint16_t) edid[16];
|
||||
if (*week == 0xFF) *week = 0;
|
||||
}
|
||||
else
|
||||
if (*week == 0xFF) {
|
||||
*week = 0;
|
||||
}
|
||||
} else {
|
||||
*year = *week = 0;
|
||||
}
|
||||
|
||||
*serial = *(uint32_t*) &edid[12];
|
||||
}
|
||||
|
||||
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length)
|
||||
{
|
||||
if (length <= 128) return false;
|
||||
for (const uint8_t* cta = &edid[128]; cta < &edid[length]; cta += 128)
|
||||
{
|
||||
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length) {
|
||||
if (length <= 128) {
|
||||
return false;
|
||||
}
|
||||
for (const uint8_t* cta = &edid[128]; cta < &edid[length]; cta += 128) {
|
||||
// https://en.wikipedia.org/wiki/Extended_Display_Identification_Data#CTA_EDID_Timing_Extension_Block
|
||||
if (cta[0] != 0x02 /* CTA EDID */) continue;
|
||||
if (cta[1] < 0x03 /* Version 3 */) continue;
|
||||
if (cta[0] != 0x02 /* CTA EDID */) {
|
||||
continue;
|
||||
}
|
||||
if (cta[1] < 0x03 /* Version 3 */) {
|
||||
continue;
|
||||
}
|
||||
const uint8_t offset = cta[2];
|
||||
if (offset <= 4) continue;
|
||||
for (uint8_t i = 4; i < offset;)
|
||||
{
|
||||
if (offset <= 4) {
|
||||
continue;
|
||||
}
|
||||
for (uint8_t i = 4; i < offset;) {
|
||||
uint8_t blkLen = cta[i] & 0x1f;
|
||||
if (blkLen > 0)
|
||||
{
|
||||
if (blkLen > 0) {
|
||||
uint8_t blkTag = (cta[i] & 0xe0) >> 5;
|
||||
if (blkTag == 0x07 /* Extended Block Type Tag */)
|
||||
{
|
||||
if (blkTag == 0x07 /* Extended Block Type Tag */) {
|
||||
uint8_t extendedTag = cta[i + 1];
|
||||
if (extendedTag == 6 /* HDR SMDB */ || extendedTag == 7 /* HDR DMDB */)
|
||||
if (extendedTag == 6 /* HDR SMDB */ || extendedTag == 7 /* HDR DMDB */) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
i += (uint8_t) (blkLen + 1);
|
||||
@@ -129,15 +113,20 @@ bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length)
|
||||
{
|
||||
if (length < 128 || length % 128 != 0) return false;
|
||||
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length) {
|
||||
if (length < 128 || length % 128 != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static const uint8_t edidHeader[] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||
if (memcmp(edid, edidHeader, sizeof(edidHeader)) != 0) return false;
|
||||
static const uint8_t edidHeader[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||
if (memcmp(edid, edidHeader, sizeof(edidHeader)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t sum = 0;
|
||||
for (uint32_t i = 0; i < 128; i++) sum += edid[i];
|
||||
for (uint32_t i = 0; i < 128; i++) {
|
||||
sum += edid[i];
|
||||
}
|
||||
|
||||
return sum == 0;
|
||||
}
|
||||
|
||||
+157
-169
@@ -7,8 +7,7 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void ffFontInit(FFfont* font)
|
||||
{
|
||||
void ffFontInit(FFfont* font) {
|
||||
// Ensure no memory allocates
|
||||
ffStrbufInit(&font->pretty);
|
||||
ffStrbufInit(&font->name);
|
||||
@@ -16,84 +15,90 @@ void ffFontInit(FFfont* font)
|
||||
ffListInit(&font->styles, sizeof(FFstrbuf));
|
||||
}
|
||||
|
||||
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
|
||||
{
|
||||
if(value == NULL || length == 0)
|
||||
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude) {
|
||||
if (value == NULL || length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufEnsureFree(strbuf, length);
|
||||
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
if(value[i] != exclude)
|
||||
strbuf->chars[strbuf->length++] = value[i];
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
if (value[i] != exclude) {
|
||||
strbuf->chars[strbuf->length++] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
static void fontInitPretty(FFfont* font)
|
||||
{
|
||||
static void fontInitPretty(FFfont* font) {
|
||||
ffStrbufAppend(&font->pretty, &font->name);
|
||||
|
||||
if(font->size.length == 0 && font->styles.length == 0)
|
||||
if (font->size.length == 0 && font->styles.length == 0) {
|
||||
return;
|
||||
else if(font->pretty.length == 0)
|
||||
} else if (font->pretty.length == 0) {
|
||||
ffStrbufAppendS(&font->pretty, "default");
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&font->pretty, " (");
|
||||
|
||||
if(font->size.length > 0)
|
||||
{
|
||||
if (font->size.length > 0) {
|
||||
ffStrbufAppend(&font->pretty, &font->size);
|
||||
if (!ffStrbufEndsWithS(&font->size, "pt") && !ffStrbufEndsWithS(&font->size, "px"))
|
||||
if (!ffStrbufEndsWithS(&font->size, "pt") && !ffStrbufEndsWithS(&font->size, "px")) {
|
||||
ffStrbufAppendS(&font->pretty, "pt");
|
||||
}
|
||||
|
||||
if(font->styles.length > 0)
|
||||
if (font->styles.length > 0) {
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < font->styles.length; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < font->styles.length; i++) {
|
||||
ffStrbufAppend(&font->pretty, FF_LIST_GET(FFstrbuf, font->styles, i));
|
||||
|
||||
if(i < font->styles.length - 1)
|
||||
if (i < font->styles.length - 1) {
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufAppendC(&font->pretty, ')');
|
||||
}
|
||||
|
||||
void ffFontInitQt(FFfont* font, const char* data)
|
||||
{
|
||||
void ffFontInitQt(FFfont* font, const char* data) {
|
||||
ffFontInit(font);
|
||||
|
||||
//See https://doc.qt.io/qt-5/qfont.html#toString
|
||||
// See https://doc.qt.io/qt-5/qfont.html#toString
|
||||
|
||||
//Family
|
||||
// Family
|
||||
data = ffStrbufAppendSUntilC(&font->name, data, ',');
|
||||
ffStrbufTrim(&font->name, ' ');
|
||||
if (!data) goto exit;
|
||||
if (!data) {
|
||||
goto exit;
|
||||
}
|
||||
data++;
|
||||
|
||||
//Size
|
||||
// Size
|
||||
data = ffStrbufAppendSUntilC(&font->size, data, ',');
|
||||
ffStrbufTrim(&font->size, ' ');
|
||||
if (!data) goto exit;
|
||||
if (!data) {
|
||||
goto exit;
|
||||
}
|
||||
data++;
|
||||
|
||||
//Style
|
||||
// Style
|
||||
data = strrchr(data, ',');
|
||||
if (!data) goto exit;
|
||||
if (!data) {
|
||||
goto exit;
|
||||
}
|
||||
data++;
|
||||
if (isalpha(*data))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (isalpha(*data)) {
|
||||
do {
|
||||
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInit(style);
|
||||
data = ffStrbufAppendSUntilC(style, data, ' ');
|
||||
if (data) data++;
|
||||
if (data) {
|
||||
data++;
|
||||
}
|
||||
} while (data);
|
||||
}
|
||||
|
||||
@@ -101,34 +106,37 @@ exit:
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
|
||||
{
|
||||
while(**data == ' ' || **data == '\t' || **data == ',')
|
||||
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer) {
|
||||
while (**data == ' ' || **data == '\t' || **data == ',') {
|
||||
++(*data);
|
||||
}
|
||||
|
||||
const char* wordStart = *data;
|
||||
|
||||
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
|
||||
while (**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\') {
|
||||
++(*data);
|
||||
}
|
||||
|
||||
uint32_t wordLength = (uint32_t) (*data - wordStart);
|
||||
if(wordLength == 0)
|
||||
if (wordLength == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(**data == '\0' || **data == '`' || **data == '\\')
|
||||
{
|
||||
if (**data == '\0' || **data == '`' || **data == '\\') {
|
||||
ffStrbufAppendNS(&font->size, wordLength, wordStart);
|
||||
if(ffStrbufEndsWithS(&font->size, "px"))
|
||||
if (ffStrbufEndsWithS(&font->size, "px")) {
|
||||
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
|
||||
}
|
||||
|
||||
double dummy;
|
||||
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
|
||||
if (sscanf(font->size.chars, "%lf", &dummy) == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufClear(&font->size);
|
||||
}
|
||||
|
||||
if(
|
||||
if (
|
||||
ffStrStartsWithIgnCase(wordStart, "Ultra") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Extra") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Semi") ||
|
||||
@@ -142,51 +150,47 @@ static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* altern
|
||||
ffStrStartsWithIgnCase(wordStart, "Bold") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Black") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Condensed") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Expanded")
|
||||
) {
|
||||
if(alternativeBuffer == NULL)
|
||||
{
|
||||
ffStrStartsWithIgnCase(wordStart, "Expanded")) {
|
||||
if (alternativeBuffer == NULL) {
|
||||
alternativeBuffer = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInit(alternativeBuffer);
|
||||
}
|
||||
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
|
||||
if(
|
||||
if (
|
||||
ffStrStartsWithIgnCase(wordStart, "Ultra ") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Extra ") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Semi ") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Demi ")
|
||||
) {
|
||||
ffStrStartsWithIgnCase(wordStart, "Demi ")) {
|
||||
fontPangoParseWord(data, font, alternativeBuffer);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(alternativeBuffer != NULL)
|
||||
{
|
||||
if (alternativeBuffer != NULL) {
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
return;
|
||||
}
|
||||
|
||||
if(font->name.length > 0)
|
||||
if (font->name.length > 0) {
|
||||
ffStrbufAppendC(&font->name, ' ');
|
||||
}
|
||||
ffStrbufAppendNS(&font->name, wordLength, wordStart);
|
||||
}
|
||||
|
||||
void ffFontInitPango(FFfont* font, const char* data)
|
||||
{
|
||||
void ffFontInitPango(FFfont* font, const char* data) {
|
||||
ffFontInit(font);
|
||||
|
||||
while(*data != '\0' && *data != '`' && *data != '\\')
|
||||
while (*data != '\0' && *data != '`' && *data != '\\') {
|
||||
fontPangoParseWord(&data, font, NULL);
|
||||
}
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitValues(FFfont* font, const char* name, const char* size)
|
||||
{
|
||||
void ffFontInitValues(FFfont* font, const char* name, const char* size) {
|
||||
ffFontInit(font);
|
||||
|
||||
ffStrbufAppendS(&font->name, name);
|
||||
@@ -196,8 +200,7 @@ void ffFontInitValues(FFfont* font, const char* name, const char* size)
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitXlfd(FFfont* font, const char* xlfd)
|
||||
{
|
||||
void ffFontInitXlfd(FFfont* font, const char* xlfd) {
|
||||
assert(xlfd && *xlfd);
|
||||
|
||||
// https://en.wikipedia.org/wiki/X_logical_font_description
|
||||
@@ -205,80 +208,78 @@ void ffFontInitXlfd(FFfont* font, const char* xlfd)
|
||||
|
||||
// XLFD: -foundry-family-weight-slant-setwidth-addstyle-pixelsize-pointsize-xres-yres-spacing-averagewidth-charsetregistry-charsetencoding
|
||||
// It often starts with '-', which would create an empty first field. Skip it to align indexes.
|
||||
if(*xlfd == '-')
|
||||
if (*xlfd == '-') {
|
||||
xlfd++;
|
||||
}
|
||||
|
||||
const char* pstart = xlfd;
|
||||
|
||||
for(int field = 0; field < 14; field++)
|
||||
{
|
||||
for (int field = 0; field < 14; field++) {
|
||||
const char* pend = strchr(pstart, '-');
|
||||
uint32_t length = pend ? (uint32_t)(pend - pstart) : (uint32_t) strlen(pstart);
|
||||
uint32_t length = pend ? (uint32_t) (pend - pstart) : (uint32_t) strlen(pstart);
|
||||
|
||||
if(length > 0)
|
||||
{
|
||||
if(field == 1) // family
|
||||
if (length > 0) {
|
||||
if (field == 1) // family
|
||||
{
|
||||
ffStrbufAppendNS(&font->name, length, pstart);
|
||||
}
|
||||
else if(field == 7) // pointsize (decipoints, preferred)
|
||||
} else if (field == 7) // pointsize (decipoints, preferred)
|
||||
{
|
||||
// parse positive integer from substring
|
||||
long deciPt = 0;
|
||||
bool ok = true;
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
char c = pstart[i];
|
||||
if(c < '0' || c > '9') { ok = false; break; }
|
||||
if (c < '0' || c > '9') {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
deciPt = deciPt * 10 + (c - '0');
|
||||
}
|
||||
|
||||
if(ok && deciPt > 0)
|
||||
{
|
||||
if (ok && deciPt > 0) {
|
||||
ffStrbufClear(&font->size);
|
||||
|
||||
char tmp[32];
|
||||
if(deciPt % 10 == 0)
|
||||
if (deciPt % 10 == 0) {
|
||||
snprintf(tmp, sizeof(tmp), "%ldpt", deciPt / 10);
|
||||
else
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "%ld.%ldpt", deciPt / 10, deciPt % 10);
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&font->size, tmp);
|
||||
}
|
||||
}
|
||||
else if(field == 6) // pixelsize (fallback if pointsize missing/invalid)
|
||||
} else if (field == 6) // pixelsize (fallback if pointsize missing/invalid)
|
||||
{
|
||||
if(font->size.length == 0)
|
||||
{
|
||||
if (font->size.length == 0) {
|
||||
long px = 0;
|
||||
bool ok = true;
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
char c = pstart[i];
|
||||
if(c < '0' || c > '9') { ok = false; break; }
|
||||
if (c < '0' || c > '9') {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
px = px * 10 + (c - '0');
|
||||
}
|
||||
|
||||
if(ok && px > 0)
|
||||
{
|
||||
if (ok && px > 0) {
|
||||
ffStrbufAppendNS(&font->size, length, pstart);
|
||||
ffStrbufAppendS(&font->size, "px");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(field >= 2 && field <= 5) // weight/slant/setwidth/addstyle
|
||||
} else if (field >= 2 && field <= 5) // weight/slant/setwidth/addstyle
|
||||
{
|
||||
// ignore "normal" (case-insensitive)
|
||||
if(!(length == 6 && ffStrStartsWithIgnCase(pstart, "normal")))
|
||||
{
|
||||
if (!(length == 6 && ffStrStartsWithIgnCase(pstart, "normal"))) {
|
||||
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInitNS(style, length, pstart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!pend)
|
||||
if (!pend) {
|
||||
break;
|
||||
}
|
||||
|
||||
pstart = pend + 1;
|
||||
}
|
||||
@@ -286,8 +287,7 @@ void ffFontInitXlfd(FFfont* font, const char* xlfd)
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitXft(FFfont* font, const char* xft)
|
||||
{
|
||||
void ffFontInitXft(FFfont* font, const char* xft) {
|
||||
assert(xft);
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xft
|
||||
@@ -302,26 +302,28 @@ void ffFontInitXft(FFfont* font, const char* xft)
|
||||
// 1) Parse "head" part before first ':' => usually "family[-size]" (may include commas)
|
||||
const char* p = xft;
|
||||
|
||||
while(*p == ' ' || *p == '\t')
|
||||
while (*p == ' ' || *p == '\t') {
|
||||
++p;
|
||||
}
|
||||
|
||||
const char* headStart = p;
|
||||
while(*p != '\0' && *p != ':')
|
||||
while (*p != '\0' && *p != ':') {
|
||||
++p;
|
||||
}
|
||||
const char* headEnd = p;
|
||||
|
||||
// trim tail spaces
|
||||
while(headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t'))
|
||||
while (headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t')) {
|
||||
--headEnd;
|
||||
}
|
||||
|
||||
// If multiple families are listed, take the first one (up to comma)
|
||||
for(const char* q = headStart; q < headEnd; ++q)
|
||||
{
|
||||
if(*q == ',')
|
||||
{
|
||||
for (const char* q = headStart; q < headEnd; ++q) {
|
||||
if (*q == ',') {
|
||||
headEnd = q;
|
||||
while(headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t'))
|
||||
while (headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t')) {
|
||||
--headEnd;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -330,56 +332,51 @@ void ffFontInitXft(FFfont* font, const char* xft)
|
||||
const char* dashPos = NULL;
|
||||
const char* sizeStart = NULL;
|
||||
|
||||
for(const char* q = headEnd; q > headStart; )
|
||||
{
|
||||
for (const char* q = headEnd; q > headStart;) {
|
||||
--q;
|
||||
if(*q == '-' && (q + 1) < headEnd && ffCharIsDigit(q[1]))
|
||||
{
|
||||
if (*q == '-' && (q + 1) < headEnd && ffCharIsDigit(q[1])) {
|
||||
dashPos = q;
|
||||
sizeStart = q + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(dashPos)
|
||||
{
|
||||
if (dashPos) {
|
||||
bool ok = true;
|
||||
bool seenDigit = false;
|
||||
for(const char* q = sizeStart; q < headEnd; ++q)
|
||||
{
|
||||
if(ffCharIsDigit(*q))
|
||||
for (const char* q = sizeStart; q < headEnd; ++q) {
|
||||
if (ffCharIsDigit(*q)) {
|
||||
seenDigit = true;
|
||||
else if(*q == '.')
|
||||
} else if (*q == '.') {
|
||||
continue;
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ok && seenDigit)
|
||||
{
|
||||
if (ok && seenDigit) {
|
||||
const char* nameEnd = dashPos;
|
||||
while(nameEnd > headStart && (nameEnd[-1] == ' ' || nameEnd[-1] == '\t'))
|
||||
while (nameEnd > headStart && (nameEnd[-1] == ' ' || nameEnd[-1] == '\t')) {
|
||||
--nameEnd;
|
||||
}
|
||||
|
||||
if(nameEnd > headStart)
|
||||
if (nameEnd > headStart) {
|
||||
ffStrbufAppendNS(&font->name, (uint32_t) (nameEnd - headStart), headStart);
|
||||
}
|
||||
|
||||
if(headEnd > sizeStart)
|
||||
if (headEnd > sizeStart) {
|
||||
ffStrbufAppendNS(&font->size, (uint32_t) (headEnd - sizeStart), sizeStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(headEnd > headStart)
|
||||
}
|
||||
} else {
|
||||
if (headEnd > headStart) {
|
||||
ffStrbufAppendNS(&font->name, (uint32_t) (headEnd - headStart), headStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(headEnd > headStart)
|
||||
} else {
|
||||
if (headEnd > headStart) {
|
||||
ffStrbufAppendNS(&font->name, (uint32_t) (headEnd - headStart), headStart);
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufTrim(&font->name, ' ');
|
||||
@@ -387,28 +384,27 @@ void ffFontInitXft(FFfont* font, const char* xft)
|
||||
|
||||
// 2) Parse key=value fields after ':' (Fontconfig-like). Fields separated by ':'.
|
||||
// Common keys: size, pixelsize, pointsize, style, weight, slant, width
|
||||
while(*p == ':')
|
||||
{
|
||||
while (*p == ':') {
|
||||
++p;
|
||||
|
||||
// key
|
||||
const char* keyStart = p;
|
||||
while(*p != '\0' && *p != '=' && *p != ':')
|
||||
while (*p != '\0' && *p != '=' && *p != ':') {
|
||||
++p;
|
||||
}
|
||||
const char* keyEnd = p;
|
||||
|
||||
if(*p != '=')
|
||||
if (*p != '=') {
|
||||
continue; // skip tokens without '='
|
||||
}
|
||||
|
||||
++p; // skip '='
|
||||
|
||||
// value (until next ':', allow backslash-escaping)
|
||||
FF_STRBUF_AUTO_DESTROY value = ffStrbufCreate();
|
||||
|
||||
while(*p != '\0' && *p != ':')
|
||||
{
|
||||
if(*p == '\\' && p[1] != '\0')
|
||||
{
|
||||
while (*p != '\0' && *p != ':') {
|
||||
if (*p == '\\' && p[1] != '\0') {
|
||||
++p;
|
||||
ffStrbufAppendC(&value, *p);
|
||||
++p;
|
||||
@@ -426,44 +422,36 @@ void ffFontInitXft(FFfont* font, const char* xft)
|
||||
|
||||
// helper: set numeric size if not set yet
|
||||
const bool sizeEmpty = (font->size.length == 0);
|
||||
if(value.length > 0)
|
||||
{
|
||||
if(
|
||||
if (value.length > 0) {
|
||||
if (
|
||||
(keyLen == 4 && ffStrStartsWithIgnCase(keyStart, "size")) ||
|
||||
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize"))
|
||||
)
|
||||
{
|
||||
if(sizeEmpty && ffCharIsDigit(value.chars[0]))
|
||||
{
|
||||
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize"))) {
|
||||
if (sizeEmpty && ffCharIsDigit(value.chars[0])) {
|
||||
ffStrbufAppend(&font->size, &value);
|
||||
ffStrbufAppendS(&font->size, keyLen == 4 ? "pt" : "px");
|
||||
}
|
||||
}
|
||||
else if(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "style"))
|
||||
{
|
||||
} else if (keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "style")) {
|
||||
// style may contain multiple words: "Bold Italic"
|
||||
const char* s = value.chars;
|
||||
while(*s != '\0')
|
||||
{
|
||||
while(*s == ' ' || *s == '\t' || *s == ',')
|
||||
while (*s != '\0') {
|
||||
while (*s == ' ' || *s == '\t' || *s == ',') {
|
||||
++s;
|
||||
}
|
||||
|
||||
const char* w = s;
|
||||
while(*s != '\0' && *s != ' ' && *s != '\t' && *s != ',')
|
||||
while (*s != '\0' && *s != ' ' && *s != '\t' && *s != ',') {
|
||||
++s;
|
||||
}
|
||||
|
||||
if(s > w)
|
||||
{
|
||||
if (s > w) {
|
||||
FFstrbuf* style = FF_LIST_ADD(FFstrbuf, font->styles);
|
||||
ffStrbufInitNS(style, (uint32_t) (s - w), w);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(
|
||||
} else if (
|
||||
(keyLen == 6 && ffStrStartsWithIgnCase(keyStart, "weight")) ||
|
||||
(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "slant")) ||
|
||||
(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "width"))
|
||||
) {
|
||||
(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "width"))) {
|
||||
// normalize: remove '-' to align with other parsers ("Semi-Bold" -> "SemiBold")
|
||||
FFstrbuf* style = FF_LIST_ADD(FFstrbuf, font->styles);
|
||||
ffStrbufInit(style);
|
||||
@@ -476,14 +464,16 @@ void ffFontInitXft(FFfont* font, const char* xft)
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf* style)
|
||||
{
|
||||
void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf* style) {
|
||||
ffFontInit(font);
|
||||
|
||||
if (name) ffStrbufInitMove(&font->name, name);
|
||||
if (size) ffStrbufInitMove(&font->size, size);
|
||||
if (style)
|
||||
{
|
||||
if (name) {
|
||||
ffStrbufInitMove(&font->name, name);
|
||||
}
|
||||
if (size) {
|
||||
ffStrbufInitMove(&font->size, size);
|
||||
}
|
||||
if (style) {
|
||||
FFstrbuf* styleBuf = FF_LIST_ADD(FFstrbuf, font->styles);
|
||||
ffStrbufInitMove(styleBuf, style);
|
||||
}
|
||||
@@ -491,30 +481,28 @@ void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName)
|
||||
{
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName) {
|
||||
const char* pspace = strrchr(rawName, ' ');
|
||||
if(pspace == NULL)
|
||||
{
|
||||
if (pspace == NULL) {
|
||||
ffFontInitCopy(font, rawName);
|
||||
return;
|
||||
}
|
||||
|
||||
ffFontInit(font);
|
||||
|
||||
ffStrbufAppendNS(&font->name, (uint32_t)(pspace - rawName), rawName);
|
||||
ffStrbufAppendNS(&font->name, (uint32_t) (pspace - rawName), rawName);
|
||||
ffStrbufAppendS(&font->size, pspace + 1);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontDestroy(FFfont* font)
|
||||
{
|
||||
void ffFontDestroy(FFfont* font) {
|
||||
ffStrbufDestroy(&font->pretty);
|
||||
ffStrbufDestroy(&font->name);
|
||||
ffStrbufDestroy(&font->size);
|
||||
|
||||
FF_LIST_FOR_EACH(FFstrbuf, str, font->styles)
|
||||
FF_LIST_FOR_EACH (FFstrbuf, str, font->styles) {
|
||||
ffStrbufDestroy(str);
|
||||
}
|
||||
ffListDestroy(&font->styles);
|
||||
}
|
||||
|
||||
+114
-156
@@ -6,61 +6,58 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
{
|
||||
switch(formatarg->type)
|
||||
{
|
||||
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg) {
|
||||
switch (formatarg->type) {
|
||||
case FF_ARG_TYPE_INT:
|
||||
ffStrbufAppendSInt(buffer, *(int32_t*)formatarg->value);
|
||||
ffStrbufAppendSInt(buffer, *(int32_t*) formatarg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT:
|
||||
ffStrbufAppendUInt(buffer, *(uint32_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint32_t*) formatarg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT64:
|
||||
ffStrbufAppendUInt(buffer, *(uint64_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint64_t*) formatarg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT16:
|
||||
ffStrbufAppendUInt(buffer, *(uint16_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint16_t*) formatarg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT8:
|
||||
ffStrbufAppendUInt(buffer, *(uint8_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint8_t*) formatarg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_STRING:
|
||||
ffStrbufAppendS(buffer, (const char*)formatarg->value);
|
||||
ffStrbufAppendS(buffer, (const char*) formatarg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_STRBUF:
|
||||
ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value);
|
||||
ffStrbufAppend(buffer, (const FFstrbuf*) formatarg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_FLOAT:
|
||||
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
ffStrbufAppendDouble(buffer, *(float*) formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
break;
|
||||
case FF_ARG_TYPE_DOUBLE:
|
||||
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
ffStrbufAppendDouble(buffer, *(double*) formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
break;
|
||||
case FF_ARG_TYPE_BOOL:
|
||||
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
|
||||
ffStrbufAppendS(buffer, *(bool*) formatarg->value ? "true" : "false");
|
||||
break;
|
||||
case FF_ARG_TYPE_LIST:
|
||||
{
|
||||
case FF_ARG_TYPE_LIST: {
|
||||
const FFlist* list = (const FFlist*) formatarg->value;
|
||||
for(uint32_t i = 0; i < list->length; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < list->length; i++) {
|
||||
ffStrbufAppend(buffer, FF_LIST_GET(FFstrbuf, *list, i));
|
||||
if(i < list->length - 1)
|
||||
if (i < list->length - 1) {
|
||||
ffStrbufAppendS(buffer, ", ");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FF_ARG_TYPE_BUFFER:
|
||||
{
|
||||
case FF_ARG_TYPE_BUFFER: {
|
||||
// Placeholder for binary data, just print the size for now
|
||||
const FFArgBuffer* argBuffer = (const FFArgBuffer*) formatarg->value;
|
||||
ffStrbufAppendF(buffer, "buffer(%u bytes)", argBuffer->length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if(formatarg->type != FF_ARG_TYPE_NULL)
|
||||
if (formatarg->type != FF_ARG_TYPE_NULL) {
|
||||
fprintf(stderr, "Error: format string \"%s\": argument is not implemented: %i\n", buffer->chars, formatarg->type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -73,62 +70,48 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
* @param placeholderValue the string to parse
|
||||
* @return uint32_t the parsed value
|
||||
*/
|
||||
static uint32_t getArgumentIndex(const char* placeholderValue, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
static uint32_t getArgumentIndex(const char* placeholderValue, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
char firstChar = placeholderValue[0];
|
||||
if (firstChar == '\0')
|
||||
if (firstChar == '\0') {
|
||||
return 0; // use arg counter
|
||||
}
|
||||
|
||||
if (firstChar >= '0' && firstChar <= '9')
|
||||
{
|
||||
if (firstChar >= '0' && firstChar <= '9') {
|
||||
char* pEnd = NULL;
|
||||
uint32_t result = (uint32_t) strtoul(placeholderValue, &pEnd, 10);
|
||||
if (result > numArgs)
|
||||
if (result > numArgs) {
|
||||
return UINT32_MAX;
|
||||
if (*pEnd != '\0')
|
||||
}
|
||||
if (*pEnd != '\0') {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else if (ffCharIsEnglishAlphabet(firstChar))
|
||||
{
|
||||
for (uint32_t i = 0; i < numArgs; ++i)
|
||||
{
|
||||
} else if (ffCharIsEnglishAlphabet(firstChar)) {
|
||||
for (uint32_t i = 0; i < numArgs; ++i) {
|
||||
const FFformatarg* arg = &arguments[i];
|
||||
if (arg->name && ffStrEqualsIgnCase(placeholderValue, arg->name))
|
||||
if (arg->name && ffStrEqualsIgnCase(placeholderValue, arg->name)) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start, const FFstrbuf* placeholderValue, uint32_t index, uint32_t formatStringLength)
|
||||
{
|
||||
static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start, const FFstrbuf* placeholderValue, uint32_t index, uint32_t formatStringLength) {
|
||||
ffStrbufAppendS(buffer, start);
|
||||
ffStrbufAppend(buffer, placeholderValue);
|
||||
|
||||
if(index < formatStringLength)
|
||||
if (index < formatStringLength) {
|
||||
ffStrbufAppendC(buffer, '}');
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool formatArgSet(const FFformatarg* arg)
|
||||
{
|
||||
return arg->value != NULL && (
|
||||
(arg->type == FF_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
|
||||
(arg->type == FF_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
|
||||
(arg->type == FF_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_BOOL && *(bool*)arg->value) ||
|
||||
(arg->type == FF_ARG_TYPE_LIST && ((FFlist*)arg->value)->length > 0)
|
||||
);
|
||||
static inline bool formatArgSet(const FFformatarg* arg) {
|
||||
return arg->value != NULL && ((arg->type == FF_ARG_TYPE_DOUBLE && *(double*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_FLOAT && *(float*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_INT && *(int*) arg->value > 0) || (arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*) arg->value)->length > 0) || (arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*) arg->value)) || (arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT && *(uint32_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_BOOL && *(bool*) arg->value) || (arg->type == FF_ARG_TYPE_LIST && ((FFlist*) arg->value)->length > 0));
|
||||
}
|
||||
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
uint32_t argCounter = 0;
|
||||
|
||||
uint32_t numOpenIfs = 0;
|
||||
@@ -136,11 +119,9 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY placeholderValue = ffStrbufCreate();
|
||||
|
||||
for(uint32_t i = 0; i < formatstr->length; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < formatstr->length; ++i) {
|
||||
// if we don't have a placeholder start just copy the chars over to output buffer
|
||||
if(formatstr->chars[i] != '{')
|
||||
{
|
||||
if (formatstr->chars[i] != '{') {
|
||||
ffStrbufAppendC(buffer, formatstr->chars[i]);
|
||||
continue;
|
||||
}
|
||||
@@ -149,8 +130,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
++i;
|
||||
|
||||
// double {{ elvaluates to a single { and doesn't count as start
|
||||
if(formatstr->chars[i] == '{')
|
||||
{
|
||||
if (formatstr->chars[i] == '{') {
|
||||
ffStrbufAppendC(buffer, '{');
|
||||
continue;
|
||||
}
|
||||
@@ -165,61 +145,58 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
|
||||
char firstChar = placeholderValue.chars[0];
|
||||
|
||||
if (placeholderValue.length == 1)
|
||||
{
|
||||
if (placeholderValue.length == 1) {
|
||||
// test if for stop, if so break the loop
|
||||
if (firstChar == '-')
|
||||
if (firstChar == '-') {
|
||||
break;
|
||||
}
|
||||
|
||||
// test for end of an if, if so do nothing
|
||||
if (firstChar == '?')
|
||||
{
|
||||
if(numOpenIfs == 0)
|
||||
if (firstChar == '?') {
|
||||
if (numOpenIfs == 0) {
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
else
|
||||
} else {
|
||||
--numOpenIfs;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// test for end of a not if, if so do nothing
|
||||
if (firstChar == '/')
|
||||
{
|
||||
if(numOpenNotIfs == 0)
|
||||
if (firstChar == '/') {
|
||||
if (numOpenNotIfs == 0) {
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
else
|
||||
} else {
|
||||
--numOpenNotIfs;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// test for end of a color, if so do nothing
|
||||
if (firstChar == '#')
|
||||
{
|
||||
if (!instance.config.display.pipe)
|
||||
if (firstChar == '#') {
|
||||
if (!instance.config.display.pipe) {
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// test for if, if so evaluate it
|
||||
if (firstChar == '?')
|
||||
{
|
||||
if (firstChar == '?') {
|
||||
ffStrbufSubstrAfter(&placeholderValue, 0);
|
||||
|
||||
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
|
||||
|
||||
// testing for an invalid index
|
||||
if (index > numArgs || index < 1)
|
||||
{
|
||||
if (index > numArgs || index < 1) {
|
||||
appendInvalidPlaceholder(buffer, "{?", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
// continue normally if an format arg is set and the value is > 0
|
||||
if (formatArgSet(&arguments[index - 1]))
|
||||
{
|
||||
if (formatArgSet(&arguments[index - 1])) {
|
||||
++numOpenIfs;
|
||||
continue;
|
||||
}
|
||||
@@ -230,22 +207,19 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
}
|
||||
|
||||
// test for not if, if so evaluate it
|
||||
if (firstChar == '/')
|
||||
{
|
||||
if (firstChar == '/') {
|
||||
ffStrbufSubstrAfter(&placeholderValue, 0);
|
||||
|
||||
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
|
||||
|
||||
// testing for an invalid index
|
||||
if (index > numArgs || index < 1)
|
||||
{
|
||||
if (index > numArgs || index < 1) {
|
||||
appendInvalidPlaceholder(buffer, "{/", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
//continue normally if an format arg is not set or the value is 0
|
||||
if (!formatArgSet(&arguments[index - 1]))
|
||||
{
|
||||
// continue normally if an format arg is not set or the value is 0
|
||||
if (!formatArgSet(&arguments[index - 1])) {
|
||||
++numOpenNotIfs;
|
||||
continue;
|
||||
}
|
||||
@@ -255,11 +229,9 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
continue;
|
||||
}
|
||||
|
||||
//test for color, if so evaluate it
|
||||
if (firstChar == '#')
|
||||
{
|
||||
if (!instance.config.display.pipe)
|
||||
{
|
||||
// test for color, if so evaluate it
|
||||
if (firstChar == '#') {
|
||||
if (!instance.config.display.pipe) {
|
||||
ffStrbufAppendS(buffer, "\e[");
|
||||
ffOptionParseColorNoClear(placeholderValue.chars + 1, buffer);
|
||||
ffStrbufAppendC(buffer, 'm');
|
||||
@@ -267,29 +239,25 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
continue;
|
||||
}
|
||||
|
||||
//test for constant or env var, if so evaluate it
|
||||
if (firstChar == '$')
|
||||
{
|
||||
// test for constant or env var, if so evaluate it
|
||||
if (firstChar == '$') {
|
||||
char* pend = NULL;
|
||||
int32_t indexSigned = (int32_t) strtol(placeholderValue.chars + 1, &pend, 10);
|
||||
if (pend == placeholderValue.chars + 1)
|
||||
{
|
||||
if (pend == placeholderValue.chars + 1) {
|
||||
// treat placeholder as an environment variable
|
||||
char* envValue = getenv(placeholderValue.chars + 1);
|
||||
if (envValue)
|
||||
if (envValue) {
|
||||
ffStrbufAppendS(buffer, envValue);
|
||||
else
|
||||
} else {
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
// treat placeholder as a constant
|
||||
uint32_t index = (uint32_t) (indexSigned < 0 ? (int32_t) instance.config.display.constants.length + indexSigned : indexSigned - 1);
|
||||
|
||||
if (*pend != '\0' || instance.config.display.constants.length <= index)
|
||||
if (*pend != '\0' || instance.config.display.constants.length <= index) {
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FFstrbuf* item = FF_LIST_GET(FFstrbuf, instance.config.display.constants, index);
|
||||
ffStrbufAppend(buffer, item);
|
||||
}
|
||||
@@ -299,115 +267,104 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
|
||||
char* pSep = placeholderValue.chars;
|
||||
char cSep = '\0';
|
||||
while (*pSep && *pSep != ':' && *pSep != '<' && *pSep != '>' && *pSep != '~')
|
||||
while (*pSep && *pSep != ':' && *pSep != '<' && *pSep != '>' && *pSep != '~') {
|
||||
++pSep;
|
||||
if (*pSep)
|
||||
{
|
||||
}
|
||||
if (*pSep) {
|
||||
cSep = *pSep;
|
||||
*pSep = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
pSep = NULL;
|
||||
}
|
||||
|
||||
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
|
||||
|
||||
// test for invalid index
|
||||
if (index == 0)
|
||||
if (index == 0) {
|
||||
index = ++argCounter;
|
||||
}
|
||||
|
||||
if (index > numArgs)
|
||||
{
|
||||
if (pSep) *pSep = cSep;
|
||||
if (index > numArgs) {
|
||||
if (pSep) {
|
||||
*pSep = cSep;
|
||||
}
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!cSep)
|
||||
if (!cSep) {
|
||||
ffFormatAppendFormatArg(buffer, &arguments[index - 1]);
|
||||
else if (cSep == '~')
|
||||
{
|
||||
} else if (cSep == '~') {
|
||||
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
|
||||
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
|
||||
|
||||
char* pEnd = NULL;
|
||||
int32_t start = (int32_t) strtol(pSep + 1, &pEnd, 10);
|
||||
if (start < 0)
|
||||
if (start < 0) {
|
||||
start = (int32_t) tempString.length + start;
|
||||
if (start >= 0 && (uint32_t) start < tempString.length)
|
||||
{
|
||||
if (*pEnd == '\0')
|
||||
}
|
||||
if (start >= 0 && (uint32_t) start < tempString.length) {
|
||||
if (*pEnd == '\0') {
|
||||
ffStrbufAppendNS(buffer, tempString.length - (uint32_t) start, &tempString.chars[start]);
|
||||
else if (*pEnd == ',')
|
||||
{
|
||||
} else if (*pEnd == ',') {
|
||||
int32_t end = (int32_t) strtol(pEnd + 1, &pEnd, 10);
|
||||
if (!*pEnd)
|
||||
{
|
||||
if (end < 0)
|
||||
if (!*pEnd) {
|
||||
if (end < 0) {
|
||||
end = (int32_t) tempString.length + end;
|
||||
if ((uint32_t) end > tempString.length)
|
||||
}
|
||||
if ((uint32_t) end > tempString.length) {
|
||||
end = (int32_t) tempString.length;
|
||||
if (end > start)
|
||||
}
|
||||
if (end > start) {
|
||||
ffStrbufAppendNS(buffer, (uint32_t) (end - start), &tempString.chars[start]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*pEnd)
|
||||
{
|
||||
if (*pEnd) {
|
||||
*pSep = cSep;
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
char* pEnd = NULL;
|
||||
int32_t truncLength = (int32_t) strtol(pSep + 1, &pEnd, 10);
|
||||
if (*pEnd != '\0')
|
||||
{
|
||||
if (*pEnd != '\0') {
|
||||
*pSep = cSep;
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ellipsis = false;
|
||||
if (truncLength < 0)
|
||||
{
|
||||
if (truncLength < 0) {
|
||||
ellipsis = true;
|
||||
truncLength = -truncLength;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
|
||||
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
|
||||
if (tempString.length == (uint32_t) truncLength)
|
||||
if (tempString.length == (uint32_t) truncLength) {
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
else if (tempString.length > (uint32_t) truncLength)
|
||||
{
|
||||
if (cSep == ':')
|
||||
{
|
||||
} else if (tempString.length > (uint32_t) truncLength) {
|
||||
if (cSep == ':') {
|
||||
ffStrbufSubstrBefore(&tempString, (uint32_t) truncLength);
|
||||
ffStrbufTrimRightSpace(&tempString);
|
||||
} else {
|
||||
ffStrbufSubstrBefore(&tempString, (uint32_t) (!ellipsis ? truncLength : truncLength - 1));
|
||||
}
|
||||
else
|
||||
ffStrbufSubstrBefore(&tempString, (uint32_t) (!ellipsis? truncLength : truncLength - 1));
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
|
||||
if (ellipsis)
|
||||
if (ellipsis) {
|
||||
ffStrbufAppendS(buffer, "…");
|
||||
}
|
||||
else if (cSep == ':')
|
||||
}
|
||||
} else if (cSep == ':') {
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
else
|
||||
{
|
||||
if (cSep == '<')
|
||||
{
|
||||
} else {
|
||||
if (cSep == '<') {
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length, ' ');
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
}
|
||||
@@ -415,6 +372,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
}
|
||||
}
|
||||
|
||||
if (!instance.config.display.pipe)
|
||||
if (!instance.config.display.pipe) {
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-10
@@ -1,24 +1,25 @@
|
||||
#include "common/frequency.h"
|
||||
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
|
||||
{
|
||||
if (mhz == 0)
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result) {
|
||||
if (mhz == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
bool spaceBeforeUnit = options->freqSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
|
||||
int8_t ndigits = options->freqNdigits;
|
||||
|
||||
if (ndigits >= 0)
|
||||
{
|
||||
if (ndigits >= 0) {
|
||||
ffStrbufAppendDouble(result, mhz / 1000., ndigits, true);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (spaceBeforeUnit) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
ffStrbufAppendS(result, "GHz");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppendUInt(result, mhz);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (spaceBeforeUnit) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
ffStrbufAppendS(result, "MHz");
|
||||
}
|
||||
return true;
|
||||
|
||||
+151
-152
@@ -11,16 +11,15 @@
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include "common/windows/unicode.h"
|
||||
# include <windows.h>
|
||||
# include "common/windows/unicode.h"
|
||||
#else
|
||||
#include <signal.h>
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
FFinstance instance; // Global singleton
|
||||
|
||||
static void initState(FFstate* state)
|
||||
{
|
||||
static void initState(FFstate* state) {
|
||||
state->logoWidth = 0;
|
||||
state->logoHeight = 0;
|
||||
state->keysHeight = 0;
|
||||
@@ -33,27 +32,26 @@ static void initState(FFstate* state)
|
||||
{
|
||||
// don't enable bright color if the terminal is in light mode
|
||||
FFTerminalThemeResult result;
|
||||
if (ffDetectTerminalTheme(&result, true /* forceEnv for performance */) && !result.bg.dark)
|
||||
if (ffDetectTerminalTheme(&result, true /* forceEnv for performance */) && !result.bg.dark) {
|
||||
state->terminalLightTheme = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void defaultConfig(void)
|
||||
{
|
||||
static void defaultConfig(void) {
|
||||
ffOptionsInitLogo(&instance.config.logo);
|
||||
ffOptionsInitGeneral(&instance.config.general);
|
||||
ffOptionsInitDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
void ffInitInstance(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
|
||||
setlocale(LC_ALL, ".UTF8");
|
||||
#else
|
||||
// Never use `setlocale(LC_ALL, "")`
|
||||
setlocale(LC_TIME, "");
|
||||
#endif
|
||||
void ffInitInstance(void) {
|
||||
#ifdef _WIN32
|
||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
|
||||
setlocale(LC_ALL, ".UTF8");
|
||||
#else
|
||||
// Never use `setlocale(LC_ALL, "")`
|
||||
setlocale(LC_TIME, "");
|
||||
#endif
|
||||
|
||||
defaultConfig();
|
||||
initState(&instance.state);
|
||||
@@ -65,62 +63,66 @@ static volatile bool ffHideCursor = true;
|
||||
static volatile UINT oldCp = CP_UTF8;
|
||||
#endif
|
||||
|
||||
static void resetConsole(void)
|
||||
{
|
||||
if(ffDisableLinewrap)
|
||||
static void resetConsole(void) {
|
||||
if (ffDisableLinewrap) {
|
||||
fputs("\033[?7h", stdout);
|
||||
}
|
||||
|
||||
if(ffHideCursor)
|
||||
if (ffHideCursor) {
|
||||
fputs("\033[?25h", stdout);
|
||||
}
|
||||
|
||||
if(instance.state.dynamicInterval > 0)
|
||||
if (instance.state.dynamicInterval > 0) {
|
||||
fputs("\033[?1049l", stdout); // Disable alternate buffer
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
fflush(stdout);
|
||||
#if defined(_WIN32)
|
||||
fflush(stdout);
|
||||
|
||||
if(oldCp != CP_UTF8)
|
||||
SetConsoleOutputCP(oldCp);
|
||||
#endif
|
||||
if (oldCp != CP_UTF8) {
|
||||
SetConsoleOutputCP(oldCp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL WINAPI consoleHandler(FF_MAYBE_UNUSED DWORD signal)
|
||||
{
|
||||
BOOL WINAPI consoleHandler(FF_MAYBE_UNUSED DWORD signal) {
|
||||
resetConsole();
|
||||
exit(0);
|
||||
}
|
||||
#else
|
||||
static void exitSignalHandler(FF_MAYBE_UNUSED int signal)
|
||||
{
|
||||
static void exitSignalHandler(FF_MAYBE_UNUSED int signal) {
|
||||
resetConsole();
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ffStart(void)
|
||||
{
|
||||
void ffStart(void) {
|
||||
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe;
|
||||
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe;
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
if (instance.config.display.noBuffer)
|
||||
if (instance.config.display.noBuffer) {
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
else
|
||||
} else {
|
||||
setvbuf(stdout, NULL, _IOFBF, 4096);
|
||||
}
|
||||
SetConsoleCtrlHandler(consoleHandler, TRUE);
|
||||
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD mode = 0;
|
||||
if (GetConsoleMode(hStdout, &mode))
|
||||
{
|
||||
if (GetConsoleMode(hStdout, &mode)) {
|
||||
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
oldCp = GetConsoleOutputCP();
|
||||
if (oldCp != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
|
||||
if (oldCp != CP_UTF8) {
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (instance.config.display.noBuffer) setvbuf(stdout, NULL, _IONBF, 0);
|
||||
struct sigaction action = { .sa_handler = exitSignalHandler };
|
||||
#else
|
||||
if (instance.config.display.noBuffer) {
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
}
|
||||
struct sigaction action = {.sa_handler = exitSignalHandler};
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
sigaction(SIGQUIT, &action, NULL);
|
||||
@@ -128,142 +130,139 @@ void ffStart(void)
|
||||
sigemptyset(&newmask);
|
||||
sigaddset(&newmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &newmask, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//reset everything to default before we start printing
|
||||
if(!instance.config.display.pipe)
|
||||
// reset everything to default before we start printing
|
||||
if (!instance.config.display.pipe) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
}
|
||||
|
||||
if(ffHideCursor)
|
||||
if (ffHideCursor) {
|
||||
fputs("\033[?25l", stdout);
|
||||
}
|
||||
|
||||
if(ffDisableLinewrap)
|
||||
if (ffDisableLinewrap) {
|
||||
fputs("\033[?7l", stdout);
|
||||
}
|
||||
|
||||
if(instance.state.dynamicInterval > 0)
|
||||
{
|
||||
if (instance.state.dynamicInterval > 0) {
|
||||
fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void ffFinish(void)
|
||||
{
|
||||
void ffFinish(void) {
|
||||
resetConsole();
|
||||
}
|
||||
|
||||
static void destroyConfig(void)
|
||||
{
|
||||
static void destroyConfig(void) {
|
||||
ffOptionsDestroyLogo(&instance.config.logo);
|
||||
ffOptionsDestroyGeneral(&instance.config.general);
|
||||
ffOptionsDestroyDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
static void destroyState(void)
|
||||
{
|
||||
static void destroyState(void) {
|
||||
ffPlatformDestroy(&instance.state.platform);
|
||||
}
|
||||
|
||||
void ffDestroyInstance(void)
|
||||
{
|
||||
void ffDestroyInstance(void) {
|
||||
destroyConfig();
|
||||
destroyState();
|
||||
}
|
||||
|
||||
//Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
|
||||
void ffListFeatures(void)
|
||||
{
|
||||
// Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
|
||||
void ffListFeatures(void) {
|
||||
fputs(
|
||||
#if FF_HAVE_THREADS
|
||||
"threads\n"
|
||||
#endif
|
||||
#if FF_HAVE_VULKAN
|
||||
"vulkan\n"
|
||||
#endif
|
||||
#if FF_HAVE_WAYLAND
|
||||
"wayland\n"
|
||||
#endif
|
||||
#if FF_HAVE_XCB_RANDR
|
||||
"xcb-randr\n"
|
||||
#endif
|
||||
#if FF_HAVE_XRANDR
|
||||
"xrandr\n"
|
||||
#endif
|
||||
#if FF_HAVE_DRM
|
||||
"drm\n"
|
||||
#endif
|
||||
#if FF_HAVE_DRM_AMDGPU
|
||||
"drm_amdgpu\n"
|
||||
#endif
|
||||
#if FF_HAVE_GIO
|
||||
"gio\n"
|
||||
#endif
|
||||
#if FF_HAVE_DCONF
|
||||
"dconf\n"
|
||||
#endif
|
||||
#if FF_HAVE_DBUS
|
||||
"dbus\n"
|
||||
#endif
|
||||
#if FF_HAVE_IMAGEMAGICK7
|
||||
"imagemagick7\n"
|
||||
#endif
|
||||
#if FF_HAVE_IMAGEMAGICK6
|
||||
"imagemagick6\n"
|
||||
#endif
|
||||
#if FF_HAVE_CHAFA
|
||||
"chafa\n"
|
||||
#endif
|
||||
#if FF_HAVE_ZLIB
|
||||
"zlib\n"
|
||||
#endif
|
||||
#if FF_HAVE_SQLITE3
|
||||
"sqlite3\n"
|
||||
#endif
|
||||
#if FF_HAVE_RPM
|
||||
"rpm\n"
|
||||
#endif
|
||||
#if FF_HAVE_EGL
|
||||
"egl\n"
|
||||
#endif
|
||||
#if FF_HAVE_GLX
|
||||
"glx\n"
|
||||
#endif
|
||||
#if FF_HAVE_OPENCL
|
||||
"opencl\n"
|
||||
#endif
|
||||
#if FF_HAVE_FREETYPE
|
||||
"freetype\n"
|
||||
#endif
|
||||
#if FF_HAVE_PULSE
|
||||
"libpulse\n"
|
||||
#endif
|
||||
#if FF_HAVE_DDCUTIL
|
||||
"libddcutil\n"
|
||||
#endif
|
||||
#if FF_HAVE_ELF || __sun || (__FreeBSD__ && !__DragonFly__) || __OpenBSD__ || __NetBSD__
|
||||
"libelf\n"
|
||||
#endif
|
||||
#if FF_HAVE_LIBZFS
|
||||
"libzfs\n"
|
||||
#endif
|
||||
#if FF_USE_SYSTEM_YYJSON
|
||||
"System yyjson\n"
|
||||
#endif
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
"linux/videodev2\n"
|
||||
#endif
|
||||
#if FF_HAVE_LINUX_WIRELESS
|
||||
"linux/wireless\n"
|
||||
#endif
|
||||
#if FF_HAVE_EMBEDDED_PCIIDS
|
||||
"Embedded pciids\n"
|
||||
#endif
|
||||
#if FF_WIN81_COMPAT
|
||||
"Windows 8.1 Compatibility\n"
|
||||
#endif
|
||||
#if FF_APPLE_MEMSIZE_USABLE
|
||||
"Apple memsize_usable\n"
|
||||
#endif
|
||||
""
|
||||
, stdout);
|
||||
#if FF_HAVE_THREADS
|
||||
"threads\n"
|
||||
#endif
|
||||
#if FF_HAVE_VULKAN
|
||||
"vulkan\n"
|
||||
#endif
|
||||
#if FF_HAVE_WAYLAND
|
||||
"wayland\n"
|
||||
#endif
|
||||
#if FF_HAVE_XCB_RANDR
|
||||
"xcb-randr\n"
|
||||
#endif
|
||||
#if FF_HAVE_XRANDR
|
||||
"xrandr\n"
|
||||
#endif
|
||||
#if FF_HAVE_DRM
|
||||
"drm\n"
|
||||
#endif
|
||||
#if FF_HAVE_DRM_AMDGPU
|
||||
"drm_amdgpu\n"
|
||||
#endif
|
||||
#if FF_HAVE_GIO
|
||||
"gio\n"
|
||||
#endif
|
||||
#if FF_HAVE_DCONF
|
||||
"dconf\n"
|
||||
#endif
|
||||
#if FF_HAVE_DBUS
|
||||
"dbus\n"
|
||||
#endif
|
||||
#if FF_HAVE_IMAGEMAGICK7
|
||||
"imagemagick7\n"
|
||||
#endif
|
||||
#if FF_HAVE_IMAGEMAGICK6
|
||||
"imagemagick6\n"
|
||||
#endif
|
||||
#if FF_HAVE_CHAFA
|
||||
"chafa\n"
|
||||
#endif
|
||||
#if FF_HAVE_ZLIB
|
||||
"zlib\n"
|
||||
#endif
|
||||
#if FF_HAVE_SQLITE3
|
||||
"sqlite3\n"
|
||||
#endif
|
||||
#if FF_HAVE_RPM
|
||||
"rpm\n"
|
||||
#endif
|
||||
#if FF_HAVE_EGL
|
||||
"egl\n"
|
||||
#endif
|
||||
#if FF_HAVE_GLX
|
||||
"glx\n"
|
||||
#endif
|
||||
#if FF_HAVE_OPENCL
|
||||
"opencl\n"
|
||||
#endif
|
||||
#if FF_HAVE_FREETYPE
|
||||
"freetype\n"
|
||||
#endif
|
||||
#if FF_HAVE_PULSE
|
||||
"libpulse\n"
|
||||
#endif
|
||||
#if FF_HAVE_DDCUTIL
|
||||
"libddcutil\n"
|
||||
#endif
|
||||
#if FF_HAVE_ELF || __sun || (__FreeBSD__ && !__DragonFly__) || __OpenBSD__ || __NetBSD__
|
||||
"libelf\n"
|
||||
#endif
|
||||
#if FF_HAVE_LIBZFS
|
||||
"libzfs\n"
|
||||
#endif
|
||||
#if FF_USE_SYSTEM_YYJSON
|
||||
"System yyjson\n"
|
||||
#endif
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
"linux/videodev2\n"
|
||||
#endif
|
||||
#if FF_HAVE_LINUX_WIRELESS
|
||||
"linux/wireless\n"
|
||||
#endif
|
||||
#if FF_HAVE_EMBEDDED_PCIIDS
|
||||
"Embedded pciids\n"
|
||||
#endif
|
||||
#if FF_WIN81_COMPAT
|
||||
"Windows 8.1 Compatibility\n"
|
||||
#endif
|
||||
#if FF_APPLE_MEMSIZE_USABLE
|
||||
"Apple memsize_usable\n"
|
||||
#endif
|
||||
"",
|
||||
stdout);
|
||||
}
|
||||
|
||||
+105
-113
@@ -8,181 +8,177 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#ifndef __APPLE__
|
||||
#include <poll.h>
|
||||
# include <poll.h>
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#if FF_HAVE_WORDEXP
|
||||
#include <wordexp.h>
|
||||
# include <wordexp.h>
|
||||
#else
|
||||
#include <glob.h>
|
||||
# include <glob.h>
|
||||
#endif
|
||||
|
||||
static void createSubfolders(const char* fileName)
|
||||
{
|
||||
static void createSubfolders(const char* fileName) {
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
|
||||
const char *token = NULL;
|
||||
while((token = strchr(fileName, '/')) != NULL)
|
||||
{
|
||||
ffStrbufAppendNS(&path, (uint32_t)(token - fileName + 1), fileName);
|
||||
const char* token = NULL;
|
||||
while ((token = strchr(fileName, '/')) != NULL) {
|
||||
ffStrbufAppendNS(&path, (uint32_t) (token - fileName + 1), fileName);
|
||||
mkdir(path.chars, S_IRWXU | S_IRGRP | S_IROTH);
|
||||
fileName = token + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
|
||||
{
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) {
|
||||
int openFlagsModes = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
|
||||
mode_t openFlagsRights = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
int FF_AUTO_CLOSE_FD fd = open(fileName, openFlagsModes, openFlagsRights);
|
||||
if(fd == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
if (fd == -1) {
|
||||
if (errno == ENOENT) {
|
||||
createSubfolders(fileName);
|
||||
fd = open(fileName, openFlagsModes, openFlagsRights);
|
||||
if(fd == -1)
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return write(fd, data, dataSize) > 0;
|
||||
}
|
||||
|
||||
static inline void readWithLength(int fd, FFstrbuf* buffer, uint32_t length)
|
||||
{
|
||||
static inline void readWithLength(int fd, FFstrbuf* buffer, uint32_t length) {
|
||||
ffStrbufEnsureFixedLengthFree(buffer, length);
|
||||
ssize_t bytesRead = 0;
|
||||
while(
|
||||
length > 0 && (bytesRead = read(fd, buffer->chars + buffer->length, length)) > 0
|
||||
) {
|
||||
while (
|
||||
length > 0 && (bytesRead = read(fd, buffer->chars + buffer->length, length)) > 0) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
length -= (uint32_t) bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void readUntilEOF(int fd, FFstrbuf* buffer)
|
||||
{
|
||||
static inline void readUntilEOF(int fd, FFstrbuf* buffer) {
|
||||
ffStrbufEnsureFree(buffer, 31);
|
||||
uint32_t available = ffStrbufGetFree(buffer);
|
||||
ssize_t bytesRead = 0;
|
||||
while(
|
||||
(bytesRead = read(fd, buffer->chars + buffer->length, available)) > 0
|
||||
) {
|
||||
while (
|
||||
(bytesRead = read(fd, buffer->chars + buffer->length, available)) > 0) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
if((uint32_t) bytesRead == available)
|
||||
if ((uint32_t) bytesRead == available) {
|
||||
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
|
||||
}
|
||||
available = ffStrbufGetFree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool ffAppendFDBuffer(int fd, FFstrbuf* buffer)
|
||||
{
|
||||
bool ffAppendFDBuffer(int fd, FFstrbuf* buffer) {
|
||||
struct stat fileInfo;
|
||||
if(fstat(fd, &fileInfo) != 0)
|
||||
if (fstat(fd, &fileInfo) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileInfo.st_size > 0)
|
||||
readWithLength(fd, buffer, (uint32_t)fileInfo.st_size);
|
||||
else
|
||||
if (fileInfo.st_size > 0) {
|
||||
readWithLength(fd, buffer, (uint32_t) fileInfo.st_size);
|
||||
} else {
|
||||
readUntilEOF(fd, buffer);
|
||||
}
|
||||
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out) {
|
||||
bool result = false;
|
||||
|
||||
#if FF_HAVE_WORDEXP
|
||||
#if FF_HAVE_WORDEXP
|
||||
|
||||
wordexp_t exp;
|
||||
if (wordexp(in, &exp, 0) != 0) // WARN: 0 = no safety flags; command substitution allowed
|
||||
if (wordexp(in, &exp, 0) != 0) { // WARN: 0 = no safety flags; command substitution allowed
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exp.we_wordc >= 1)
|
||||
{
|
||||
if (exp.we_wordc >= 1) {
|
||||
result = true;
|
||||
ffStrbufSetS(out, exp.we_wordv[exp.we_wordc > 1 ? ffTimeGetNow() % exp.we_wordc : 0]);
|
||||
}
|
||||
|
||||
wordfree(&exp);
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
glob_t gb;
|
||||
if (glob(in, GLOB_NOSORT
|
||||
#ifdef GLOB_TILDE
|
||||
| GLOB_TILDE
|
||||
#endif
|
||||
#ifdef GLOB_BRACE
|
||||
| GLOB_BRACE
|
||||
#endif
|
||||
, NULL, &gb) != 0)
|
||||
# ifdef GLOB_TILDE
|
||||
| GLOB_TILDE
|
||||
# endif
|
||||
# ifdef GLOB_BRACE
|
||||
| GLOB_BRACE
|
||||
# endif
|
||||
,
|
||||
NULL,
|
||||
&gb) != 0)
|
||||
return false;
|
||||
|
||||
if (gb.gl_pathc >= 1)
|
||||
{
|
||||
if (gb.gl_pathc >= 1) {
|
||||
result = true;
|
||||
ffStrbufSetS(out, gb.gl_pathv[gb.gl_pathc > 1 ? ffTimeGetNow() % (unsigned) gb.gl_pathc : 0]);
|
||||
}
|
||||
|
||||
globfree(&gb);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ftty = -1;
|
||||
static struct termios oldTerm;
|
||||
void restoreTerm(void)
|
||||
{
|
||||
void restoreTerm(void) {
|
||||
tcsetattr(ftty, TCSAFLUSH, &oldTerm);
|
||||
}
|
||||
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...)
|
||||
{
|
||||
if (ftty < 0)
|
||||
{
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...) {
|
||||
if (ftty < 0) {
|
||||
ftty = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC);
|
||||
if (ftty < 0)
|
||||
if (ftty < 0) {
|
||||
return "open(\"/dev/tty\", O_RDWR | O_NOCTTY | O_CLOEXEC) failed";
|
||||
}
|
||||
|
||||
if(tcgetattr(ftty, &oldTerm) == -1)
|
||||
if (tcgetattr(ftty, &oldTerm) == -1) {
|
||||
return "tcgetattr(STDIN_FILENO, &oldTerm) failed";
|
||||
}
|
||||
|
||||
struct termios newTerm = oldTerm;
|
||||
newTerm.c_lflag &= (tcflag_t) ~(ICANON | ECHO);
|
||||
if(tcsetattr(ftty, TCSAFLUSH, &newTerm) == -1)
|
||||
if (tcsetattr(ftty, TCSAFLUSH, &newTerm) == -1) {
|
||||
return "tcsetattr(STDIN_FILENO, TCSAFLUSH, &newTerm)";
|
||||
}
|
||||
atexit(restoreTerm);
|
||||
}
|
||||
|
||||
ffWriteFDData(ftty, strlen(request), request);
|
||||
|
||||
//Give the terminal some time to respond
|
||||
#ifndef __APPLE__
|
||||
if(poll(&(struct pollfd) { .fd = ftty, .events = POLLIN }, 1, FF_IO_TERM_RESP_WAIT_MS) <= 0)
|
||||
// Give the terminal some time to respond
|
||||
#ifndef __APPLE__
|
||||
if (poll(&(struct pollfd) {.fd = ftty, .events = POLLIN}, 1, FF_IO_TERM_RESP_WAIT_MS) <= 0) {
|
||||
return "poll(/dev/tty) timeout or failed";
|
||||
#else
|
||||
}
|
||||
#else
|
||||
{
|
||||
// On macOS, poll(/dev/tty) always returns immediately
|
||||
// See also https://nathancraddock.com/blog/macos-dev-tty-polling/
|
||||
fd_set rd;
|
||||
FD_ZERO(&rd);
|
||||
FD_SET(ftty, &rd);
|
||||
if(select(ftty + 1, &rd, NULL, NULL, &(struct timeval) { .tv_sec = FF_IO_TERM_RESP_WAIT_MS / 1000, .tv_usec = (FF_IO_TERM_RESP_WAIT_MS % 1000) * 1000 }) <= 0)
|
||||
if (select(ftty + 1, &rd, NULL, NULL, &(struct timeval) {.tv_sec = FF_IO_TERM_RESP_WAIT_MS / 1000, .tv_usec = (FF_IO_TERM_RESP_WAIT_MS % 1000) * 1000}) <= 0) {
|
||||
return "select(/dev/tty) timeout or failed";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
char buffer[1024];
|
||||
size_t bytesRead = 0;
|
||||
@@ -190,12 +186,10 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
ssize_t nRead = read(ftty, buffer + bytesRead, sizeof(buffer) - bytesRead - 1);
|
||||
|
||||
if (nRead <= 0)
|
||||
{
|
||||
if (nRead <= 0) {
|
||||
va_end(args);
|
||||
return "read(STDIN_FILENO, buffer, sizeof(buffer) - 1) failed";
|
||||
}
|
||||
@@ -208,13 +202,13 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
int ret = vsscanf(buffer, format, cargs);
|
||||
va_end(cargs);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (ret <= 0) {
|
||||
va_end(args);
|
||||
return "vsscanf(buffer, format, args) failed";
|
||||
}
|
||||
if (ret >= nParams)
|
||||
if (ret >= nParams) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
@@ -222,22 +216,22 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffSuppressIO(bool suppress)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (instance.config.display.debugMode)
|
||||
bool ffSuppressIO(bool suppress) {
|
||||
#ifndef NDEBUG
|
||||
if (instance.config.display.debugMode) {
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool init = false;
|
||||
static int origOut = -1;
|
||||
static int origErr = -1;
|
||||
static int nullFile = -1;
|
||||
|
||||
if(!init)
|
||||
{
|
||||
if(!suppress)
|
||||
if (!init) {
|
||||
if (!suppress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
origOut = dup(STDOUT_FILENO);
|
||||
origErr = dup(STDERR_FILENO);
|
||||
@@ -245,8 +239,9 @@ bool ffSuppressIO(bool suppress)
|
||||
init = true;
|
||||
}
|
||||
|
||||
if(nullFile == -1)
|
||||
if (nullFile == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
@@ -256,47 +251,48 @@ bool ffSuppressIO(bool suppress)
|
||||
return true;
|
||||
}
|
||||
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
|
||||
{
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty) {
|
||||
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
|
||||
if (dfd < 0)
|
||||
if (dfd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
DIR* dir = fdopendir(dfd);
|
||||
if(dir == NULL)
|
||||
if (dir == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t folderLength = folder->length;
|
||||
|
||||
if(pretty && folderName != NULL)
|
||||
{
|
||||
for(uint8_t i = 0; i < indentation - 1; i++)
|
||||
if (pretty && folderName != NULL) {
|
||||
for (uint8_t i = 0; i < indentation - 1; i++) {
|
||||
fputs(" | ", stdout);
|
||||
}
|
||||
printf("%s/\n", folderName);
|
||||
}
|
||||
|
||||
struct dirent* entry;
|
||||
|
||||
while((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.') // skip hidden files
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (entry->d_name[0] == '.') { // skip hidden files
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isDir = false;
|
||||
#if !defined(__sun) && !defined(__HAIKU__)
|
||||
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
|
||||
if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) {
|
||||
isDir = entry->d_type == DT_DIR;
|
||||
else
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
struct stat stbuf;
|
||||
if (fstatat(dfd, entry->d_name, &stbuf, 0) < 0)
|
||||
if (fstatat(dfd, entry->d_name, &stbuf, 0) < 0) {
|
||||
isDir = false;
|
||||
else
|
||||
} else {
|
||||
isDir = S_ISDIR(stbuf.st_mode);
|
||||
}
|
||||
}
|
||||
if (isDir)
|
||||
{
|
||||
if (isDir) {
|
||||
ffStrbufAppendS(folder, entry->d_name);
|
||||
ffStrbufAppendC(folder, '/');
|
||||
listFilesRecursively(baseLength, folder, (uint8_t) (indentation + 1), entry->d_name, pretty);
|
||||
@@ -304,13 +300,11 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pretty)
|
||||
{
|
||||
for(uint8_t i = 0; i < indentation; i++)
|
||||
if (pretty) {
|
||||
for (uint8_t i = 0; i < indentation; i++) {
|
||||
fputs(" | ", stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
fputs(folder->chars + baseLength, stdout);
|
||||
}
|
||||
|
||||
@@ -320,23 +314,21 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void ffListFilesRecursively(const char* path, bool pretty)
|
||||
{
|
||||
void ffListFilesRecursively(const char* path, bool pretty) {
|
||||
FF_STRBUF_AUTO_DESTROY folder = ffStrbufCreateS(path);
|
||||
ffStrbufEnsureEndsWithC(&folder, '/');
|
||||
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
FFNativeFD ffGetNullFD(void) {
|
||||
static FFNativeFD hNullFile = -1;
|
||||
if (hNullFile != -1)
|
||||
if (hNullFile != -1) {
|
||||
return hNullFile;
|
||||
}
|
||||
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
bool ffRemoveFile(const char* fileName)
|
||||
{
|
||||
bool ffRemoveFile(const char* fileName) {
|
||||
return unlink(fileName) == 0;
|
||||
}
|
||||
|
||||
+135
-148
@@ -6,15 +6,13 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static bool createSubfolders(wchar_t* fileName)
|
||||
{
|
||||
static bool createSubfolders(wchar_t* fileName) {
|
||||
HANDLE hRoot = ffGetPeb()->ProcessParameters->CurrentDirectory.Handle;
|
||||
bool closeRoot = false;
|
||||
wchar_t* ptr = fileName;
|
||||
|
||||
// Absolute drive path: C:\...
|
||||
if (ffCharIsEnglishAlphabet((char)ptr[0]) && ptr[1] == L':' && ptr[2] == L'\\')
|
||||
{
|
||||
if (ffCharIsEnglishAlphabet((char) ptr[0]) && ptr[1] == L':' && ptr[2] == L'\\') {
|
||||
wchar_t saved = ptr[3];
|
||||
ptr[3] = L'\0';
|
||||
|
||||
@@ -25,26 +23,27 @@ static bool createSubfolders(wchar_t* fileName)
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
NULL);
|
||||
|
||||
ptr[3] = saved;
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
if (hRoot == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
closeRoot = true;
|
||||
ptr += 3; // skip "C:\"
|
||||
}
|
||||
// UNC path: \\server\share\...
|
||||
else if (ptr[0] == L'\\' && ptr[1] == L'\\')
|
||||
{
|
||||
else if (ptr[0] == L'\\' && ptr[1] == L'\\') {
|
||||
wchar_t* serverEnd = wcschr(ptr + 2, L'\\');
|
||||
if (serverEnd == NULL)
|
||||
if (serverEnd == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t* shareEnd = wcschr(serverEnd + 1, L'\\');
|
||||
if (shareEnd == NULL)
|
||||
if (shareEnd == NULL) {
|
||||
return true; // no parent subfolder exists before file name
|
||||
}
|
||||
|
||||
wchar_t saved = *shareEnd;
|
||||
*shareEnd = L'\0';
|
||||
@@ -56,21 +55,20 @@ static bool createSubfolders(wchar_t* fileName)
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
NULL);
|
||||
|
||||
*shareEnd = saved;
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
if (hRoot == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
closeRoot = true;
|
||||
ptr = shareEnd + 1; // first component under share
|
||||
}
|
||||
// Rooted path on current drive: \foo\bar
|
||||
else if (ptr[0] == L'\\')
|
||||
{
|
||||
else if (ptr[0] == L'\\') {
|
||||
UNICODE_STRING* dosPath = &ffGetPeb()->ProcessParameters->CurrentDirectory.DosPath;
|
||||
wchar_t driveRoot[] = { dosPath->Buffer[0], L':', L'\\', L'\0' };
|
||||
wchar_t driveRoot[] = {dosPath->Buffer[0], L':', L'\\', L'\0'};
|
||||
hRoot = CreateFileW(
|
||||
driveRoot,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
@@ -78,23 +76,22 @@ static bool createSubfolders(wchar_t* fileName)
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
NULL);
|
||||
if (hRoot == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
closeRoot = true;
|
||||
ptr++; // skip leading '\'
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
wchar_t* token = wcschr(ptr, L'\\');
|
||||
if (token == NULL)
|
||||
if (token == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip empty path segments caused by duplicated '\'
|
||||
if (token == ptr)
|
||||
{
|
||||
if (token == ptr) {
|
||||
ptr = token + 1;
|
||||
continue;
|
||||
}
|
||||
@@ -110,8 +107,8 @@ static bool createSubfolders(wchar_t* fileName)
|
||||
.RootDirectory = hRoot,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Buffer = ptr,
|
||||
.Length = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
|
||||
.MaximumLength = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
|
||||
.Length = (USHORT) ((USHORT) (token - ptr) * sizeof(wchar_t)),
|
||||
.MaximumLength = (USHORT) ((USHORT) (token - ptr) * sizeof(wchar_t)),
|
||||
},
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
},
|
||||
@@ -122,155 +119,153 @@ static bool createSubfolders(wchar_t* fileName)
|
||||
FILE_OPEN_IF,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
0);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
if (!NT_SUCCESS(status)) {
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE) {
|
||||
NtClose(hRoot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE) {
|
||||
NtClose(hRoot);
|
||||
}
|
||||
hRoot = hNew;
|
||||
closeRoot = true;
|
||||
|
||||
ptr = token + 1;
|
||||
}
|
||||
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE) {
|
||||
NtClose(hRoot);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
|
||||
{
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) {
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
ULONG len = 0;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG) strlen(fileName) + 1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < len / sizeof(wchar_t); ++i)
|
||||
{
|
||||
if (fileNameW[i] == L'/')
|
||||
for (ULONG i = 0; i < len / sizeof(wchar_t); ++i) {
|
||||
if (fileNameW[i] == L'/') {
|
||||
fileNameW[i] = L'\\';
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (GetLastError() == ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
if (!createSubfolders(fileNameW))
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
if (GetLastError() == ERROR_PATH_NOT_FOUND) {
|
||||
if (!createSubfolders(fileNameW)) {
|
||||
return false;
|
||||
}
|
||||
handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD written;
|
||||
return !!WriteFile(handle, data, (DWORD)dataSize, &written, NULL);
|
||||
return !!WriteFile(handle, data, (DWORD) dataSize, &written, NULL);
|
||||
}
|
||||
|
||||
static inline void readWithLength(HANDLE handle, FFstrbuf* buffer, uint32_t length)
|
||||
{
|
||||
static inline void readWithLength(HANDLE handle, FFstrbuf* buffer, uint32_t length) {
|
||||
ffStrbufEnsureFree(buffer, length);
|
||||
DWORD bytesRead = 0;
|
||||
while(
|
||||
while (
|
||||
length > 0 &&
|
||||
ReadFile(handle, buffer->chars + buffer->length, length, &bytesRead, NULL) != FALSE &&
|
||||
bytesRead > 0
|
||||
) {
|
||||
bytesRead > 0) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
length -= (uint32_t) bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer)
|
||||
{
|
||||
static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer) {
|
||||
ffStrbufEnsureFree(buffer, 31);
|
||||
uint32_t available = ffStrbufGetFree(buffer);
|
||||
DWORD bytesRead = 0;
|
||||
while(
|
||||
while (
|
||||
ReadFile(handle, buffer->chars + buffer->length, available, &bytesRead, NULL) != FALSE &&
|
||||
bytesRead > 0
|
||||
) {
|
||||
bytesRead > 0) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
if((uint32_t) bytesRead == available)
|
||||
if ((uint32_t) bytesRead == available) {
|
||||
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
|
||||
}
|
||||
available = ffStrbufGetFree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
|
||||
{
|
||||
bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer) {
|
||||
FILE_STANDARD_INFORMATION fileInfo;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
if(!NT_SUCCESS(NtQueryInformationFile(handle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation)))
|
||||
if (!NT_SUCCESS(NtQueryInformationFile(handle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation))) {
|
||||
fileInfo.EndOfFile.QuadPart = 0;
|
||||
}
|
||||
|
||||
if (fileInfo.EndOfFile.QuadPart > 0)
|
||||
readWithLength(handle, buffer, (uint32_t)fileInfo.EndOfFile.QuadPart);
|
||||
else
|
||||
if (fileInfo.EndOfFile.QuadPart > 0) {
|
||||
readWithLength(handle, buffer, (uint32_t) fileInfo.EndOfFile.QuadPart);
|
||||
} else {
|
||||
readUntilEOF(handle, buffer);
|
||||
}
|
||||
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory)
|
||||
{
|
||||
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory) {
|
||||
assert(fileNameLen <= 0x7FFF);
|
||||
|
||||
HANDLE hFile;
|
||||
IO_STATUS_BLOCK iosb = {};
|
||||
if(!NT_SUCCESS(NtOpenFile(&hFile,
|
||||
(directory ? FILE_LIST_DIRECTORY | FILE_TRAVERSE : FILE_READ_DATA | FILE_READ_EA) | FILE_READ_ATTRIBUTES | SYNCHRONIZE, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = dfd,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Buffer = (PWSTR) fileName,
|
||||
.Length = fileNameLen * (USHORT) sizeof(wchar_t),
|
||||
.MaximumLength = (fileNameLen + 1) * (USHORT) sizeof(wchar_t),
|
||||
if (!NT_SUCCESS(NtOpenFile(&hFile,
|
||||
(directory ? FILE_LIST_DIRECTORY | FILE_TRAVERSE : FILE_READ_DATA | FILE_READ_EA) | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
||||
&(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = dfd,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Buffer = (PWSTR) fileName,
|
||||
.Length = fileNameLen * (USHORT) sizeof(wchar_t),
|
||||
.MaximumLength = (fileNameLen + 1) * (USHORT) sizeof(wchar_t),
|
||||
},
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
},
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
},
|
||||
&iosb,
|
||||
FILE_SHARE_READ | (directory ? FILE_SHARE_WRITE | FILE_SHARE_DELETE : 0),
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE)
|
||||
)))
|
||||
&iosb,
|
||||
FILE_SHARE_READ | (directory ? FILE_SHARE_WRITE | FILE_SHARE_DELETE : 0),
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE)))) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return hFile;
|
||||
}
|
||||
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, int oflag)
|
||||
{
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, int oflag) {
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
ULONG len;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG) strlen(fileName) + 1))) {
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
// Implies `fileNameW[len] = L'\0';` and `len` includes the null terminator
|
||||
len /= sizeof(wchar_t); // convert from bytes to characters
|
||||
|
||||
for (uint32_t i = 0; i < len - 1; ++i)
|
||||
{
|
||||
if (fileNameW[i] == L'/')
|
||||
for (uint32_t i = 0; i < len - 1; ++i) {
|
||||
if (fileNameW[i] == L'/') {
|
||||
fileNameW[i] = L'\\';
|
||||
}
|
||||
}
|
||||
|
||||
return openatW(dfd, fileNameW, (uint16_t)(len - 1), !!(oflag & O_DIRECTORY));
|
||||
return openatW(dfd, fileNameW, (uint16_t) (len - 1), !!(oflag & O_DIRECTORY));
|
||||
}
|
||||
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out) {
|
||||
if (in[0] == '~') {
|
||||
if ((in[1] == '/' || in[1] == '\\' || in[1] == '\0') && !ffStrContainsC(in, '%')) {
|
||||
ffStrbufSet(out, &instance.state.platform.homeDir);
|
||||
@@ -281,24 +276,26 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
|
||||
wchar_t pathInW[MAX_PATH], pathOutW[MAX_PATH];
|
||||
ULONG len = (ULONG) strlen(in);
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathInW, (ULONG) sizeof(pathInW), &len, in, len)))
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathInW, (ULONG) sizeof(pathInW), &len, in, len))) {
|
||||
return false;
|
||||
}
|
||||
len /= sizeof(wchar_t); // convert from bytes to characters
|
||||
|
||||
size_t outLen; // in characters, including null terminator
|
||||
if (!NT_SUCCESS(RtlExpandEnvironmentStrings(NULL, pathInW, len, pathOutW, ARRAY_SIZE(pathOutW), &outLen)))
|
||||
if (!NT_SUCCESS(RtlExpandEnvironmentStrings(NULL, pathInW, len, pathOutW, ARRAY_SIZE(pathOutW), &outLen))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufSetNWS(out, (uint32_t) outLen - 1, pathOutW);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffSuppressIO(bool suppress)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (instance.config.display.debugMode)
|
||||
bool ffSuppressIO(bool suppress) {
|
||||
#ifndef NDEBUG
|
||||
if (instance.config.display.debugMode) {
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool init = false;
|
||||
static HANDLE hOrigOut = INVALID_HANDLE_VALUE;
|
||||
@@ -308,10 +305,10 @@ bool ffSuppressIO(bool suppress)
|
||||
static int fOrigErr = -1;
|
||||
static int fNullFile = -1;
|
||||
|
||||
if (!init)
|
||||
{
|
||||
if(!suppress)
|
||||
if (!init) {
|
||||
if (!suppress) {
|
||||
return true;
|
||||
}
|
||||
|
||||
hOrigOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hOrigErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
@@ -321,8 +318,9 @@ bool ffSuppressIO(bool suppress)
|
||||
|
||||
init = true;
|
||||
}
|
||||
if (hNullFile == INVALID_HANDLE_VALUE || fNullFile == -1)
|
||||
if (hNullFile == INVALID_HANDLE_VALUE || fNullFile == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
@@ -335,14 +333,13 @@ bool ffSuppressIO(bool suppress)
|
||||
return true;
|
||||
}
|
||||
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
|
||||
{
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty) {
|
||||
uint32_t folderLength = folder->length;
|
||||
|
||||
if(pretty && folderName != NULL)
|
||||
{
|
||||
for(uint8_t i = 0; i < indentation - 1; i++)
|
||||
if (pretty && folderName != NULL) {
|
||||
for (uint8_t i = 0; i < indentation - 1; i++) {
|
||||
fputs(" | ", stdout);
|
||||
}
|
||||
printf("%s/\n", folderName);
|
||||
}
|
||||
|
||||
@@ -350,15 +347,15 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
|
||||
WIN32_FIND_DATAA entry;
|
||||
HANDLE hFind = FindFirstFileA(folder->chars, &entry);
|
||||
ffStrbufTrimRight(folder, '*');
|
||||
if(hFind == INVALID_HANDLE_VALUE)
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if(ffStrEquals(entry.cFileName, ".") || ffStrEquals(entry.cFileName, ".."))
|
||||
do {
|
||||
if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
if (ffStrEquals(entry.cFileName, ".") || ffStrEquals(entry.cFileName, "..")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(folder, folderLength);
|
||||
ffStrbufAppendS(folder, entry.cFileName);
|
||||
@@ -368,13 +365,11 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pretty)
|
||||
{
|
||||
for(uint8_t i = 0; i < indentation; i++)
|
||||
if (pretty) {
|
||||
for (uint8_t i = 0; i < indentation; i++) {
|
||||
fputs(" | ", stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
fputs(folder->chars + baseLength, stdout);
|
||||
}
|
||||
|
||||
@@ -383,20 +378,17 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
void ffListFilesRecursively(const char* path, bool pretty)
|
||||
{
|
||||
void ffListFilesRecursively(const char* path, bool pretty) {
|
||||
FF_STRBUF_AUTO_DESTROY folder = ffStrbufCreateS(path);
|
||||
ffStrbufEnsureEndsWithC(&folder, '/');
|
||||
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
|
||||
}
|
||||
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...)
|
||||
{
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...) {
|
||||
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
FF_AUTO_CLOSE_FD HANDLE hConin = INVALID_HANDLE_VALUE;
|
||||
DWORD inputMode;
|
||||
if (!GetConsoleMode(hInput, &inputMode))
|
||||
{
|
||||
if (!GetConsoleMode(hInput, &inputMode)) {
|
||||
hConin = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
|
||||
hInput = hConin;
|
||||
}
|
||||
@@ -409,18 +401,15 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
FF_AUTO_CLOSE_FD HANDLE hConout = INVALID_HANDLE_VALUE;
|
||||
DWORD outputMode;
|
||||
if (!GetConsoleMode(hOutput, &outputMode))
|
||||
{
|
||||
if (!GetConsoleMode(hOutput, &outputMode)) {
|
||||
hConout = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
|
||||
hOutput = hConout;
|
||||
}
|
||||
WriteFile(hOutput, request, (DWORD) strlen(request), &bytes, NULL);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (NtWaitForSingleObject(hInput, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) FF_IO_TERM_RESP_WAIT_MS * -10000 }) != STATUS_WAIT_0)
|
||||
{
|
||||
while (true) {
|
||||
if (NtWaitForSingleObject(hInput, FALSE, &(LARGE_INTEGER) {.QuadPart = (int64_t) FF_IO_TERM_RESP_WAIT_MS * -10000}) != STATUS_WAIT_0) {
|
||||
SetConsoleMode(hInput, inputMode);
|
||||
return "NtWaitForSingleObject() failed or timeout";
|
||||
}
|
||||
@@ -428,17 +417,18 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
// Ignore all unexpected input events
|
||||
INPUT_RECORD record;
|
||||
DWORD len = 0;
|
||||
if (!PeekConsoleInputW(hInput, &record, 1, &len))
|
||||
if (!PeekConsoleInputW(hInput, &record, 1, &len)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
record.EventType == KEY_EVENT &&
|
||||
record.Event.KeyEvent.uChar.UnicodeChar != L'\r' &&
|
||||
record.Event.KeyEvent.uChar.UnicodeChar != L'\n'
|
||||
)
|
||||
record.Event.KeyEvent.uChar.UnicodeChar != L'\n') {
|
||||
break;
|
||||
else
|
||||
} else {
|
||||
ReadConsoleInputW(hInput, &record, 1, &len);
|
||||
}
|
||||
}
|
||||
|
||||
va_list args;
|
||||
@@ -447,11 +437,9 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
char buffer[1024];
|
||||
uint32_t bytesRead = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
DWORD bytes = 0;
|
||||
if (!ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL) || bytes == 0)
|
||||
{
|
||||
if (!ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL) || bytes == 0) {
|
||||
va_end(args);
|
||||
return "ReadFile() failed";
|
||||
}
|
||||
@@ -464,13 +452,13 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
int ret = vsscanf(buffer, format, cargs);
|
||||
va_end(cargs);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (ret <= 0) {
|
||||
va_end(args);
|
||||
return "vsscanf(buffer, format, args) failed";
|
||||
}
|
||||
if (ret >= nParams)
|
||||
if (ret >= nParams) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SetConsoleMode(hInput, inputMode);
|
||||
@@ -480,11 +468,11 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
FFNativeFD ffGetNullFD(void) {
|
||||
static FFNativeFD hNullFile = INVALID_HANDLE_VALUE;
|
||||
if (hNullFile != INVALID_HANDLE_VALUE)
|
||||
if (hNullFile != INVALID_HANDLE_VALUE) {
|
||||
return hNullFile;
|
||||
}
|
||||
hNullFile = CreateFileW(
|
||||
L"NUL",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
@@ -492,7 +480,7 @@ FFNativeFD ffGetNullFD(void)
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
&(SECURITY_ATTRIBUTES){
|
||||
&(SECURITY_ATTRIBUTES) {
|
||||
.nLength = sizeof(SECURITY_ATTRIBUTES),
|
||||
.lpSecurityDescriptor = NULL,
|
||||
.bInheritHandle = TRUE,
|
||||
@@ -500,7 +488,6 @@ FFNativeFD ffGetNullFD(void)
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
bool ffRemoveFile(const char* fileName)
|
||||
{
|
||||
bool ffRemoveFile(const char* fileName) {
|
||||
return DeleteFileA(fileName) != FALSE;
|
||||
}
|
||||
|
||||
+152
-147
@@ -12,135 +12,117 @@
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if (unsafe_yyjson_equals_str(key, "type") || unsafe_yyjson_equals_str(key, "condition"))
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs) {
|
||||
if (unsafe_yyjson_equals_str(key, "type") || unsafe_yyjson_equals_str(key, "condition")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unsafe_yyjson_equals_str(key, "key"))
|
||||
{
|
||||
if (unsafe_yyjson_equals_str(key, "key")) {
|
||||
ffStrbufSetJsonVal(&moduleArgs->key, val);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "format"))
|
||||
{
|
||||
} else if (unsafe_yyjson_equals_str(key, "format")) {
|
||||
ffStrbufSetJsonVal(&moduleArgs->outputFormat, val);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "outputColor"))
|
||||
{
|
||||
} else if (unsafe_yyjson_equals_str(key, "outputColor")) {
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->outputColor);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "keyColor"))
|
||||
{
|
||||
} else if (unsafe_yyjson_equals_str(key, "keyColor")) {
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->keyColor);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "keyWidth"))
|
||||
{
|
||||
} else if (unsafe_yyjson_equals_str(key, "keyWidth")) {
|
||||
moduleArgs->keyWidth = (uint32_t) yyjson_get_uint(val);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "keyIcon"))
|
||||
{
|
||||
} else if (unsafe_yyjson_equals_str(key, "keyIcon")) {
|
||||
ffStrbufSetJsonVal(&moduleArgs->keyIcon, val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if (moduleArgs->key.length > 0)
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs) {
|
||||
if (moduleArgs->key.length > 0) {
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "key", &moduleArgs->key);
|
||||
if (moduleArgs->outputFormat.length > 0)
|
||||
}
|
||||
if (moduleArgs->outputFormat.length > 0) {
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "format", &moduleArgs->outputFormat);
|
||||
if (moduleArgs->outputColor.length > 0)
|
||||
}
|
||||
if (moduleArgs->outputColor.length > 0) {
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "outputColor", &moduleArgs->outputColor);
|
||||
if (moduleArgs->keyColor.length > 0)
|
||||
}
|
||||
if (moduleArgs->keyColor.length > 0) {
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyColor", &moduleArgs->keyColor);
|
||||
if (moduleArgs->keyWidth > 0)
|
||||
}
|
||||
if (moduleArgs->keyWidth > 0) {
|
||||
yyjson_mut_obj_add_uint(doc, module, "keyWidth", moduleArgs->keyWidth);
|
||||
if (moduleArgs->keyIcon.length > 0)
|
||||
}
|
||||
if (moduleArgs->keyIcon.length > 0) {
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyIcon", &moduleArgs->keyIcon);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[])
|
||||
{
|
||||
if (yyjson_is_int(val))
|
||||
{
|
||||
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[]) {
|
||||
if (yyjson_is_int(val)) {
|
||||
int intVal = yyjson_get_int(val);
|
||||
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair)
|
||||
{
|
||||
if (intVal == pPair->value)
|
||||
{
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair) {
|
||||
if (intVal == pPair->value) {
|
||||
*result = pPair->value;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "Invalid enum integer";
|
||||
}
|
||||
else if (yyjson_is_str(val))
|
||||
{
|
||||
} else if (yyjson_is_str(val)) {
|
||||
const char* strVal = yyjson_get_str(val);
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair)
|
||||
{
|
||||
if (ffStrEqualsIgnCase(strVal, pPair->key))
|
||||
{
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair) {
|
||||
if (ffStrEqualsIgnCase(strVal, pPair->key)) {
|
||||
*result = pPair->value;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "Invalid enum string";
|
||||
}
|
||||
else
|
||||
} else {
|
||||
return "Invalid enum value type; must be a string or integer";
|
||||
}
|
||||
}
|
||||
|
||||
static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_mut_doc* jsonDoc)
|
||||
{
|
||||
if(!ffCharIsEnglishAlphabet(type[0])) return false;
|
||||
static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_mut_doc* jsonDoc) {
|
||||
if (!ffCharIsEnglishAlphabet(type[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(type[0]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(type[0]) - 'A']; *modules; ++modules) {
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(type, baseInfo->name))
|
||||
{
|
||||
if (ffStrEqualsIgnCase(type, baseInfo->name)) {
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (jsonVal) baseInfo->parseJsonObject(optionBuf, jsonVal);
|
||||
if (jsonVal) {
|
||||
baseInfo->parseJsonObject(optionBuf, jsonVal);
|
||||
}
|
||||
bool succeeded;
|
||||
if (jsonDoc)
|
||||
{
|
||||
if (jsonDoc) {
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
if (baseInfo->generateJsonResult) {
|
||||
succeeded = baseInfo->generateJsonResult(optionBuf, jsonDoc, module);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unsupported for JSON format");
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else {
|
||||
succeeded = baseInfo->printModule(optionBuf);
|
||||
}
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonDoc)
|
||||
{
|
||||
if (jsonDoc) {
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
|
||||
yyjson_mut_obj_add_strcpy(jsonDoc, module, "type", type);
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unknown module type");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FFModuleArgs moduleArgs;
|
||||
ffOptionInitModuleArg(&moduleArgs, "");
|
||||
ffPrintError(type, 0, &moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown module type");
|
||||
@@ -149,61 +131,71 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
|
||||
return false;
|
||||
}
|
||||
|
||||
static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
{
|
||||
switch (type[0])
|
||||
{
|
||||
case 'b': case 'B': {
|
||||
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME))
|
||||
static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
switch (type[0]) {
|
||||
case 'b':
|
||||
case 'B': {
|
||||
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME)) {
|
||||
ffPrepareCPUUsage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': case 'C': {
|
||||
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME))
|
||||
{
|
||||
case 'c':
|
||||
case 'C': {
|
||||
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME)) {
|
||||
__attribute__((__cleanup__(ffDestroyCommandOptions))) FFCommandOptions options;
|
||||
ffInitCommandOptions(&options);
|
||||
if (module) ffCommandModuleInfo.parseJsonObject(&options, module);
|
||||
if (module) {
|
||||
ffCommandModuleInfo.parseJsonObject(&options, module);
|
||||
}
|
||||
ffPrepareCommand(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'd': case 'D': {
|
||||
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
|
||||
{
|
||||
case 'd':
|
||||
case 'D': {
|
||||
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME)) {
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
if (module) ffDiskIOModuleInfo.parseJsonObject(&options, module);
|
||||
if (module) {
|
||||
ffDiskIOModuleInfo.parseJsonObject(&options, module);
|
||||
}
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'n': case 'N': {
|
||||
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME))
|
||||
{
|
||||
case 'n':
|
||||
case 'N': {
|
||||
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME)) {
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
if (module) ffNetIOModuleInfo.parseJsonObject(&options, module);
|
||||
if (module) {
|
||||
ffNetIOModuleInfo.parseJsonObject(&options, module);
|
||||
}
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': case 'P': {
|
||||
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME))
|
||||
{
|
||||
case 'p':
|
||||
case 'P': {
|
||||
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME)) {
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
if (module) ffPublicIPModuleInfo.parseJsonObject(&options, module);
|
||||
if (module) {
|
||||
ffPublicIPModuleInfo.parseJsonObject(&options, module);
|
||||
}
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'w': case 'W': {
|
||||
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME))
|
||||
{
|
||||
case 'w':
|
||||
case 'W': {
|
||||
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME)) {
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
if (module) ffWeatherModuleInfo.parseJsonObject(&options, module);
|
||||
if (module) {
|
||||
ffWeatherModuleInfo.parseJsonObject(&options, module);
|
||||
}
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
break;
|
||||
@@ -211,141 +203,154 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
}
|
||||
}
|
||||
|
||||
static bool matchesJsonArray(const char* str, yyjson_val* val)
|
||||
{
|
||||
static bool matchesJsonArray(const char* str, yyjson_val* val) {
|
||||
assert(val);
|
||||
|
||||
if (unsafe_yyjson_is_str(val))
|
||||
if (unsafe_yyjson_is_str(val)) {
|
||||
return ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(val));
|
||||
}
|
||||
|
||||
if (!unsafe_yyjson_is_arr(val)) return false;
|
||||
if (!unsafe_yyjson_is_arr(val)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val* item;
|
||||
yyjson_arr_foreach(val, idx, max, item)
|
||||
{
|
||||
if (yyjson_is_str(item) && ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(item)))
|
||||
yyjson_arr_foreach (val, idx, max, item) {
|
||||
if (yyjson_is_str(item) && ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(item))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* printJsonConfig(FFdata* data, bool prepare)
|
||||
{
|
||||
static const char* printJsonConfig(FFdata* data, bool prepare) {
|
||||
yyjson_mut_doc* jsonDoc = data->resultDoc;
|
||||
yyjson_val* const root = yyjson_doc_get_root(data->configDoc);
|
||||
assert(root);
|
||||
|
||||
if (!yyjson_is_obj(root))
|
||||
if (!yyjson_is_obj(root)) {
|
||||
return "Invalid JSON config format. Root value must be an object";
|
||||
}
|
||||
|
||||
yyjson_val* modules = yyjson_obj_get(root, "modules");
|
||||
if (!modules) return NULL;
|
||||
if (!yyjson_is_arr(modules)) return "Property 'modules' must be an array of strings or objects";
|
||||
if (!modules) {
|
||||
return NULL;
|
||||
}
|
||||
if (!yyjson_is_arr(modules)) {
|
||||
return "Property 'modules' must be an array of strings or objects";
|
||||
}
|
||||
|
||||
bool succeeded = true;
|
||||
int32_t thres = instance.config.display.stat;
|
||||
yyjson_val* item;
|
||||
size_t idx, max;
|
||||
yyjson_arr_foreach(modules, idx, max, item)
|
||||
{
|
||||
yyjson_arr_foreach (modules, idx, max, item) {
|
||||
double ms = 0;
|
||||
if(!prepare && thres >= 0)
|
||||
if (!prepare && thres >= 0) {
|
||||
ms = ffTimeGetTick();
|
||||
}
|
||||
|
||||
yyjson_val* module = item;
|
||||
const char* type = yyjson_get_str(module);
|
||||
if (type)
|
||||
if (type) {
|
||||
module = NULL;
|
||||
else if (yyjson_is_obj(module))
|
||||
{
|
||||
} else if (yyjson_is_obj(module)) {
|
||||
yyjson_val* conditions = yyjson_obj_get(module, "condition");
|
||||
if (conditions)
|
||||
{
|
||||
if (!yyjson_is_obj(conditions))
|
||||
if (conditions) {
|
||||
if (!yyjson_is_obj(conditions)) {
|
||||
return "Property 'conditions' must be an object";
|
||||
}
|
||||
|
||||
yyjson_val* system = yyjson_obj_get(conditions, "system");
|
||||
if (system && !matchesJsonArray(ffVersionResult.sysName, system))
|
||||
if (system && !matchesJsonArray(ffVersionResult.sysName, system)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
system = yyjson_obj_get(conditions, "!system");
|
||||
if (system && matchesJsonArray(ffVersionResult.sysName, system))
|
||||
if (system && matchesJsonArray(ffVersionResult.sysName, system)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yyjson_val* arch = yyjson_obj_get(conditions, "arch");
|
||||
if (arch && !matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
if (arch && !matchesJsonArray(ffVersionResult.architecture, arch)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
arch = yyjson_obj_get(conditions, "!arch");
|
||||
if (arch && matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
if (arch && matchesJsonArray(ffVersionResult.architecture, arch)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yyjson_val* previousSucceeded = yyjson_obj_get(conditions, "succeeded");
|
||||
if (previousSucceeded && !unsafe_yyjson_is_null(previousSucceeded))
|
||||
{
|
||||
if (!unsafe_yyjson_is_bool(previousSucceeded))
|
||||
if (previousSucceeded && !unsafe_yyjson_is_null(previousSucceeded)) {
|
||||
if (!unsafe_yyjson_is_bool(previousSucceeded)) {
|
||||
return "Property 'succeeded' in 'condition' must be a boolean";
|
||||
if (succeeded != unsafe_yyjson_get_bool(previousSucceeded))
|
||||
}
|
||||
if (succeeded != unsafe_yyjson_get_bool(previousSucceeded)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type = yyjson_get_str(yyjson_obj_get(module, "type"));
|
||||
if (!type) return "module object must contain a \"type\" key ( case sensitive )";
|
||||
if (yyjson_obj_size(module) == 1) // contains only Property type
|
||||
if (!type) {
|
||||
return "module object must contain a \"type\" key ( case sensitive )";
|
||||
}
|
||||
if (yyjson_obj_size(module) == 1) { // contains only Property type
|
||||
module = NULL;
|
||||
}
|
||||
else
|
||||
}
|
||||
} else {
|
||||
return "modules must be an array of strings or objects";
|
||||
}
|
||||
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, type, ':'))
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, type, ':')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(prepare)
|
||||
if (prepare) {
|
||||
prepareModuleJsonObject(type, module);
|
||||
else
|
||||
} else {
|
||||
succeeded = parseModuleJsonObject(type, module, jsonDoc);
|
||||
}
|
||||
|
||||
if(!prepare && thres >= 0)
|
||||
{
|
||||
if (!prepare && thres >= 0) {
|
||||
ms = ffTimeGetTick() - ms;
|
||||
if (jsonDoc)
|
||||
{
|
||||
if (jsonDoc) {
|
||||
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(jsonDoc->root);
|
||||
yyjson_mut_obj_add_real(jsonDoc, moduleJson, "stat", ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
char str[64];
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
if (thres > 0) {
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW
|
||||
: FF_COLOR_FG_RED),
|
||||
ms);
|
||||
}
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!instance.config.display.noBuffer && !jsonDoc) fflush(stdout);
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
if (!instance.config.display.noBuffer && !jsonDoc) {
|
||||
fflush(stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffPrintJsonConfig(FFdata* data, bool prepare)
|
||||
{
|
||||
void ffPrintJsonConfig(FFdata* data, bool prepare) {
|
||||
yyjson_mut_doc* jsonDoc = data->resultDoc;
|
||||
const char* error = printJsonConfig(data, prepare);
|
||||
if (error)
|
||||
{
|
||||
if (jsonDoc)
|
||||
{
|
||||
if (error) {
|
||||
if (jsonDoc) {
|
||||
yyjson_mut_val* obj = yyjson_mut_obj(jsonDoc);
|
||||
yyjson_mut_obj_add_str(jsonDoc, obj, "error", error);
|
||||
yyjson_mut_doc_set_root(jsonDoc, obj);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
ffPrintError("JsonConfig", 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "%s", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include <IOKit/kext/KextManager.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
bool ffKmodLoaded(const char* modName) {
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
bool ffKmodLoaded(const char* modName) {
|
||||
return modfind(modName) >= 0;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/io.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
bool ffKmodLoaded(const char* modName) {
|
||||
static FFstrbuf modules;
|
||||
if (modules.chars == NULL)
|
||||
{
|
||||
if (modules.chars == NULL) {
|
||||
ffStrbufInitS(&modules, "\n");
|
||||
ffAppendFileBuffer("/proc/modules", &modules);
|
||||
}
|
||||
|
||||
if (modules.length == 0) return false;
|
||||
if (modules.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t len = (uint32_t) strlen(modName);
|
||||
if (len > 250) return false;
|
||||
if (len > 250) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char temp[256];
|
||||
temp[0] = '\n';
|
||||
|
||||
+11
-14
@@ -4,39 +4,36 @@
|
||||
#include <sys/module.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
typedef struct __attribute__((__packed__)) FFNbsdModList
|
||||
{
|
||||
typedef struct __attribute__((__packed__)) FFNbsdModList {
|
||||
int len;
|
||||
modstat_t mods[];
|
||||
} FFNbsdModList;
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
bool ffKmodLoaded(const char* modName) {
|
||||
static FFNbsdModList* list = NULL;
|
||||
|
||||
if (list == NULL)
|
||||
{
|
||||
if (list == NULL) {
|
||||
struct iovec iov = {};
|
||||
|
||||
for (size_t len = 8192;; len = iov.iov_len)
|
||||
{
|
||||
for (size_t len = 8192;; len = iov.iov_len) {
|
||||
iov.iov_len = len;
|
||||
iov.iov_base = realloc(iov.iov_base, len);
|
||||
if (modctl(MODCTL_STAT, &iov) < 0)
|
||||
{
|
||||
if (modctl(MODCTL_STAT, &iov) < 0) {
|
||||
free(iov.iov_base);
|
||||
return true; // ignore errors
|
||||
}
|
||||
|
||||
if (len >= iov.iov_len) break;
|
||||
if (len >= iov.iov_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = (FFNbsdModList*) iov.iov_base;
|
||||
}
|
||||
|
||||
for (int i = 0; i < list->len; i++)
|
||||
{
|
||||
if (ffStrEquals(list->mods[i].ms_name, modName))
|
||||
for (int i = 0; i < list->len; i++) {
|
||||
if (ffStrEquals(list->mods[i].ms_name, modName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "common/kmod.h"
|
||||
|
||||
bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName)
|
||||
{
|
||||
bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName) {
|
||||
return true; // Don't generate kernel module related errors
|
||||
}
|
||||
|
||||
@@ -4,20 +4,19 @@
|
||||
#include <sys/modctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
bool ffKmodLoaded(const char* modName) {
|
||||
struct modinfo modinfo = {
|
||||
.mi_id = -1,
|
||||
.mi_nextid = -1,
|
||||
.mi_info = MI_INFO_ALL,
|
||||
};
|
||||
|
||||
for (int id = -1; modctl(MODINFO, id, &modinfo) == 0; id = modinfo.mi_id)
|
||||
{
|
||||
for (int id = -1; modctl(MODINFO, id, &modinfo) == 0; id = modinfo.mi_id) {
|
||||
modinfo.mi_name[MODMAXNAMELEN - 1] = '\0';
|
||||
|
||||
if (ffStrEquals(modinfo.mi_name, modName))
|
||||
if (ffStrEquals(modinfo.mi_name, modName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return !(errno == EINVAL || errno == ENOENT);
|
||||
|
||||
@@ -3,24 +3,25 @@
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
bool ffKmodLoaded(const char* modName) {
|
||||
ULONG bufferSize = 0;
|
||||
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &bufferSize);
|
||||
if (bufferSize == 0)
|
||||
if (bufferSize == 0) {
|
||||
return true; // ignore errors
|
||||
}
|
||||
|
||||
FF_AUTO_FREE RTL_PROCESS_MODULES* buffer = malloc(bufferSize);
|
||||
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation, buffer, bufferSize, &bufferSize)))
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation, buffer, bufferSize, &bufferSize))) {
|
||||
return true; // ignore errors
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < buffer->NumberOfModules; i++)
|
||||
{
|
||||
for (ULONG i = 0; i < buffer->NumberOfModules; i++) {
|
||||
const char* name = (const char*) buffer->Modules[i].FullPathName + buffer->Modules[i].OffsetToFileName;
|
||||
|
||||
if (ffStrEqualsIgnCase(name, modName))
|
||||
if (ffStrEqualsIgnCase(name, modName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
+62
-67
@@ -2,91 +2,91 @@
|
||||
#include "common/library.h"
|
||||
|
||||
#if _WIN32
|
||||
#include "common/debug.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include <errno.h>
|
||||
#include <ntstatus.h>
|
||||
# include "common/debug.h"
|
||||
# include "common/windows/nt.h"
|
||||
# include <errno.h>
|
||||
# include <ntstatus.h>
|
||||
#endif
|
||||
|
||||
#ifndef FF_DISABLE_DLOPEN
|
||||
|
||||
#include <stdarg.h>
|
||||
# include <stdarg.h>
|
||||
|
||||
//Clang doesn't define __SANITIZE_ADDRESS__ but defines __has_feature(address_sanitizer)
|
||||
#if !defined(__SANITIZE_ADDRESS__) && defined(__has_feature)
|
||||
#if __has_feature(address_sanitizer)
|
||||
#define __SANITIZE_ADDRESS__
|
||||
#endif
|
||||
#endif
|
||||
// Clang doesn't define __SANITIZE_ADDRESS__ but defines __has_feature(address_sanitizer)
|
||||
# if !defined(__SANITIZE_ADDRESS__) && defined(__has_feature)
|
||||
# if __has_feature(address_sanitizer)
|
||||
# define __SANITIZE_ADDRESS__
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#ifndef FF_DLOPEN_FLAGS
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
#define FF_DLOPEN_FLAGS RTLD_LAZY | RTLD_NODELETE
|
||||
#else
|
||||
#define FF_DLOPEN_FLAGS RTLD_LAZY
|
||||
#endif
|
||||
#endif
|
||||
# ifndef FF_DLOPEN_FLAGS
|
||||
# ifdef __SANITIZE_ADDRESS__
|
||||
# define FF_DLOPEN_FLAGS RTLD_LAZY | RTLD_NODELETE
|
||||
# else
|
||||
# define FF_DLOPEN_FLAGS RTLD_LAZY
|
||||
# endif
|
||||
# endif
|
||||
|
||||
static void* libraryLoad(const char* path, int maxVersion)
|
||||
{
|
||||
static void* libraryLoad(const char* path, int maxVersion) {
|
||||
void* result = dlopen(path, FF_DLOPEN_FLAGS);
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN32
|
||||
|
||||
// libX.dll.1 never exists on Windows, while libX-1.dll may exist
|
||||
FF_UNUSED(maxVersion)
|
||||
|
||||
if(result != NULL)
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t pathLen = ffStrbufLastIndexC(&instance.state.platform.exePath, '/');
|
||||
if (pathLen == instance.state.platform.exePath.length)
|
||||
if (pathLen == instance.state.platform.exePath.length) {
|
||||
return result;
|
||||
}
|
||||
|
||||
char absPath[MAX_PATH * 2];
|
||||
strcpy(mempcpy(absPath, instance.state.platform.exePath.chars, pathLen + 1), path);
|
||||
return dlopen(absPath, FF_DLOPEN_FLAGS);
|
||||
|
||||
#else
|
||||
# else
|
||||
|
||||
if(result != NULL || maxVersion < 0)
|
||||
if (result != NULL || maxVersion < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY pathbuf = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&pathbuf, path);
|
||||
ffStrbufAppendC(&pathbuf, '.');
|
||||
|
||||
for(int i = maxVersion; i >= 0; --i)
|
||||
{
|
||||
for (int i = maxVersion; i >= 0; --i) {
|
||||
uint32_t originalLength = pathbuf.length;
|
||||
ffStrbufAppendSInt(&pathbuf, i);
|
||||
|
||||
result = dlopen(pathbuf.chars, FF_DLOPEN_FLAGS);
|
||||
if(result != NULL)
|
||||
if (result != NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(&pathbuf, originalLength);
|
||||
}
|
||||
|
||||
#endif
|
||||
# endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* ffLibraryLoad(const char* path, int maxVersion, ...)
|
||||
{
|
||||
void* ffLibraryLoad(const char* path, int maxVersion, ...) {
|
||||
void* result = libraryLoad(path, maxVersion);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
if (!result) {
|
||||
va_list defaultNames;
|
||||
va_start(defaultNames, maxVersion);
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
const char* pathRest = va_arg(defaultNames, const char*);
|
||||
if(pathRest == NULL)
|
||||
if (pathRest == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
int maxVersionRest = va_arg(defaultNames, int);
|
||||
result = libraryLoad(pathRest, maxVersionRest);
|
||||
@@ -102,27 +102,25 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...)
|
||||
|
||||
#if _WIN32
|
||||
|
||||
void* dlopen(const char* path, FF_MAYBE_UNUSED int mode)
|
||||
{
|
||||
void* dlopen(const char* path, FF_MAYBE_UNUSED int mode) {
|
||||
wchar_t pathW[MAX_PATH + 1];
|
||||
ULONG pathWBytes = 0;
|
||||
|
||||
NTSTATUS status = RtlUTF8ToUnicodeN(pathW, sizeof(pathW), &pathWBytes, path, (uint32_t)strlen(path) + 1);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
NTSTATUS status = RtlUTF8ToUnicodeN(pathW, sizeof(pathW), &pathWBytes, path, (uint32_t) strlen(path) + 1);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("RtlUTF8ToUnicodeN failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PVOID module = NULL;
|
||||
status = LdrLoadDll(NULL, NULL, &(UNICODE_STRING) {
|
||||
.Length = (USHORT) pathWBytes - sizeof(wchar_t), // Exclude null terminator
|
||||
.MaximumLength = (USHORT) pathWBytes,
|
||||
.Buffer = pathW,
|
||||
}, &module);
|
||||
.Length = (USHORT) pathWBytes - sizeof(wchar_t), // Exclude null terminator
|
||||
.MaximumLength = (USHORT) pathWBytes,
|
||||
.Buffer = pathW,
|
||||
},
|
||||
&module);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("LdrLoadDll failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
@@ -130,47 +128,44 @@ void* dlopen(const char* path, FF_MAYBE_UNUSED int mode)
|
||||
return module;
|
||||
}
|
||||
|
||||
int dlclose(void* handle)
|
||||
{
|
||||
int dlclose(void* handle) {
|
||||
NTSTATUS status = LdrUnloadDll(handle);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("LdrUnloadDll failed for handle %p with status 0x%08lX: %s", handle, status, ffDebugNtStatus(status));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* dlsym(void* handle, const char* symbol)
|
||||
{
|
||||
void* dlsym(void* handle, const char* symbol) {
|
||||
void* address;
|
||||
USHORT symbolBytes = (USHORT) strlen(symbol) + 1;
|
||||
NTSTATUS status = LdrGetProcedureAddress(handle, &(ANSI_STRING) {
|
||||
.Length = symbolBytes - sizeof(char),
|
||||
.MaximumLength = symbolBytes,
|
||||
.Buffer = (char*) symbol,
|
||||
}, 0, &address);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
.Length = symbolBytes - sizeof(char),
|
||||
.MaximumLength = symbolBytes,
|
||||
.Buffer = (char*) symbol,
|
||||
},
|
||||
0,
|
||||
&address);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("LdrGetProcedureAddress failed for symbol %s with status 0x%08lX: %s", symbol, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
void* ffLibraryGetModule(const wchar_t* libraryFileName)
|
||||
{
|
||||
void* ffLibraryGetModule(const wchar_t* libraryFileName) {
|
||||
assert(libraryFileName != NULL && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
|
||||
|
||||
void* module = NULL;
|
||||
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t)) + sizeof(wchar_t);
|
||||
NTSTATUS status = LdrGetDllHandle(NULL, NULL, &(UNICODE_STRING) {
|
||||
.Length = libraryFileNameBytes - sizeof(wchar_t),
|
||||
.MaximumLength = libraryFileNameBytes,
|
||||
.Buffer = (wchar_t*) libraryFileName,
|
||||
}, &module);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
.Length = libraryFileNameBytes - sizeof(wchar_t),
|
||||
.MaximumLength = libraryFileNameBytes,
|
||||
.Buffer = (wchar_t*) libraryFileName,
|
||||
},
|
||||
&module);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("LdrGetDllHandle failed for library %ls with status 0x%08lX: %s", libraryFileName, status, ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void* memrchr(const void* s, int c, size_t n)
|
||||
{
|
||||
if (n == 0) return NULL;
|
||||
void* memrchr(const void* s, int c, size_t n) {
|
||||
if (n == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint8_t uc = (uint8_t) c;
|
||||
|
||||
const uint8_t* p = (const uint8_t*) s + n;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
if (*--p == uc) return (void*) p;
|
||||
while (n--) {
|
||||
if (*--p == uc) {
|
||||
return (void*) p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#include "common/netif.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
# include <net/if.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void)
|
||||
{
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void) {
|
||||
static FFNetifDefaultRouteResult result;
|
||||
if (result.status == FF_NETIF_UNINITIALIZED) {
|
||||
result.status = ffNetifGetDefaultRouteImplV4(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
|
||||
@@ -14,8 +13,7 @@ const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void)
|
||||
return &result;
|
||||
}
|
||||
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void)
|
||||
{
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void) {
|
||||
static FFNetifDefaultRouteResult result;
|
||||
if (result.status == FF_NETIF_UNINITIALIZED) {
|
||||
result.status = ffNetifGetDefaultRouteImplV6(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
|
||||
|
||||
@@ -8,68 +8,66 @@
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
|
||||
#if __APPLE__
|
||||
// https://github.com/apple-oss-distributions/network_cmds/blob/8f38231438e6a4d16ef8015e97e12c2c05105644/rtsol.tproj/if.c#L243
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint32_t))
|
||||
// https://github.com/apple-oss-distributions/network_cmds/blob/8f38231438e6a4d16ef8015e97e12c2c05105644/rtsol.tproj/if.c#L243
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(uint32_t))
|
||||
#elif __sun
|
||||
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L339
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L339
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#else
|
||||
#error unknown platform
|
||||
# error unknown platform
|
||||
#endif
|
||||
|
||||
static struct sockaddr *
|
||||
get_rt_address(struct rt_msghdr *rtm, int desired)
|
||||
{
|
||||
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
|
||||
static struct sockaddr*
|
||||
get_rt_address(struct rt_msghdr* rtm, int desired) {
|
||||
struct sockaddr* sa = (struct sockaddr*) (rtm + 1);
|
||||
|
||||
for (int i = 0; i < RTAX_MAX; i++)
|
||||
{
|
||||
if (rtm->rtm_addrs & (1 << i))
|
||||
{
|
||||
if ((1 << i) == desired)
|
||||
for (int i = 0; i < RTAX_MAX; i++) {
|
||||
if (rtm->rtm_addrs & (1 << i)) {
|
||||
if ((1 << i) == desired) {
|
||||
return sa;
|
||||
}
|
||||
|
||||
#ifndef __sun
|
||||
#ifndef __sun
|
||||
uint32_t salen = sa->sa_len;
|
||||
#else
|
||||
#else
|
||||
uint32_t salen;
|
||||
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L2941
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
salen = sizeof (struct sockaddr_in);
|
||||
break;
|
||||
case AF_LINK:
|
||||
salen = sizeof (struct sockaddr_dl);
|
||||
break;
|
||||
case AF_INET6:
|
||||
salen = sizeof (struct sockaddr_in6);
|
||||
break;
|
||||
default:
|
||||
salen = sizeof (struct sockaddr);
|
||||
break;
|
||||
case AF_INET:
|
||||
salen = sizeof(struct sockaddr_in);
|
||||
break;
|
||||
case AF_LINK:
|
||||
salen = sizeof(struct sockaddr_dl);
|
||||
break;
|
||||
case AF_INET6:
|
||||
salen = sizeof(struct sockaddr_in6);
|
||||
break;
|
||||
default:
|
||||
salen = sizeof(struct sockaddr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
sa = (struct sockaddr *)(ROUNDUP(salen) + (char *)sa);
|
||||
#endif
|
||||
sa = (struct sockaddr*) (ROUNDUP(salen) + (char*) sa);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
// https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
if (pfRoute < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char*) &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
uint32_t pid = instance.state.platform.pid;
|
||||
@@ -90,38 +88,38 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
},
|
||||
.dst = {
|
||||
.sin_family = AF_INET,
|
||||
#ifndef __sun
|
||||
#ifndef __sun
|
||||
.sin_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == (pid_t) pid))
|
||||
;
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == (pid_t) pid));
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl*) get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#endif
|
||||
) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
// Get the preferred source address
|
||||
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(&rtmsg.hdr, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET)
|
||||
struct sockaddr_in* src = (struct sockaddr_in*) get_rt_address(&rtmsg.hdr, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET) {
|
||||
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -131,18 +129,18 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
// https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
|
||||
if (pfRoute < 0)
|
||||
if (pfRoute < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char*) &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
uint32_t pid = instance.state.platform.pid;
|
||||
@@ -163,29 +161,28 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
},
|
||||
.dst = {
|
||||
.sin6_family = AF_INET6,
|
||||
#ifndef __sun
|
||||
#ifndef __sun
|
||||
.sin6_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == (pid_t) pid))
|
||||
;
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == (pid_t) pid));
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl*) get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#endif
|
||||
) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
|
||||
+43
-48
@@ -9,75 +9,72 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
|
||||
#if __DragonFly__
|
||||
// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/cf0aa2f1e47a3f0a6055fe427563cb3f3e627064/sys/net/route.h#L315C9-L315C19
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/cf0aa2f1e47a3f0a6055fe427563cb3f3e627064/sys/net/route.h#L315C9-L315C19
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#elif __FreeBSD__
|
||||
// https://github.com/freebsd/freebsd-src/blob/e4c0ecba44b20ebb2e4d80978c2cb6d16b730cb9/sys/net/route.h#L368C9-L368C16
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
// https://github.com/freebsd/freebsd-src/blob/e4c0ecba44b20ebb2e4d80978c2cb6d16b730cb9/sys/net/route.h#L368C9-L368C16
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#elif __NetBSD__
|
||||
// https://github.com/NetBSD/src/blob/29beb637d057520c0ed37ac2cde966f7cc0cadf4/sys/net/route.h#L330
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
|
||||
// https://github.com/NetBSD/src/blob/29beb637d057520c0ed37ac2cde966f7cc0cadf4/sys/net/route.h#L330
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
|
||||
#elif __OpenBSD__
|
||||
// https://github.com/openbsd/src/blob/ca647cfa4ec3ccb8360714bc0ebc32a394f7fb6a/regress/sys/netinet/bindconnect/bindconnect.c#L250
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
// https://github.com/openbsd/src/blob/ca647cfa4ec3ccb8360714bc0ebc32a394f7fb6a/regress/sys/netinet/bindconnect/bindconnect.c#L250
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#else
|
||||
#error unknown platform
|
||||
# error unknown platform
|
||||
#endif
|
||||
|
||||
static struct sockaddr *
|
||||
get_rt_address(struct rt_msghdr *rtm, int desired)
|
||||
{
|
||||
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
|
||||
static struct sockaddr*
|
||||
get_rt_address(struct rt_msghdr* rtm, int desired) {
|
||||
struct sockaddr* sa = (struct sockaddr*) (rtm + 1);
|
||||
|
||||
for (int i = 0; i < RTAX_MAX; i++)
|
||||
{
|
||||
if (rtm->rtm_addrs & (1 << i))
|
||||
{
|
||||
if ((1 << i) == desired)
|
||||
for (int i = 0; i < RTAX_MAX; i++) {
|
||||
if (rtm->rtm_addrs & (1 << i)) {
|
||||
if ((1 << i) == desired) {
|
||||
return sa;
|
||||
sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
|
||||
}
|
||||
sa = (struct sockaddr*) (ROUNDUP(sa->sa_len) + (char*) sa);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY};
|
||||
size_t needed;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE char* buf = malloc(needed);
|
||||
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* lim = buf + needed;
|
||||
struct rt_msghdr* rtm;
|
||||
for (char* next = buf; next < lim; next += rtm->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
|
||||
for (char* next = buf; next < lim; next += rtm->rtm_msglen) {
|
||||
rtm = (struct rt_msghdr*) next;
|
||||
struct sockaddr* sa = (struct sockaddr*) (rtm + 1);
|
||||
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET))
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK)
|
||||
{
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET)) {
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl*) get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
// Get the preferred source address
|
||||
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(rtm, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET)
|
||||
struct sockaddr_in* src = (struct sockaddr_in*) get_rt_address(rtm, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET) {
|
||||
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -86,31 +83,29 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};
|
||||
size_t needed;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE char* buf = malloc(needed);
|
||||
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* lim = buf + needed;
|
||||
struct rt_msghdr* rtm;
|
||||
for (char* next = buf; next < lim; next += rtm->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
|
||||
for (char* next = buf; next < lim; next += rtm->rtm_msglen) {
|
||||
rtm = (struct rt_msghdr*) next;
|
||||
struct sockaddr* sa = (struct sockaddr*) (rtm + 1);
|
||||
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET6))
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK)
|
||||
{
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET6)) {
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl*) get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
|
||||
@@ -7,18 +7,20 @@
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/route", "r");
|
||||
|
||||
if (!netRoute) return false;
|
||||
if (!netRoute) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// skip first line
|
||||
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
|
||||
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu, ...
|
||||
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", result->ifName, &destination) == 2)
|
||||
{
|
||||
if (destination != 0) continue;
|
||||
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", result->ifName, &destination) == 2) {
|
||||
if (destination != 0) {
|
||||
continue;
|
||||
}
|
||||
result->ifIndex = if_nametoindex(result->ifName);
|
||||
// TODO: Get the preferred source address
|
||||
return true;
|
||||
@@ -27,8 +29,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
// TODO: AF_INET6
|
||||
FF_UNUSED(result);
|
||||
return false;
|
||||
|
||||
@@ -11,85 +11,95 @@
|
||||
|
||||
// loosely based on Haiku's src/bin/network/route/route.cpp
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
if (pfRoute < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ifconf config;
|
||||
config.ifc_len = sizeof(config.ifc_value);
|
||||
if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0)
|
||||
if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int size = config.ifc_value;
|
||||
if (size <= 0)
|
||||
if (size <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE void *buffer = malloc((size_t) size);
|
||||
FF_AUTO_FREE void* buffer = malloc((size_t) size);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.ifc_len = size;
|
||||
config.ifc_buf = buffer;
|
||||
if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
|
||||
if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ifreq *interface = (struct ifreq*)buffer;
|
||||
struct ifreq *end = (struct ifreq*)((uint8_t*)buffer + size);
|
||||
struct ifreq* interface = (struct ifreq*) buffer;
|
||||
struct ifreq* end = (struct ifreq*) ((uint8_t*) buffer + size);
|
||||
|
||||
while (interface < end) {
|
||||
if (interface->ifr_route.flags & RTF_DEFAULT) {
|
||||
// interface->ifr_metric?
|
||||
strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
|
||||
result->ifIndex = if_nametoindex(interface->ifr_name);
|
||||
if (interface->ifr_route.source)
|
||||
result->preferredSourceAddrV4 = ((struct sockaddr_in*)interface->ifr_route.source)->sin_addr.s_addr;
|
||||
if (interface->ifr_route.source) {
|
||||
result->preferredSourceAddrV4 = ((struct sockaddr_in*) interface->ifr_route.source)->sin_addr.s_addr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t addressSize = 0;
|
||||
if (interface->ifr_route.destination != NULL)
|
||||
if (interface->ifr_route.destination != NULL) {
|
||||
addressSize += interface->ifr_route.destination->sa_len;
|
||||
if (interface->ifr_route.mask != NULL)
|
||||
}
|
||||
if (interface->ifr_route.mask != NULL) {
|
||||
addressSize += interface->ifr_route.mask->sa_len;
|
||||
if (interface->ifr_route.gateway != NULL)
|
||||
}
|
||||
if (interface->ifr_route.gateway != NULL) {
|
||||
addressSize += interface->ifr_route.gateway->sa_len;
|
||||
}
|
||||
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
interface = (struct ifreq*) ((addr_t) interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET6);
|
||||
if (pfRoute < 0)
|
||||
if (pfRoute < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ifconf config;
|
||||
config.ifc_len = sizeof(config.ifc_value);
|
||||
if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0)
|
||||
if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int size = config.ifc_value;
|
||||
if (size <= 0)
|
||||
if (size <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE void *buffer = malloc((size_t) size);
|
||||
FF_AUTO_FREE void* buffer = malloc((size_t) size);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.ifc_len = size;
|
||||
config.ifc_buf = buffer;
|
||||
if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
|
||||
if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ifreq *interface = (struct ifreq*)buffer;
|
||||
struct ifreq *end = (struct ifreq*)((uint8_t*)buffer + size);
|
||||
struct ifreq* interface = (struct ifreq*) buffer;
|
||||
struct ifreq* end = (struct ifreq*) ((uint8_t*) buffer + size);
|
||||
|
||||
while (interface < end) {
|
||||
if (interface->ifr_route.flags & RTF_DEFAULT) {
|
||||
@@ -99,14 +109,17 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
|
||||
size_t addressSize = 0;
|
||||
if (interface->ifr_route.destination != NULL)
|
||||
if (interface->ifr_route.destination != NULL) {
|
||||
addressSize += interface->ifr_route.destination->sa_len;
|
||||
if (interface->ifr_route.mask != NULL)
|
||||
}
|
||||
if (interface->ifr_route.mask != NULL) {
|
||||
addressSize += interface->ifr_route.mask->sa_len;
|
||||
if (interface->ifr_route.gateway != NULL)
|
||||
}
|
||||
if (interface->ifr_route.gateway != NULL) {
|
||||
addressSize += interface->ifr_route.gateway->sa_len;
|
||||
}
|
||||
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
interface = (struct ifreq*) ((addr_t) interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,11 @@
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
FF_DEBUG("Starting IPv4 default route detection");
|
||||
|
||||
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
if (sock_fd < 0) {
|
||||
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
@@ -25,11 +23,11 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
// Bind socket
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
if (bind(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
|
||||
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
@@ -52,8 +50,8 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
// Route message
|
||||
.rtm = {
|
||||
.rtm_family = AF_INET,
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_tos = 0,
|
||||
.rtm_table = RT_TABLE_UNSPEC,
|
||||
.rtm_protocol = RTPROT_UNSPEC,
|
||||
@@ -71,12 +69,11 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
|
||||
struct sockaddr_nl dest_addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
|
||||
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0, (struct sockaddr*) &dest_addr, sizeof(dest_addr));
|
||||
|
||||
if (sent != sizeof(req)) {
|
||||
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
|
||||
@@ -91,17 +88,15 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
uint32_t minMetric = UINT32_MAX;
|
||||
FF_MAYBE_UNUSED int routeCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&src_addr, &src_addr_len);
|
||||
while (true) {
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0, (struct sockaddr*) &src_addr, &src_addr_len);
|
||||
|
||||
if (received < 0) {
|
||||
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received >= (ssize_t)sizeof(buffer)) {
|
||||
if (received >= (ssize_t) sizeof(buffer)) {
|
||||
FF_DEBUG("Received truncated message: received %zd, bufsize %zu", received, sizeof(buffer));
|
||||
return false;
|
||||
}
|
||||
@@ -117,20 +112,19 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
uint32_t prefsrc;
|
||||
} entry;
|
||||
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*) buffer;
|
||||
NLMSG_OK(nlh, received);
|
||||
nlh = NLMSG_NEXT(nlh, received))
|
||||
{
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
|
||||
nlh = NLMSG_NEXT(nlh, received)) {
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid) {
|
||||
continue;
|
||||
if (nlh->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
}
|
||||
if (nlh->nlmsg_type == NLMSG_DONE) {
|
||||
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*)NLMSG_DATA(nlh))->error));
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*) NLMSG_DATA(nlh))->error));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -140,7 +134,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
|
||||
routeCount++;
|
||||
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
|
||||
struct rtmsg* rtm = (struct rtmsg*) NLMSG_DATA(nlh);
|
||||
if (rtm->rtm_family != AF_INET) {
|
||||
FF_DEBUG("Skipping non-IPv4 route #%d (family=%d)", routeCount, rtm->rtm_family);
|
||||
continue;
|
||||
@@ -158,44 +152,47 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
|
||||
FF_DEBUG("Processing IPv4 default route candidate #%d", routeCount);
|
||||
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
|
||||
entry = (__typeof__(entry)) {}; // Default to zero metric (no RTA_PRIORITY found)
|
||||
|
||||
// Parse route attributes
|
||||
size_t rtm_len = RTM_PAYLOAD(nlh);
|
||||
for (struct rtattr* rta = RTM_RTA(rtm);
|
||||
RTA_OK(rta, rtm_len);
|
||||
rta = RTA_NEXT(rta, rtm_len))
|
||||
{
|
||||
if (RTA_PAYLOAD(rta) < sizeof(uint32_t))
|
||||
rta = RTA_NEXT(rta, rtm_len)) {
|
||||
if (RTA_PAYLOAD(rta) < sizeof(uint32_t)) {
|
||||
continue; // Skip invalid attributes
|
||||
}
|
||||
|
||||
uint32_t rta_data = *(uint32_t*) RTA_DATA(rta);
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
FF_DEBUG("Unexpected RTA_DST: %s (len=%u)", inet_ntoa((struct in_addr) { .s_addr = rta_data }), rtm->rtm_dst_len);
|
||||
FF_DEBUG("Unexpected RTA_DST: %s (len=%u)", inet_ntoa((struct in_addr) {.s_addr = rta_data}), rtm->rtm_dst_len);
|
||||
goto next;
|
||||
case RTA_OIF:
|
||||
entry.ifindex = rta_data;
|
||||
FF_DEBUG("Found interface index: %u", entry.ifindex);
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
FF_DEBUG("Found gateway: %s", inet_ntoa(*(struct in_addr*)&rta_data));
|
||||
if (rta_data == 0) goto next;
|
||||
FF_DEBUG("Found gateway: %s", inet_ntoa(*(struct in_addr*) &rta_data));
|
||||
if (rta_data == 0) {
|
||||
goto next;
|
||||
}
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
FF_DEBUG("Found metric: %u", rta_data);
|
||||
if (rta_data >= minMetric) goto next;
|
||||
if (rta_data >= minMetric) {
|
||||
goto next;
|
||||
}
|
||||
entry.metric = rta_data;
|
||||
break;
|
||||
case RTA_PREFSRC:
|
||||
entry.prefsrc = rta_data;
|
||||
FF_DEBUG("Found preferred source: %s", inet_ntoa(*(struct in_addr*)&rta_data));
|
||||
FF_DEBUG("Found preferred source: %s", inet_ntoa(*(struct in_addr*) &rta_data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric)
|
||||
{
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric) {
|
||||
next:
|
||||
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
continue;
|
||||
@@ -204,8 +201,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
result->ifIndex = entry.ifindex;
|
||||
FF_DEBUG("Updated best route: ifindex=%u, metric=%u, prefsrc=%x", entry.ifindex, entry.metric, entry.prefsrc);
|
||||
result->preferredSourceAddrV4 = entry.prefsrc;
|
||||
if (minMetric == 0)
|
||||
{
|
||||
if (minMetric == 0) {
|
||||
FF_DEBUG("Found zero metric route, stopping further processing");
|
||||
break; // Stop processing if we found a zero metric route
|
||||
}
|
||||
@@ -213,8 +209,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
|
||||
exit:
|
||||
if (minMetric < UINT32_MAX)
|
||||
{
|
||||
if (minMetric < UINT32_MAX) {
|
||||
if_indextoname(result->ifIndex, result->ifName);
|
||||
FF_DEBUG("Found default IPv4 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
|
||||
return true;
|
||||
@@ -223,13 +218,11 @@ exit:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
FF_DEBUG("Starting IPv6 default route detection");
|
||||
|
||||
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
if (sock_fd < 0) {
|
||||
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
@@ -241,11 +234,11 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
// Bind socket
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
if (bind(sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
|
||||
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
@@ -267,9 +260,9 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
},
|
||||
// Route message
|
||||
.rtm = {
|
||||
.rtm_family = AF_INET6, // IPv6 instead of IPv4
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_family = AF_INET6, // IPv6 instead of IPv4
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_tos = 0,
|
||||
.rtm_table = RT_TABLE_UNSPEC,
|
||||
.rtm_protocol = RTPROT_UNSPEC,
|
||||
@@ -287,12 +280,11 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
|
||||
struct sockaddr_nl dest_addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
|
||||
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0, (struct sockaddr*) &dest_addr, sizeof(dest_addr));
|
||||
|
||||
if (sent != sizeof(req)) {
|
||||
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
|
||||
@@ -307,17 +299,15 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
uint32_t minMetric = UINT32_MAX;
|
||||
FF_MAYBE_UNUSED int routeCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&src_addr, &src_addr_len);
|
||||
while (true) {
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0, (struct sockaddr*) &src_addr, &src_addr_len);
|
||||
|
||||
if (received < 0) {
|
||||
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received >= (ssize_t)sizeof(buffer)) {
|
||||
if (received >= (ssize_t) sizeof(buffer)) {
|
||||
FF_DEBUG("Received truncated message: received %zd, bufsize %zu", received, sizeof(buffer));
|
||||
return false;
|
||||
}
|
||||
@@ -332,20 +322,19 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
uint32_t ifindex;
|
||||
} entry;
|
||||
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*) buffer;
|
||||
NLMSG_OK(nlh, received);
|
||||
nlh = NLMSG_NEXT(nlh, received))
|
||||
{
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
|
||||
nlh = NLMSG_NEXT(nlh, received)) {
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid) {
|
||||
continue;
|
||||
if (nlh->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
}
|
||||
if (nlh->nlmsg_type == NLMSG_DONE) {
|
||||
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*)NLMSG_DATA(nlh))->error));
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*) NLMSG_DATA(nlh))->error));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -355,7 +344,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
|
||||
routeCount++;
|
||||
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
|
||||
struct rtmsg* rtm = (struct rtmsg*) NLMSG_DATA(nlh);
|
||||
if (rtm->rtm_family != AF_INET6) {
|
||||
FF_DEBUG("Skipping non-IPv6 route #%d (family=%d)", routeCount, rtm->rtm_family);
|
||||
continue;
|
||||
@@ -373,14 +362,13 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
|
||||
FF_DEBUG("Processing IPv6 default route candidate #%d", routeCount);
|
||||
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
|
||||
entry = (__typeof__(entry)) {}; // Default to zero metric (no RTA_PRIORITY found)
|
||||
|
||||
// Parse route attributes
|
||||
size_t rtm_len = RTM_PAYLOAD(nlh);
|
||||
for (struct rtattr* rta = RTM_RTA(rtm);
|
||||
RTA_OK(rta, rtm_len);
|
||||
rta = RTA_NEXT(rta, rtm_len))
|
||||
{
|
||||
rta = RTA_NEXT(rta, rtm_len)) {
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
|
||||
@@ -398,7 +386,9 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
case RTA_GATEWAY:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
|
||||
struct in6_addr* gw = (struct in6_addr*) RTA_DATA(rta);
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(gw)) goto next;
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(gw)) {
|
||||
goto next;
|
||||
}
|
||||
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
|
||||
FF_DEBUG("Found gateway: %s", inet_ntop(AF_INET6, gw, str, sizeof(str)));
|
||||
}
|
||||
@@ -407,15 +397,16 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
|
||||
uint32_t metric = *(uint32_t*) RTA_DATA(rta);
|
||||
FF_DEBUG("Found metric: %u", metric);
|
||||
if (metric >= minMetric) goto next;
|
||||
if (metric >= minMetric) {
|
||||
goto next;
|
||||
}
|
||||
entry.metric = metric;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric)
|
||||
{
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric) {
|
||||
next:
|
||||
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
continue;
|
||||
@@ -424,8 +415,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
result->ifIndex = entry.ifindex;
|
||||
FF_DEBUG("Updated best route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
|
||||
if (minMetric == 0)
|
||||
{
|
||||
if (minMetric == 0) {
|
||||
FF_DEBUG("Found zero metric route, stopping further processing");
|
||||
break; // Stop processing if we found a zero metric route
|
||||
}
|
||||
@@ -433,8 +423,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
}
|
||||
|
||||
exit:
|
||||
if (minMetric < UINT32_MAX)
|
||||
{
|
||||
if (minMetric < UINT32_MAX) {
|
||||
if_indextoname(result->ifIndex, result->ifName);
|
||||
FF_DEBUG("Found default IPv6 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
|
||||
return true;
|
||||
|
||||
@@ -4,29 +4,26 @@
|
||||
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
|
||||
#include <iphlpapi.h>
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool foundDefault = false;
|
||||
uint32_t smallestMetric = UINT32_MAX;
|
||||
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
|
||||
{
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i) {
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0)
|
||||
{
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0) {
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
|
||||
{
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp) {
|
||||
MIB_IPINTERFACE_ROW ipInterfaceRow = {
|
||||
.Family = AF_INET,
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
@@ -34,11 +31,11 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
|
||||
uint32_t realMetric = row->Metric /* Metric offset */;
|
||||
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow))) {
|
||||
realMetric += ipInterfaceRow.Metric /* Interface metric */;
|
||||
}
|
||||
|
||||
if (realMetric < smallestMetric)
|
||||
{
|
||||
if (realMetric < smallestMetric) {
|
||||
smallestMetric = realMetric;
|
||||
result->ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
@@ -53,30 +50,26 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
return foundDefault;
|
||||
}
|
||||
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool foundDefault = false;
|
||||
uint32_t smallestMetric = UINT32_MAX;
|
||||
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
|
||||
{
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i) {
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))
|
||||
{
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr)) {
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
|
||||
{
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp) {
|
||||
MIB_IPINTERFACE_ROW ipInterfaceRow = {
|
||||
.Family = AF_INET6,
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
@@ -84,11 +77,11 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
|
||||
uint32_t realMetric = row->Metric /* Metric offset */;
|
||||
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow))) {
|
||||
realMetric += ipInterfaceRow.Metric /* Interface metric */;
|
||||
}
|
||||
|
||||
if (realMetric < smallestMetric)
|
||||
{
|
||||
if (realMetric < smallestMetric) {
|
||||
smallestMetric = realMetric;
|
||||
result->ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
#include "common/debug.h"
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
# include <zlib.h>
|
||||
|
||||
struct FFZlibLibrary
|
||||
{
|
||||
struct FFZlibLibrary {
|
||||
FF_LIBRARY_SYMBOL(inflateInit2_)
|
||||
FF_LIBRARY_SYMBOL(inflate)
|
||||
FF_LIBRARY_SYMBOL(inflateEnd)
|
||||
@@ -16,18 +15,17 @@ struct FFZlibLibrary
|
||||
bool inited;
|
||||
} zlibData;
|
||||
|
||||
const char* ffNetworkingLoadZlibLibrary(void)
|
||||
{
|
||||
if (!zlibData.inited)
|
||||
{
|
||||
const char* ffNetworkingLoadZlibLibrary(void) {
|
||||
if (!zlibData.inited) {
|
||||
zlibData.inited = true;
|
||||
FF_LIBRARY_LOAD_MESSAGE(zlib,
|
||||
#ifdef _WIN32
|
||||
"zlib1"
|
||||
#else
|
||||
"libz"
|
||||
#endif
|
||||
FF_LIBRARY_EXTENSION, 2)
|
||||
# ifdef _WIN32
|
||||
"zlib1"
|
||||
# else
|
||||
"libz"
|
||||
# endif
|
||||
FF_LIBRARY_EXTENSION,
|
||||
2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateInit2_)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflate)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateEnd)
|
||||
@@ -37,16 +35,16 @@ const char* ffNetworkingLoadZlibLibrary(void)
|
||||
}
|
||||
|
||||
// Try to pre-read gzip header to determine uncompressed size
|
||||
static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize)
|
||||
{
|
||||
static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize) {
|
||||
// gzip file format: http://www.zlib.org/rfc-gzip.html
|
||||
if (dataSize < 10 || ((const uint8_t*)data)[0] != 0x1f || ((const uint8_t*)data)[1] != 0x8b)
|
||||
if (dataSize < 10 || ((const uint8_t*) data)[0] != 0x1f || ((const uint8_t*) data)[1] != 0x8b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Uncompressed size in gzip format is stored in the last 4 bytes, but only valid if data is less than 4GB
|
||||
if (dataSize > 18) {
|
||||
// Get ISIZE value from the end of file (little endian)
|
||||
const uint8_t* tail = (const uint8_t*)data + dataSize - 4;
|
||||
const uint8_t* tail = (const uint8_t*) data + dataSize - 4;
|
||||
uint32_t uncompressedSize = (uint32_t) tail[0] | ((uint32_t) tail[1] << 8u) | ((uint32_t) tail[2] << 16u) | ((uint32_t) tail[3] << 24u);
|
||||
|
||||
// For valid gzip files, this value is the length of the uncompressed data modulo 2^32
|
||||
@@ -65,8 +63,7 @@ static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize)
|
||||
}
|
||||
|
||||
// Decompress gzip content
|
||||
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
|
||||
{
|
||||
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd) {
|
||||
assert(headerEnd != NULL && *headerEnd == '\r');
|
||||
|
||||
// Calculate header size
|
||||
@@ -96,7 +93,7 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
|
||||
uint32_t compressedSize = buffer->length - headerSize - 4;
|
||||
|
||||
// Check if content is actually in gzip format (gzip header magic is 0x1f 0x8b)
|
||||
if (compressedSize < 2 || (uint8_t)bodyStart[0] != 0x1f || (uint8_t)bodyStart[1] != 0x8b) {
|
||||
if (compressedSize < 2 || (uint8_t) bodyStart[0] != 0x1f || (uint8_t) bodyStart[1] != 0x8b) {
|
||||
FF_DEBUG("Content is not valid gzip format, skipping decompression");
|
||||
return false;
|
||||
}
|
||||
@@ -113,14 +110,14 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
|
||||
.zalloc = Z_NULL,
|
||||
.zfree = Z_NULL,
|
||||
.opaque = Z_NULL,
|
||||
.avail_in = (uInt)compressedSize,
|
||||
.next_in = (Bytef*)bodyStart,
|
||||
.avail_out = (uInt)ffStrbufGetFree(&decompressedBuffer),
|
||||
.next_out = (Bytef*)decompressedBuffer.chars,
|
||||
.avail_in = (uInt) compressedSize,
|
||||
.next_in = (Bytef*) bodyStart,
|
||||
.avail_out = (uInt) ffStrbufGetFree(&decompressedBuffer),
|
||||
.next_out = (Bytef*) decompressedBuffer.chars,
|
||||
};
|
||||
|
||||
// Initialize decompression engine
|
||||
if (zlibData.ffinflateInit2_(&zs, 16 + MAX_WBITS, ZLIB_VERSION, (int)sizeof(z_stream)) != Z_OK) {
|
||||
if (zlibData.ffinflateInit2_(&zs, 16 + MAX_WBITS, ZLIB_VERSION, (int) sizeof(z_stream)) != Z_OK) {
|
||||
FF_DEBUG("Failed to initialize decompression engine");
|
||||
return false;
|
||||
}
|
||||
@@ -130,20 +127,19 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
|
||||
int result = zlibData.ffinflate(&zs, Z_FINISH);
|
||||
|
||||
// If output buffer is insufficient, try to extend buffer
|
||||
while (result == Z_BUF_ERROR || (result != Z_STREAM_END && zs.avail_out == 0))
|
||||
{
|
||||
while (result == Z_BUF_ERROR || (result != Z_STREAM_END && zs.avail_out == 0)) {
|
||||
FF_DEBUG("Output buffer insufficient, trying to extend");
|
||||
|
||||
// Save already decompressed data amount
|
||||
uint32_t alreadyDecompressed = (uint32_t)(availableOut - zs.avail_out);
|
||||
uint32_t alreadyDecompressed = (uint32_t) (availableOut - zs.avail_out);
|
||||
decompressedBuffer.length += alreadyDecompressed;
|
||||
decompressedBuffer.chars[decompressedBuffer.length] = '\0';
|
||||
|
||||
ffStrbufEnsureFree(&decompressedBuffer, decompressedBuffer.length / 2);
|
||||
|
||||
// Set output parameters to point to new buffer
|
||||
zs.avail_out = (uInt)ffStrbufGetFree(&decompressedBuffer);
|
||||
zs.next_out = (Bytef*)(decompressedBuffer.chars + decompressedBuffer.length);
|
||||
zs.avail_out = (uInt) ffStrbufGetFree(&decompressedBuffer);
|
||||
zs.next_out = (Bytef*) (decompressedBuffer.chars + decompressedBuffer.length);
|
||||
availableOut = zs.avail_out;
|
||||
|
||||
// Decompress again
|
||||
@@ -153,7 +149,7 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
|
||||
zlibData.ffinflateEnd(&zs);
|
||||
|
||||
// Calculate decompressed size
|
||||
uint32_t decompressedSize = (uint32_t)(availableOut - zs.avail_out);
|
||||
uint32_t decompressedSize = (uint32_t) (availableOut - zs.avail_out);
|
||||
decompressedBuffer.length += decompressedSize;
|
||||
decompressedBuffer.chars[decompressedBuffer.length] = '\0';
|
||||
FF_DEBUG("Successfully decompressed %u bytes compressed data to %u bytes", compressedSize, decompressedBuffer.length);
|
||||
@@ -163,19 +159,13 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, buffer))
|
||||
{
|
||||
if (ffStrStartsWithIgnCase(line, "Content-Encoding:"))
|
||||
{
|
||||
while (ffStrbufGetline(&line, &len, buffer)) {
|
||||
if (ffStrStartsWithIgnCase(line, "Content-Encoding:")) {
|
||||
continue;
|
||||
}
|
||||
else if (ffStrStartsWithIgnCase(line, "Content-Length:"))
|
||||
{
|
||||
} else if (ffStrStartsWithIgnCase(line, "Content-Length:")) {
|
||||
ffStrbufAppendF(&newBuffer, "Content-Length: %u\r\n", decompressedBuffer.length);
|
||||
continue;
|
||||
}
|
||||
else if (line[0] == '\r')
|
||||
{
|
||||
} else if (line[0] == '\r') {
|
||||
ffStrbufAppendS(&newBuffer, "\r\n");
|
||||
ffStrbufGetlineRestore(&line, &len, buffer);
|
||||
break;
|
||||
|
||||
+164
-176
@@ -16,132 +16,137 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static const char* tryNonThreadingFastPath(FFNetworkingState* state)
|
||||
{
|
||||
#if defined(TCP_FASTOPEN) || __APPLE__
|
||||
static const char* tryNonThreadingFastPath(FFNetworkingState* state) {
|
||||
#if defined(TCP_FASTOPEN) || __APPLE__
|
||||
|
||||
if (!state->tfo)
|
||||
{
|
||||
#if __linux__ || __GNU__
|
||||
// Linux doesn't support sendto() on unconnected sockets
|
||||
FF_DEBUG("TCP Fast Open disabled, skipping");
|
||||
return "TCP Fast Open disabled";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_DEBUG("Attempting to use TCP Fast Open to connect");
|
||||
if (!state->tfo) {
|
||||
# if __linux__ || __GNU__
|
||||
// Linux doesn't support sendto() on unconnected sockets
|
||||
FF_DEBUG("TCP Fast Open disabled, skipping");
|
||||
return "TCP Fast Open disabled";
|
||||
# endif
|
||||
} else {
|
||||
FF_DEBUG("Attempting to use TCP Fast Open to connect");
|
||||
|
||||
#ifndef __APPLE__ // On macOS, TCP_FASTOPEN doesn't seem to be needed
|
||||
// Set TCP Fast Open
|
||||
int flag = 1;
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP,
|
||||
#ifdef __APPLE__
|
||||
# ifndef __APPLE__ // On macOS, TCP_FASTOPEN doesn't seem to be needed
|
||||
// Set TCP Fast Open
|
||||
int flag = 1;
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP,
|
||||
# ifdef __APPLE__
|
||||
// https://github.com/rust-lang/libc/pull/3135
|
||||
0x218 // TCP_FASTOPEN_FORCE_ENABLE
|
||||
#else
|
||||
# else
|
||||
TCP_FASTOPEN
|
||||
#endif
|
||||
, &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", strerror(errno));
|
||||
return "setsockopt(TCP_FASTOPEN) failed";
|
||||
} else {
|
||||
#if __linux__ || __GNU__
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option, queue length: %d", flag);
|
||||
#elif defined(__APPLE__)
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN_FORCE_ENABLE option");
|
||||
#else
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
,
|
||||
&flag,
|
||||
sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", strerror(errno));
|
||||
return "setsockopt(TCP_FASTOPEN) failed";
|
||||
} else {
|
||||
# if __linux__ || __GNU__
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option, queue length: %d", flag);
|
||||
# elif defined(__APPLE__)
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN_FORCE_ENABLE option");
|
||||
# else
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option");
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
FF_DEBUG("Using sendto() + MSG_DONTWAIT to send %u bytes of data", state->command.length);
|
||||
ssize_t sent = sendto(state->sockfd,
|
||||
state->command.chars,
|
||||
state->command.length,
|
||||
#ifdef MSG_FASTOPEN
|
||||
MSG_FASTOPEN |
|
||||
#endif
|
||||
#ifdef MSG_NOSIGNAL
|
||||
MSG_NOSIGNAL |
|
||||
#endif
|
||||
MSG_DONTWAIT,
|
||||
state->addr->ai_addr,
|
||||
state->addr->ai_addrlen);
|
||||
#else
|
||||
if (fcntl(state->sockfd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
|
||||
return "fcntl(F_SETFL) failed";
|
||||
}
|
||||
FF_DEBUG("Using connectx() to send %u bytes of data", state->command.length);
|
||||
// Use connectx to establish connection and send data in one call
|
||||
size_t sent;
|
||||
if (connectx(state->sockfd,
|
||||
# ifndef __APPLE__
|
||||
FF_DEBUG("Using sendto() + MSG_DONTWAIT to send %u bytes of data", state->command.length);
|
||||
ssize_t sent = sendto(state->sockfd,
|
||||
state->command.chars,
|
||||
state->command.length,
|
||||
# ifdef MSG_FASTOPEN
|
||||
MSG_FASTOPEN |
|
||||
# endif
|
||||
# ifdef MSG_NOSIGNAL
|
||||
MSG_NOSIGNAL |
|
||||
# endif
|
||||
MSG_DONTWAIT,
|
||||
state->addr->ai_addr,
|
||||
state->addr->ai_addrlen);
|
||||
# else
|
||||
if (fcntl(state->sockfd, F_SETFL, O_NONBLOCK) == -1) {
|
||||
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
|
||||
return "fcntl(F_SETFL) failed";
|
||||
}
|
||||
FF_DEBUG("Using connectx() to send %u bytes of data", state->command.length);
|
||||
// Use connectx to establish connection and send data in one call
|
||||
size_t sent;
|
||||
if (connectx(state->sockfd,
|
||||
&(sa_endpoints_t) {
|
||||
.sae_dstaddr = state->addr->ai_addr,
|
||||
.sae_dstaddrlen = state->addr->ai_addrlen,
|
||||
},
|
||||
SAE_ASSOCID_ANY, state->tfo ? CONNECT_DATA_IDEMPOTENT : 0,
|
||||
SAE_ASSOCID_ANY,
|
||||
state->tfo ? CONNECT_DATA_IDEMPOTENT : 0,
|
||||
&(struct iovec) {
|
||||
.iov_base = state->command.chars,
|
||||
.iov_len = state->command.length,
|
||||
}, 1, &sent, NULL) != 0) sent = 0;
|
||||
if (fcntl(state->sockfd, F_SETFL, 0) == -1) {
|
||||
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
|
||||
return "fcntl(F_SETFL) failed";
|
||||
}
|
||||
#endif
|
||||
if (sent > 0 || (errno == EAGAIN || errno == EWOULDBLOCK
|
||||
#ifdef __APPLE__
|
||||
// On macOS EINPROGRESS means the connection cannot be completed immediately
|
||||
// On Linux, it means the TFO cookie is not available locally
|
||||
|| errno == EINPROGRESS
|
||||
#endif
|
||||
))
|
||||
{
|
||||
FF_DEBUG(
|
||||
#ifdef __APPLE__
|
||||
"connectx()"
|
||||
#else
|
||||
"sendto()"
|
||||
#endif
|
||||
" %s (sent=%zd, %s)", errno == 0 ? "succeeded" : "was in progress", sent, strerror(errno));
|
||||
freeaddrinfo(state->addr);
|
||||
state->addr = NULL;
|
||||
ffStrbufDestroy(&state->command);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
},
|
||||
1,
|
||||
&sent,
|
||||
NULL) != 0) {
|
||||
sent = 0;
|
||||
}
|
||||
if (fcntl(state->sockfd, F_SETFL, 0) == -1) {
|
||||
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
|
||||
return "fcntl(F_SETFL) failed";
|
||||
}
|
||||
# endif
|
||||
if (sent > 0 || (errno == EAGAIN || errno == EWOULDBLOCK
|
||||
# ifdef __APPLE__
|
||||
// On macOS EINPROGRESS means the connection cannot be completed immediately
|
||||
// On Linux, it means the TFO cookie is not available locally
|
||||
|| errno == EINPROGRESS
|
||||
# endif
|
||||
)) {
|
||||
FF_DEBUG(
|
||||
#ifdef __APPLE__
|
||||
# ifdef __APPLE__
|
||||
"connectx()"
|
||||
#else
|
||||
# else
|
||||
"sendto()"
|
||||
#endif
|
||||
" failed: %s", strerror(errno));
|
||||
#ifdef __APPLE__
|
||||
return "connectx() failed";
|
||||
#else
|
||||
return "sendto() failed";
|
||||
#endif
|
||||
#else
|
||||
FF_UNUSED(state);
|
||||
return "TFO support is not available";
|
||||
#endif
|
||||
# endif
|
||||
" %s (sent=%zd, %s)",
|
||||
errno == 0 ? "succeeded" : "was in progress",
|
||||
sent,
|
||||
strerror(errno));
|
||||
freeaddrinfo(state->addr);
|
||||
state->addr = NULL;
|
||||
ffStrbufDestroy(&state->command);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_DEBUG(
|
||||
# ifdef __APPLE__
|
||||
"connectx()"
|
||||
# else
|
||||
"sendto()"
|
||||
# endif
|
||||
" failed: %s",
|
||||
strerror(errno));
|
||||
# ifdef __APPLE__
|
||||
return "connectx() failed";
|
||||
# else
|
||||
return "sendto() failed";
|
||||
# endif
|
||||
#else
|
||||
FF_UNUSED(state);
|
||||
return "TFO support is not available";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Traditional connect and send function
|
||||
static const char* connectAndSend(FFNetworkingState* state)
|
||||
{
|
||||
static const char* connectAndSend(FFNetworkingState* state) {
|
||||
const char* ret = NULL;
|
||||
FF_DEBUG("Using traditional connection method to connect");
|
||||
|
||||
FF_DEBUG("Attempting connect() to server...");
|
||||
if(connect(state->sockfd, state->addr->ai_addr, state->addr->ai_addrlen) == -1)
|
||||
{
|
||||
if (connect(state->sockfd, state->addr->ai_addr, state->addr->ai_addrlen) == -1) {
|
||||
FF_DEBUG("connect() failed: %s", strerror(errno));
|
||||
ret = "connect() failed";
|
||||
goto error;
|
||||
@@ -149,8 +154,7 @@ static const char* connectAndSend(FFNetworkingState* state)
|
||||
FF_DEBUG("connect() succeeded");
|
||||
|
||||
FF_DEBUG("Attempting to send %u bytes of data...", state->command.length);
|
||||
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
|
||||
{
|
||||
if (send(state->sockfd, state->command.chars, state->command.length, 0) < 0) {
|
||||
FF_DEBUG("send() failed: %s", strerror(errno));
|
||||
ret = "send() failed";
|
||||
goto error;
|
||||
@@ -176,8 +180,7 @@ exit:
|
||||
FF_THREAD_ENTRY_DECL_WRAPPER(connectAndSend, FFNetworkingState*);
|
||||
|
||||
// Parallel DNS resolution and socket creation
|
||||
static const char* initNetworkingState(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
static const char* initNetworkingState(FFNetworkingState* state, const char* host, const char* path, const char* headers) {
|
||||
FF_DEBUG("Initializing network connection state: host=%s, path=%s", host, path);
|
||||
|
||||
// Initialize command and host information
|
||||
@@ -197,25 +200,23 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
|
||||
ffStrbufAppendS(&state->command, headers);
|
||||
ffStrbufAppendS(&state->command, "\r\n");
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
#ifdef FF_HAVE_THREADS
|
||||
state->thread = 0;
|
||||
FF_DEBUG("Thread ID initialized to 0");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const char* ret = NULL;
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
|
||||
.ai_socktype = SOCK_STREAM,
|
||||
.ai_flags = AI_NUMERICSERV
|
||||
};
|
||||
.ai_flags = AI_NUMERICSERV};
|
||||
|
||||
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
|
||||
// Use AI_NUMERICSERV flag to indicate the service is a numeric port, reducing parsing time
|
||||
|
||||
int gaiRes = getaddrinfo(host, "80", &hints, &state->addr);
|
||||
if(gaiRes != 0)
|
||||
{
|
||||
if (gaiRes != 0) {
|
||||
FF_DEBUG("getaddrinfo() failed: %s (res=%d)", gai_strerror(gaiRes), gaiRes);
|
||||
ret = "getaddrinfo() failed";
|
||||
goto error;
|
||||
@@ -224,8 +225,7 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
|
||||
|
||||
FF_DEBUG("Creating socket");
|
||||
state->sockfd = socket(state->addr->ai_family, state->addr->ai_socktype, state->addr->ai_protocol);
|
||||
if(state->sockfd == -1)
|
||||
{
|
||||
if (state->sockfd == -1) {
|
||||
FF_DEBUG("socket() failed: %s", strerror(errno));
|
||||
ret = "socket() failed";
|
||||
goto error;
|
||||
@@ -233,57 +233,56 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
|
||||
FF_DEBUG("Socket creation successful: fd=%d", state->sockfd);
|
||||
|
||||
int flag = 1;
|
||||
#ifdef TCP_NODELAY
|
||||
#ifdef TCP_NODELAY
|
||||
// Disable Nagle's algorithm to reduce small packet transmission delay
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_NODELAY: %s", strerror(errno));
|
||||
} else {
|
||||
FF_DEBUG("Successfully disabled Nagle's algorithm");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TCP_QUICKACK
|
||||
#ifdef TCP_QUICKACK
|
||||
// Set TCP_QUICKACK option to avoid delayed acknowledgments
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_QUICKACK: %s", strerror(errno));
|
||||
} else {
|
||||
FF_DEBUG("Successfully enabled TCP quick acknowledgment");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (state->timeout > 0)
|
||||
{
|
||||
if (state->timeout > 0) {
|
||||
FF_DEBUG("Setting connection timeout: %u ms", state->timeout);
|
||||
FF_MAYBE_UNUSED uint32_t sec = state->timeout / 1000;
|
||||
if (sec == 0) sec = 1;
|
||||
if (sec == 0) {
|
||||
sec = 1;
|
||||
}
|
||||
|
||||
#ifdef TCP_CONNECTIONTIMEOUT
|
||||
#ifdef TCP_CONNECTIONTIMEOUT
|
||||
FF_DEBUG("Using TCP_CONNECTIONTIMEOUT: %u seconds", sec);
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &sec, sizeof(sec));
|
||||
#elif defined(TCP_KEEPINIT)
|
||||
#elif defined(TCP_KEEPINIT)
|
||||
FF_DEBUG("Using TCP_KEEPINIT: %u seconds", sec);
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_KEEPINIT, &sec, sizeof(sec));
|
||||
#elif defined(TCP_USER_TIMEOUT)
|
||||
#elif defined(TCP_USER_TIMEOUT)
|
||||
FF_DEBUG("Using TCP_USER_TIMEOUT: %u milliseconds", state->timeout);
|
||||
setsockopt(state->sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &state->timeout, sizeof(state->timeout));
|
||||
#else
|
||||
#else
|
||||
FF_DEBUG("Current platform does not support TCP connection timeout");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
error:
|
||||
FF_DEBUG("Error occurred during initialization");
|
||||
if (state->addr != NULL)
|
||||
{
|
||||
if (state->addr != NULL) {
|
||||
FF_DEBUG("Releasing address information");
|
||||
freeaddrinfo(state->addr);
|
||||
state->addr = NULL;
|
||||
}
|
||||
|
||||
if (state->sockfd > 0)
|
||||
{
|
||||
if (state->sockfd > 0) {
|
||||
FF_DEBUG("Closing socket: fd=%d", state->sockfd);
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
@@ -291,31 +290,26 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers) {
|
||||
FF_DEBUG("Preparing to send HTTP request: host=%s, path=%s", host, path);
|
||||
|
||||
if (state->compression)
|
||||
{
|
||||
if (state->compression) {
|
||||
FF_DEBUG("Compression enabled, checking if zlib is available");
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
const char* zlibError = ffNetworkingLoadZlibLibrary();
|
||||
// Only enable compression if zlib library is successfully loaded
|
||||
if (zlibError == NULL)
|
||||
{
|
||||
if (zlibError == NULL) {
|
||||
FF_DEBUG("Successfully loaded zlib library, compression enabled");
|
||||
} else {
|
||||
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
|
||||
state->compression = false;
|
||||
}
|
||||
#else
|
||||
#else
|
||||
FF_DEBUG("zlib not supported at build time, compression disabled");
|
||||
state->compression = false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
} else {
|
||||
FF_DEBUG("Compression disabled");
|
||||
}
|
||||
|
||||
@@ -333,33 +327,30 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
}
|
||||
FF_DEBUG("TryNonThreadingFastPath() failed: %s, trying traditional connection", tfoResult);
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (instance.config.general.multithreading)
|
||||
{
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (instance.config.general.multithreading) {
|
||||
FF_DEBUG("Multithreading mode enabled, creating connection thread");
|
||||
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
|
||||
if (state->thread) {
|
||||
FF_DEBUG("Thread creation successful: thread=%p", (void*)(uintptr_t)state->thread);
|
||||
FF_DEBUG("Thread creation successful: thread=%p", (void*) (uintptr_t) state->thread);
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Thread creation failed");
|
||||
} else {
|
||||
FF_DEBUG("Multithreading mode disabled, connecting in main thread");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return connectAndSend(state);
|
||||
}
|
||||
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
|
||||
{
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer) {
|
||||
assert(buffer->allocated > 0);
|
||||
FF_DEBUG("Preparing to receive HTTP response");
|
||||
uint32_t timeout = state->timeout;
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (state->thread)
|
||||
{
|
||||
#ifdef FF_HAVE_THREADS
|
||||
if (state->thread) {
|
||||
FF_DEBUG("Connection thread is running, waiting for it to complete (timeout=%u ms)", timeout);
|
||||
if (!ffThreadJoin(state->thread, timeout)) {
|
||||
FF_DEBUG("Thread join failed or timed out");
|
||||
@@ -368,10 +359,9 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
FF_DEBUG("Thread completed successfully");
|
||||
state->thread = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(state->sockfd == -1)
|
||||
{
|
||||
if (state->sockfd == -1) {
|
||||
FF_DEBUG("Invalid socket, HTTP request might have failed");
|
||||
return "ffNetworkingSendHttpRequest() failed";
|
||||
}
|
||||
@@ -380,24 +370,22 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
int rcvbuf = 65536; // 64KB
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifdef __APPLE__
|
||||
// poll for the socket to be readable.
|
||||
// Because of the non-blocking connectx() call, the connection might not be established yet
|
||||
FF_DEBUG("Using poll() to check if socket is readable");
|
||||
{
|
||||
int pollRes = poll(&(struct pollfd) {
|
||||
.fd = state->sockfd,
|
||||
.events = POLLIN
|
||||
}, 1, timeout > 0 ? (int) timeout : -1);
|
||||
if (pollRes == 0)
|
||||
{
|
||||
.fd = state->sockfd,
|
||||
.events = POLLIN},
|
||||
1,
|
||||
timeout > 0 ? (int) timeout : -1);
|
||||
if (pollRes == 0) {
|
||||
FF_DEBUG("poll() timed out after %u ms", timeout);
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
return "poll() timeout";
|
||||
}
|
||||
else if (pollRes == -1)
|
||||
{
|
||||
} else if (pollRes == -1) {
|
||||
FF_DEBUG("poll() failed: %s", strerror(errno));
|
||||
close(state->sockfd);
|
||||
state->sockfd = -1;
|
||||
@@ -405,19 +393,17 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
}
|
||||
}
|
||||
FF_DEBUG("Socket is readable, proceeding to receive data");
|
||||
#else
|
||||
if(timeout > 0)
|
||||
{
|
||||
#else
|
||||
if (timeout > 0) {
|
||||
FF_DEBUG("Setting receive timeout: %u ms", timeout);
|
||||
struct timeval timev;
|
||||
timev.tv_sec = timeout / 1000;
|
||||
timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); //milliseconds to microseconds
|
||||
timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); // milliseconds to microseconds
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (shutdown(state->sockfd, SHUT_WR) == -1)
|
||||
{
|
||||
if (shutdown(state->sockfd, SHUT_WR) == -1) {
|
||||
FF_DEBUG("Failed to shutdown socket send: %s", strerror(errno));
|
||||
// Not a critical error, continue anyway
|
||||
}
|
||||
@@ -429,7 +415,9 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
|
||||
do {
|
||||
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
|
||||
++recvCount, buffer->length, ffStrbufGetFree(buffer));
|
||||
++recvCount,
|
||||
buffer->length,
|
||||
ffStrbufGetFree(buffer));
|
||||
|
||||
// We set `Connection: close`, so the server will close the connection when done.
|
||||
// Thus we can use MSG_WAITALL to wait until the buffer is full or the connection is closed.
|
||||
@@ -453,7 +441,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
if (headerEnd == 0) {
|
||||
char* pHeaderEnd = memmem(buffer->chars, buffer->length, "\r\n\r\n", 4);
|
||||
if (pHeaderEnd) {
|
||||
headerEnd = (uint32_t)(pHeaderEnd - buffer->chars);
|
||||
headerEnd = (uint32_t) (pHeaderEnd - buffer->chars);
|
||||
FF_DEBUG("Found HTTP header end marker, position: %u", headerEnd);
|
||||
|
||||
// Check for Content-Length header to pre-allocate enough memory
|
||||
@@ -496,8 +484,8 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
return "Invalid response";
|
||||
}
|
||||
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
if (state->compression) {
|
||||
FF_DEBUG("Content received, checking if compressed");
|
||||
if (!ffNetworkingDecompressGzip(buffer, buffer->chars + headerEnd)) {
|
||||
@@ -507,7 +495,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <mswsock.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
//Must be included after <mswsock.h>
|
||||
// Must be included after <mswsock.h>
|
||||
#include "fastfetch.h"
|
||||
#include "common/networking.h"
|
||||
#include "common/stringUtils.h"
|
||||
@@ -9,23 +9,22 @@
|
||||
|
||||
static LPFN_CONNECTEX ConnectEx;
|
||||
|
||||
static const char* initWsaData(WSADATA* wsaData)
|
||||
{
|
||||
static const char* initWsaData(WSADATA* wsaData) {
|
||||
FF_DEBUG("Initializing WinSock");
|
||||
if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0) {
|
||||
if (WSAStartup(MAKEWORD(2, 2), wsaData) != 0) {
|
||||
FF_DEBUG("WSAStartup() failed");
|
||||
return "WSAStartup() failed";
|
||||
}
|
||||
|
||||
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2) {
|
||||
if (LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2) {
|
||||
FF_DEBUG("Invalid wsaData version found: %d.%d", LOBYTE(wsaData->wVersion), HIBYTE(wsaData->wVersion));
|
||||
WSACleanup();
|
||||
return "Invalid wsaData version found";
|
||||
}
|
||||
|
||||
//Dummy socket needed for WSAIoctl
|
||||
// Dummy socket needed for WSAIoctl
|
||||
SOCKET sockfd = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
|
||||
if(sockfd == INVALID_SOCKET) {
|
||||
if (sockfd == INVALID_SOCKET) {
|
||||
FF_DEBUG("WSASocketW(AF_INET, SOCK_STREAM) failed");
|
||||
WSACleanup();
|
||||
return "WSASocketW(AF_INET, SOCK_STREAM) failed";
|
||||
@@ -33,10 +32,7 @@ static const char* initWsaData(WSADATA* wsaData)
|
||||
|
||||
DWORD dwBytes;
|
||||
GUID guid = WSAID_CONNECTEX;
|
||||
if(WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||
&guid, sizeof(guid),
|
||||
&ConnectEx, sizeof(ConnectEx),
|
||||
&dwBytes, NULL, NULL) != 0) {
|
||||
if (WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), &dwBytes, NULL, NULL) != 0) {
|
||||
FF_DEBUG("WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
|
||||
closesocket(sockfd);
|
||||
WSACleanup();
|
||||
@@ -49,45 +45,36 @@ static const char* initWsaData(WSADATA* wsaData)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
|
||||
{
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers) {
|
||||
FF_DEBUG("Preparing to send HTTP request: host=%s, path=%s", host, path);
|
||||
|
||||
if (state->compression)
|
||||
{
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
if (state->compression) {
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
const char* zlibError = ffNetworkingLoadZlibLibrary();
|
||||
// Only enable compression if zlib library is successfully loaded
|
||||
if (zlibError == NULL)
|
||||
{
|
||||
if (zlibError == NULL) {
|
||||
FF_DEBUG("Successfully loaded zlib library, compression enabled");
|
||||
} else {
|
||||
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
|
||||
state->compression = false;
|
||||
}
|
||||
#else
|
||||
#else
|
||||
FF_DEBUG("zlib not supported at build time, compression disabled");
|
||||
state->compression = false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
} else {
|
||||
FF_DEBUG("Compression disabled");
|
||||
}
|
||||
|
||||
static WSADATA wsaData;
|
||||
if (wsaData.wVersion == 0)
|
||||
{
|
||||
if (wsaData.wVersion == 0) {
|
||||
const char* error = initWsaData(&wsaData);
|
||||
if (error != NULL)
|
||||
{
|
||||
if (error != NULL) {
|
||||
wsaData.wVersion = (WORD) -1;
|
||||
FF_DEBUG("WinSock initialization failed: %s", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
else if (wsaData.wVersion == (WORD) -1)
|
||||
{
|
||||
} else if (wsaData.wVersion == (WORD) -1) {
|
||||
FF_DEBUG("WinSock initialization previously failed");
|
||||
return "initWsaData() failed before";
|
||||
}
|
||||
@@ -100,54 +87,52 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
};
|
||||
|
||||
wchar_t hostW[256];
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(hostW, (ULONG) sizeof(hostW), NULL, host, (ULONG) strlen(host) + 1)))
|
||||
{
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(hostW, (ULONG) sizeof(hostW), NULL, host, (ULONG) strlen(host) + 1))) {
|
||||
FF_DEBUG("Failed to convert host to wide string: %s", host);
|
||||
return "Failed to convert host to wide string";
|
||||
}
|
||||
|
||||
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
|
||||
if(GetAddrInfoW(hostW, L"80", &hints, &addr) != 0)
|
||||
{
|
||||
if (GetAddrInfoW(hostW, L"80", &hints, &addr) != 0) {
|
||||
FF_DEBUG("GetAddrInfoW() failed");
|
||||
return "GetAddrInfoW() failed";
|
||||
}
|
||||
|
||||
state->sockfd = WSASocketW(addr->ai_family, addr->ai_socktype, addr->ai_protocol, NULL, 0, 0);
|
||||
if(state->sockfd == INVALID_SOCKET)
|
||||
{
|
||||
if (state->sockfd == INVALID_SOCKET) {
|
||||
FF_DEBUG("WSASocketW() failed");
|
||||
FreeAddrInfoW(addr);
|
||||
return "WSASocketW() failed";
|
||||
}
|
||||
|
||||
DWORD flag = 1;
|
||||
#ifdef TCP_NODELAY
|
||||
#ifdef TCP_NODELAY
|
||||
// Enable TCP_NODELAY to disable Nagle's algorithm
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)) != 0) {
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_NODELAY: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
} else {
|
||||
FF_DEBUG("Successfully disabled Nagle's algorithm");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set timeout if needed
|
||||
if (state->timeout > 0) {
|
||||
FF_DEBUG("Setting connection timeout: %u ms", state->timeout);
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&state->timeout, sizeof(state->timeout));
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*) &state->timeout, sizeof(state->timeout));
|
||||
}
|
||||
|
||||
//ConnectEx requires the socket to be initially bound
|
||||
if((state->ipv6
|
||||
? bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in6) {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = in6addr_any,
|
||||
}, sizeof(struct sockaddr_in6))
|
||||
: bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in) {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = INADDR_ANY,
|
||||
}, sizeof(struct sockaddr_in))) != 0)
|
||||
{
|
||||
// ConnectEx requires the socket to be initially bound
|
||||
if ((state->ipv6
|
||||
? bind(state->sockfd, (SOCKADDR*) &(struct sockaddr_in6) {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = in6addr_any,
|
||||
},
|
||||
sizeof(struct sockaddr_in6))
|
||||
: bind(state->sockfd, (SOCKADDR*) &(struct sockaddr_in) {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = INADDR_ANY,
|
||||
},
|
||||
sizeof(struct sockaddr_in))) != 0) {
|
||||
FF_DEBUG("bind() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
closesocket(state->sockfd);
|
||||
FreeAddrInfoW(addr);
|
||||
@@ -156,9 +141,8 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
}
|
||||
|
||||
// Initialize overlapped structure with WSA event for asynchronous I/O
|
||||
state->overlapped = (OVERLAPPED){
|
||||
.hEvent = WSACreateEvent()
|
||||
};
|
||||
state->overlapped = (OVERLAPPED) {
|
||||
.hEvent = WSACreateEvent()};
|
||||
|
||||
if (state->overlapped.hEvent == WSA_INVALID_EVENT) {
|
||||
FF_DEBUG("WSACreateEvent() failed");
|
||||
@@ -185,49 +169,39 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
ffStrbufAppendS(&state->command, headers);
|
||||
ffStrbufAppendS(&state->command, "\r\n");
|
||||
|
||||
#ifdef TCP_FASTOPEN
|
||||
if (state->tfo)
|
||||
{
|
||||
#ifdef TCP_FASTOPEN
|
||||
if (state->tfo) {
|
||||
// Set TCP Fast Open
|
||||
flag = 1;
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_FASTOPEN, (char*)&flag, sizeof(flag)) != 0) {
|
||||
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_FASTOPEN, (char*) &flag, sizeof(flag)) != 0) {
|
||||
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
} else {
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_DEBUG("TCP Fast Open disabled");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
FF_DEBUG("Using ConnectEx to send %u bytes of data", state->command.length);
|
||||
DWORD sent = 0;
|
||||
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen,
|
||||
state->command.chars, state->command.length, &sent, &state->overlapped);
|
||||
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int) addr->ai_addrlen, state->command.chars, state->command.length, &sent, &state->overlapped);
|
||||
|
||||
FreeAddrInfoW(addr);
|
||||
addr = NULL;
|
||||
|
||||
if(!result)
|
||||
{
|
||||
if (WSAGetLastError() != WSA_IO_PENDING)
|
||||
{
|
||||
if (!result) {
|
||||
if (WSAGetLastError() != WSA_IO_PENDING) {
|
||||
FF_DEBUG("ConnectEx() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
WSACloseEvent(state->overlapped.hEvent);
|
||||
closesocket(state->sockfd);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
ffStrbufDestroy(&state->command);
|
||||
return "ConnectEx() failed";
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_DEBUG("ConnectEx() pending");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_DEBUG("ConnectEx() succeeded, sent %u bytes of data", (unsigned) sent);
|
||||
}
|
||||
|
||||
@@ -235,31 +209,28 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
|
||||
{
|
||||
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer) {
|
||||
assert(buffer->allocated > 0);
|
||||
FF_DEBUG("Preparing to receive HTTP response");
|
||||
|
||||
if (state->sockfd == INVALID_SOCKET)
|
||||
{
|
||||
if (state->sockfd == INVALID_SOCKET) {
|
||||
FF_DEBUG("Invalid socket, HTTP request might have failed");
|
||||
return "ffNetworkingSendHttpRequest() failed";
|
||||
}
|
||||
|
||||
uint32_t timeout = state->timeout;
|
||||
if (timeout > 0)
|
||||
{
|
||||
if (timeout > 0) {
|
||||
FF_DEBUG("WSAWaitForMultipleEvents with timeout: %u ms", timeout);
|
||||
DWORD result = WSAWaitForMultipleEvents(1, &state->overlapped.hEvent, TRUE, timeout, FALSE);
|
||||
if (result != WSA_WAIT_EVENT_0)
|
||||
{
|
||||
if (result != WSA_WAIT_EVENT_0) {
|
||||
if (result == WSA_WAIT_TIMEOUT) {
|
||||
FF_DEBUG("WSAWaitForMultipleEvents timed out");
|
||||
} else {
|
||||
FF_DEBUG("WSAWaitForMultipleEvents failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
}
|
||||
if (CancelIoEx((HANDLE) state->sockfd, &state->overlapped))
|
||||
if (CancelIoEx((HANDLE) state->sockfd, &state->overlapped)) {
|
||||
WSAWaitForMultipleEvents(1, &state->overlapped.hEvent, TRUE, 10, TRUE);
|
||||
}
|
||||
WSACloseEvent(state->overlapped.hEvent);
|
||||
closesocket(state->sockfd);
|
||||
ffStrbufDestroy(&state->command);
|
||||
@@ -268,8 +239,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
}
|
||||
|
||||
DWORD transfer, flags;
|
||||
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags))
|
||||
{
|
||||
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags)) {
|
||||
FF_DEBUG("WSAGetOverlappedResult failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
closesocket(state->sockfd);
|
||||
WSACloseEvent(state->overlapped.hEvent);
|
||||
@@ -281,28 +251,24 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
WSACloseEvent(state->overlapped.hEvent);
|
||||
state->overlapped.hEvent = NULL;
|
||||
|
||||
if (setsockopt(state->sockfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0)
|
||||
{
|
||||
if (setsockopt(state->sockfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0) {
|
||||
FF_DEBUG("Failed to update connect context: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
// Not a critical error, continue anyway
|
||||
}
|
||||
|
||||
if (shutdown(state->sockfd, SD_SEND) == SOCKET_ERROR)
|
||||
{
|
||||
if (shutdown(state->sockfd, SD_SEND) == SOCKET_ERROR) {
|
||||
FF_DEBUG("Failed to shutdown socket send: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
// Not a critical error, continue anyway
|
||||
}
|
||||
|
||||
if(timeout > 0)
|
||||
{
|
||||
if (timeout > 0) {
|
||||
FF_DEBUG("Setting receive timeout: %u ms", timeout);
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
|
||||
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
// Set larger receive buffer for better performance
|
||||
int rcvbuf = 65536; // 64KB
|
||||
if (setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&rcvbuf, sizeof(rcvbuf)))
|
||||
{
|
||||
if (setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, (const char*) &rcvbuf, sizeof(rcvbuf))) {
|
||||
FF_DEBUG("Failed to set SO_RCVBUF: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
|
||||
// Not a critical error, continue anyway
|
||||
}
|
||||
@@ -314,13 +280,20 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
|
||||
do {
|
||||
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
|
||||
++recvCount, buffer->length, ffStrbufGetFree(buffer));
|
||||
++recvCount,
|
||||
buffer->length,
|
||||
ffStrbufGetFree(buffer));
|
||||
|
||||
DWORD received = 0, recvFlags = 0;
|
||||
int recvResult = WSARecv(state->sockfd, &(WSABUF) {
|
||||
.buf = buffer->chars + buffer->length,
|
||||
.len = (ULONG) ffStrbufGetFree(buffer),
|
||||
}, 1, &received, &recvFlags, NULL, NULL);
|
||||
.buf = buffer->chars + buffer->length,
|
||||
.len = (ULONG) ffStrbufGetFree(buffer),
|
||||
},
|
||||
1,
|
||||
&received,
|
||||
&recvFlags,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (recvResult == SOCKET_ERROR || received == 0) {
|
||||
if (recvResult == 0 && received == 0) {
|
||||
@@ -340,7 +313,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
if (headerEnd == 0) {
|
||||
char* pHeaderEnd = strstr(buffer->chars, "\r\n\r\n");
|
||||
if (pHeaderEnd) {
|
||||
headerEnd = (uint32_t)(pHeaderEnd - buffer->chars);
|
||||
headerEnd = (uint32_t) (pHeaderEnd - buffer->chars);
|
||||
FF_DEBUG("Found HTTP header end marker, position: %u", headerEnd);
|
||||
|
||||
// Check for Content-Length header to pre-allocate enough memory
|
||||
@@ -358,7 +331,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
}
|
||||
} while (ffStrbufGetFree(buffer) > 0);
|
||||
|
||||
FF_DEBUG("Closing socket: fd=%u", (unsigned)state->sockfd);
|
||||
FF_DEBUG("Closing socket: fd=%u", (unsigned) state->sockfd);
|
||||
closesocket(state->sockfd);
|
||||
state->sockfd = INVALID_SOCKET;
|
||||
|
||||
@@ -378,14 +351,15 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
|
||||
if (ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
|
||||
FF_DEBUG("Received valid HTTP 200 response, content length: %u bytes, total length: %u bytes",
|
||||
contentLength, buffer->length);
|
||||
contentLength,
|
||||
buffer->length);
|
||||
} else {
|
||||
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
|
||||
return "Invalid response";
|
||||
}
|
||||
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
if (state->compression) {
|
||||
FF_DEBUG("Content received, checking if compressed");
|
||||
if (!ffNetworkingDecompressGzip(buffer, buffer->chars + headerEnd)) {
|
||||
@@ -395,7 +369,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+56
-95
@@ -4,34 +4,35 @@
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
// Return start position of the inner key if the argument key belongs to the module specified, NULL otherwise
|
||||
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName)
|
||||
{
|
||||
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName) {
|
||||
const char* subKey = argumentKey;
|
||||
if(!(subKey[0] == '-' && subKey[1] == '-'))
|
||||
if (!(subKey[0] == '-' && subKey[1] == '-')) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
subKey += 2;
|
||||
uint32_t moduleNameLen = (uint32_t)strlen(moduleName);
|
||||
if(strncasecmp(subKey, moduleName, moduleNameLen) != 0)
|
||||
uint32_t moduleNameLen = (uint32_t) strlen(moduleName);
|
||||
if (strncasecmp(subKey, moduleName, moduleNameLen) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
subKey += moduleNameLen;
|
||||
|
||||
if(subKey[0] == '\0')
|
||||
if (subKey[0] == '\0') {
|
||||
return subKey;
|
||||
}
|
||||
|
||||
if(subKey[0] != '-')
|
||||
if (subKey[0] != '-') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
subKey += 1;
|
||||
|
||||
return subKey;
|
||||
}
|
||||
|
||||
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer)
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer) {
|
||||
if (value == NULL) {
|
||||
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
|
||||
exit(477);
|
||||
}
|
||||
@@ -39,18 +40,15 @@ void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* b
|
||||
ffStrbufSetS(buffer, value);
|
||||
}
|
||||
|
||||
uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value)
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value) {
|
||||
if (value == NULL) {
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
|
||||
exit(480);
|
||||
}
|
||||
|
||||
char* end;
|
||||
uint32_t num = (uint32_t) strtoul(value, &end, 10);
|
||||
if(*end != '\0')
|
||||
{
|
||||
if (*end != '\0') {
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
|
||||
exit(479);
|
||||
}
|
||||
@@ -58,18 +56,15 @@ uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value)
|
||||
return num;
|
||||
}
|
||||
|
||||
int32_t ffOptionParseInt32(const char* argumentKey, const char* value)
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
int32_t ffOptionParseInt32(const char* argumentKey, const char* value) {
|
||||
if (value == NULL) {
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
|
||||
exit(480);
|
||||
}
|
||||
|
||||
char* end;
|
||||
int32_t num = (int32_t) strtol(value, &end, 10);
|
||||
if(*end != '\0')
|
||||
{
|
||||
if (*end != '\0') {
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
|
||||
exit(479);
|
||||
}
|
||||
@@ -77,42 +72,38 @@ int32_t ffOptionParseInt32(const char* argumentKey, const char* value)
|
||||
return num;
|
||||
}
|
||||
|
||||
int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[])
|
||||
{
|
||||
if(requestedKey == NULL)
|
||||
{
|
||||
int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]) {
|
||||
if (requestedKey == NULL) {
|
||||
fprintf(stderr, "Error: usage: %s <value>\n", argumentKey);
|
||||
exit(476);
|
||||
}
|
||||
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair)
|
||||
{
|
||||
if(ffStrEqualsIgnCase(requestedKey, pPair->key))
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair) {
|
||||
if (ffStrEqualsIgnCase(requestedKey, pPair->key)) {
|
||||
return pPair->value;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Error: unknown %s value: %s\n", argumentKey, requestedKey);
|
||||
exit(478);
|
||||
}
|
||||
|
||||
bool ffOptionParseBoolean(const char* str)
|
||||
{
|
||||
bool ffOptionParseBoolean(const char* str) {
|
||||
return (
|
||||
!ffStrSet(str) ||
|
||||
ffStrEqualsIgnCase(str, "true") ||
|
||||
ffStrEqualsIgnCase(str, "yes") ||
|
||||
ffStrEqualsIgnCase(str, "on") ||
|
||||
ffStrEqualsIgnCase(str, "1")
|
||||
);
|
||||
ffStrEqualsIgnCase(str, "yes") ||
|
||||
ffStrEqualsIgnCase(str, "on") ||
|
||||
ffStrEqualsIgnCase(str, "1"));
|
||||
}
|
||||
|
||||
void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
{
|
||||
if (!value || value[0] == '\0') return;
|
||||
void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer) {
|
||||
if (!value || value[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
// If value is already an ANSI escape code, use it
|
||||
if (value[0] == '\e' && value[1] == '[')
|
||||
{
|
||||
if (value[0] == '\e' && value[1] == '[') {
|
||||
ffStrbufAppendS(buffer, value + 2);
|
||||
ffStrbufTrimRight(buffer, 'm');
|
||||
return;
|
||||
@@ -120,54 +111,28 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
|
||||
ffStrbufEnsureFree(buffer, 63);
|
||||
|
||||
while(*value != '\0')
|
||||
{
|
||||
#define FF_APPEND_COLOR_CODE_COND(prefix, code) \
|
||||
if(ffStrStartsWithIgnCase(value, #prefix)) { ffStrbufAppendS(buffer, code); value += strlen(#prefix); continue; }
|
||||
#define FF_APPEND_COLOR_PROP_COND(prefix, prop) \
|
||||
if(ffStrStartsWithIgnCase(value, #prefix)) { if (instance.config.display.prop.length) ffStrbufAppend(buffer, &instance.config.display.prop); else ffStrbufAppendS(buffer, FF_COLOR_FG_DEFAULT); value += strlen(#prefix); continue; }
|
||||
while (*value != '\0') {
|
||||
#define FF_APPEND_COLOR_CODE_COND(prefix, code) \
|
||||
if (ffStrStartsWithIgnCase(value, #prefix)) { \
|
||||
ffStrbufAppendS(buffer, code); \
|
||||
value += strlen(#prefix); \
|
||||
continue; \
|
||||
}
|
||||
#define FF_APPEND_COLOR_PROP_COND(prefix, prop) \
|
||||
if (ffStrStartsWithIgnCase(value, #prefix)) { \
|
||||
if (instance.config.display.prop.length) ffStrbufAppend(buffer, &instance.config.display.prop); \
|
||||
else ffStrbufAppendS(buffer, FF_COLOR_FG_DEFAULT); \
|
||||
value += strlen(#prefix); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
if (ffCharIsEnglishAlphabet(value[0]))
|
||||
{
|
||||
if (ffCharIsEnglishAlphabet(value[0])) {
|
||||
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
|
||||
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM)
|
||||
else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC)
|
||||
else FF_APPEND_COLOR_CODE_COND(underline_, FF_COLOR_MODE_UNDERLINE)
|
||||
else FF_APPEND_COLOR_CODE_COND(blink_, FF_COLOR_MODE_BLINK)
|
||||
else FF_APPEND_COLOR_CODE_COND(inverse_, FF_COLOR_MODE_INVERSE)
|
||||
else FF_APPEND_COLOR_CODE_COND(hidden_, FF_COLOR_MODE_HIDDEN)
|
||||
else FF_APPEND_COLOR_CODE_COND(strike_, FF_COLOR_MODE_STRIKETHROUGH)
|
||||
else FF_APPEND_COLOR_CODE_COND(black, FF_COLOR_FG_BLACK)
|
||||
else FF_APPEND_COLOR_CODE_COND(red, FF_COLOR_FG_RED)
|
||||
else FF_APPEND_COLOR_CODE_COND(green, FF_COLOR_FG_GREEN)
|
||||
else FF_APPEND_COLOR_CODE_COND(yellow, FF_COLOR_FG_YELLOW)
|
||||
else FF_APPEND_COLOR_CODE_COND(blue, FF_COLOR_FG_BLUE)
|
||||
else FF_APPEND_COLOR_CODE_COND(magenta, FF_COLOR_FG_MAGENTA)
|
||||
else FF_APPEND_COLOR_CODE_COND(cyan, FF_COLOR_FG_CYAN)
|
||||
else FF_APPEND_COLOR_CODE_COND(white, FF_COLOR_FG_WHITE)
|
||||
else FF_APPEND_COLOR_CODE_COND(default, FF_COLOR_FG_DEFAULT)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_black, FF_COLOR_FG_LIGHT_BLACK)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_red, FF_COLOR_FG_LIGHT_RED)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_green, FF_COLOR_FG_LIGHT_GREEN)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_yellow, FF_COLOR_FG_LIGHT_YELLOW)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_blue, FF_COLOR_FG_LIGHT_BLUE)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_magenta, FF_COLOR_FG_LIGHT_MAGENTA)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_cyan, FF_COLOR_FG_LIGHT_CYAN)
|
||||
else FF_APPEND_COLOR_CODE_COND(light_white, FF_COLOR_FG_LIGHT_WHITE)
|
||||
else FF_APPEND_COLOR_PROP_COND(keys, colorKeys)
|
||||
else FF_APPEND_COLOR_PROP_COND(title, colorTitle)
|
||||
else FF_APPEND_COLOR_PROP_COND(output, colorOutput)
|
||||
else FF_APPEND_COLOR_PROP_COND(separator, colorSeparator)
|
||||
else
|
||||
{
|
||||
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD) else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD) else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM) else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC) else FF_APPEND_COLOR_CODE_COND(underline_, FF_COLOR_MODE_UNDERLINE) else FF_APPEND_COLOR_CODE_COND(blink_, FF_COLOR_MODE_BLINK) else FF_APPEND_COLOR_CODE_COND(inverse_, FF_COLOR_MODE_INVERSE) else FF_APPEND_COLOR_CODE_COND(hidden_, FF_COLOR_MODE_HIDDEN) else FF_APPEND_COLOR_CODE_COND(strike_, FF_COLOR_MODE_STRIKETHROUGH) else FF_APPEND_COLOR_CODE_COND(black, FF_COLOR_FG_BLACK) else FF_APPEND_COLOR_CODE_COND(red, FF_COLOR_FG_RED) else FF_APPEND_COLOR_CODE_COND(green, FF_COLOR_FG_GREEN) else FF_APPEND_COLOR_CODE_COND(yellow, FF_COLOR_FG_YELLOW) else FF_APPEND_COLOR_CODE_COND(blue, FF_COLOR_FG_BLUE) else FF_APPEND_COLOR_CODE_COND(magenta, FF_COLOR_FG_MAGENTA) else FF_APPEND_COLOR_CODE_COND(cyan, FF_COLOR_FG_CYAN) else FF_APPEND_COLOR_CODE_COND(white, FF_COLOR_FG_WHITE) else FF_APPEND_COLOR_CODE_COND(default, FF_COLOR_FG_DEFAULT) else FF_APPEND_COLOR_CODE_COND(light_black, FF_COLOR_FG_LIGHT_BLACK) else FF_APPEND_COLOR_CODE_COND(light_red, FF_COLOR_FG_LIGHT_RED) else FF_APPEND_COLOR_CODE_COND(light_green, FF_COLOR_FG_LIGHT_GREEN) else FF_APPEND_COLOR_CODE_COND(light_yellow, FF_COLOR_FG_LIGHT_YELLOW) else FF_APPEND_COLOR_CODE_COND(light_blue, FF_COLOR_FG_LIGHT_BLUE) else FF_APPEND_COLOR_CODE_COND(light_magenta, FF_COLOR_FG_LIGHT_MAGENTA) else FF_APPEND_COLOR_CODE_COND(light_cyan, FF_COLOR_FG_LIGHT_CYAN) else FF_APPEND_COLOR_CODE_COND(light_white, FF_COLOR_FG_LIGHT_WHITE) else FF_APPEND_COLOR_PROP_COND(keys, colorKeys) else FF_APPEND_COLOR_PROP_COND(title, colorTitle) else FF_APPEND_COLOR_PROP_COND(output, colorOutput) else FF_APPEND_COLOR_PROP_COND(separator, colorSeparator) else {
|
||||
fprintf(stderr, "Error: invalid color code found: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
}
|
||||
else if (value[0] == '@')
|
||||
{
|
||||
} else if (value[0] == '@') {
|
||||
// Xterm 256 color
|
||||
++value;
|
||||
char* pend = NULL;
|
||||
@@ -181,9 +146,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
ffStrbufAppendUInt(buffer, color);
|
||||
value = pend;
|
||||
continue;
|
||||
}
|
||||
else if (value[0] == '#')
|
||||
{
|
||||
} else if (value[0] == '#') {
|
||||
// RGB color
|
||||
++value;
|
||||
char* pend = NULL;
|
||||
@@ -195,13 +158,11 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
if (pend - value > 6) {
|
||||
fprintf(stderr, "Error: RGB color code too long: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
else if (pend - value == 3) {
|
||||
} else if (pend - value == 3) {
|
||||
rgb = ((rgb & 0xF00) >> 8) * 0x110000 +
|
||||
((rgb & 0x0F0) >> 4) * 0x001100 +
|
||||
((rgb & 0x00F) >> 0) * 0x000011;
|
||||
}
|
||||
else if (pend - value != 6) {
|
||||
((rgb & 0x0F0) >> 4) * 0x001100 +
|
||||
((rgb & 0x00F) >> 0) * 0x000011;
|
||||
} else if (pend - value != 6) {
|
||||
fprintf(stderr, "Error: invalid RGB color code length: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
@@ -214,7 +175,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
ffStrbufAppendC(buffer, *value);
|
||||
++value;
|
||||
|
||||
#undef FF_APPEND_COLOR_CODE_COND
|
||||
#undef FF_APPEND_COLOR_PROP_COND
|
||||
#undef FF_APPEND_COLOR_CODE_COND
|
||||
#undef FF_APPEND_COLOR_PROP_COND
|
||||
}
|
||||
}
|
||||
|
||||
+40
-64
@@ -4,94 +4,86 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat"
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wformat"
|
||||
#endif
|
||||
|
||||
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch)
|
||||
{
|
||||
if(major->length > 0)
|
||||
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch) {
|
||||
if (major->length > 0) {
|
||||
ffStrbufAppend(buffer, major);
|
||||
else if(minor->length > 0 || patch->length > 0)
|
||||
} else if (minor->length > 0 || patch->length > 0) {
|
||||
ffStrbufAppendC(buffer, '1');
|
||||
}
|
||||
|
||||
if(minor->length == 0 && patch->length == 0)
|
||||
if (minor->length == 0 && patch->length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
|
||||
if(minor->length > 0)
|
||||
if (minor->length > 0) {
|
||||
ffStrbufAppend(buffer, minor);
|
||||
else if(patch->length > 0)
|
||||
} else if (patch->length > 0) {
|
||||
ffStrbufAppendC(buffer, '0');
|
||||
}
|
||||
|
||||
if(patch->length == 0)
|
||||
if (patch->length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
|
||||
ffStrbufAppend(buffer, patch);
|
||||
}
|
||||
|
||||
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2)
|
||||
{
|
||||
if(version1->major != version2->major)
|
||||
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2) {
|
||||
if (version1->major != version2->major) {
|
||||
return version1->major > version2->major ? 1 : -1;
|
||||
}
|
||||
|
||||
if(version1->minor != version2->minor)
|
||||
if (version1->minor != version2->minor) {
|
||||
return version1->minor > version2->minor ? 1 : -1;
|
||||
}
|
||||
|
||||
if(version1->patch != version2->patch)
|
||||
if (version1->patch != version2->patch) {
|
||||
return version1->patch > version2->patch ? 1 : -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty)
|
||||
{
|
||||
if(version->major > 0 || version->minor > 0 || version->patch > 0)
|
||||
{
|
||||
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty) {
|
||||
if (version->major > 0 || version->minor > 0 || version->patch > 0) {
|
||||
ffStrbufAppendUInt(pretty, version->major);
|
||||
}
|
||||
|
||||
if(version->minor > 0 || version->patch > 0)
|
||||
{
|
||||
if (version->minor > 0 || version->patch > 0) {
|
||||
ffStrbufAppendC(pretty, '.');
|
||||
ffStrbufAppendUInt(pretty, version->minor);
|
||||
}
|
||||
|
||||
if(version->patch > 0)
|
||||
{
|
||||
if (version->patch > 0) {
|
||||
ffStrbufAppendC(pretty, '.');
|
||||
ffStrbufAppendUInt(pretty, version->patch);
|
||||
}
|
||||
}
|
||||
|
||||
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
|
||||
{
|
||||
if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0)
|
||||
{
|
||||
if((ffStrbufIgnCaseEqual(gtk2, gtk3)) && (ffStrbufIgnCaseEqual(gtk2, gtk4)))
|
||||
{
|
||||
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4) {
|
||||
if (gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0) {
|
||||
if ((ffStrbufIgnCaseEqual(gtk2, gtk3)) && (ffStrbufIgnCaseEqual(gtk2, gtk4))) {
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK2/3/4]");
|
||||
}
|
||||
else if(ffStrbufIgnCaseEqual(gtk2, gtk3))
|
||||
{
|
||||
} else if (ffStrbufIgnCaseEqual(gtk2, gtk3)) {
|
||||
ffStrbufAppend(buffer, gtk3);
|
||||
ffStrbufAppendS(buffer, " [GTK2/3], ");
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK4]");
|
||||
}
|
||||
else if(ffStrbufIgnCaseEqual(gtk3, gtk4))
|
||||
{
|
||||
} else if (ffStrbufIgnCaseEqual(gtk3, gtk4)) {
|
||||
ffStrbufAppend(buffer, gtk2);
|
||||
ffStrbufAppendS(buffer, " [GTK2], ");
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK3/4]");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppend(buffer, gtk2);
|
||||
ffStrbufAppendS(buffer, " [GTK2], ");
|
||||
ffStrbufAppend(buffer, gtk3);
|
||||
@@ -99,54 +91,38 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK4]");
|
||||
}
|
||||
}
|
||||
else if(gtk2->length > 0 && gtk3->length > 0)
|
||||
{
|
||||
if(ffStrbufIgnCaseEqual(gtk2, gtk3))
|
||||
{
|
||||
} else if (gtk2->length > 0 && gtk3->length > 0) {
|
||||
if (ffStrbufIgnCaseEqual(gtk2, gtk3)) {
|
||||
ffStrbufAppend(buffer, gtk3);
|
||||
ffStrbufAppendS(buffer, " [GTK2/3]");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppend(buffer, gtk2);
|
||||
ffStrbufAppendS(buffer, " [GTK2], ");
|
||||
ffStrbufAppend(buffer, gtk3);
|
||||
ffStrbufAppendS(buffer, " [GTK3]");
|
||||
}
|
||||
}
|
||||
else if(gtk3->length > 0 && gtk4->length > 0)
|
||||
{
|
||||
if(ffStrbufIgnCaseEqual(gtk3, gtk4))
|
||||
{
|
||||
} else if (gtk3->length > 0 && gtk4->length > 0) {
|
||||
if (ffStrbufIgnCaseEqual(gtk3, gtk4)) {
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK3/4]");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
ffStrbufAppend(buffer, gtk3);
|
||||
ffStrbufAppendS(buffer, " [GTK3], ");
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK4]");
|
||||
}
|
||||
}
|
||||
else if(gtk2->length > 0)
|
||||
{
|
||||
} else if (gtk2->length > 0) {
|
||||
ffStrbufAppend(buffer, gtk2);
|
||||
ffStrbufAppendS(buffer, " [GTK2]");
|
||||
}
|
||||
else if(gtk3->length > 0)
|
||||
{
|
||||
} else if (gtk3->length > 0) {
|
||||
ffStrbufAppend(buffer, gtk3);
|
||||
ffStrbufAppendS(buffer, " [GTK3]");
|
||||
}
|
||||
else if(gtk4->length > 0)
|
||||
{
|
||||
} else if (gtk4->length > 0) {
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK4]");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic pop
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
+74
-113
@@ -3,44 +3,49 @@
|
||||
#include "common/arrayUtils.h"
|
||||
|
||||
#if !_WIN32
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
{
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) {
|
||||
char* path = getenv("PATH");
|
||||
if(!path)
|
||||
if (!path) {
|
||||
return "$PATH not set";
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN32
|
||||
const bool appendExe = !ffStrEndsWithIgnCase(name, ".exe");
|
||||
#endif
|
||||
# endif
|
||||
|
||||
for (char* token = path; *token; path = token + 1)
|
||||
{
|
||||
for (char* token = path; *token; path = token + 1) {
|
||||
token = strchr(path,
|
||||
#ifdef _WIN32
|
||||
';'
|
||||
#else
|
||||
':'
|
||||
#endif
|
||||
# ifdef _WIN32
|
||||
';'
|
||||
# else
|
||||
':'
|
||||
# endif
|
||||
);
|
||||
if (!token) token = path + strlen(path);
|
||||
if (!token) {
|
||||
token = path + strlen(path);
|
||||
}
|
||||
|
||||
ffStrbufSetNS(result, (uint32_t)(token - path), path);
|
||||
ffStrbufSetNS(result, (uint32_t) (token - path), path);
|
||||
ffStrbufEnsureEndsWithC(result,
|
||||
#ifdef _WIN32
|
||||
'\\'
|
||||
#else
|
||||
'/'
|
||||
#endif
|
||||
# ifdef _WIN32
|
||||
'\\'
|
||||
# else
|
||||
'/'
|
||||
# endif
|
||||
);
|
||||
ffStrbufAppendS(result, name);
|
||||
#ifdef _WIN32
|
||||
if (appendExe) ffStrbufAppendS(result, ".exe");
|
||||
if (!ffPathExists(result->chars, FF_PATHTYPE_FILE))
|
||||
# ifdef _WIN32
|
||||
if (appendExe) {
|
||||
ffStrbufAppendS(result, ".exe");
|
||||
}
|
||||
if (!ffPathExists(result->chars, FF_PATHTYPE_FILE)) {
|
||||
continue;
|
||||
#else
|
||||
if (access(result->chars, X_OK) != 0)
|
||||
}
|
||||
# else
|
||||
if (access(result->chars, X_OK) != 0) {
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
# endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -48,17 +53,15 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
return "Executable not found";
|
||||
}
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <errno.h>
|
||||
#include <stdalign.h>
|
||||
# include <windows.h>
|
||||
# include <winioctl.h>
|
||||
# include <errno.h>
|
||||
# include <stdalign.h>
|
||||
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
{
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) {
|
||||
char buffer[MAX_PATH + 1];
|
||||
DWORD length = SearchPathA(NULL, name, ".exe", sizeof(buffer), buffer, NULL);
|
||||
if (length == 0)
|
||||
{
|
||||
if (length == 0) {
|
||||
ffStrbufClear(result);
|
||||
return "Executable not found";
|
||||
}
|
||||
@@ -66,10 +69,8 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int winerr2Errno(DWORD err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
static inline int winerr2Errno(DWORD err) {
|
||||
switch (err) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
case ERROR_INVALID_NAME:
|
||||
@@ -89,24 +90,20 @@ static inline int winerr2Errno(DWORD err)
|
||||
}
|
||||
}
|
||||
|
||||
char* frealpath(HANDLE hFile, char* resolved_name)
|
||||
{
|
||||
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !hFile, false))
|
||||
{
|
||||
char* frealpath(HANDLE hFile, char* resolved_name) {
|
||||
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !hFile, false)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t resolvedNameW[MAX_PATH + 4]; /* +4 for "\\\\?\\" prefix */
|
||||
DWORD lenW = GetFinalPathNameByHandleW(hFile, resolvedNameW, (DWORD)ARRAY_SIZE(resolvedNameW), FILE_NAME_NORMALIZED);
|
||||
DWORD lenW = GetFinalPathNameByHandleW(hFile, resolvedNameW, (DWORD) ARRAY_SIZE(resolvedNameW), FILE_NAME_NORMALIZED);
|
||||
|
||||
if (lenW == 0)
|
||||
{
|
||||
if (lenW == 0) {
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
if (lenW >= ARRAY_SIZE(resolvedNameW))
|
||||
{
|
||||
if (lenW >= ARRAY_SIZE(resolvedNameW)) {
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
@@ -115,51 +112,41 @@ char* frealpath(HANDLE hFile, char* resolved_name)
|
||||
wchar_t* srcW = resolvedNameW;
|
||||
DWORD srcLenW = lenW;
|
||||
|
||||
if (srcLenW >= 8 && wcsncmp(resolvedNameW, L"\\\\?\\UNC\\", 8) == 0)
|
||||
{
|
||||
if (srcLenW >= 8 && wcsncmp(resolvedNameW, L"\\\\?\\UNC\\", 8) == 0) {
|
||||
/* Convert "\\?\UNC\server\share" to "\\server\share" */
|
||||
srcW += 6;
|
||||
srcLenW -= 6;
|
||||
*srcW = L'\\';
|
||||
}
|
||||
else if (srcLenW >= 4 && wcsncmp(resolvedNameW, L"\\\\?\\", 4) == 0)
|
||||
{
|
||||
} else if (srcLenW >= 4 && wcsncmp(resolvedNameW, L"\\\\?\\", 4) == 0) {
|
||||
srcW += 4;
|
||||
srcLenW -= 4;
|
||||
}
|
||||
|
||||
if (resolved_name)
|
||||
{
|
||||
if (resolved_name) {
|
||||
ULONG outBytes = 0;
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(resolved_name, MAX_PATH, &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
|
||||
{
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(resolved_name, MAX_PATH, &outBytes, srcW, (ULONG) (srcLenW * sizeof(wchar_t))))) {
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (outBytes > MAX_PATH)
|
||||
{
|
||||
if (outBytes > MAX_PATH) {
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return resolved_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* UTF-8 worst-case: up to 4 bytes per UTF-16 code unit */
|
||||
char tmp[(MAX_PATH + 4) * 4];
|
||||
ULONG outBytes = 0;
|
||||
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(tmp, (ULONG)sizeof(tmp), &outBytes, srcW, (ULONG)(srcLenW * sizeof(wchar_t)))))
|
||||
{
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(tmp, (ULONG) sizeof(tmp), &outBytes, srcW, (ULONG) (srcLenW * sizeof(wchar_t))))) {
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resolved_name = (char*)malloc(outBytes);
|
||||
if (!resolved_name)
|
||||
{
|
||||
resolved_name = (char*) malloc(outBytes);
|
||||
if (!resolved_name) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
@@ -171,10 +158,8 @@ char* frealpath(HANDLE hFile, char* resolved_name)
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
|
||||
{
|
||||
if (!file_name)
|
||||
{
|
||||
char* realpath(const char* __restrict file_name, char* __restrict resolved_name) {
|
||||
if (!file_name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@@ -182,8 +167,7 @@ char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
ULONG lenBytes = 0;
|
||||
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG)sizeof(fileNameW), &lenBytes, file_name, (ULONG)strlen(file_name) + 1)))
|
||||
{
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &lenBytes, file_name, (ULONG) strlen(file_name) + 1))) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
@@ -197,8 +181,7 @@ char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
@@ -206,18 +189,15 @@ char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
|
||||
return frealpath(hFile, resolved_name);
|
||||
}
|
||||
|
||||
ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz)
|
||||
{
|
||||
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !buf || bufsiz == 0, false))
|
||||
{
|
||||
ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz) {
|
||||
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !buf || bufsiz == 0, false)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
alignas(REPARSE_DATA_BUFFER) BYTE reparseBuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
DWORD bytesReturned = 0;
|
||||
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseBuf, (DWORD) sizeof(reparseBuf), &bytesReturned, NULL))
|
||||
{
|
||||
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseBuf, (DWORD) sizeof(reparseBuf), &bytesReturned, NULL)) {
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
@@ -226,59 +206,45 @@ ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz)
|
||||
const wchar_t* targetW = NULL;
|
||||
USHORT targetBytes = 0;
|
||||
|
||||
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
|
||||
{
|
||||
if (rp->SymbolicLinkReparseBuffer.PrintNameLength > 0)
|
||||
{
|
||||
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
|
||||
if (rp->SymbolicLinkReparseBuffer.PrintNameLength > 0) {
|
||||
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
(rp->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->SymbolicLinkReparseBuffer.PrintNameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
targetW = rp->SymbolicLinkReparseBuffer.PathBuffer +
|
||||
(rp->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||
|
||||
if (targetBytes >= 8 &&
|
||||
wcsncmp(targetW, L"\\??\\", 4) == 0)
|
||||
{
|
||||
wcsncmp(targetW, L"\\??\\", 4) == 0) {
|
||||
targetW += 4;
|
||||
targetBytes -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
|
||||
{
|
||||
if (rp->MountPointReparseBuffer.PrintNameLength > 0)
|
||||
{
|
||||
} else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
|
||||
if (rp->MountPointReparseBuffer.PrintNameLength > 0) {
|
||||
targetW = rp->MountPointReparseBuffer.PathBuffer +
|
||||
(rp->MountPointReparseBuffer.PrintNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->MountPointReparseBuffer.PrintNameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
targetW = rp->MountPointReparseBuffer.PathBuffer +
|
||||
(rp->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t));
|
||||
targetBytes = rp->MountPointReparseBuffer.SubstituteNameLength;
|
||||
|
||||
if (targetBytes >= 8 &&
|
||||
wcsncmp(targetW, L"\\??\\", 4) == 0)
|
||||
{
|
||||
wcsncmp(targetW, L"\\??\\", 4) == 0) {
|
||||
targetW += 4;
|
||||
targetBytes -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ULONG outBytes = 0;
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(buf, (ULONG) bufsiz, &outBytes, targetW, targetBytes)))
|
||||
{
|
||||
if (!NT_SUCCESS(RtlUnicodeToUTF8N(buf, (ULONG) bufsiz, &outBytes, targetW, targetBytes))) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
@@ -287,18 +253,15 @@ ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz)
|
||||
return (ssize_t) outBytes;
|
||||
}
|
||||
|
||||
ssize_t readlink(const char* path, char* buf, size_t bufsiz)
|
||||
{
|
||||
if (!path || !buf || bufsiz == 0)
|
||||
{
|
||||
ssize_t readlink(const char* path, char* buf, size_t bufsiz) {
|
||||
if (!path || !buf || bufsiz == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
wchar_t pathW[MAX_PATH];
|
||||
ULONG pathWBytes = 0;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathW, (ULONG) sizeof(pathW), &pathWBytes, path, (ULONG) strlen(path) + 1)))
|
||||
{
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathW, (ULONG) sizeof(pathW), &pathWBytes, path, (ULONG) strlen(path) + 1))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -310,11 +273,9 @@ ssize_t readlink(const char* path, char* buf, size_t bufsiz)
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||
NULL
|
||||
);
|
||||
NULL);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
errno = winerr2Errno(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
+103
-133
@@ -6,44 +6,42 @@
|
||||
#include "common/textModifier.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
static void appendOutputColor(FFstrbuf* buffer, const FFModuleArgs* module)
|
||||
{
|
||||
if (module->outputColor.length)
|
||||
static void appendOutputColor(FFstrbuf* buffer, const FFModuleArgs* module) {
|
||||
if (module->outputColor.length) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", module->outputColor.chars);
|
||||
else if (instance.config.display.colorOutput.length)
|
||||
} else if (instance.config.display.colorOutput.length) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", instance.config.display.colorOutput.chars);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFlags* result)
|
||||
{
|
||||
if (yyjson_is_uint(jsonVal))
|
||||
{
|
||||
const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFlags* result) {
|
||||
if (yyjson_is_uint(jsonVal)) {
|
||||
*result = (FFPercentageTypeFlags) yyjson_get_uint(jsonVal);
|
||||
return NULL;
|
||||
}
|
||||
if (yyjson_is_arr(jsonVal))
|
||||
{
|
||||
if (yyjson_is_arr(jsonVal)) {
|
||||
FFPercentageTypeFlags flags = 0;
|
||||
|
||||
yyjson_val* item;
|
||||
size_t idx, max;
|
||||
yyjson_arr_foreach(jsonVal, idx, max, item)
|
||||
{
|
||||
yyjson_arr_foreach (jsonVal, idx, max, item) {
|
||||
const char* flag = yyjson_get_str(item);
|
||||
if (!flag)
|
||||
if (!flag) {
|
||||
return "Error: percent.type: invalid flag string";
|
||||
if (ffStrEqualsIgnCase(flag, "num"))
|
||||
}
|
||||
if (ffStrEqualsIgnCase(flag, "num")) {
|
||||
flags |= FF_PERCENTAGE_TYPE_NUM_BIT;
|
||||
else if (ffStrEqualsIgnCase(flag, "bar"))
|
||||
} else if (ffStrEqualsIgnCase(flag, "bar")) {
|
||||
flags |= FF_PERCENTAGE_TYPE_BAR_BIT;
|
||||
else if (ffStrEqualsIgnCase(flag, "hide-others"))
|
||||
} else if (ffStrEqualsIgnCase(flag, "hide-others")) {
|
||||
flags |= FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT;
|
||||
else if (ffStrEqualsIgnCase(flag, "num-color"))
|
||||
} else if (ffStrEqualsIgnCase(flag, "num-color")) {
|
||||
flags |= FF_PERCENTAGE_TYPE_NUM_COLOR_BIT;
|
||||
else if (ffStrEqualsIgnCase(flag, "bar-monochrome"))
|
||||
} else if (ffStrEqualsIgnCase(flag, "bar-monochrome")) {
|
||||
flags |= FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT;
|
||||
else
|
||||
} else {
|
||||
return "Error: percent.type: unknown flag string";
|
||||
}
|
||||
}
|
||||
|
||||
*result = flags;
|
||||
@@ -53,8 +51,7 @@ const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFl
|
||||
return "Error: usage: percent.type must be a number or an array of strings";
|
||||
}
|
||||
|
||||
void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, const FFModuleArgs* module)
|
||||
{
|
||||
void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, const FFModuleArgs* module) {
|
||||
uint8_t green = config.green, yellow = config.yellow;
|
||||
assert(green <= 100 && yellow <= 100);
|
||||
|
||||
@@ -65,30 +62,24 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
uint8_t blocksPercent = (uint8_t) (percent / 100.0 * options->barWidth + 0.5);
|
||||
assert(blocksPercent <= options->barWidth);
|
||||
|
||||
if(!borderAsValue && options->barBorderLeft.length)
|
||||
{
|
||||
if(!options->pipe && options->barColorBorder.length > 0)
|
||||
if (!borderAsValue && options->barBorderLeft.length) {
|
||||
if (!options->pipe && options->barColorBorder.length > 0) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
|
||||
}
|
||||
ffStrbufAppend(buffer, &options->barBorderLeft);
|
||||
}
|
||||
|
||||
if (percent == -DBL_MAX)
|
||||
{
|
||||
if (percent == -DBL_MAX) {
|
||||
// Use total color for simplification
|
||||
if(!options->pipe && options->barColorTotal.length > 0)
|
||||
if (!options->pipe && options->barColorTotal.length > 0) {
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
|
||||
|
||||
for (uint8_t i = 0; i < options->barWidth; ++i)
|
||||
{
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeft
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for (uint8_t i = 0; i < options->barWidth; ++i) {
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0 ? &options->barBorderLeft : borderAsValue && i == options->barWidth - 1 ? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
} else {
|
||||
const char* colorGreen = options->percentColorGreen.chars;
|
||||
const char* colorYellow = options->percentColorYellow.chars;
|
||||
const char* colorRed = options->percentColorRed.chars;
|
||||
@@ -98,76 +89,70 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
bool autoColorElapsed = ffStrbufIgnCaseEqualS(&options->barColorElapsed, "auto");
|
||||
|
||||
bool monochrome = (percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT) || !autoColorElapsed;
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && monochrome)
|
||||
{
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && monochrome) {
|
||||
const char* color = NULL;
|
||||
if (!autoColorElapsed)
|
||||
if (!autoColorElapsed) {
|
||||
color = options->barColorElapsed.chars;
|
||||
else if (green <= yellow)
|
||||
{
|
||||
if (percent < green) color = colorGreen;
|
||||
else if (percent < yellow) color = colorYellow;
|
||||
else color = colorRed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (percent < yellow) color = colorRed;
|
||||
else if (percent < green) color = colorYellow;
|
||||
else color = colorGreen;
|
||||
} else if (green <= yellow) {
|
||||
if (percent < green) {
|
||||
color = colorGreen;
|
||||
} else if (percent < yellow) {
|
||||
color = colorYellow;
|
||||
} else {
|
||||
color = colorRed;
|
||||
}
|
||||
} else {
|
||||
if (percent < yellow) {
|
||||
color = colorRed;
|
||||
} else if (percent < green) {
|
||||
color = colorYellow;
|
||||
} else {
|
||||
color = colorGreen;
|
||||
}
|
||||
}
|
||||
ffStrbufAppendF(buffer, "\e[%sm", color);
|
||||
}
|
||||
for (uint8_t i = 0; i < blocksPercent; ++i)
|
||||
{
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && !monochrome)
|
||||
{
|
||||
for (uint8_t i = 0; i < blocksPercent; ++i) {
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && !monochrome) {
|
||||
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
if (i == section2Begin)
|
||||
if (i == section2Begin) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
|
||||
else if (i == section1Begin)
|
||||
} else if (i == section1Begin) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else if (i == 0)
|
||||
} else if (i == 0) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
|
||||
}
|
||||
}
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeftElapsed
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRightElapsed
|
||||
: &options->barCharElapsed);
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0 ? &options->barBorderLeftElapsed : borderAsValue && i == options->barWidth - 1 ? &options->barBorderRightElapsed
|
||||
: &options->barCharElapsed);
|
||||
}
|
||||
|
||||
if (blocksPercent < options->barWidth)
|
||||
{
|
||||
if(!options->pipe && options->barColorTotal.length > 0)
|
||||
if (blocksPercent < options->barWidth) {
|
||||
if (!options->pipe && options->barColorTotal.length > 0) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorTotal.chars);
|
||||
for (uint8_t i = blocksPercent; i < options->barWidth; ++i)
|
||||
{
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeft
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
for (uint8_t i = blocksPercent; i < options->barWidth; ++i) {
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0 ? &options->barBorderLeft : borderAsValue && i == options->barWidth - 1 ? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!borderAsValue && options->barBorderRight.length)
|
||||
{
|
||||
if(!options->pipe && options->barColorBorder.length > 0)
|
||||
if (!borderAsValue && options->barBorderRight.length) {
|
||||
if (!options->pipe && options->barColorBorder.length > 0) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
|
||||
}
|
||||
ffStrbufAppend(buffer, &options->barBorderRight);
|
||||
}
|
||||
|
||||
if(!options->pipe && (options->barColorElapsed.length > 0 || options->barColorTotal.length > 0 || options->barColorBorder.length > 0))
|
||||
{
|
||||
if (!options->pipe && (options->barColorElapsed.length > 0 || options->barColorTotal.length > 0 || options->barColorBorder.length > 0)) {
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
appendOutputColor(buffer, module);
|
||||
}
|
||||
}
|
||||
|
||||
void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, bool parentheses, const FFModuleArgs* module)
|
||||
{
|
||||
void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, bool parentheses, const FFModuleArgs* module) {
|
||||
uint8_t green = config.green, yellow = config.yellow;
|
||||
assert(green <= 100 && yellow <= 100);
|
||||
|
||||
@@ -176,61 +161,57 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
|
||||
bool colored = !!(percentType & FF_PERCENTAGE_TYPE_NUM_COLOR_BIT);
|
||||
|
||||
if (parentheses)
|
||||
if (parentheses) {
|
||||
ffStrbufAppendC(buffer, '(');
|
||||
}
|
||||
|
||||
if (colored && !options->pipe)
|
||||
{
|
||||
if (colored && !options->pipe) {
|
||||
const char* colorGreen = options->percentColorGreen.chars;
|
||||
const char* colorYellow = options->percentColorYellow.chars;
|
||||
const char* colorRed = options->percentColorRed.chars;
|
||||
|
||||
if(percent == -DBL_MAX)
|
||||
if (percent == -DBL_MAX) {
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
|
||||
else if(green <= yellow)
|
||||
{
|
||||
if (percent > yellow)
|
||||
} else if (green <= yellow) {
|
||||
if (percent > yellow) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorRed);
|
||||
else if (percent > green)
|
||||
} else if (percent > green) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (percent < yellow)
|
||||
}
|
||||
} else {
|
||||
if (percent < yellow) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorRed);
|
||||
else if (percent < green)
|
||||
} else if (percent < green) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent,
|
||||
options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent, options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
|
||||
if (colored && !options->pipe)
|
||||
{
|
||||
if (colored && !options->pipe) {
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
appendOutputColor(buffer, module);
|
||||
}
|
||||
|
||||
if (parentheses)
|
||||
if (parentheses) {
|
||||
ffStrbufAppendC(buffer, ')');
|
||||
}
|
||||
}
|
||||
|
||||
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentageModuleConfig* config)
|
||||
{
|
||||
if (!ffStrStartsWithIgnCase(subkey, "percent-"))
|
||||
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentageModuleConfig* config) {
|
||||
if (!ffStrStartsWithIgnCase(subkey, "percent-")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subkey += strlen("percent-");
|
||||
|
||||
if (ffStrEqualsIgnCase(subkey, "green"))
|
||||
{
|
||||
if (ffStrEqualsIgnCase(subkey, "green")) {
|
||||
uint32_t num = ffOptionParseUInt32(key, value);
|
||||
if (num > 100)
|
||||
{
|
||||
if (num > 100) {
|
||||
fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key);
|
||||
exit(480);
|
||||
}
|
||||
@@ -238,11 +219,9 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ffStrEqualsIgnCase(subkey, "yellow"))
|
||||
{
|
||||
if (ffStrEqualsIgnCase(subkey, "yellow")) {
|
||||
uint32_t num = ffOptionParseUInt32(key, value);
|
||||
if (num > 100)
|
||||
{
|
||||
if (num > 100) {
|
||||
fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key);
|
||||
exit(480);
|
||||
}
|
||||
@@ -250,8 +229,7 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ffStrEqualsIgnCase(subkey, "type"))
|
||||
{
|
||||
if (ffStrEqualsIgnCase(subkey, "type")) {
|
||||
config->type = (FFPercentageTypeFlags) ffOptionParseUInt32(key, value);
|
||||
return true;
|
||||
}
|
||||
@@ -259,25 +237,22 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config)
|
||||
{
|
||||
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config) {
|
||||
assert(key);
|
||||
|
||||
if (!unsafe_yyjson_equals_str(key, "percent"))
|
||||
if (!unsafe_yyjson_equals_str(key, "percent")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!yyjson_is_obj(value))
|
||||
{
|
||||
if (!yyjson_is_obj(value)) {
|
||||
fprintf(stderr, "Error: usage: %s must be an object\n", unsafe_yyjson_get_str(key));
|
||||
exit(480);
|
||||
}
|
||||
|
||||
yyjson_val* greenVal = yyjson_obj_get(value, "green");
|
||||
if (greenVal)
|
||||
{
|
||||
if (greenVal) {
|
||||
int num = yyjson_get_int(greenVal);
|
||||
if (num < 0 || num > 100)
|
||||
{
|
||||
if (num < 0 || num > 100) {
|
||||
fputs("Error: usage: percent.green must be between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
}
|
||||
@@ -285,11 +260,9 @@ bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageMo
|
||||
}
|
||||
|
||||
yyjson_val* yellowVal = yyjson_obj_get(value, "yellow");
|
||||
if (yellowVal)
|
||||
{
|
||||
if (yellowVal) {
|
||||
int num = yyjson_get_int(yellowVal);
|
||||
if (num < 0 || num > 100)
|
||||
{
|
||||
if (num < 0 || num > 100) {
|
||||
fputs("Error: usage: percent.yellow must be between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
}
|
||||
@@ -297,11 +270,9 @@ bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageMo
|
||||
}
|
||||
|
||||
yyjson_val* typeVal = yyjson_obj_get(value, "type");
|
||||
if (typeVal)
|
||||
{
|
||||
if (typeVal) {
|
||||
const char* error = ffPercentParseTypeJsonConfig(typeVal, &config->type);
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
fputs(error, stderr);
|
||||
exit(480);
|
||||
}
|
||||
@@ -310,8 +281,7 @@ bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageMo
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config)
|
||||
{
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config) {
|
||||
yyjson_mut_val* percent = yyjson_mut_obj_add_obj(doc, module, "percent");
|
||||
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
|
||||
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
|
||||
|
||||
+58
-57
@@ -3,145 +3,146 @@
|
||||
#include "common/textModifier.h"
|
||||
#include "logo/logo.h"
|
||||
|
||||
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType)
|
||||
{
|
||||
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType) {
|
||||
ffLogoPrintLine();
|
||||
|
||||
//This is used by --set-keyless, in this case we want neither the module name nor the separator
|
||||
if(moduleName == NULL)
|
||||
// This is used by --set-keyless, in this case we want neither the module name nor the separator
|
||||
if (moduleName == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
//This is used as a magic value for hiding keys
|
||||
if (!(moduleArgs && ffStrbufEqualS(&moduleArgs->key, " ")) && instance.config.display.keyType != FF_MODULE_KEY_TYPE_NONE)
|
||||
{
|
||||
// This is used as a magic value for hiding keys
|
||||
if (!(moduleArgs && ffStrbufEqualS(&moduleArgs->key, " ")) && instance.config.display.keyType != FF_MODULE_KEY_TYPE_NONE) {
|
||||
ffPrintCharTimes(' ', instance.config.display.keyPaddingLeft);
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
{
|
||||
if (!instance.config.display.pipe) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
if (instance.config.display.brightColor)
|
||||
if (instance.config.display.brightColor) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
|
||||
}
|
||||
|
||||
if(moduleArgs && !(printType & FF_PRINT_TYPE_NO_CUSTOM_KEY_COLOR) && moduleArgs->keyColor.length > 0)
|
||||
if (moduleArgs && !(printType & FF_PRINT_TYPE_NO_CUSTOM_KEY_COLOR) && moduleArgs->keyColor.length > 0) {
|
||||
ffPrintColor(&moduleArgs->keyColor);
|
||||
else
|
||||
} else {
|
||||
ffPrintColor(&instance.config.display.colorKeys);
|
||||
}
|
||||
}
|
||||
|
||||
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_ICON && moduleArgs && moduleArgs->keyIcon.length > 0)
|
||||
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_ICON && moduleArgs && moduleArgs->keyIcon.length > 0) {
|
||||
ffStrbufWriteTo(&moduleArgs->keyIcon, stdout);
|
||||
}
|
||||
|
||||
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_STRING)
|
||||
{
|
||||
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_STRING) {
|
||||
ffPrintCharTimes(' ', instance.config.display.keyType >> FF_MODULE_KEY_TYPE_SPACE_SHIFT);
|
||||
|
||||
//NULL check is required for modules with custom keys, e.g. disk with the folder path
|
||||
if((printType & FF_PRINT_TYPE_NO_CUSTOM_KEY) || !moduleArgs || moduleArgs->key.length == 0)
|
||||
{
|
||||
// NULL check is required for modules with custom keys, e.g. disk with the folder path
|
||||
if ((printType & FF_PRINT_TYPE_NO_CUSTOM_KEY) || !moduleArgs || moduleArgs->key.length == 0) {
|
||||
fputs(moduleName, stdout);
|
||||
|
||||
if(moduleIndex > 0)
|
||||
if (moduleIndex > 0) {
|
||||
printf(" %hhu", moduleIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
} else {
|
||||
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
|
||||
FF_PARSE_FORMAT_STRING_CHECKED(&key, &moduleArgs->key, ((FFformatarg[]) {
|
||||
FF_ARG(moduleIndex, "index"),
|
||||
FF_ARG(moduleArgs->keyIcon, "icon"),
|
||||
}));
|
||||
FF_ARG(moduleIndex, "index"),
|
||||
FF_ARG(moduleArgs->keyIcon, "icon"),
|
||||
}));
|
||||
ffStrbufWriteTo(&key, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
{
|
||||
if (!instance.config.display.pipe) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
ffPrintColor(&instance.config.display.colorSeparator);
|
||||
}
|
||||
|
||||
ffStrbufWriteTo(&instance.config.display.keyValueSeparator, stdout);
|
||||
|
||||
if(!instance.config.display.pipe && instance.config.display.colorSeparator.length)
|
||||
if (!instance.config.display.pipe && instance.config.display.colorSeparator.length) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
}
|
||||
|
||||
if (!(printType & FF_PRINT_TYPE_NO_CUSTOM_KEY_WIDTH))
|
||||
{
|
||||
if (!(printType & FF_PRINT_TYPE_NO_CUSTOM_KEY_WIDTH)) {
|
||||
uint32_t keyWidth = moduleArgs && moduleArgs->keyWidth > 0 ? moduleArgs->keyWidth : instance.config.display.keyWidth;
|
||||
if (keyWidth > 0)
|
||||
if (keyWidth > 0) {
|
||||
printf("\e[%uG", (unsigned) (keyWidth + instance.state.logoWidth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
{
|
||||
if (!instance.config.display.pipe) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
if (moduleArgs && moduleArgs->outputColor.length)
|
||||
if (moduleArgs && moduleArgs->outputColor.length) {
|
||||
ffPrintColor(&moduleArgs->outputColor);
|
||||
else if (instance.config.display.colorOutput.length)
|
||||
} else if (instance.config.display.colorOutput.length) {
|
||||
ffPrintColor(&instance.config.display.colorOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (moduleArgs)
|
||||
if (moduleArgs) {
|
||||
ffParseFormatString(&buffer, &moduleArgs->outputFormat, numArgs, arguments);
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendS(&buffer, "unknown");
|
||||
}
|
||||
|
||||
ffPrintLogoAndKey(moduleName, moduleIndex, moduleArgs, printType);
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
|
||||
{
|
||||
if(!instance.config.display.showErrors)
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...) {
|
||||
if (!instance.config.display.showErrors) {
|
||||
return;
|
||||
}
|
||||
|
||||
ffPrintLogoAndKey(moduleName, moduleIndex, moduleArgs, printType);
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
if (!instance.config.display.pipe) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
|
||||
}
|
||||
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
vprintf(message, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
if (!instance.config.display.pipe) {
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void ffPrintColor(const FFstrbuf* colorValue)
|
||||
{
|
||||
//If the color is not set, this would reset in \033[m, which resets everything.
|
||||
//So we only print it, if the main color is at least one char.
|
||||
if(colorValue->length == 0)
|
||||
void ffPrintColor(const FFstrbuf* colorValue) {
|
||||
// If the color is not set, this would reset in \033[m, which resets everything.
|
||||
// So we only print it, if the main color is at least one char.
|
||||
if (colorValue->length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\e[%sm", colorValue->chars);
|
||||
}
|
||||
|
||||
void ffPrintCharTimes(char c, uint32_t times)
|
||||
{
|
||||
if(times == 0)
|
||||
void ffPrintCharTimes(char c, uint32_t times) {
|
||||
if (times == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(times == 1)
|
||||
{
|
||||
if (times == 1) {
|
||||
putchar(c);
|
||||
return;
|
||||
}
|
||||
|
||||
char str[32];
|
||||
memset(str, c, sizeof(str)); //2 instructions when compiling with AVX2 enabled
|
||||
for(uint32_t i = sizeof(str); i <= times; i += (uint32_t)sizeof(str))
|
||||
memset(str, c, sizeof(str)); // 2 instructions when compiling with AVX2 enabled
|
||||
for (uint32_t i = sizeof(str); i <= times; i += (uint32_t) sizeof(str)) {
|
||||
fwrite(str, 1, sizeof(str), stdout);
|
||||
}
|
||||
uint32_t remaining = times % sizeof(str);
|
||||
if(remaining > 0)
|
||||
if (remaining > 0) {
|
||||
fwrite(str, 1, remaining, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
+291
-276
@@ -13,28 +13,28 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
#if !(__ANDROID__ || __OpenBSD__)
|
||||
#include <spawn.h>
|
||||
# include <spawn.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/sysctl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/user.h>
|
||||
# include <sys/sysctl.h>
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
#include <libproc.h>
|
||||
# include <libproc.h>
|
||||
#elif defined(__sun)
|
||||
#include <procfs.h>
|
||||
# include <procfs.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <kvm.h>
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
# include <kvm.h>
|
||||
#elif defined(__NetBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__HAIKU__)
|
||||
#include <OS.h>
|
||||
#include <image.h>
|
||||
# include <OS.h>
|
||||
# include <image.h>
|
||||
#endif
|
||||
|
||||
#ifndef environ
|
||||
@@ -43,31 +43,30 @@ extern char** environ;
|
||||
|
||||
enum { FF_PIPE_BUFSIZ = 8192 };
|
||||
|
||||
static inline int ffPipe2(int* fds, int flags)
|
||||
{
|
||||
#ifndef FF_HAVE_PIPE2
|
||||
if(pipe(fds) == -1)
|
||||
return -1;
|
||||
fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | flags);
|
||||
fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | flags);
|
||||
return 0;
|
||||
#else
|
||||
return pipe2(fds, flags);
|
||||
#endif
|
||||
static inline int ffPipe2(int* fds, int flags) {
|
||||
#ifndef FF_HAVE_PIPE2
|
||||
if (pipe(fds) == -1) {
|
||||
return -1;
|
||||
}
|
||||
fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | flags);
|
||||
fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | flags);
|
||||
return 0;
|
||||
#else
|
||||
return pipe2(fds, flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Not thread-safe
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
|
||||
{
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle) {
|
||||
int pipes[2];
|
||||
if(ffPipe2(pipes, O_CLOEXEC) == -1)
|
||||
if (ffPipe2(pipes, O_CLOEXEC) == -1) {
|
||||
return "pipe() failed";
|
||||
}
|
||||
|
||||
pid_t childPid = -1;
|
||||
int nullFile = ffGetNullFD();
|
||||
|
||||
#if !(__ANDROID__ || __OpenBSD__)
|
||||
#if !(__ANDROID__ || __OpenBSD__)
|
||||
|
||||
// NetBSD / Darwin: native syscall
|
||||
// Linux (glibc): clone3-execve
|
||||
@@ -83,33 +82,29 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
static char* oldLang = NULL;
|
||||
static int langIndex = -1;
|
||||
|
||||
if (langIndex >= 0)
|
||||
{
|
||||
if (langIndex >= 0) {
|
||||
// Found before
|
||||
if (oldLang) // oldLang was set only if it needed to be changed
|
||||
{
|
||||
if (environ[langIndex] != oldLang)
|
||||
{
|
||||
if (environ[langIndex] != oldLang) {
|
||||
// environ is changed outside of this function
|
||||
langIndex = -1;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
environ[langIndex] = (char*) "LANG=C.UTF-8";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (langIndex < 0)
|
||||
{
|
||||
for (int i = 0; environ[i] != NULL; i++)
|
||||
{
|
||||
if (ffStrStartsWith(environ[i], "LANG="))
|
||||
{
|
||||
if (langIndex < 0) {
|
||||
for (int i = 0; environ[i] != NULL; i++) {
|
||||
if (ffStrStartsWith(environ[i], "LANG=")) {
|
||||
langIndex = i;
|
||||
const char* langValue = environ[i] + 5; // Skip "LANG="
|
||||
if (ffStrEqualsIgnCase(langValue, "C") ||
|
||||
ffStrStartsWithIgnCase(environ[i], "C.") ||
|
||||
ffStrEqualsIgnCase(langValue, "en_US") ||
|
||||
ffStrStartsWithIgnCase(langValue, "en_US."))
|
||||
ffStrStartsWithIgnCase(langValue, "en_US.")) {
|
||||
break; // No need to change LANG
|
||||
}
|
||||
oldLang = environ[i];
|
||||
environ[i] = (char*) "LANG=C.UTF-8"; // Set LANG to C.UTF-8 for consistent output
|
||||
break;
|
||||
@@ -119,33 +114,32 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
|
||||
int ret = posix_spawnp(&childPid, argv[0], &file_actions, NULL, argv, environ);
|
||||
|
||||
if (oldLang)
|
||||
if (oldLang) {
|
||||
environ[langIndex] = oldLang;
|
||||
}
|
||||
|
||||
posix_spawn_file_actions_destroy(&file_actions);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
if (ret != 0) {
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
if (ret == ENOENT)
|
||||
if (ret == ENOENT) {
|
||||
return "command not found";
|
||||
}
|
||||
return "posix_spawnp() failed";
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
// https://github.com/termux/termux-packages/issues/25369
|
||||
childPid = fork();
|
||||
if(childPid == -1)
|
||||
{
|
||||
if (childPid == -1) {
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
return "fork() failed";
|
||||
}
|
||||
|
||||
if(childPid == 0)
|
||||
{
|
||||
if (childPid == 0) {
|
||||
// Child process
|
||||
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
|
||||
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
|
||||
@@ -154,7 +148,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
close(pipes[1]);
|
||||
outHandle->pid = childPid;
|
||||
@@ -162,8 +156,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
{
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
|
||||
assert(handle->pipeRead != -1);
|
||||
assert(handle->pid != -1);
|
||||
|
||||
@@ -174,20 +167,15 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
handle->pid = -1;
|
||||
char str[FF_PIPE_BUFSIZ];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (timeout >= 0)
|
||||
{
|
||||
struct pollfd pollfd = { childPipeFd, POLLIN, 0 };
|
||||
for (;;) {
|
||||
if (timeout >= 0) {
|
||||
struct pollfd pollfd = {childPipeFd, POLLIN, 0};
|
||||
int pollret = poll(&pollfd, 1, timeout);
|
||||
if (pollret == 0)
|
||||
{
|
||||
if (pollret == 0) {
|
||||
kill(childPid, SIGTERM);
|
||||
waitpid(childPid, NULL, 0);
|
||||
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
|
||||
}
|
||||
else if (pollret < 0 || (pollfd.revents & POLLERR))
|
||||
{
|
||||
} else if (pollret < 0 || (pollfd.revents & POLLERR)) {
|
||||
kill(childPid, SIGTERM);
|
||||
waitpid(childPid, NULL, 0);
|
||||
return pollret < 0
|
||||
@@ -197,63 +185,65 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
}
|
||||
|
||||
ssize_t nRead = read(childPipeFd, str, FF_PIPE_BUFSIZ);
|
||||
if (nRead > 0)
|
||||
if (nRead > 0) {
|
||||
ffStrbufAppendNS(buffer, (uint32_t) nRead, str);
|
||||
else if (nRead == 0)
|
||||
{
|
||||
} else if (nRead == 0) {
|
||||
int stat_loc = 0;
|
||||
if (childPid > 0 && waitpid(childPid, &stat_loc, 0) == childPid)
|
||||
{
|
||||
if (!WIFEXITED(stat_loc))
|
||||
if (childPid > 0 && waitpid(childPid, &stat_loc, 0) == childPid) {
|
||||
if (!WIFEXITED(stat_loc)) {
|
||||
return "child process exited abnormally";
|
||||
if (WEXITSTATUS(stat_loc) == 127)
|
||||
}
|
||||
if (WEXITSTATUS(stat_loc) == 127) {
|
||||
return "command not found";
|
||||
}
|
||||
// We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c`
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else if (nRead < 0)
|
||||
} else if (nRead < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed";
|
||||
}
|
||||
|
||||
void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath)
|
||||
{
|
||||
void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath) {
|
||||
assert(processName->length > 0);
|
||||
ffStrbufClear(exe);
|
||||
if (exePath) ffStrbufClear(exePath);
|
||||
if (exePath) {
|
||||
ffStrbufClear(exePath);
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__GNU__)
|
||||
#if defined(__linux__) || defined(__GNU__)
|
||||
|
||||
char filePath[64];
|
||||
snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid);
|
||||
snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int) pid);
|
||||
|
||||
if(ffReadFileBuffer(filePath, exe))
|
||||
{
|
||||
if (ffReadFileBuffer(filePath, exe)) {
|
||||
const char* p = exe->chars;
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
|
||||
if (len + 1 < exe->length)
|
||||
{
|
||||
if (len + 1 < exe->length) {
|
||||
const char* name = memrchr(p, '/', len);
|
||||
if (name) name++; else name = p;
|
||||
if (name) {
|
||||
name++;
|
||||
} else {
|
||||
name = p;
|
||||
}
|
||||
|
||||
// For interpreters, try to find the real script path in the arguments
|
||||
if (ffStrStartsWith(name, "python")
|
||||
#ifndef __ANDROID__
|
||||
# ifndef __ANDROID__
|
||||
|| ffStrEquals(name, "guile") // for shepherd
|
||||
#endif
|
||||
)
|
||||
{
|
||||
# endif
|
||||
) {
|
||||
// `cmdline` always ends with a trailing '\0', and ffReadFileBuffer appends another \0
|
||||
// So `exe->chars` is always double '\0' terminated
|
||||
for (p = p + len + 1; *p && *p == '-'; p += strlen(p) + 1) // Skip arguments
|
||||
for (p = p + len + 1; *p && *p == '-'; p += strlen(p) + 1) { // Skip arguments
|
||||
assert(p - exe->chars < exe->allocated);
|
||||
if (*p)
|
||||
{
|
||||
}
|
||||
if (*p) {
|
||||
len = (uint32_t) strlen(p);
|
||||
memmove(exe->chars, p, len + 1);
|
||||
}
|
||||
@@ -262,12 +252,11 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
|
||||
|
||||
assert(len < exe->allocated);
|
||||
exe->length = len;
|
||||
ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash
|
||||
ffStrbufTrimLeft(exe, '-'); // Login shells start with a dash
|
||||
}
|
||||
|
||||
if (exePath)
|
||||
{
|
||||
snprintf(filePath, sizeof(filePath), "/proc/%d/exe", (int)pid);
|
||||
if (exePath) {
|
||||
snprintf(filePath, sizeof(filePath), "/proc/%d/exe", (int) pid);
|
||||
char buf[PATH_MAX];
|
||||
ssize_t length = readlink(filePath, buf, PATH_MAX - 1);
|
||||
if (length > 0) // doesn't contain trailing NUL
|
||||
@@ -275,64 +264,68 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
|
||||
buf[length] = '\0';
|
||||
// When the process is a deleted executable, the resolved path is like `/usr/bin/app (deleted)`
|
||||
// But we can still access the binary via `/proc/pid/exe`. See #2136
|
||||
if (ffPathExists(buf, FF_PATHTYPE_ANY))
|
||||
ffStrbufSetNS(exePath, (uint32_t)length, buf);
|
||||
if (ffPathExists(buf, FF_PATHTYPE_ANY)) {
|
||||
ffStrbufSetNS(exePath, (uint32_t) length, buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (exePath->length == 0)
|
||||
if (exePath->length == 0) {
|
||||
ffStrbufSetS(exePath, filePath);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
size_t len = 0;
|
||||
int mibs[] = { CTL_KERN, KERN_PROCARGS2, pid };
|
||||
if (sysctl(mibs, ARRAY_SIZE(mibs), NULL, &len, NULL, 0) == 0)
|
||||
{// try get arg0
|
||||
//don't know why if don't let len longer, proArgs2 and len will change during the following sysctl() in old MacOS version.
|
||||
int mibs[] = {CTL_KERN, KERN_PROCARGS2, pid};
|
||||
if (sysctl(mibs, ARRAY_SIZE(mibs), NULL, &len, NULL, 0) == 0) { // try get arg0
|
||||
// don't know why if don't let len longer, proArgs2 and len will change during the following sysctl() in old MacOS version.
|
||||
len++;
|
||||
FF_AUTO_FREE char* const procArgs2 = malloc(len);
|
||||
if (sysctl(mibs, ARRAY_SIZE(mibs), procArgs2, &len, NULL, 0) == 0)
|
||||
{
|
||||
if (sysctl(mibs, ARRAY_SIZE(mibs), procArgs2, &len, NULL, 0) == 0) {
|
||||
// https://gist.github.com/nonowarn/770696#file-getargv-c-L46
|
||||
uint32_t argc = *(uint32_t*) procArgs2;
|
||||
const char* realExePath = procArgs2 + sizeof(argc);
|
||||
|
||||
const char* arg0 = memchr(realExePath, '\0', len - (size_t) (realExePath - procArgs2));
|
||||
if (exePath)
|
||||
if (exePath) {
|
||||
ffStrbufSetNS(exePath, (uint32_t) (arg0 - realExePath), realExePath);
|
||||
|
||||
do arg0++; while (*arg0 == '\0');
|
||||
assert(arg0 < procArgs2 + len);
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
// #977
|
||||
const char* p = strrchr(arg0, '/');
|
||||
if (p)
|
||||
p++;
|
||||
else
|
||||
p = arg0;
|
||||
if (ffStrStartsWithIgnCase(p, "python")) // /opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/Resources/Python.app/Contents/MacOS/Python /Users/carter/.local/bin/xonsh
|
||||
arg0 = p + strlen(p) + 1;
|
||||
}
|
||||
|
||||
if (*arg0 == '-') arg0++; // Login shells
|
||||
do {
|
||||
arg0++;
|
||||
} while (*arg0 == '\0');
|
||||
assert(arg0 < procArgs2 + len);
|
||||
|
||||
if (argc > 1) {
|
||||
// #977
|
||||
const char* p = strrchr(arg0, '/');
|
||||
if (p) {
|
||||
p++;
|
||||
} else {
|
||||
p = arg0;
|
||||
}
|
||||
if (ffStrStartsWithIgnCase(p, "python")) { // /opt/homebrew/Cellar/python@3.12/3.12.3/Frameworks/Python.framework/Versions/3.12/Resources/Python.app/Contents/MacOS/Python /Users/carter/.local/bin/xonsh
|
||||
arg0 = p + strlen(p) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (*arg0 == '-') {
|
||||
arg0++; // Login shells
|
||||
}
|
||||
|
||||
ffStrbufSetS(exe, arg0);
|
||||
}
|
||||
}
|
||||
|
||||
if (exePath || exe->length == 0)
|
||||
{
|
||||
if (exePath || exe->length == 0) {
|
||||
char buf[PROC_PIDPATHINFO_MAXSIZE];
|
||||
int length = proc_pidpath(pid, buf, ARRAY_SIZE(buf));
|
||||
if (length > 0)
|
||||
{
|
||||
if (exe->length == 0)
|
||||
if (length > 0) {
|
||||
if (exe->length == 0) {
|
||||
ffStrbufSetNS(exe, (uint32_t) length, buf);
|
||||
if (exePath)
|
||||
{
|
||||
}
|
||||
if (exePath) {
|
||||
// We don't use exec_path above as exePath because it's a relative path and can be different
|
||||
// from the actual executable being run (for example, when the original file is moved)
|
||||
ffStrbufSetNS(exePath, (uint32_t) length, buf);
|
||||
@@ -340,142 +333,159 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
|
||||
size_t size = ARG_MAX;
|
||||
FF_AUTO_FREE char* args = malloc(size);
|
||||
|
||||
static_assert(ARG_MAX > PATH_MAX, "");
|
||||
|
||||
if(exePath && sysctl(
|
||||
(int[]){CTL_KERN,
|
||||
#if __FreeBSD__
|
||||
KERN_PROC, KERN_PROC_PATHNAME, pid
|
||||
#else
|
||||
KERN_PROC_ARGS, pid, KERN_PROC_PATHNAME
|
||||
#endif
|
||||
}, 4,
|
||||
args, &size,
|
||||
NULL, 0
|
||||
) == 0)
|
||||
if (exePath && sysctl((int[]) {CTL_KERN,
|
||||
# if __FreeBSD__
|
||||
KERN_PROC,
|
||||
KERN_PROC_PATHNAME,
|
||||
pid
|
||||
# else
|
||||
KERN_PROC_ARGS,
|
||||
pid,
|
||||
KERN_PROC_PATHNAME
|
||||
# endif
|
||||
},
|
||||
4,
|
||||
args,
|
||||
&size,
|
||||
NULL,
|
||||
0) == 0)
|
||||
ffStrbufSetNS(exePath, (uint32_t) (size - 1), args);
|
||||
|
||||
size = ARG_MAX;
|
||||
if(sysctl(
|
||||
(int[]){CTL_KERN,
|
||||
#if __FreeBSD__
|
||||
KERN_PROC, KERN_PROC_ARGS, pid
|
||||
#else
|
||||
KERN_PROC_ARGS, pid, KERN_PROC_ARGV,
|
||||
#endif
|
||||
}, 4,
|
||||
args, &size,
|
||||
NULL, 0
|
||||
) == 0)
|
||||
{
|
||||
if (sysctl(
|
||||
(int[]) {CTL_KERN,
|
||||
# if __FreeBSD__
|
||||
KERN_PROC,
|
||||
KERN_PROC_ARGS,
|
||||
pid
|
||||
# else
|
||||
KERN_PROC_ARGS,
|
||||
pid,
|
||||
KERN_PROC_ARGV,
|
||||
# endif
|
||||
},
|
||||
4,
|
||||
args,
|
||||
&size,
|
||||
NULL,
|
||||
0) == 0) {
|
||||
char* arg0 = args;
|
||||
size_t arg0Len = strlen(args);
|
||||
if (size > arg0Len + 1)
|
||||
{
|
||||
if (size > arg0Len + 1) {
|
||||
char* p = (char*) memrchr(args, '/', arg0Len);
|
||||
if (p)
|
||||
if (p) {
|
||||
p++;
|
||||
else
|
||||
} else {
|
||||
p = arg0;
|
||||
}
|
||||
if (ffStrStartsWith(p, "python")) // /usr/local/bin/python3.9 /home/carter/.local/bin/xonsh
|
||||
{
|
||||
arg0 += arg0Len + 1;
|
||||
}
|
||||
}
|
||||
if (arg0[0] == '-') arg0++;
|
||||
if (arg0[0] == '-') {
|
||||
arg0++;
|
||||
}
|
||||
ffStrbufSetS(exe, arg0);
|
||||
}
|
||||
|
||||
#elif defined(__sun)
|
||||
#elif defined(__sun)
|
||||
|
||||
char filePath[128];
|
||||
snprintf(filePath, sizeof(filePath), "/proc/%d/psinfo", (int) pid);
|
||||
psinfo_t proc;
|
||||
if (ffReadFileData(filePath, sizeof(proc), &proc) == sizeof(proc))
|
||||
{
|
||||
if (ffReadFileData(filePath, sizeof(proc), &proc) == sizeof(proc)) {
|
||||
const char* args = proc.pr_psargs;
|
||||
if (args[0] == '-') ++args;
|
||||
if (args[0] == '-') {
|
||||
++args;
|
||||
}
|
||||
const char* end = strchr(args, ' ');
|
||||
ffStrbufSetNS(exe, end ? (uint32_t) (end - args) : (uint32_t) strlen(args), args);
|
||||
}
|
||||
|
||||
if (exePath)
|
||||
{
|
||||
if (exePath) {
|
||||
snprintf(filePath, sizeof(filePath), "/proc/%d/path/a.out", (int) pid);
|
||||
char buf[PATH_MAX];
|
||||
ssize_t length = readlink(filePath, buf, PATH_MAX - 1);
|
||||
if (length > 0) // doesn't contain trailing NUL
|
||||
{
|
||||
buf[length] = '\0';
|
||||
ffStrbufSetNS(exePath, (uint32_t)length, buf);
|
||||
ffStrbufSetNS(exePath, (uint32_t) length, buf);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
kvm_t* kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
int count = 0;
|
||||
const struct kinfo_proc* proc = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &count);
|
||||
if (proc)
|
||||
{
|
||||
if (proc) {
|
||||
char** argv = kvm_getargv(kd, proc, 0);
|
||||
if (argv)
|
||||
{
|
||||
if (argv) {
|
||||
const char* arg0 = argv[0];
|
||||
if (arg0[0] == '-') arg0++;
|
||||
if (arg0[0] == '-') {
|
||||
arg0++;
|
||||
}
|
||||
ffStrbufSetS(exe, arg0);
|
||||
}
|
||||
}
|
||||
kvm_close(kd);
|
||||
|
||||
#elif defined(__HAIKU__)
|
||||
#elif defined(__HAIKU__)
|
||||
|
||||
image_info info;
|
||||
int32 cookie = 0;
|
||||
|
||||
while (get_next_image_info(pid, &cookie, &info) == B_OK)
|
||||
{
|
||||
if (info.type != B_APP_IMAGE) continue;
|
||||
while (get_next_image_info(pid, &cookie, &info) == B_OK) {
|
||||
if (info.type != B_APP_IMAGE) {
|
||||
continue;
|
||||
}
|
||||
ffStrbufSetS(exe, info.name);
|
||||
|
||||
if (exePath)
|
||||
if (exePath) {
|
||||
ffStrbufSet(exePath, exe);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(exe->length == 0)
|
||||
if (exe->length == 0) {
|
||||
ffStrbufSet(exe, processName);
|
||||
}
|
||||
|
||||
assert(exe->length > 0);
|
||||
uint32_t lastSlashIndex = ffStrbufLastIndexC(exe, '/');
|
||||
if(lastSlashIndex < exe->length)
|
||||
if (lastSlashIndex < exe->length) {
|
||||
*exeName = exe->chars + lastSlashIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, int32_t* tty)
|
||||
{
|
||||
if (pid <= 0)
|
||||
const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, int32_t* tty) {
|
||||
if (pid <= 0) {
|
||||
return "Invalid pid";
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__GNU__)
|
||||
#if defined(__linux__) || defined(__GNU__)
|
||||
|
||||
char procFilePath[64];
|
||||
#if __linux__
|
||||
# if __linux__
|
||||
if (ppid || tty)
|
||||
#endif
|
||||
# endif
|
||||
{
|
||||
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/stat", (int)pid);
|
||||
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/stat", (int) pid);
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData(procFilePath, sizeof(buf) - 1, buf);
|
||||
if(nRead <= 8)
|
||||
if (nRead <= 8) {
|
||||
return "ffReadFileData(/proc/pid/stat, PROC_FILE_BUFFSIZ-1, buf) failed";
|
||||
}
|
||||
buf[nRead] = '\0'; // pid (comm) state ppid pgrp session tty
|
||||
|
||||
const char* pState = NULL;
|
||||
@@ -483,175 +493,180 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
|
||||
{
|
||||
// comm in `/proc/pid/stat` is not encoded, and may contain ' ', ')' or even `\n`
|
||||
const char* start = memchr(buf, '(', (size_t) nRead);
|
||||
if (!start)
|
||||
if (!start) {
|
||||
return "memchr(stat, '(') failed";
|
||||
}
|
||||
start++;
|
||||
const char* end = memrchr(start, ')', (size_t) nRead - (size_t) (start - buf));
|
||||
if (!end)
|
||||
if (!end) {
|
||||
return "memrchr(stat, ')') failed";
|
||||
}
|
||||
ffStrbufSetNS(name, (uint32_t) (end - start), start);
|
||||
ffStrbufTrimRightSpace(name);
|
||||
if (name->chars[0] == '\0')
|
||||
if (name->chars[0] == '\0') {
|
||||
return "process name is empty";
|
||||
}
|
||||
pState = end + 2; // skip ") "
|
||||
}
|
||||
|
||||
#if !__linux__
|
||||
# if !__linux__
|
||||
if (ppid || tty)
|
||||
#endif
|
||||
# endif
|
||||
{
|
||||
int ppid_, tty_;
|
||||
if(sscanf(pState + 2, "%d %*d %*d %d", &ppid_, &tty_) < 2)
|
||||
if (sscanf(pState + 2, "%d %*d %*d %d", &ppid_, &tty_) < 2) {
|
||||
return "sscanf(stat) failed";
|
||||
}
|
||||
|
||||
if (ppid)
|
||||
if (ppid) {
|
||||
*ppid = (pid_t) ppid_;
|
||||
if (tty)
|
||||
}
|
||||
if (tty) {
|
||||
*tty = tty_ & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
#if __linux__
|
||||
else
|
||||
{
|
||||
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/comm", (int)pid);
|
||||
# if __linux__
|
||||
else {
|
||||
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/comm", (int) pid);
|
||||
ssize_t nRead = ffReadFileBuffer(procFilePath, name);
|
||||
if(nRead <= 0)
|
||||
if (nRead <= 0) {
|
||||
return "ffReadFileBuffer(/proc/pid/comm, name) failed";
|
||||
}
|
||||
ffStrbufTrimRightSpace(name);
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
struct kinfo_proc proc;
|
||||
size_t size = sizeof(proc);
|
||||
if(sysctl(
|
||||
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4,
|
||||
&proc, &size,
|
||||
NULL, 0
|
||||
))
|
||||
if (sysctl(
|
||||
(int[]) {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4, &proc, &size, NULL, 0)) {
|
||||
return "sysctl(KERN_PROC_PID) failed";
|
||||
}
|
||||
|
||||
ffStrbufSetS(name, proc.kp_proc.p_comm); //trancated to 16 chars
|
||||
if (ppid)
|
||||
*ppid = (pid_t)proc.kp_eproc.e_ppid;
|
||||
if (tty)
|
||||
{
|
||||
ffStrbufSetS(name, proc.kp_proc.p_comm); // trancated to 16 chars
|
||||
if (ppid) {
|
||||
*ppid = (pid_t) proc.kp_eproc.e_ppid;
|
||||
}
|
||||
if (tty) {
|
||||
*tty = ((proc.kp_eproc.e_tdev >> 24) & 0xFF) == 0x10
|
||||
? proc.kp_eproc.e_tdev & 0xFFFFFF
|
||||
: -1;
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
#ifdef __DragonFly__
|
||||
#define ki_comm kp_comm
|
||||
#define ki_ppid kp_ppid
|
||||
#define ki_tdev kp_tdev
|
||||
#define ki_flag kp_flags
|
||||
#endif
|
||||
# ifdef __DragonFly__
|
||||
# define ki_comm kp_comm
|
||||
# define ki_ppid kp_ppid
|
||||
# define ki_tdev kp_tdev
|
||||
# define ki_flag kp_flags
|
||||
# endif
|
||||
|
||||
struct kinfo_proc proc;
|
||||
size_t size = sizeof(proc);
|
||||
if(sysctl(
|
||||
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4,
|
||||
&proc, &size,
|
||||
NULL, 0
|
||||
))
|
||||
if (sysctl(
|
||||
(int[]) {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4, &proc, &size, NULL, 0)) {
|
||||
return "sysctl(KERN_PROC_PID) failed";
|
||||
|
||||
ffStrbufSetS(name, proc.ki_comm);
|
||||
if (ppid)
|
||||
*ppid = (pid_t)proc.ki_ppid;
|
||||
if (tty)
|
||||
{
|
||||
if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT)
|
||||
{
|
||||
const char* ttyName = devname(proc.ki_tdev, S_IFCHR);
|
||||
if (ffStrStartsWith(ttyName, "pts/"))
|
||||
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
|
||||
else
|
||||
*tty = -1;
|
||||
}
|
||||
else
|
||||
*tty = -1;
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
ffStrbufSetS(name, proc.ki_comm);
|
||||
if (ppid) {
|
||||
*ppid = (pid_t) proc.ki_ppid;
|
||||
}
|
||||
if (tty) {
|
||||
if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT) {
|
||||
const char* ttyName = devname(proc.ki_tdev, S_IFCHR);
|
||||
if (ffStrStartsWith(ttyName, "pts/")) {
|
||||
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
|
||||
} else {
|
||||
*tty = -1;
|
||||
}
|
||||
} else {
|
||||
*tty = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
|
||||
struct kinfo_proc2 proc;
|
||||
size_t size = sizeof(proc);
|
||||
if(sysctl(
|
||||
(int[]){CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid, sizeof(proc), 1}, 6,
|
||||
&proc, &size,
|
||||
NULL, 0
|
||||
) != 0)
|
||||
if (sysctl(
|
||||
(int[]) {CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid, sizeof(proc), 1}, 6, &proc, &size, NULL, 0) != 0) {
|
||||
return "sysctl(KERN_PROC_PID) failed";
|
||||
|
||||
ffStrbufSetS(name, proc.p_comm);
|
||||
if (ppid)
|
||||
*ppid = (pid_t)proc.p_ppid;
|
||||
if (tty)
|
||||
{
|
||||
if (proc.p_flag & P_CONTROLT)
|
||||
{
|
||||
const char* ttyName = devname(proc.p_tdev, S_IFCHR);
|
||||
if (ffStrStartsWith(ttyName, "pts/"))
|
||||
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
|
||||
else
|
||||
*tty = -1;
|
||||
}
|
||||
else
|
||||
*tty = -1;
|
||||
}
|
||||
|
||||
#elif defined(__sun)
|
||||
ffStrbufSetS(name, proc.p_comm);
|
||||
if (ppid) {
|
||||
*ppid = (pid_t) proc.p_ppid;
|
||||
}
|
||||
if (tty) {
|
||||
if (proc.p_flag & P_CONTROLT) {
|
||||
const char* ttyName = devname(proc.p_tdev, S_IFCHR);
|
||||
if (ffStrStartsWith(ttyName, "pts/")) {
|
||||
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
|
||||
} else {
|
||||
*tty = -1;
|
||||
}
|
||||
} else {
|
||||
*tty = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__sun)
|
||||
char path[128];
|
||||
snprintf(path, sizeof(path), "/proc/%d/psinfo", (int) pid);
|
||||
psinfo_t proc;
|
||||
if (ffReadFileData(path, sizeof(proc), &proc) != sizeof(proc))
|
||||
if (ffReadFileData(path, sizeof(proc), &proc) != sizeof(proc)) {
|
||||
return "ffReadFileData(psinfo) failed";
|
||||
}
|
||||
|
||||
ffStrbufSetS(name, proc.pr_fname);
|
||||
if (ppid)
|
||||
if (ppid) {
|
||||
*ppid = proc.pr_ppid;
|
||||
if (tty)
|
||||
}
|
||||
if (tty) {
|
||||
*tty = (int) proc.pr_ttydev;
|
||||
}
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__)
|
||||
|
||||
kvm_t* kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
int count = 0;
|
||||
const struct kinfo_proc* proc = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &count);
|
||||
if (proc)
|
||||
{
|
||||
if (proc) {
|
||||
ffStrbufSetS(name, proc->p_comm);
|
||||
if (ppid)
|
||||
if (ppid) {
|
||||
*ppid = proc->p_ppid;
|
||||
if (tty)
|
||||
}
|
||||
if (tty) {
|
||||
*tty = (int) proc->p_tdev;
|
||||
}
|
||||
}
|
||||
kvm_close(kd);
|
||||
if (!proc)
|
||||
if (!proc) {
|
||||
return "kvm_getprocs() failed";
|
||||
}
|
||||
|
||||
#elif defined(__HAIKU__)
|
||||
#elif defined(__HAIKU__)
|
||||
|
||||
team_info info;
|
||||
if (get_team_info(pid, &info) == B_OK)
|
||||
{
|
||||
if (get_team_info(pid, &info) == B_OK) {
|
||||
ffStrbufSetS(name, info.name);
|
||||
if (ppid)
|
||||
if (ppid) {
|
||||
*ppid = info.parent;
|
||||
}
|
||||
}
|
||||
|
||||
FF_UNUSED(tty);
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
return "Unsupported platform";
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -11,45 +11,44 @@
|
||||
|
||||
enum { FF_PIPE_BUFSIZ = 8192 };
|
||||
|
||||
static void argvToCmdline(char* const argv[], FFstrbuf* result)
|
||||
{
|
||||
static void argvToCmdline(char* const argv[], FFstrbuf* result) {
|
||||
// From https://gist.github.com/jin-x/cdd641d98887524b091fb1f82a68717d
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY temp = ffStrbufCreate();
|
||||
for (int i = 0; argv[i] != NULL; i++)
|
||||
{
|
||||
for (int i = 0; argv[i] != NULL; i++) {
|
||||
ffStrbufSetS(&temp, argv[i]);
|
||||
// Add slash (\) before double quotes (") and duplicate slashes before it
|
||||
for (
|
||||
uint32_t pos = ffStrbufFirstIndexC(&temp, '"'), cnt;
|
||||
pos != temp.length;
|
||||
pos = ffStrbufNextIndexC(&temp, pos + cnt * 2, '"')
|
||||
) {
|
||||
pos = ffStrbufNextIndexC(&temp, pos + cnt * 2, '"')) {
|
||||
cnt = 1;
|
||||
while (pos > 0 && temp.chars[pos - 1] == '\\') { ++cnt, --pos; }
|
||||
ffStrbufInsertNC(&temp, pos, cnt, '\\');
|
||||
}
|
||||
|
||||
// Add quotes around string if whitespace chars are present (with slash duplicating at the end of string)
|
||||
if (ffStrbufFirstIndexS(&temp, " \t") != temp.length)
|
||||
{
|
||||
if (ffStrbufFirstIndexS(&temp, " \t") != temp.length) {
|
||||
uint32_t pos = temp.length;
|
||||
uint32_t cnt = 0;
|
||||
while (pos > 0 && temp.chars[pos - 1] == '\\') { ++cnt, --pos; }
|
||||
if (cnt > 0) ffStrbufAppendNC(&temp, cnt, '\\');
|
||||
if (cnt > 0) {
|
||||
ffStrbufAppendNC(&temp, cnt, '\\');
|
||||
}
|
||||
ffStrbufPrependC(&temp, '"');
|
||||
ffStrbufAppendC(&temp, '"');
|
||||
}
|
||||
|
||||
// Add space delimiter
|
||||
if (i > 0) ffStrbufAppendC(result, ' ');
|
||||
if (i > 0) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
ffStrbufAppend(result, &temp);
|
||||
ffStrbufClear(&temp);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
|
||||
{
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle) {
|
||||
const int32_t timeout = instance.config.general.processingTimeout;
|
||||
|
||||
wchar_t pipeName[32];
|
||||
@@ -64,39 +63,36 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
FF_PIPE_BUFSIZ,
|
||||
FF_PIPE_BUFSIZ,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
if (hChildPipeRead == INVALID_HANDLE_VALUE)
|
||||
NULL);
|
||||
if (hChildPipeRead == INVALID_HANDLE_VALUE) {
|
||||
return "CreateNamedPipeW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
|
||||
}
|
||||
|
||||
HANDLE hChildPipeWrite = CreateFileW(
|
||||
pipeName,
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
&(SECURITY_ATTRIBUTES){
|
||||
&(SECURITY_ATTRIBUTES) {
|
||||
.nLength = sizeof(SECURITY_ATTRIBUTES),
|
||||
.lpSecurityDescriptor = NULL,
|
||||
.bInheritHandle = TRUE,
|
||||
},
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
if (hChildPipeWrite == INVALID_HANDLE_VALUE)
|
||||
NULL);
|
||||
if (hChildPipeWrite == INVALID_HANDLE_VALUE) {
|
||||
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION piProcInfo = {};
|
||||
STARTUPINFOW siStartInfo = {
|
||||
.cb = sizeof(siStartInfo),
|
||||
.dwFlags = STARTF_USESTDHANDLES,
|
||||
};
|
||||
if (useStdErr)
|
||||
{
|
||||
if (useStdErr) {
|
||||
siStartInfo.hStdOutput = ffGetNullFD();
|
||||
siStartInfo.hStdError = hChildPipeWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
siStartInfo.hStdOutput = hChildPipeWrite;
|
||||
siStartInfo.hStdError = ffGetNullFD();
|
||||
}
|
||||
@@ -107,52 +103,51 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
|
||||
argvToCmdline(argv, &buf);
|
||||
uint32_t cmdlineBytes = (buf.length + 1) * sizeof(wchar_t);
|
||||
cmdline = malloc(cmdlineBytes);
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, NULL, buf.chars, buf.length + 1)))
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, NULL, buf.chars, buf.length + 1))) {
|
||||
return "RtlUTF8ToUnicodeN() failed";
|
||||
}
|
||||
}
|
||||
|
||||
BOOL success = CreateProcessW(
|
||||
NULL, // application name
|
||||
cmdline, // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
NULL, // use parent's environment
|
||||
NULL, // use parent's current directory
|
||||
&siStartInfo, // STARTUPINFO pointer
|
||||
&piProcInfo // receives PROCESS_INFORMATION
|
||||
NULL, // application name
|
||||
cmdline, // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
NULL, // use parent's environment
|
||||
NULL, // use parent's current directory
|
||||
&siStartInfo, // STARTUPINFO pointer
|
||||
&piProcInfo // receives PROCESS_INFORMATION
|
||||
);
|
||||
|
||||
NtClose(hChildPipeWrite);
|
||||
if(!success)
|
||||
{
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
if (!success) {
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
return "command not found";
|
||||
}
|
||||
return "CreateProcessW() failed";
|
||||
}
|
||||
|
||||
NtClose(piProcInfo.hThread); // we don't need the thread handle
|
||||
outHandle->pid = piProcInfo.hProcess;
|
||||
outHandle->pipeRead = hChildPipeRead;
|
||||
outHandle->pid = piProcInfo.hProcess;
|
||||
outHandle->pipeRead = hChildPipeRead;
|
||||
hChildPipeRead = INVALID_HANDLE_VALUE; // ownership transferred, don't close it
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void terminateChildProcess(HANDLE hProcess, HANDLE hChildPipeRead, HANDLE hReadEvent, IO_STATUS_BLOCK* piosb)
|
||||
{
|
||||
static void terminateChildProcess(HANDLE hProcess, HANDLE hChildPipeRead, HANDLE hReadEvent, IO_STATUS_BLOCK* piosb) {
|
||||
IO_STATUS_BLOCK cancelIosb = {};
|
||||
if (NT_SUCCESS(NtCancelIoFileEx(hChildPipeRead, piosb, &cancelIosb)))
|
||||
{
|
||||
if (hReadEvent)
|
||||
NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) { .QuadPart = -100000 }); // wait for cancellation to complete
|
||||
if (NT_SUCCESS(NtCancelIoFileEx(hChildPipeRead, piosb, &cancelIosb))) {
|
||||
if (hReadEvent) {
|
||||
NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) {.QuadPart = -100000}); // wait for cancellation to complete
|
||||
}
|
||||
}
|
||||
NtTerminateProcess(hProcess, 1);
|
||||
}
|
||||
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
{
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
|
||||
assert(handle->pipeRead != INVALID_HANDLE_VALUE);
|
||||
assert(handle->pid != INVALID_HANDLE_VALUE);
|
||||
|
||||
@@ -163,14 +158,14 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
handle->pid = INVALID_HANDLE_VALUE;
|
||||
handle->pipeRead = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (timeout >= 0 && !NT_SUCCESS(NtCreateEvent(&hReadEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))
|
||||
if (timeout >= 0 && !NT_SUCCESS(NtCreateEvent(&hReadEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) {
|
||||
return "NtCreateEvent() failed";
|
||||
}
|
||||
|
||||
char str[FF_PIPE_BUFSIZ];
|
||||
uint32_t nRead = 0;
|
||||
IO_STATUS_BLOCK iosb = {};
|
||||
do
|
||||
{
|
||||
do {
|
||||
NTSTATUS status = NtReadFile(
|
||||
hChildPipeRead,
|
||||
hReadEvent,
|
||||
@@ -180,33 +175,29 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
str,
|
||||
(ULONG) sizeof(str),
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (status == STATUS_PENDING)
|
||||
{
|
||||
switch (NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 }))
|
||||
{
|
||||
case STATUS_WAIT_0:
|
||||
status = iosb.Status;
|
||||
break;
|
||||
NULL);
|
||||
if (status == STATUS_PENDING) {
|
||||
switch (NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) {.QuadPart = (int64_t) timeout * -10000})) {
|
||||
case STATUS_WAIT_0:
|
||||
status = iosb.Status;
|
||||
break;
|
||||
|
||||
case STATUS_TIMEOUT:
|
||||
{
|
||||
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
|
||||
return "NtReadFile(hChildPipeRead) timed out";
|
||||
}
|
||||
case STATUS_TIMEOUT: {
|
||||
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
|
||||
return "NtReadFile(hChildPipeRead) timed out";
|
||||
}
|
||||
|
||||
default:
|
||||
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
|
||||
return "NtWaitForSingleObject(hReadEvent) failed";
|
||||
default:
|
||||
terminateChildProcess(hProcess, hChildPipeRead, hReadEvent, &iosb);
|
||||
return "NtWaitForSingleObject(hReadEvent) failed";
|
||||
}
|
||||
}
|
||||
|
||||
if (status == STATUS_PIPE_BROKEN || status == STATUS_END_OF_FILE)
|
||||
if (status == STATUS_PIPE_BROKEN || status == STATUS_END_OF_FILE) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (!NT_SUCCESS(status)) {
|
||||
terminateChildProcess(hProcess, hChildPipeRead, NULL, &iosb);
|
||||
return "NtReadFile(hChildPipeRead) failed";
|
||||
}
|
||||
@@ -215,81 +206,75 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
ffStrbufAppendNS(buffer, nRead, str);
|
||||
} while (nRead > 0);
|
||||
|
||||
exit:
|
||||
{
|
||||
PROCESS_BASIC_INFORMATION info = {};
|
||||
ULONG size;
|
||||
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
|
||||
{
|
||||
assert(size == sizeof(info));
|
||||
if (info.ExitStatus != STILL_ACTIVE && info.ExitStatus != 0)
|
||||
return "Child process exited with an error";
|
||||
exit: {
|
||||
PROCESS_BASIC_INFORMATION info = {};
|
||||
ULONG size;
|
||||
if (NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size))) {
|
||||
assert(size == sizeof(info));
|
||||
if (info.ExitStatus != STILL_ACTIVE && info.ExitStatus != 0) {
|
||||
return "Child process exited with an error";
|
||||
}
|
||||
else
|
||||
return "NtQueryInformationProcess(ProcessBasicInformation) failed";
|
||||
} else {
|
||||
return "NtQueryInformationProcess(ProcessBasicInformation) failed";
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui)
|
||||
{
|
||||
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui) {
|
||||
FF_AUTO_CLOSE_FD HANDLE hProcess = NtCurrentProcess();
|
||||
if(pid != 0)
|
||||
{
|
||||
if (pid != 0) {
|
||||
if (!NT_SUCCESS(NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
}, &(CLIENT_ID) { .UniqueProcess = (HANDLE)(uintptr_t) pid })))
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
},
|
||||
&(CLIENT_ID) {.UniqueProcess = (HANDLE) (uintptr_t) pid}))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(ppid)
|
||||
{
|
||||
if (ppid) {
|
||||
PROCESS_BASIC_INFORMATION info = {};
|
||||
ULONG size;
|
||||
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
|
||||
{
|
||||
if (NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size))) {
|
||||
assert(size == sizeof(info));
|
||||
*ppid = (uint32_t)info.InheritedFromUniqueProcessId;
|
||||
}
|
||||
else
|
||||
*ppid = (uint32_t) info.InheritedFromUniqueProcessId;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(exe)
|
||||
{
|
||||
if (exe) {
|
||||
// TODO: It's possible to query the command line with `NtQueryInformationProcess(60/*ProcessCommandLineInformation*/)` since Windows 8.1
|
||||
|
||||
alignas(UNICODE_STRING) uint8_t buffer[4096];
|
||||
ULONG size;
|
||||
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, &buffer, sizeof(buffer), &size)))
|
||||
{
|
||||
UNICODE_STRING* imagePath = (UNICODE_STRING*)buffer;
|
||||
if (NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, &buffer, sizeof(buffer), &size))) {
|
||||
UNICODE_STRING* imagePath = (UNICODE_STRING*) buffer;
|
||||
ffStrbufSetNWS(exe, imagePath->Length / sizeof(wchar_t), imagePath->Buffer);
|
||||
|
||||
if (exePath) ffStrbufSet(exePath, exe);
|
||||
if (exePath) {
|
||||
ffStrbufSet(exePath, exe);
|
||||
}
|
||||
|
||||
if (pname && exeName)
|
||||
{
|
||||
if (pname && exeName) {
|
||||
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
|
||||
ffStrbufSetS(pname, *exeName);
|
||||
}
|
||||
}
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (gui)
|
||||
{
|
||||
if (gui) {
|
||||
SECTION_IMAGE_INFORMATION info = {};
|
||||
ULONG size;
|
||||
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageInformation, &info, sizeof(info), &size)))
|
||||
{
|
||||
if (NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageInformation, &info, sizeof(info), &size))) {
|
||||
assert(size == sizeof(info));
|
||||
*gui = info.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -6,61 +6,63 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#ifdef _WIN32
|
||||
#include "common/windows/getline.h"
|
||||
# include "common/windows/getline.h"
|
||||
#endif
|
||||
|
||||
bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
if(**line == '\0')
|
||||
bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer) {
|
||||
if (**line == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Skip any amount of whitespace at the begin of line
|
||||
while(**line == ' ' || **line == '\t')
|
||||
// Skip any amount of whitespace at the begin of line
|
||||
while (**line == ' ' || **line == '\t') {
|
||||
++(*line);
|
||||
}
|
||||
|
||||
while(*start != '\0')
|
||||
{
|
||||
while (*start != '\0') {
|
||||
// Any amount of whitespace in the format string matches any amount of whitespace in the line, even none
|
||||
if(*start == ' ' || *start == '\t')
|
||||
{
|
||||
while(*start == ' ' || *start == '\t')
|
||||
if (*start == ' ' || *start == '\t') {
|
||||
while (*start == ' ' || *start == '\t') {
|
||||
++start;
|
||||
}
|
||||
|
||||
while(**line == ' ' || **line == '\t')
|
||||
while (**line == ' ' || **line == '\t') {
|
||||
++(*line);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Line doesn't match start, skip it
|
||||
if(tolower(**line) != tolower(*start) || **line == '\0')
|
||||
// Line doesn't match start, skip it
|
||||
if (tolower(**line) != tolower(*start) || **line == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Line and start match, continue testing
|
||||
// Line and start match, continue testing
|
||||
++(*line);
|
||||
++start;
|
||||
}
|
||||
|
||||
char valueEnd = '\n';
|
||||
|
||||
//Allow faster parsing of XML
|
||||
if(*(*line - 1) == '>')
|
||||
// Allow faster parsing of XML
|
||||
if (*(*line - 1) == '>') {
|
||||
valueEnd = '<';
|
||||
}
|
||||
|
||||
//Skip any amount of whitespace at the begin of the value
|
||||
while(**line == ' ' || **line == '\t')
|
||||
// Skip any amount of whitespace at the begin of the value
|
||||
while (**line == ' ' || **line == '\t') {
|
||||
++(*line);
|
||||
}
|
||||
|
||||
//Allow faster parsing of quotet values
|
||||
if(**line == '"' || **line == '\'')
|
||||
{
|
||||
// Allow faster parsing of quotet values
|
||||
if (**line == '"' || **line == '\'') {
|
||||
valueEnd = **line;
|
||||
++(*line);
|
||||
}
|
||||
|
||||
//Copy the value to the buffer
|
||||
while(**line != valueEnd && **line != '\n' && **line != '\0')
|
||||
{
|
||||
// Copy the value to the buffer
|
||||
while (**line != valueEnd && **line != '\n' && **line != '\0') {
|
||||
ffStrbufAppendC(buffer, **line);
|
||||
++(*line);
|
||||
}
|
||||
@@ -70,17 +72,17 @@ bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buff
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
while(!ffParsePropLinePointer(&lines, start, buffer))
|
||||
{
|
||||
while(*lines != '\0' && *lines != '\n')
|
||||
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer) {
|
||||
while (!ffParsePropLinePointer(&lines, start, buffer)) {
|
||||
while (*lines != '\0' && *lines != '\n') {
|
||||
++lines;
|
||||
}
|
||||
|
||||
if(*lines == '\0')
|
||||
if (*lines == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Skip '\n'
|
||||
// Skip '\n'
|
||||
++lines;
|
||||
}
|
||||
|
||||
@@ -91,81 +93,79 @@ bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer)
|
||||
// Buffers which already contain content are not overwritten
|
||||
// The last occurrence of start in the first file will be the one used
|
||||
|
||||
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries) {
|
||||
FF_AUTO_CLOSE_FILE FILE* file = fopen(filename, "r");
|
||||
if (file == NULL)
|
||||
if (file == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool valueStorage[32];
|
||||
bool* unsetValues = valueStorage;
|
||||
|
||||
if (numQueries > ARRAY_SIZE(valueStorage))
|
||||
if (numQueries > ARRAY_SIZE(valueStorage)) {
|
||||
unsetValues = malloc(sizeof(bool) * numQueries);
|
||||
|
||||
bool allSet = true;
|
||||
for (uint32_t i = 0; i < numQueries; i++)
|
||||
{
|
||||
unsetValues[i] = queries[i].buffer->length == 0;
|
||||
if (unsetValues[i])
|
||||
allSet = false;
|
||||
}
|
||||
|
||||
if (!allSet)
|
||||
{
|
||||
bool allSet = true;
|
||||
for (uint32_t i = 0; i < numQueries; i++) {
|
||||
unsetValues[i] = queries[i].buffer->length == 0;
|
||||
if (unsetValues[i]) {
|
||||
allSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allSet) {
|
||||
FF_AUTO_FREE char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
while (getline(&line, &len, file) != -1)
|
||||
{
|
||||
for(uint32_t i = 0; i < numQueries; i++)
|
||||
{
|
||||
if(!unsetValues[i])
|
||||
while (getline(&line, &len, file) != -1) {
|
||||
for (uint32_t i = 0; i < numQueries; i++) {
|
||||
if (!unsetValues[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t currentLength = queries[i].buffer->length;
|
||||
queries[i].buffer->length = 0;
|
||||
if(!ffParsePropLine(line, queries[i].start, queries[i].buffer))
|
||||
if (!ffParsePropLine(line, queries[i].start, queries[i].buffer)) {
|
||||
queries[i].buffer->length = currentLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(unsetValues != valueStorage)
|
||||
if (unsetValues != valueStorage) {
|
||||
free(unsetValues);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffParsePropFileHomeValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
bool ffParsePropFileHomeValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries) {
|
||||
FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateF("%s/%s", instance.state.platform.homeDir.chars, relativeFile);
|
||||
return ffParsePropFileValues(absolutePath.chars, numQueries, queries);
|
||||
}
|
||||
|
||||
bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uint32_t numQueries, FFpropquery* queries) {
|
||||
bool foundAFile = false;
|
||||
|
||||
FF_LIST_FOR_EACH(FFstrbuf, dirPrefix, *list)
|
||||
{
|
||||
FF_LIST_FOR_EACH (FFstrbuf, dirPrefix, *list) {
|
||||
const uint32_t dirPrefixLength = dirPrefix->length;
|
||||
ffStrbufAppendS(dirPrefix, relativeFile);
|
||||
if(ffParsePropFileValues(dirPrefix->chars, numQueries, queries))
|
||||
if (ffParsePropFileValues(dirPrefix->chars, numQueries, queries)) {
|
||||
foundAFile = true;
|
||||
}
|
||||
ffStrbufSubstrBefore(dirPrefix, dirPrefixLength);
|
||||
|
||||
bool allSet = true;
|
||||
for(uint32_t k = 0; k < numQueries; k++)
|
||||
{
|
||||
if(queries[k].buffer->length == 0)
|
||||
{
|
||||
for (uint32_t k = 0; k < numQueries; k++) {
|
||||
if (queries[k].buffer->length == 0) {
|
||||
allSet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(allSet)
|
||||
if (allSet) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundAFile;
|
||||
|
||||
+145
-155
@@ -7,39 +7,38 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifdef FF_HAVE_GIO
|
||||
#include <gio/gio.h>
|
||||
# include <gio/gio.h>
|
||||
|
||||
typedef struct GVariantGetters
|
||||
{
|
||||
typedef struct GVariantGetters {
|
||||
FF_LIBRARY_SYMBOL(g_variant_dup_string)
|
||||
FF_LIBRARY_SYMBOL(g_variant_get_boolean)
|
||||
FF_LIBRARY_SYMBOL(g_variant_get_int32)
|
||||
FF_LIBRARY_SYMBOL(g_variant_unref)
|
||||
} GVariantGetters;
|
||||
|
||||
static FFvariant getGVariantValue(GVariant* variant, FFvarianttype type, const GVariantGetters* variantGetters)
|
||||
{
|
||||
static FFvariant getGVariantValue(GVariant* variant, FFvarianttype type, const GVariantGetters* variantGetters) {
|
||||
FFvariant result;
|
||||
|
||||
if(variant == NULL)
|
||||
if (variant == NULL) {
|
||||
result = FF_VARIANT_NULL;
|
||||
else if(type == FF_VARIANT_TYPE_STRING)
|
||||
} else if (type == FF_VARIANT_TYPE_STRING) {
|
||||
result = (FFvariant) {.strValue = variantGetters->ffg_variant_dup_string(variant, NULL)}; // Dup string, so that variant itself can be freed
|
||||
else if(type == FF_VARIANT_TYPE_BOOL)
|
||||
} else if (type == FF_VARIANT_TYPE_BOOL) {
|
||||
result = (FFvariant) {.boolValue = (bool) variantGetters->ffg_variant_get_boolean(variant), .boolValueSet = true};
|
||||
else if(type == FF_VARIANT_TYPE_INT)
|
||||
} else if (type == FF_VARIANT_TYPE_INT) {
|
||||
result = (FFvariant) {.intValue = variantGetters->ffg_variant_get_int32(variant)};
|
||||
else
|
||||
} else {
|
||||
result = FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(variant)
|
||||
if (variant) {
|
||||
variantGetters->ffg_variant_unref(variant);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct GSettingsData
|
||||
{
|
||||
typedef struct GSettingsData {
|
||||
FF_LIBRARY_SYMBOL(g_settings_schema_source_lookup)
|
||||
FF_LIBRARY_SYMBOL(g_settings_schema_has_key)
|
||||
FF_LIBRARY_SYMBOL(g_settings_new_full)
|
||||
@@ -53,12 +52,10 @@ typedef struct GSettingsData
|
||||
bool inited;
|
||||
} GSettingsData;
|
||||
|
||||
static const GSettingsData* getGSettingsData(void)
|
||||
{
|
||||
static const GSettingsData* getGSettingsData(void) {
|
||||
static GSettingsData data;
|
||||
|
||||
if (!data.inited)
|
||||
{
|
||||
if (!data.inited) {
|
||||
data.inited = true;
|
||||
FF_LIBRARY_LOAD(libgsettings, NULL, "libgio-2.0" FF_LIBRARY_EXTENSION, 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_schema_source_lookup, NULL)
|
||||
@@ -75,56 +72,61 @@ static const GSettingsData* getGSettingsData(void)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_unref, NULL);
|
||||
|
||||
data.schemaSource = data.ffg_settings_schema_source_get_default();
|
||||
if (data.schemaSource)
|
||||
if (data.schemaSource) {
|
||||
libgsettings = NULL;
|
||||
}
|
||||
}
|
||||
if(!data.schemaSource)
|
||||
if (!data.schemaSource) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &data;
|
||||
}
|
||||
|
||||
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type)
|
||||
{
|
||||
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type) {
|
||||
const GSettingsData* data = getGSettingsData();
|
||||
if(data == NULL)
|
||||
if (data == NULL) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
GSettingsSchema* schema = data->ffg_settings_schema_source_lookup(data->schemaSource, schemaName, true);
|
||||
if(schema == NULL)
|
||||
if (schema == NULL) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(data->ffg_settings_schema_has_key(schema, key) == false)
|
||||
if (data->ffg_settings_schema_has_key(schema, key) == false) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
GSettings* settings = data->ffg_settings_new_full(schema, NULL, path);
|
||||
if(settings == NULL)
|
||||
if (settings == NULL) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
GVariant* variant = data->ffg_settings_get_value(settings, key);
|
||||
if(variant != NULL)
|
||||
if (variant != NULL) {
|
||||
return getGVariantValue(variant, type, &data->variantGetters);
|
||||
}
|
||||
|
||||
variant = data->ffg_settings_get_user_value(settings, key);
|
||||
if(variant != NULL)
|
||||
if (variant != NULL) {
|
||||
return getGVariantValue(variant, type, &data->variantGetters);
|
||||
}
|
||||
|
||||
variant = data->ffg_settings_get_default_value(settings, key);
|
||||
return getGVariantValue(variant, type, &data->variantGetters);
|
||||
}
|
||||
#else //FF_HAVE_GIO
|
||||
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type)
|
||||
{
|
||||
#else // FF_HAVE_GIO
|
||||
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type) {
|
||||
FF_UNUSED(schemaName, path, key, type)
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#endif //FF_HAVE_GIO
|
||||
#endif // FF_HAVE_GIO
|
||||
|
||||
#ifdef FF_HAVE_DCONF
|
||||
#include <dconf.h>
|
||||
# include <dconf.h>
|
||||
|
||||
typedef struct DConfData
|
||||
{
|
||||
typedef struct DConfData {
|
||||
FF_LIBRARY_SYMBOL(dconf_client_read_full)
|
||||
FF_LIBRARY_SYMBOL(dconf_client_new)
|
||||
GVariantGetters variantGetters;
|
||||
@@ -133,12 +135,10 @@ typedef struct DConfData
|
||||
bool inited;
|
||||
} DConfData;
|
||||
|
||||
static const DConfData* getDConfData(void)
|
||||
{
|
||||
static const DConfData* getDConfData(void) {
|
||||
static DConfData data;
|
||||
|
||||
if (!data.inited)
|
||||
{
|
||||
if (!data.inited) {
|
||||
data.inited = true;
|
||||
|
||||
FF_LIBRARY_LOAD(libdconf, NULL, "libdconf" FF_LIBRARY_EXTENSION, 2);
|
||||
@@ -150,127 +150,124 @@ static const DConfData* getDConfData(void)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_unref, NULL)
|
||||
|
||||
data.client = data.ffdconf_client_new();
|
||||
if (data.client)
|
||||
if (data.client) {
|
||||
libdconf = NULL;
|
||||
}
|
||||
}
|
||||
if(!data.client)
|
||||
if (!data.client) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &data;
|
||||
}
|
||||
|
||||
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type)
|
||||
{
|
||||
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type) {
|
||||
const DConfData* data = getDConfData();
|
||||
if(data == NULL)
|
||||
if (data == NULL) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
GVariant* variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_FLAGS_NONE, NULL);
|
||||
if(variant != NULL)
|
||||
if (variant != NULL) {
|
||||
return getGVariantValue(variant, type, &data->variantGetters);
|
||||
}
|
||||
|
||||
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_USER_VALUE, NULL);
|
||||
if(variant != NULL)
|
||||
if (variant != NULL) {
|
||||
return getGVariantValue(variant, type, &data->variantGetters);
|
||||
}
|
||||
|
||||
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_DEFAULT_VALUE, NULL);
|
||||
return getGVariantValue(variant, type, &data->variantGetters);
|
||||
}
|
||||
#else //FF_HAVE_DCONF
|
||||
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type)
|
||||
{
|
||||
#else // FF_HAVE_DCONF
|
||||
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type) {
|
||||
FF_UNUSED(key, type)
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#endif //FF_HAVE_DCONF
|
||||
#endif // FF_HAVE_DCONF
|
||||
|
||||
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
|
||||
{
|
||||
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type) {
|
||||
FFvariant gsettings = ffSettingsGetGSettings(gsettingsSchemaName, gsettingsPath, gsettingsKey, type);
|
||||
|
||||
if(
|
||||
if (
|
||||
(type == FF_VARIANT_TYPE_BOOL && gsettings.boolValueSet) ||
|
||||
(type != FF_VARIANT_TYPE_BOOL && gsettings.strValue != NULL)
|
||||
) return gsettings;
|
||||
(type != FF_VARIANT_TYPE_BOOL && gsettings.strValue != NULL)) {
|
||||
return gsettings;
|
||||
}
|
||||
|
||||
return ffSettingsGetDConf(dconfKey, type);
|
||||
}
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
# include "common/dbus.h"
|
||||
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
|
||||
{
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type) {
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetProperty", channelName, propertyName);
|
||||
if(!reply)
|
||||
if (!reply) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
if (!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_INT)
|
||||
{
|
||||
if (type == FF_VARIANT_TYPE_INT) {
|
||||
int32_t value;
|
||||
if (ffDBusGetInt(&dbus, &rootIterator, &value))
|
||||
{
|
||||
if (ffDBusGetInt(&dbus, &rootIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .intValue = value };
|
||||
return (FFvariant) {.intValue = value};
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_STRING)
|
||||
{
|
||||
if (type == FF_VARIANT_TYPE_STRING) {
|
||||
FFstrbuf value = ffStrbufCreate();
|
||||
if (ffDBusGetString(&dbus, &rootIterator, &value))
|
||||
{
|
||||
if (ffDBusGetString(&dbus, &rootIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
|
||||
return (FFvariant) {.strValue = value.chars}; // Leaks value.chars
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_BOOL)
|
||||
{
|
||||
if (type == FF_VARIANT_TYPE_BOOL) {
|
||||
bool value;
|
||||
if (ffDBusGetBool(&dbus, &rootIterator, &value))
|
||||
{
|
||||
if (ffDBusGetBool(&dbus, &rootIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .boolValue = value, .boolValueSet = true };
|
||||
return (FFvariant) {.boolValue = value, .boolValueSet = true};
|
||||
}
|
||||
}
|
||||
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \
|
||||
{ \
|
||||
if(!(dbus).lib->ffdbus_message_iter_next(iterator)) \
|
||||
break; \
|
||||
continue; \
|
||||
# define FF_DBUS_ITER_CONTINUE(dbus, iterator) \
|
||||
{ \
|
||||
if (!(dbus).lib->ffdbus_message_iter_next(iterator)) \
|
||||
break; \
|
||||
continue; \
|
||||
}
|
||||
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb) {
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
|
||||
{
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
|
||||
return FF_VARIANT_NULL;
|
||||
|
||||
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetAllProperties", channelName, propertyPrefix);
|
||||
if(!reply)
|
||||
if (!reply) {
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
if (!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
@@ -278,10 +275,10 @@ FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* pro
|
||||
DBusMessageIter arrayIterator;
|
||||
dbus.lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
|
||||
while (true) {
|
||||
if (dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) {
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
|
||||
}
|
||||
|
||||
DBusMessageIter dictIterator;
|
||||
dbus.lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator);
|
||||
@@ -289,38 +286,34 @@ FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* pro
|
||||
const char* key;
|
||||
dbus.lib->ffdbus_message_iter_get_basic(&dictIterator, &key);
|
||||
|
||||
if (cb(data, key)) FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
|
||||
if (cb(data, key)) {
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
|
||||
}
|
||||
dbus.lib->ffdbus_message_iter_next(&dictIterator);
|
||||
|
||||
if(type == FF_VARIANT_TYPE_INT)
|
||||
{
|
||||
if (type == FF_VARIANT_TYPE_INT) {
|
||||
int32_t value;
|
||||
if (ffDBusGetInt(&dbus, &dictIterator, &value))
|
||||
{
|
||||
if (ffDBusGetInt(&dbus, &dictIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .intValue = value };
|
||||
return (FFvariant) {.intValue = value};
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_STRING)
|
||||
{
|
||||
if (type == FF_VARIANT_TYPE_STRING) {
|
||||
FFstrbuf value = ffStrbufCreate();
|
||||
if (ffDBusGetString(&dbus, &dictIterator, &value))
|
||||
{
|
||||
if (ffDBusGetString(&dbus, &dictIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
|
||||
return (FFvariant) {.strValue = value.chars}; // Leaks value.chars
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_BOOL)
|
||||
{
|
||||
if (type == FF_VARIANT_TYPE_BOOL) {
|
||||
bool value;
|
||||
if (ffDBusGetBool(&dbus, &dictIterator, &value))
|
||||
{
|
||||
if (ffDBusGetBool(&dbus, &dictIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .boolValue = value, .boolValueSet = true };
|
||||
return (FFvariant) {.boolValue = value, .boolValueSet = true};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,24 +322,21 @@ FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* pro
|
||||
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#else //FF_HAVE_DBUS
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
|
||||
{
|
||||
#else // FF_HAVE_DBUS
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type) {
|
||||
FF_UNUSED(channelName, propertyName, type)
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
|
||||
{
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb) {
|
||||
FF_UNUSED(channelName, propertyPrefix, type, data, cb);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#endif //FF_HAVE_DBUS
|
||||
#endif // FF_HAVE_DBUS
|
||||
|
||||
#ifdef FF_HAVE_SQLITE3
|
||||
#include <sqlite3.h>
|
||||
# include <sqlite3.h>
|
||||
|
||||
typedef struct SQLiteData
|
||||
{
|
||||
typedef struct SQLiteData {
|
||||
FF_LIBRARY_SYMBOL(sqlite3_open_v2)
|
||||
FF_LIBRARY_SYMBOL(sqlite3_prepare_v2)
|
||||
FF_LIBRARY_SYMBOL(sqlite3_step)
|
||||
@@ -359,12 +349,10 @@ typedef struct SQLiteData
|
||||
bool inited;
|
||||
} SQLiteData;
|
||||
|
||||
static const SQLiteData* getSQLiteData(void)
|
||||
{
|
||||
static const SQLiteData* getSQLiteData(void) {
|
||||
static SQLiteData data;
|
||||
|
||||
if (!data.inited)
|
||||
{
|
||||
if (!data.inited) {
|
||||
data.inited = true;
|
||||
FF_LIBRARY_LOAD(libsqlite, NULL, "libsqlite3" FF_LIBRARY_EXTENSION, 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_open_v2, NULL)
|
||||
@@ -378,34 +366,35 @@ static const SQLiteData* getSQLiteData(void)
|
||||
libsqlite = NULL;
|
||||
}
|
||||
|
||||
if (!data.ffsqlite3_close)
|
||||
if (!data.ffsqlite3_close) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &data;
|
||||
}
|
||||
|
||||
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query)
|
||||
{
|
||||
if(!ffPathExists(dbPath, FF_PATHTYPE_FILE))
|
||||
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query) {
|
||||
if (!ffPathExists(dbPath, FF_PATHTYPE_FILE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const SQLiteData* data = getSQLiteData();
|
||||
if(data == NULL)
|
||||
if (data == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sqlite3* db;
|
||||
if(data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
|
||||
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
if(data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, NULL) != SQLITE_OK)
|
||||
{
|
||||
if (data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, NULL) != SQLITE_OK) {
|
||||
data->ffsqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(data->ffsqlite3_step(stmt) != SQLITE_ROW || data->ffsqlite3_data_count(stmt) < 1)
|
||||
{
|
||||
if (data->ffsqlite3_step(stmt) != SQLITE_ROW || data->ffsqlite3_data_count(stmt) < 1) {
|
||||
data->ffsqlite3_finalize(stmt);
|
||||
data->ffsqlite3_close(db);
|
||||
return 0;
|
||||
@@ -419,71 +408,72 @@ int ffSettingsGetSQLite3Int(const char* dbPath, const char* query)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result)
|
||||
{
|
||||
if(!ffPathExists(dbPath, FF_PATHTYPE_FILE))
|
||||
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result) {
|
||||
if (!ffPathExists(dbPath, FF_PATHTYPE_FILE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const SQLiteData* data = getSQLiteData();
|
||||
if(data == NULL)
|
||||
if (data == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3* db;
|
||||
if(data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
|
||||
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
if(data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, NULL) != SQLITE_OK)
|
||||
{
|
||||
if (data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, NULL) != SQLITE_OK) {
|
||||
data->ffsqlite3_close(db);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data->ffsqlite3_step(stmt) != SQLITE_ROW || data->ffsqlite3_data_count(stmt) < 1)
|
||||
{
|
||||
if (data->ffsqlite3_step(stmt) != SQLITE_ROW || data->ffsqlite3_data_count(stmt) < 1) {
|
||||
data->ffsqlite3_finalize(stmt);
|
||||
data->ffsqlite3_close(db);
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufSetS(result, (const char *) data->ffsqlite3_column_text(stmt, 0));
|
||||
ffStrbufSetS(result, (const char*) data->ffsqlite3_column_text(stmt, 0));
|
||||
|
||||
data->ffsqlite3_finalize(stmt);
|
||||
data->ffsqlite3_close(db);
|
||||
|
||||
return true;
|
||||
}
|
||||
#else //FF_HAVE_SQLITE3
|
||||
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query)
|
||||
{
|
||||
#else // FF_HAVE_SQLITE3
|
||||
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query) {
|
||||
FF_UNUSED(dbPath, query)
|
||||
return 0;
|
||||
}
|
||||
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result)
|
||||
{
|
||||
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result) {
|
||||
FF_UNUSED(dbPath, query, result)
|
||||
return false;
|
||||
}
|
||||
#endif //FF_HAVE_SQLITE3
|
||||
#endif // FF_HAVE_SQLITE3
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <sys/system_properties.h>
|
||||
# include <sys/system_properties.h>
|
||||
bool ffSettingsGetAndroidProperty(const char* propName, FFstrbuf* result) {
|
||||
ffStrbufEnsureFree(result, PROP_VALUE_MAX);
|
||||
int len = __system_property_get(propName, result->chars + result->length);
|
||||
if (len <= 0) return false;
|
||||
if (len <= 0) {
|
||||
return false;
|
||||
}
|
||||
result->length += (uint32_t) len;
|
||||
result->chars[result->length] = '\0';
|
||||
return true;
|
||||
}
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <kenv.h>
|
||||
bool ffSettingsGetFreeBSDKenv(const char* propName, FFstrbuf* result)
|
||||
{
|
||||
//https://wiki.ghostbsd.org/index.php/Kenv
|
||||
# include <kenv.h>
|
||||
bool ffSettingsGetFreeBSDKenv(const char* propName, FFstrbuf* result) {
|
||||
// https://wiki.ghostbsd.org/index.php/Kenv
|
||||
ffStrbufEnsureFree(result, KENV_MVALLEN);
|
||||
int len = kenv(KENV_GET, propName, result->chars + result->length, KENV_MVALLEN);
|
||||
if (len <= 1) return false; // number of bytes copied, including NUL terminator
|
||||
if (len <= 1) {
|
||||
return false; // number of bytes copied, including NUL terminator
|
||||
}
|
||||
result->length += (uint32_t) len - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
+9
-11
@@ -2,32 +2,30 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes)
|
||||
{
|
||||
static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes) {
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
double size = (double) bytes;
|
||||
uint8_t counter = 0;
|
||||
|
||||
while(size >= base && counter < options->sizeMaxPrefix && prefixes[counter + 1])
|
||||
{
|
||||
while (size >= base && counter < options->sizeMaxPrefix && prefixes[counter + 1]) {
|
||||
size /= base;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter == 0)
|
||||
if (counter == 0) {
|
||||
ffStrbufAppendUInt(result, bytes);
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits, true);
|
||||
if (options->sizeSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER)
|
||||
}
|
||||
if (options->sizeSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER) {
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
ffStrbufAppendS(result, prefixes[counter]);
|
||||
}
|
||||
|
||||
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result)
|
||||
{
|
||||
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result) {
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
switch (options->sizeBinaryPrefix)
|
||||
{
|
||||
switch (options->sizeBinaryPrefix) {
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
|
||||
appendNum(result, bytes, 1024, (const char*[]) {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL});
|
||||
break;
|
||||
|
||||
+159
-184
@@ -4,11 +4,9 @@
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
bool ffIsSmbiosValueSet(FFstrbuf* value)
|
||||
{
|
||||
bool ffIsSmbiosValueSet(FFstrbuf* value) {
|
||||
ffStrbufTrimRightSpace(value);
|
||||
return
|
||||
value->length > 0 &&
|
||||
return value->length > 0 &&
|
||||
!ffStrbufStartsWithIgnCaseS(value, "To be filled") &&
|
||||
!ffStrbufStartsWithIgnCaseS(value, "To be set") &&
|
||||
!ffStrbufStartsWithIgnCaseS(value, "OEM") &&
|
||||
@@ -36,43 +34,36 @@ bool ffIsSmbiosValueSet(FFstrbuf* value)
|
||||
!ffStrbufIgnCaseEqualS(value, "Standard") && ({
|
||||
// Some SMBIOS implementations use "0x0000" to indicate an unset value, even for strings.
|
||||
bool zero = ffStrbufStartsWithS(value, "0x0");
|
||||
if (zero)
|
||||
{
|
||||
for (size_t i = 2; i < value->length; i++)
|
||||
{
|
||||
if (zero) {
|
||||
for (size_t i = 2; i < value->length; i++) {
|
||||
char c = value->chars[i];
|
||||
if (c != '0')
|
||||
{
|
||||
if (c != '0') {
|
||||
zero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
!zero;
|
||||
})
|
||||
;
|
||||
});
|
||||
}
|
||||
|
||||
static bool smbiosTableInitialized = false;
|
||||
static FFSmbiosHeaderTable smbiosTable;
|
||||
|
||||
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header)
|
||||
{
|
||||
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header) {
|
||||
const char* p = ((const char*) header) + header->Length;
|
||||
if (*p)
|
||||
{
|
||||
do
|
||||
if (*p) {
|
||||
do {
|
||||
p += strlen(p) + 1;
|
||||
while (*p);
|
||||
} while (*p);
|
||||
} else { // The terminator is always double 0 even if there is no string
|
||||
p++;
|
||||
}
|
||||
else // The terminator is always double 0 even if there is no string
|
||||
p ++;
|
||||
|
||||
return (const FFSmbiosHeader*) (p + 1);
|
||||
}
|
||||
|
||||
static bool parseSmbiosTable(const uint8_t* data, uint32_t length)
|
||||
{
|
||||
static bool parseSmbiosTable(const uint8_t* data, uint32_t length) {
|
||||
const FFSmbiosHeader* endOfTable = NULL;
|
||||
|
||||
FF_DEBUG("Parsing SMBIOS table structures with length %u bytes", length);
|
||||
@@ -80,52 +71,49 @@ static bool parseSmbiosTable(const uint8_t* data, uint32_t length)
|
||||
for (
|
||||
const FFSmbiosHeader* header = (const FFSmbiosHeader*) data;
|
||||
(const uint8_t*) header + sizeof(FFSmbiosHeader) < (const uint8_t*) data + length;
|
||||
header = ffSmbiosNextEntry(header)
|
||||
)
|
||||
{
|
||||
header = ffSmbiosNextEntry(header)) {
|
||||
++totalCount;
|
||||
endOfTable = header;
|
||||
|
||||
// This doesn't verify the entire structure (e.g. string section can still be truncated),
|
||||
// but at least ensures the formatted section is valid and prevents infinite loops
|
||||
// when the table is severely malformed.
|
||||
if (__builtin_expect((const uint8_t*) header + header->Length > (const uint8_t*) data + length, false))
|
||||
{
|
||||
if (__builtin_expect((const uint8_t*) header + header->Length > (const uint8_t*) data + length, false)) {
|
||||
FF_DEBUG("Truncated SMBIOS structure at offset 0x%lx: length %u is too small",
|
||||
(unsigned long)((const uint8_t*) header - data), header->Length);
|
||||
(unsigned long) ((const uint8_t*) header - data),
|
||||
header->Length);
|
||||
break;
|
||||
}
|
||||
|
||||
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE)
|
||||
{
|
||||
if (!smbiosTable[header->Type])
|
||||
{
|
||||
if (header->Type < FF_SMBIOS_TYPE_END_OF_TABLE) {
|
||||
if (!smbiosTable[header->Type]) {
|
||||
smbiosTable[header->Type] = header;
|
||||
FF_DEBUG("Found SMBIOS structure type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
header->Type,
|
||||
header->Handle,
|
||||
header->Length);
|
||||
structureCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_DEBUG("Duplicate SMBIOS structure type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
header->Type,
|
||||
header->Handle,
|
||||
header->Length);
|
||||
}
|
||||
}
|
||||
else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE)
|
||||
{
|
||||
} else if (header->Type == FF_SMBIOS_TYPE_END_OF_TABLE) {
|
||||
FF_DEBUG("Reached SMBIOS end of type %u, handle 0x%04X, length %u",
|
||||
header->Type, header->Handle, header->Length);
|
||||
header->Type,
|
||||
header->Handle,
|
||||
header->Length);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_DEBUG("Found custom SMBIOS structure type %u, handle 0x%04X, length %u; ignoring",
|
||||
header->Type, header->Handle, header->Length);
|
||||
header->Type,
|
||||
header->Handle,
|
||||
header->Length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!endOfTable)
|
||||
{
|
||||
if (!endOfTable) {
|
||||
FF_DEBUG("No SMBIOS structures found in table");
|
||||
return false;
|
||||
}
|
||||
@@ -140,60 +128,58 @@ static bool parseSmbiosTable(const uint8_t* data, uint32_t length)
|
||||
}
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined(__HAIKU__) || defined(__OpenBSD__) || defined(__GNU__)
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stddef.h>
|
||||
# include <fcntl.h>
|
||||
# include <sys/stat.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/mman.h>
|
||||
# include <stddef.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include "common/properties.h"
|
||||
#elif defined(__FreeBSD__)
|
||||
#include "common/settings.h"
|
||||
#define loff_t off_t // FreeBSD doesn't have loff_t
|
||||
#elif defined(__sun)
|
||||
#define loff_t off_t
|
||||
#elif defined(__NetBSD__)
|
||||
#include "common/sysctl.h"
|
||||
#define loff_t off_t
|
||||
#endif
|
||||
# ifdef __linux__
|
||||
# include "common/properties.h"
|
||||
# elif defined(__FreeBSD__)
|
||||
# include "common/settings.h"
|
||||
# define loff_t off_t // FreeBSD doesn't have loff_t
|
||||
# elif defined(__sun)
|
||||
# define loff_t off_t
|
||||
# elif defined(__NetBSD__)
|
||||
# include "common/sysctl.h"
|
||||
# define loff_t off_t
|
||||
# endif
|
||||
|
||||
#ifdef __linux__
|
||||
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer)
|
||||
{
|
||||
# ifdef __linux__
|
||||
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer) {
|
||||
// /sys/class/dmi/id/* are all pseudo-files with very small content
|
||||
// so reading the whole file at once is efficient
|
||||
ffStrbufEnsureFixedLengthFree(buffer, 127);
|
||||
|
||||
ssize_t len = ffReadFileData(devicesPath, buffer->allocated - 1, buffer->chars);
|
||||
if (len > 0)
|
||||
{
|
||||
if (len > 0) {
|
||||
assert(len < buffer->allocated);
|
||||
buffer->chars[len] = '\0';
|
||||
buffer->length = (uint32_t) len;
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
if (ffIsSmbiosValueSet(buffer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
len = ffReadFileData(classPath, buffer->allocated - 1, buffer->chars);
|
||||
if (len > 0)
|
||||
{
|
||||
if (len > 0) {
|
||||
assert(len < buffer->allocated);
|
||||
buffer->chars[len] = '\0';
|
||||
buffer->length = (uint32_t) len;
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
if(ffIsSmbiosValueSet(buffer))
|
||||
if (ffIsSmbiosValueSet(buffer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufClear(buffer);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
typedef struct FFSmbios20EntryPoint
|
||||
{
|
||||
typedef struct FFSmbios20EntryPoint {
|
||||
uint8_t AnchorString[4];
|
||||
uint8_t EntryPointStructureChecksum;
|
||||
uint8_t EntryPointLength;
|
||||
@@ -212,8 +198,7 @@ typedef struct FFSmbios20EntryPoint
|
||||
static_assert(offsetof(FFSmbios20EntryPoint, SmbiosBcdRevision) == 0x1E,
|
||||
"FFSmbios20EntryPoint: Wrong struct alignment");
|
||||
|
||||
typedef struct FFSmbios30EntryPoint
|
||||
{
|
||||
typedef struct FFSmbios30EntryPoint {
|
||||
uint8_t AnchorString[5];
|
||||
uint8_t EntryPointStructureChecksum;
|
||||
uint8_t EntryPointLength;
|
||||
@@ -229,38 +214,35 @@ typedef struct FFSmbios30EntryPoint
|
||||
static_assert(offsetof(FFSmbios30EntryPoint, StructureTableAddress) == 0x10,
|
||||
"FFSmbios30EntryPoint: Wrong struct alignment");
|
||||
|
||||
typedef union FFSmbiosEntryPoint
|
||||
{
|
||||
typedef union FFSmbiosEntryPoint {
|
||||
FFSmbios20EntryPoint Smbios20;
|
||||
FFSmbios30EntryPoint Smbios30;
|
||||
} FFSmbiosEntryPoint;
|
||||
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
{
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
|
||||
static FFstrbuf buffer;
|
||||
|
||||
if (!smbiosTableInitialized)
|
||||
{
|
||||
if (!smbiosTableInitialized) {
|
||||
smbiosTableInitialized = true;
|
||||
FF_DEBUG("Initializing SMBIOS buffer");
|
||||
ffStrbufInit(&buffer);
|
||||
#if !__HAIKU__ && !__OpenBSD__ && !__DragonFly__ && !__GNU__
|
||||
#ifdef __linux__
|
||||
# if !__HAIKU__ && !__OpenBSD__ && !__DragonFly__ && !__GNU__
|
||||
# ifdef __linux__
|
||||
FF_DEBUG("Using Linux implementation - trying /sys/firmware/dmi/tables/DMI");
|
||||
if (!ffAppendFileBuffer("/sys/firmware/dmi/tables/DMI", &buffer))
|
||||
#endif
|
||||
# endif
|
||||
{
|
||||
#if !defined(__sun) && !defined(__NetBSD__)
|
||||
# if !defined(__sun) && !defined(__NetBSD__)
|
||||
FF_DEBUG("Using memory-mapped implementation");
|
||||
FF_STRBUF_AUTO_DESTROY strEntryAddress = ffStrbufCreate();
|
||||
#ifdef __FreeBSD__
|
||||
# ifdef __FreeBSD__
|
||||
FF_DEBUG("Using FreeBSD kenv implementation");
|
||||
if (!ffSettingsGetFreeBSDKenv("hint.smbios.0.mem", &strEntryAddress)) {
|
||||
FF_DEBUG("Failed to get SMBIOS address from FreeBSD kenv");
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Got SMBIOS address from kenv: %s", strEntryAddress.chars);
|
||||
#elif defined(__linux__)
|
||||
# elif defined(__linux__)
|
||||
{
|
||||
FF_DEBUG("Using Linux EFI systab implementation");
|
||||
FF_STRBUF_AUTO_DESTROY systab = ffStrbufCreate();
|
||||
@@ -275,14 +257,14 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
}
|
||||
FF_DEBUG("Found SMBIOS entry in systab: %s", strEntryAddress.chars);
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
loff_t entryAddress = (loff_t) strtol(strEntryAddress.chars, NULL, 16);
|
||||
if (entryAddress == 0) {
|
||||
FF_DEBUG("Invalid SMBIOS entry address: 0");
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Parsed SMBIOS entry address: 0x%lx", (unsigned long)entryAddress);
|
||||
FF_DEBUG("Parsed SMBIOS entry address: 0x%lx", (unsigned long) entryAddress);
|
||||
|
||||
FF_AUTO_CLOSE_FD int fd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
@@ -293,9 +275,9 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
|
||||
FFSmbiosEntryPoint entryPoint;
|
||||
FF_DEBUG("Attempting to read %zu bytes from physical address 0x%lx",
|
||||
sizeof(entryPoint), (unsigned long)entryAddress);
|
||||
if (pread(fd, &entryPoint, sizeof(entryPoint), entryAddress) < 0x10)
|
||||
{
|
||||
sizeof(entryPoint),
|
||||
(unsigned long) entryAddress);
|
||||
if (pread(fd, &entryPoint, sizeof(entryPoint), entryAddress) < 0x10) {
|
||||
FF_DEBUG("pread failed, trying mmap");
|
||||
// `pread /dev/mem` returns EFAULT in FreeBSD
|
||||
// https://stackoverflow.com/questions/69372330/how-to-read-dev-mem-using-read
|
||||
@@ -310,14 +292,14 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
} else {
|
||||
FF_DEBUG("Successfully read entry point data via pread");
|
||||
}
|
||||
#else
|
||||
# else
|
||||
// Sun or NetBSD
|
||||
FF_DEBUG("Using %s specific implementation",
|
||||
#ifdef __NetBSD__
|
||||
# ifdef __NetBSD__
|
||||
"NetBSD"
|
||||
#else
|
||||
# else
|
||||
"SunOS"
|
||||
#endif
|
||||
# endif
|
||||
);
|
||||
|
||||
FF_AUTO_CLOSE_FD int fd = open("/dev/smbios", O_RDONLY | O_CLOEXEC);
|
||||
@@ -328,80 +310,79 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
FF_DEBUG("/dev/smbios opened successfully with fd=%d", fd);
|
||||
|
||||
FFSmbiosEntryPoint entryPoint;
|
||||
#ifdef __NetBSD__
|
||||
# ifdef __NetBSD__
|
||||
off_t addr = (off_t) ffSysctlGetInt64("machdep.smbios", 0);
|
||||
if (addr == 0) {
|
||||
FF_DEBUG("Failed to get SMBIOS address from sysctl");
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Got SMBIOS address from sysctl: 0x%lx", (unsigned long)addr);
|
||||
FF_DEBUG("Got SMBIOS address from sysctl: 0x%lx", (unsigned long) addr);
|
||||
|
||||
if (pread(fd, &entryPoint, sizeof(entryPoint), addr) < 1) {
|
||||
FF_DEBUG("Failed to read SMBIOS entry point: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Successfully read SMBIOS entry point");
|
||||
#else
|
||||
# else
|
||||
FF_DEBUG("Reading SMBIOS entry point from /dev/smbios");
|
||||
if (ffReadFDData(fd, sizeof(entryPoint), &entryPoint) < 1) {
|
||||
FF_DEBUG("Failed to read SMBIOS entry point: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Successfully read SMBIOS entry point");
|
||||
#endif
|
||||
#endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
uint32_t tableLength = 0;
|
||||
loff_t tableAddress = 0;
|
||||
if (memcmp(entryPoint.Smbios20.AnchorString, "_SM_", sizeof(entryPoint.Smbios20.AnchorString)) == 0)
|
||||
{
|
||||
if (memcmp(entryPoint.Smbios20.AnchorString, "_SM_", sizeof(entryPoint.Smbios20.AnchorString)) == 0) {
|
||||
FF_DEBUG("Found SMBIOS 2.0 entry point");
|
||||
if (entryPoint.Smbios20.EntryPointLength != sizeof(entryPoint.Smbios20)) {
|
||||
FF_DEBUG("Invalid SMBIOS 2.0 entry point length: %u (expected %zu)",
|
||||
entryPoint.Smbios20.EntryPointLength, sizeof(entryPoint.Smbios20));
|
||||
entryPoint.Smbios20.EntryPointLength,
|
||||
sizeof(entryPoint.Smbios20));
|
||||
return NULL;
|
||||
}
|
||||
tableLength = entryPoint.Smbios20.StructureTableLength;
|
||||
tableAddress = (loff_t) entryPoint.Smbios20.StructureTableAddress;
|
||||
FF_DEBUG("SMBIOS 2.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u",
|
||||
tableLength, (unsigned long)tableAddress,
|
||||
entryPoint.Smbios20.SmbiosMajorVersion, entryPoint.Smbios20.SmbiosMinorVersion);
|
||||
}
|
||||
else if (memcmp(entryPoint.Smbios30.AnchorString, "_SM3_", sizeof(entryPoint.Smbios30.AnchorString)) == 0)
|
||||
{
|
||||
tableLength,
|
||||
(unsigned long) tableAddress,
|
||||
entryPoint.Smbios20.SmbiosMajorVersion,
|
||||
entryPoint.Smbios20.SmbiosMinorVersion);
|
||||
} else if (memcmp(entryPoint.Smbios30.AnchorString, "_SM3_", sizeof(entryPoint.Smbios30.AnchorString)) == 0) {
|
||||
FF_DEBUG("Found SMBIOS 3.0 entry point");
|
||||
if (entryPoint.Smbios30.EntryPointLength != sizeof(entryPoint.Smbios30)) {
|
||||
FF_DEBUG("Invalid SMBIOS 3.0 entry point length: %u (expected %zu)",
|
||||
entryPoint.Smbios30.EntryPointLength, sizeof(entryPoint.Smbios30));
|
||||
entryPoint.Smbios30.EntryPointLength,
|
||||
sizeof(entryPoint.Smbios30));
|
||||
return NULL;
|
||||
}
|
||||
tableLength = entryPoint.Smbios30.StructureTableMaximumSize;
|
||||
tableAddress = (loff_t) entryPoint.Smbios30.StructureTableAddress;
|
||||
FF_DEBUG("SMBIOS 3.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u.%u",
|
||||
tableLength, (unsigned long)tableAddress,
|
||||
entryPoint.Smbios30.SmbiosMajorVersion, entryPoint.Smbios30.SmbiosMinorVersion, entryPoint.Smbios30.SmbiosDocrev);
|
||||
}
|
||||
else {
|
||||
tableLength,
|
||||
(unsigned long) tableAddress,
|
||||
entryPoint.Smbios30.SmbiosMajorVersion,
|
||||
entryPoint.Smbios30.SmbiosMinorVersion,
|
||||
entryPoint.Smbios30.SmbiosDocrev);
|
||||
} else {
|
||||
FF_DEBUG("Unknown SMBIOS entry point format");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ffStrbufEnsureFixedLengthFree(&buffer, tableLength);
|
||||
FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long)tableAddress);
|
||||
if (pread(fd, buffer.chars, tableLength, tableAddress) == (ssize_t) tableLength)
|
||||
{
|
||||
FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long) tableAddress);
|
||||
if (pread(fd, buffer.chars, tableLength, tableAddress) == (ssize_t) tableLength) {
|
||||
buffer.length = tableLength;
|
||||
buffer.chars[buffer.length] = '\0';
|
||||
FF_DEBUG("Successfully read SMBIOS table data: %u bytes", tableLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FF_DEBUG("pread failed, trying mmap");
|
||||
// entryPoint.StructureTableAddress must be page aligned.
|
||||
// Unaligned physical memory access results in all kinds of crashes.
|
||||
void* p = mmap(NULL, tableLength, PROT_READ, MAP_SHARED, fd, tableAddress);
|
||||
if (p == MAP_FAILED)
|
||||
{
|
||||
if (p == MAP_FAILED) {
|
||||
FF_DEBUG("mmap failed: %s", strerror(errno));
|
||||
ffStrbufDestroy(&buffer); // free buffer and reset state
|
||||
return NULL;
|
||||
@@ -411,25 +392,26 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
FF_DEBUG("Successfully read SMBIOS table data via mmap: %u bytes", tableLength);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# else
|
||||
{
|
||||
FF_DEBUG("Using %s implementation",
|
||||
#if __HAIKU__
|
||||
# if __HAIKU__
|
||||
"Haiku"
|
||||
#else
|
||||
# else
|
||||
"OpenBSD"
|
||||
#endif
|
||||
# endif
|
||||
);
|
||||
|
||||
uint32_t tableLength = 0;
|
||||
off_t tableAddress = 0;
|
||||
FF_AUTO_CLOSE_FD int fd = open(
|
||||
#if __HAIKU__
|
||||
# if __HAIKU__
|
||||
"/dev/misc/mem"
|
||||
#else
|
||||
# else
|
||||
"/dev/mem" // kern.securelevel must be -1
|
||||
#endif
|
||||
, O_RDONLY | O_CLOEXEC);
|
||||
# endif
|
||||
,
|
||||
O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
FF_DEBUG("Failed to open memory device: %s", strerror(errno));
|
||||
return NULL;
|
||||
@@ -448,37 +430,40 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
}
|
||||
FF_DEBUG("Successfully read 0x10000 bytes from physical address 0xF0000");
|
||||
|
||||
for (off_t offset = 0; offset <= 0xffe0; offset += 0x10)
|
||||
{
|
||||
FFSmbiosEntryPoint* p = (void*)(smBiosBase + offset);
|
||||
if (memcmp(p, "_SM3_", sizeof(p->Smbios30.AnchorString)) == 0)
|
||||
{
|
||||
FF_DEBUG("Found SMBIOS 3.0 entry point at offset 0x%lx", (unsigned long)offset);
|
||||
for (off_t offset = 0; offset <= 0xffe0; offset += 0x10) {
|
||||
FFSmbiosEntryPoint* p = (void*) (smBiosBase + offset);
|
||||
if (memcmp(p, "_SM3_", sizeof(p->Smbios30.AnchorString)) == 0) {
|
||||
FF_DEBUG("Found SMBIOS 3.0 entry point at offset 0x%lx", (unsigned long) offset);
|
||||
if (p->Smbios30.EntryPointLength != sizeof(p->Smbios30)) {
|
||||
FF_DEBUG("Invalid SMBIOS 3.0 entry point length: %u (expected %zu)",
|
||||
p->Smbios30.EntryPointLength, sizeof(p->Smbios30));
|
||||
p->Smbios30.EntryPointLength,
|
||||
sizeof(p->Smbios30));
|
||||
return NULL;
|
||||
}
|
||||
tableLength = p->Smbios30.StructureTableMaximumSize;
|
||||
tableAddress = (off_t) p->Smbios30.StructureTableAddress;
|
||||
FF_DEBUG("SMBIOS 3.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u.%u",
|
||||
tableLength, (unsigned long)tableAddress,
|
||||
p->Smbios30.SmbiosMajorVersion, p->Smbios30.SmbiosMinorVersion, p->Smbios30.SmbiosDocrev);
|
||||
tableLength,
|
||||
(unsigned long) tableAddress,
|
||||
p->Smbios30.SmbiosMajorVersion,
|
||||
p->Smbios30.SmbiosMinorVersion,
|
||||
p->Smbios30.SmbiosDocrev);
|
||||
break;
|
||||
}
|
||||
else if (memcmp(p, "_SM_", sizeof(p->Smbios20.AnchorString)) == 0)
|
||||
{
|
||||
FF_DEBUG("Found SMBIOS 2.0 entry point at offset 0x%lx", (unsigned long)offset);
|
||||
} else if (memcmp(p, "_SM_", sizeof(p->Smbios20.AnchorString)) == 0) {
|
||||
FF_DEBUG("Found SMBIOS 2.0 entry point at offset 0x%lx", (unsigned long) offset);
|
||||
if (p->Smbios20.EntryPointLength != sizeof(p->Smbios20)) {
|
||||
FF_DEBUG("Invalid SMBIOS 2.0 entry point length: %u (expected %zu)",
|
||||
p->Smbios20.EntryPointLength, sizeof(p->Smbios20));
|
||||
p->Smbios20.EntryPointLength,
|
||||
sizeof(p->Smbios20));
|
||||
return NULL;
|
||||
}
|
||||
tableLength = p->Smbios20.StructureTableLength;
|
||||
tableAddress = (off_t) p->Smbios20.StructureTableAddress;
|
||||
FF_DEBUG("SMBIOS 2.0: tableLength=0x%x, tableAddress=0x%lx, version=%u.%u",
|
||||
tableLength, (unsigned long)tableAddress,
|
||||
p->Smbios20.SmbiosMajorVersion, p->Smbios20.SmbiosMinorVersion);
|
||||
tableLength,
|
||||
(unsigned long) tableAddress,
|
||||
p->Smbios20.SmbiosMajorVersion,
|
||||
p->Smbios20.SmbiosMinorVersion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -488,22 +473,21 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
}
|
||||
|
||||
ffStrbufEnsureFixedLengthFree(&buffer, tableLength);
|
||||
FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long)tableAddress);
|
||||
if (pread(fd, buffer.chars, tableLength, tableAddress) == tableLength)
|
||||
{
|
||||
FF_DEBUG("Attempting to read SMBIOS table data: %u bytes at 0x%lx", tableLength, (unsigned long) tableAddress);
|
||||
if (pread(fd, buffer.chars, tableLength, tableAddress) == tableLength) {
|
||||
buffer.length = tableLength;
|
||||
buffer.chars[buffer.length] = '\0';
|
||||
FF_DEBUG("Successfully read SMBIOS table data: %u bytes", tableLength);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
FF_DEBUG("Failed to read SMBIOS table data: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
if (!parseSmbiosTable((const uint8_t*) buffer.chars, buffer.length))
|
||||
if (!parseSmbiosTable((const uint8_t*) buffer.chars, buffer.length)) {
|
||||
ffStrbufClear(&buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer.length == 0) {
|
||||
@@ -514,12 +498,11 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
return &smbiosTable;
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
#include "common/windows/nt.h"
|
||||
# include "common/windows/nt.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmultichar"
|
||||
# pragma GCC diagnostic ignored "-Wmultichar"
|
||||
|
||||
typedef struct FFRawSmbiosData
|
||||
{
|
||||
typedef struct FFRawSmbiosData {
|
||||
uint8_t Used20CallingMethod;
|
||||
uint8_t SMBIOSMajorVersion;
|
||||
uint8_t SMBIOSMinorVersion;
|
||||
@@ -528,12 +511,10 @@ typedef struct FFRawSmbiosData
|
||||
uint8_t SMBIOSTableData[];
|
||||
} FFRawSmbiosData;
|
||||
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
{
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
|
||||
static SYSTEM_FIRMWARE_TABLE_INFORMATION* buffer;
|
||||
|
||||
if (!smbiosTableInitialized)
|
||||
{
|
||||
if (!smbiosTableInitialized) {
|
||||
smbiosTableInitialized = true;
|
||||
FF_DEBUG("Initializing Windows SMBIOS buffer");
|
||||
|
||||
@@ -550,7 +531,8 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
}
|
||||
if (bufSize != sfti.TableBufferLength + (ULONG) sizeof(sfti)) {
|
||||
FF_DEBUG("Firmware table size mismatch: NtQuerySystemInformation returned %lu but expected %lu",
|
||||
bufSize, sfti.TableBufferLength + (ULONG) sizeof(sfti));
|
||||
bufSize,
|
||||
sfti.TableBufferLength + (ULONG) sizeof(sfti));
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Firmware table size: %lu bytes", bufSize);
|
||||
@@ -559,8 +541,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
*buffer = sfti;
|
||||
FF_DEBUG("Allocated buffer for SMBIOS data");
|
||||
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemFirmwareTableInformation, buffer, bufSize, &bufSize)))
|
||||
{
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemFirmwareTableInformation, buffer, bufSize, &bufSize))) {
|
||||
FF_DEBUG("NtQuerySystemInformation(SystemFirmwareTableInformation) failed");
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
@@ -569,10 +550,11 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
FFRawSmbiosData* rawData = (FFRawSmbiosData*) buffer->TableBuffer;
|
||||
|
||||
FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes",
|
||||
rawData->SMBIOSMajorVersion, rawData->SMBIOSMinorVersion, rawData->Length);
|
||||
rawData->SMBIOSMajorVersion,
|
||||
rawData->SMBIOSMinorVersion,
|
||||
rawData->Length);
|
||||
|
||||
if (!parseSmbiosTable(rawData->SMBIOSTableData, rawData->Length))
|
||||
{
|
||||
if (!parseSmbiosTable(rawData->SMBIOSTableData, rawData->Length)) {
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
return NULL;
|
||||
@@ -586,34 +568,29 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
return &smbiosTable;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include "common/apple/cf_helpers.h"
|
||||
# include "common/apple/cf_helpers.h"
|
||||
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
{
|
||||
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
|
||||
static CFDataRef smbiosDataBuffer;
|
||||
|
||||
if (!smbiosTableInitialized)
|
||||
{
|
||||
if (!smbiosTableInitialized) {
|
||||
smbiosTableInitialized = true;
|
||||
FF_DEBUG("Initializing SMBIOS buffer on Apple platform");
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMBIOS"));
|
||||
|
||||
if (!registryEntry)
|
||||
{
|
||||
if (!registryEntry) {
|
||||
FF_DEBUG("IOServiceGetMatchingService() failed to find AppleSMBIOS");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_DEBUG("AppleSMBIOS service found, retrieving SMBIOS data");
|
||||
smbiosDataBuffer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("SMBIOS"), kCFAllocatorDefault, kNilOptions);
|
||||
if (!smbiosDataBuffer)
|
||||
{
|
||||
if (!smbiosDataBuffer) {
|
||||
FF_DEBUG("IORegistryEntryCreateCFProperty() failed to get SMBIOS data");
|
||||
return NULL;
|
||||
}
|
||||
if (CFGetTypeID(smbiosDataBuffer) != CFDataGetTypeID())
|
||||
{
|
||||
if (CFGetTypeID(smbiosDataBuffer) != CFDataGetTypeID()) {
|
||||
FF_DEBUG("Unexpected SMBIOS data type: expected CFData");
|
||||
CFRelease(smbiosDataBuffer);
|
||||
smbiosDataBuffer = NULL;
|
||||
@@ -621,16 +598,14 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
|
||||
}
|
||||
|
||||
FF_DEBUG("Successfully retrieved SMBIOS data: %lu bytes", CFDataGetLength(smbiosDataBuffer));
|
||||
if (!parseSmbiosTable((const uint8_t*) CFDataGetBytePtr(smbiosDataBuffer), (uint32_t) CFDataGetLength(smbiosDataBuffer)))
|
||||
{
|
||||
if (!parseSmbiosTable((const uint8_t*) CFDataGetBytePtr(smbiosDataBuffer), (uint32_t) CFDataGetLength(smbiosDataBuffer))) {
|
||||
CFRelease(smbiosDataBuffer);
|
||||
smbiosDataBuffer = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!smbiosDataBuffer)
|
||||
{
|
||||
if (!smbiosDataBuffer) {
|
||||
FF_DEBUG("No valid SMBIOS data available");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+28
-26
@@ -3,86 +3,88 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
const char* ffSysctlGetString(int mib1, int mib2, FFstrbuf* result)
|
||||
{
|
||||
const char* ffSysctlGetString(int mib1, int mib2, FFstrbuf* result) {
|
||||
size_t neededLength;
|
||||
if (sysctl((int[]) {mib1, mib2}, 2, NULL, &neededLength, NULL, 0) != 0 || neededLength == 1) //neededLength is 1 for empty strings, because of the null terminator
|
||||
if (sysctl((int[]) {mib1, mib2}, 2, NULL, &neededLength, NULL, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
|
||||
return "sysctlbyname() failed";
|
||||
}
|
||||
|
||||
ffStrbufEnsureFree(result, (uint32_t) neededLength - 1);
|
||||
|
||||
if (sysctl((int[]) {mib1, mib2}, 2, result->chars + result->length, &neededLength, NULL, 0) == 0)
|
||||
if (sysctl((int[]) {mib1, mib2}, 2, result->chars + result->length, &neededLength, NULL, 0) == 0) {
|
||||
result->length += (uint32_t) neededLength - 1;
|
||||
}
|
||||
|
||||
result->chars[result->length] = '\0';
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ffSysctlGetInt(int mib1, int mib2, int defaultValue)
|
||||
{
|
||||
int ffSysctlGetInt(int mib1, int mib2, int defaultValue) {
|
||||
int result;
|
||||
size_t neededLength = sizeof(result);
|
||||
if (sysctl((int[]) {mib1, mib2}, 2, &result, &neededLength, NULL, 0) != 0)
|
||||
if (sysctl((int[]) {mib1, mib2}, 2, &result, &neededLength, NULL, 0) != 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t ffSysctlGetInt64(int mib1, int mib2, int64_t defaultValue)
|
||||
{
|
||||
int64_t ffSysctlGetInt64(int mib1, int mib2, int64_t defaultValue) {
|
||||
int64_t result;
|
||||
size_t neededLength = sizeof(result);
|
||||
if(sysctl((int[]) {mib1, mib2}, 2, &result, &neededLength, NULL, 0) != 0)
|
||||
if (sysctl((int[]) {mib1, mib2}, 2, &result, &neededLength, NULL, 0) != 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
const char* ffSysctlGetString(const char* propName, FFstrbuf* result)
|
||||
{
|
||||
const char* ffSysctlGetString(const char* propName, FFstrbuf* result) {
|
||||
size_t neededLength;
|
||||
if(sysctlbyname(propName, NULL, &neededLength, NULL, 0) != 0 || neededLength == 1) //neededLength is 1 for empty strings, because of the null terminator
|
||||
if (sysctlbyname(propName, NULL, &neededLength, NULL, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
|
||||
return "sysctlbyname() failed";
|
||||
}
|
||||
|
||||
ffStrbufEnsureFree(result, (uint32_t) neededLength - 1);
|
||||
|
||||
if(sysctlbyname(propName, result->chars + result->length, &neededLength, NULL, 0) == 0)
|
||||
if (sysctlbyname(propName, result->chars + result->length, &neededLength, NULL, 0) == 0) {
|
||||
result->length += (uint32_t) neededLength - 1;
|
||||
}
|
||||
|
||||
result->chars[result->length] = '\0';
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ffSysctlGetInt(const char* propName, int defaultValue)
|
||||
{
|
||||
int ffSysctlGetInt(const char* propName, int defaultValue) {
|
||||
int result;
|
||||
size_t neededLength = sizeof(result);
|
||||
if(sysctlbyname(propName, &result, &neededLength, NULL, 0) != 0)
|
||||
if (sysctlbyname(propName, &result, &neededLength, NULL, 0) != 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t ffSysctlGetInt64(const char* propName, int64_t defaultValue)
|
||||
{
|
||||
int64_t ffSysctlGetInt64(const char* propName, int64_t defaultValue) {
|
||||
int64_t result;
|
||||
size_t neededLength = sizeof(result);
|
||||
if(sysctlbyname(propName, &result, &neededLength, NULL, 0) != 0)
|
||||
if (sysctlbyname(propName, &result, &neededLength, NULL, 0) != 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // OpenBSD
|
||||
|
||||
void* ffSysctlGetData(int* request, u_int requestLength, size_t* resultLength)
|
||||
{
|
||||
if(sysctl(request, requestLength, NULL, resultLength, NULL, 0) != 0)
|
||||
void* ffSysctlGetData(int* request, u_int requestLength, size_t* resultLength) {
|
||||
if (sysctl(request, requestLength, NULL, resultLength, NULL, 0) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* data = malloc(*resultLength);
|
||||
if(data == NULL)
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(sysctl(request, requestLength, data, resultLength, NULL, 0) != 0)
|
||||
{
|
||||
if (sysctl(request, requestLength, data, resultLength, NULL, 0) != 0) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+45
-64
@@ -3,10 +3,10 @@
|
||||
#include "common/textModifier.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module)
|
||||
{
|
||||
if (celsius == -DBL_MAX) // ignores invalid value
|
||||
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module) {
|
||||
if (celsius == -DBL_MAX) { // ignores invalid value
|
||||
return;
|
||||
}
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
const char* colorGreen = options->tempColorGreen.chars;
|
||||
@@ -15,76 +15,68 @@ void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig confi
|
||||
|
||||
uint8_t green = config.green, yellow = config.yellow;
|
||||
|
||||
if (!options->pipe)
|
||||
{
|
||||
if(green <= yellow)
|
||||
{
|
||||
if (celsius > yellow)
|
||||
if (!options->pipe) {
|
||||
if (green <= yellow) {
|
||||
if (celsius > yellow) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorRed);
|
||||
else if (celsius > green)
|
||||
} else if (celsius > green) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (celsius < yellow)
|
||||
}
|
||||
} else {
|
||||
if (celsius < yellow) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorRed);
|
||||
else if (celsius < green)
|
||||
} else if (celsius < green) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else
|
||||
} else {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (options->tempUnit)
|
||||
{
|
||||
switch (options->tempUnit) {
|
||||
case FF_TEMPERATURE_UNIT_DEFAULT:
|
||||
case FF_TEMPERATURE_UNIT_CELSIUS:
|
||||
ffStrbufAppendF(buffer, "%.*f%s°C", options->tempNdigits, celsius,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
ffStrbufAppendF(buffer, "%.*f%s°C", options->tempNdigits, celsius, options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
break;
|
||||
case FF_TEMPERATURE_UNIT_FAHRENHEIT:
|
||||
ffStrbufAppendF(buffer, "%.*f%s°F", options->tempNdigits, celsius * 1.8 + 32,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
ffStrbufAppendF(buffer, "%.*f%s°F", options->tempNdigits, celsius * 1.8 + 32, options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
break;
|
||||
case FF_TEMPERATURE_UNIT_KELVIN:
|
||||
ffStrbufAppendF(buffer, "%.*f%sK", options->tempNdigits, celsius + 273.15,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ");
|
||||
ffStrbufAppendF(buffer, "%.*f%sK", options->tempNdigits, celsius + 273.15, options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!options->pipe)
|
||||
{
|
||||
if (!options->pipe) {
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
if (module->outputColor.length)
|
||||
if (module->outputColor.length) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", module->outputColor.chars);
|
||||
else if (instance.config.display.colorOutput.length)
|
||||
} else if (instance.config.display.colorOutput.length) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", instance.config.display.colorOutput.chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config)
|
||||
{
|
||||
if (!ffStrStartsWithIgnCase(subkey, "temp"))
|
||||
bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config) {
|
||||
if (!ffStrStartsWithIgnCase(subkey, "temp")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (subkey[strlen("temp")] == '\0')
|
||||
{
|
||||
if (subkey[strlen("temp")] == '\0') {
|
||||
*useTemp = ffOptionParseBoolean(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (subkey[strlen("temp")] != '-')
|
||||
if (subkey[strlen("temp")] != '-') {
|
||||
return false;
|
||||
}
|
||||
|
||||
subkey += strlen("temp-");
|
||||
|
||||
if (ffStrEqualsIgnCase(subkey, "green"))
|
||||
{
|
||||
if (ffStrEqualsIgnCase(subkey, "green")) {
|
||||
uint32_t num = ffOptionParseUInt32(key, value);
|
||||
if (num > 100)
|
||||
{
|
||||
if (num > 100) {
|
||||
fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key);
|
||||
exit(480);
|
||||
}
|
||||
@@ -92,11 +84,9 @@ bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char*
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ffStrEqualsIgnCase(subkey, "yellow"))
|
||||
{
|
||||
if (ffStrEqualsIgnCase(subkey, "yellow")) {
|
||||
uint32_t num = ffOptionParseUInt32(key, value);
|
||||
if (num > 100)
|
||||
{
|
||||
if (num > 100) {
|
||||
fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key);
|
||||
exit(480);
|
||||
}
|
||||
@@ -107,27 +97,24 @@ bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char*
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
|
||||
{
|
||||
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config) {
|
||||
assert(key);
|
||||
|
||||
if (!unsafe_yyjson_equals_str(key, "temp"))
|
||||
if (!unsafe_yyjson_equals_str(key, "temp")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (yyjson_is_bool(value))
|
||||
{
|
||||
if (yyjson_is_bool(value)) {
|
||||
*useTemp = yyjson_get_bool(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (yyjson_is_null(value))
|
||||
{
|
||||
if (yyjson_is_null(value)) {
|
||||
*useTemp = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!yyjson_is_obj(value))
|
||||
{
|
||||
if (!yyjson_is_obj(value)) {
|
||||
fprintf(stderr, "Error: usage: %s must be an object or a boolean\n", unsafe_yyjson_get_str(key));
|
||||
exit(480);
|
||||
}
|
||||
@@ -135,11 +122,9 @@ bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, F
|
||||
*useTemp = true;
|
||||
|
||||
yyjson_val* greenVal = yyjson_obj_get(value, "green");
|
||||
if (greenVal)
|
||||
{
|
||||
if (greenVal) {
|
||||
int num = yyjson_get_int(greenVal);
|
||||
if (num < 0 || num > 100)
|
||||
{
|
||||
if (num < 0 || num > 100) {
|
||||
fputs("Error: usage: temp.green must be between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
}
|
||||
@@ -147,11 +132,9 @@ bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, F
|
||||
}
|
||||
|
||||
yyjson_val* yellowVal = yyjson_obj_get(value, "yellow");
|
||||
if (yellowVal)
|
||||
{
|
||||
if (yellowVal) {
|
||||
int num = yyjson_get_int(yellowVal);
|
||||
if (num < 0 || num > 100)
|
||||
{
|
||||
if (num < 0 || num > 100) {
|
||||
fputs("Error: usage: temp.yellow must be between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
}
|
||||
@@ -161,12 +144,10 @@ bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, F
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config)
|
||||
{
|
||||
if (!temp)
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config) {
|
||||
if (!temp) {
|
||||
yyjson_mut_obj_add_bool(doc, module, "temp", false);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
yyjson_mut_val* temp = yyjson_mut_obj_add_obj(doc, module, "temp");
|
||||
yyjson_mut_obj_add_uint(doc, temp, "green", config.green);
|
||||
yyjson_mut_obj_add_uint(doc, temp, "yellow", config.yellow);
|
||||
|
||||
+32
-30
@@ -5,13 +5,14 @@
|
||||
char ffTimeInternalBuffer[64]; // Reduce memory usage and prevent redundant allocations
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat"
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wformat"
|
||||
#endif
|
||||
|
||||
const char* ffTimeToFullStr(uint64_t msec)
|
||||
{
|
||||
if (msec == 0) return "";
|
||||
const char* ffTimeToFullStr(uint64_t msec) {
|
||||
if (msec == 0) {
|
||||
return "";
|
||||
}
|
||||
time_t tsec = (time_t) (msec / 1000);
|
||||
const struct tm* tm = localtime(&tsec);
|
||||
|
||||
@@ -22,18 +23,20 @@ const char* ffTimeToFullStr(uint64_t msec)
|
||||
return ffTimeInternalBuffer;
|
||||
}
|
||||
|
||||
const char* ffTimeToShortStr(uint64_t msec)
|
||||
{
|
||||
if (msec == 0) return "";
|
||||
const char* ffTimeToShortStr(uint64_t msec) {
|
||||
if (msec == 0) {
|
||||
return "";
|
||||
}
|
||||
time_t tsec = (time_t) (msec / 1000);
|
||||
|
||||
strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer), "%F %T", localtime(&tsec));
|
||||
return ffTimeInternalBuffer;
|
||||
}
|
||||
|
||||
const char* ffTimeToTimeStr(uint64_t msec)
|
||||
{
|
||||
if (msec == 0) return "";
|
||||
const char* ffTimeToTimeStr(uint64_t msec) {
|
||||
if (msec == 0) {
|
||||
return "";
|
||||
}
|
||||
time_t tsec = (time_t) (msec / 1000);
|
||||
|
||||
uint32_t len = (uint32_t) strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer), "%T", localtime(&tsec));
|
||||
@@ -42,34 +45,35 @@ const char* ffTimeToTimeStr(uint64_t msec)
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic pop
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
|
||||
{
|
||||
FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs) {
|
||||
FFTimeGetAgeResult result = {};
|
||||
if (__builtin_expect(birthMs == 0 || nowMs < birthMs, 0))
|
||||
if (__builtin_expect(birthMs == 0 || nowMs < birthMs, 0)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
time_t birth_s = (time_t) (birthMs / 1000);
|
||||
struct tm birth_tm;
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
localtime_s(&birth_tm, &birth_s);
|
||||
#else
|
||||
#else
|
||||
localtime_r(&birth_s, &birth_tm);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
time_t now_s = (time_t) (nowMs / 1000);
|
||||
struct tm now_tm;
|
||||
#ifdef _WIN32
|
||||
#ifdef _WIN32
|
||||
localtime_s(&now_tm, &now_s);
|
||||
#else
|
||||
#else
|
||||
localtime_r(&now_s, &now_tm);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
result.years = (uint32_t) (now_tm.tm_year - birth_tm.tm_year);
|
||||
if (now_tm.tm_yday < birth_tm.tm_yday)
|
||||
if (now_tm.tm_yday < birth_tm.tm_yday) {
|
||||
result.years--;
|
||||
}
|
||||
|
||||
birth_tm.tm_year += (int) result.years;
|
||||
birth_s = mktime(&birth_tm);
|
||||
@@ -83,13 +87,11 @@ FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
double ffQpcMultiplier;
|
||||
double ffQpcMultiplier;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void ffTimeInitQpcMultiplier(void)
|
||||
{
|
||||
LARGE_INTEGER frequency;
|
||||
RtlQueryPerformanceFrequency(&frequency);
|
||||
ffQpcMultiplier = 1000. / (double) frequency.QuadPart;
|
||||
}
|
||||
__attribute__((constructor)) static void ffTimeInitQpcMultiplier(void) {
|
||||
LARGE_INTEGER frequency;
|
||||
RtlQueryPerformanceFrequency(&frequency);
|
||||
ffQpcMultiplier = 1000. / (double) frequency.QuadPart;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "common/wcwidth.h"
|
||||
#include "3rdparty/widecharwidth/widechar_width_c.h"
|
||||
|
||||
int mk_wcwidth(uint32_t wc)
|
||||
{
|
||||
int mk_wcwidth(uint32_t wc) {
|
||||
// // We render U+1F6E1 (🛡) with a width of 2,
|
||||
// // but widechar_width says it has a width of 1 because Unicode classifies it as "neutral".
|
||||
// //
|
||||
|
||||
+125
-132
@@ -4,94 +4,89 @@
|
||||
#include "common/FFlist.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <fileapi.h>
|
||||
#include <handleapi.h>
|
||||
#include <io.h>
|
||||
#include "common/windows/nt.h"
|
||||
typedef HANDLE FFNativeFD;
|
||||
#define FF_INVALID_FD INVALID_HANDLE_VALUE
|
||||
# include <fileapi.h>
|
||||
# include <handleapi.h>
|
||||
# include <io.h>
|
||||
# include "common/windows/nt.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>
|
||||
#include <fcntl.h>
|
||||
typedef int FFNativeFD;
|
||||
#define FF_INVALID_FD (-1)
|
||||
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
|
||||
// one safe way to read correct data is reading the whole file in a single read syscall
|
||||
#define PROC_FILE_BUFFSIZ (32 * 1024)
|
||||
# include <unistd.h>
|
||||
# include <dirent.h>
|
||||
# include <sys/stat.h>
|
||||
# include <errno.h>
|
||||
# include <limits.h>
|
||||
# include <fcntl.h>
|
||||
typedef int FFNativeFD;
|
||||
# define FF_INVALID_FD (-1)
|
||||
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
|
||||
// one safe way to read correct data is reading the whole file in a single read syscall
|
||||
# define PROC_FILE_BUFFSIZ (32 * 1024)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
#ifndef O_RDONLY
|
||||
#define O_RDONLY 0
|
||||
#endif
|
||||
#ifndef O_DIRECTORY
|
||||
#define O_DIRECTORY 0200000
|
||||
#endif
|
||||
# ifndef O_CLOEXEC
|
||||
# define O_CLOEXEC 0
|
||||
# endif
|
||||
# ifndef O_RDONLY
|
||||
# define O_RDONLY 0
|
||||
# endif
|
||||
# ifndef O_DIRECTORY
|
||||
# define O_DIRECTORY 0200000
|
||||
# endif
|
||||
|
||||
// Only O_RDONLY is supported
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, int oflag);
|
||||
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
|
||||
#endif
|
||||
|
||||
|
||||
static inline bool ffIsValidNativeFD(FFNativeFD fd)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return fd >= 0;
|
||||
#else
|
||||
// https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
|
||||
return fd != INVALID_HANDLE_VALUE && fd != NULL;
|
||||
#endif
|
||||
static inline bool ffIsValidNativeFD(FFNativeFD fd) {
|
||||
#ifndef _WIN32
|
||||
return fd >= 0;
|
||||
#else
|
||||
// https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
|
||||
return fd != INVALID_HANDLE_VALUE && fd != NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapClose(FFNativeFD* pfd)
|
||||
{
|
||||
static inline bool wrapClose(FFNativeFD* pfd) {
|
||||
assert(pfd);
|
||||
|
||||
if (!ffIsValidNativeFD(*pfd))
|
||||
if (!ffIsValidNativeFD(*pfd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
close(*pfd);
|
||||
#else
|
||||
NtClose(*pfd);
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
close(*pfd);
|
||||
#else
|
||||
NtClose(*pfd);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
|
||||
|
||||
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
return unixfd;
|
||||
#else
|
||||
return (FFNativeFD) _get_osfhandle(unixfd);
|
||||
#endif
|
||||
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd) {
|
||||
#ifndef _WIN32
|
||||
return unixfd;
|
||||
#else
|
||||
return (FFNativeFD) _get_osfhandle(unixfd);
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(3)
|
||||
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 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
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content)
|
||||
{
|
||||
static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content) {
|
||||
return ffWriteFDData(fd, content->length, content->chars);
|
||||
}
|
||||
|
||||
@@ -99,103 +94,98 @@ FF_C_NONNULL(1, 3)
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer) {
|
||||
return ffWriteFileData(fileName, buffer->length, buffer->chars);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(3)
|
||||
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;
|
||||
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
|
||||
return (ssize_t) bytesRead;
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
|
||||
|
||||
FF_C_NONNULL(1, 3)
|
||||
static inline ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
static inline ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data) {
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd =
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
#else
|
||||
#else
|
||||
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
if (!ffIsValidNativeFD(fd)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2, 4)
|
||||
static inline ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
static inline ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data) {
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
if (!ffIsValidNativeFD(fd)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
static inline bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) {
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd =
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
#else
|
||||
#else
|
||||
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
if (!ffIsValidNativeFD(fd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2, 3)
|
||||
static inline bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer) {
|
||||
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if (!ffIsValidNativeFD(fd))
|
||||
if (!ffIsValidNativeFD(fd)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
static inline bool ffReadFDBuffer(FFNativeFD fd, FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffReadFDBuffer(FFNativeFD fd, FFstrbuf* buffer) {
|
||||
ffStrbufClear(buffer);
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer) {
|
||||
ffStrbufClear(buffer);
|
||||
return ffAppendFileBuffer(fileName, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2, 3)
|
||||
static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer) {
|
||||
ffStrbufClear(buffer);
|
||||
return ffAppendFileBufferRelative(dfd, fileName, buffer);
|
||||
}
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFPathType
|
||||
{
|
||||
typedef enum __attribute__((__packed__)) FFPathType {
|
||||
FF_PATHTYPE_FILE = 1 << 0,
|
||||
FF_PATHTYPE_DIRECTORY = 1 << 1,
|
||||
FF_PATHTYPE_ANY = FF_PATHTYPE_FILE | FF_PATHTYPE_DIRECTORY,
|
||||
@@ -203,48 +193,51 @@ typedef enum __attribute__((__packed__)) FFPathType
|
||||
} FFPathType;
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static inline bool ffPathExists(const char* path, FFPathType pathType) {
|
||||
#ifdef _WIN32
|
||||
|
||||
wchar_t wPath[MAX_PATH];
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(wPath, (ULONG) sizeof(wPath), NULL, path, (ULONG)strlen(path) + 1)))
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(wPath, (ULONG) sizeof(wPath), NULL, path, (ULONG) strlen(path) + 1))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD attr = GetFileAttributesW(wPath);
|
||||
|
||||
if(attr == INVALID_FILE_ATTRIBUTES)
|
||||
if (attr == INVALID_FILE_ATTRIBUTES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pathType & FF_PATHTYPE_FILE && !(attr & FILE_ATTRIBUTE_DIRECTORY))
|
||||
if (pathType & FF_PATHTYPE_FILE && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(pathType & FF_PATHTYPE_DIRECTORY && (attr & FILE_ATTRIBUTE_DIRECTORY))
|
||||
if (pathType & FF_PATHTYPE_DIRECTORY && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
if (pathType == FF_PATHTYPE_ANY)
|
||||
{
|
||||
if (pathType == FF_PATHTYPE_ANY) {
|
||||
// Zero overhead
|
||||
return access(path, F_OK) == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
struct stat fileStat;
|
||||
if(stat(path, &fileStat) != 0)
|
||||
if (stat(path, &fileStat) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int mode = fileStat.st_mode & S_IFMT;
|
||||
|
||||
if(pathType & FF_PATHTYPE_FILE && mode != S_IFDIR)
|
||||
if (pathType & FF_PATHTYPE_FILE && mode != S_IFDIR) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(pathType & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR)
|
||||
if (pathType & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -261,9 +254,10 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
// Not thread safe!
|
||||
bool ffSuppressIO(bool suppress);
|
||||
|
||||
static inline void ffUnsuppressIO(bool* suppressed)
|
||||
{
|
||||
if (!*suppressed) return;
|
||||
static inline void ffUnsuppressIO(bool* suppressed) {
|
||||
if (!*suppressed) {
|
||||
return;
|
||||
}
|
||||
ffSuppressIO(false);
|
||||
*suppressed = false;
|
||||
}
|
||||
@@ -273,11 +267,11 @@ static inline void ffUnsuppressIO(bool* suppressed)
|
||||
void ffListFilesRecursively(const char* path, bool pretty);
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapFclose(FILE** pfile)
|
||||
{
|
||||
static inline bool wrapFclose(FILE** pfile) {
|
||||
assert(pfile);
|
||||
if (!*pfile)
|
||||
if (!*pfile) {
|
||||
return false;
|
||||
}
|
||||
fclose(*pfile);
|
||||
return true;
|
||||
}
|
||||
@@ -285,20 +279,20 @@ static inline bool wrapFclose(FILE** pfile)
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
#ifndef _WIN32
|
||||
static inline bool wrapClosedir(DIR** pdir)
|
||||
{
|
||||
static inline bool wrapClosedir(DIR** pdir) {
|
||||
assert(pdir);
|
||||
if (!*pdir)
|
||||
if (!*pdir) {
|
||||
return false;
|
||||
}
|
||||
closedir(*pdir);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static inline bool wrapClosedir(HANDLE* pdir)
|
||||
{
|
||||
static inline bool wrapClosedir(HANDLE* pdir) {
|
||||
assert(pdir);
|
||||
if (!*pdir)
|
||||
if (!*pdir) {
|
||||
return false;
|
||||
}
|
||||
FindClose(*pdir);
|
||||
return true;
|
||||
}
|
||||
@@ -306,16 +300,15 @@ static inline bool wrapClosedir(HANDLE* pdir)
|
||||
#define FF_AUTO_CLOSE_DIR __attribute__((__cleanup__(wrapClosedir)))
|
||||
|
||||
FF_C_NONNULL(1, 2, 3)
|
||||
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result)
|
||||
{
|
||||
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result) {
|
||||
// configDirs is a list of FFstrbufs include the trailing slash
|
||||
FF_LIST_FOR_EACH(FFstrbuf, dir, *configDirs)
|
||||
{
|
||||
FF_LIST_FOR_EACH (FFstrbuf, dir, *configDirs) {
|
||||
ffStrbufClear(result);
|
||||
ffStrbufAppend(result, dir);
|
||||
ffStrbufAppendS(result, fileSubpath);
|
||||
if (ffPathExists(result->chars, FF_PATHTYPE_FILE))
|
||||
if (ffPathExists(result->chars, FF_PATHTYPE_FILE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs);
|
||||
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[]);
|
||||
|
||||
yyjson_api_inline yyjson_mut_val* yyjson_mut_strbuf(yyjson_mut_doc *doc, const FFstrbuf* buf) {
|
||||
yyjson_api_inline yyjson_mut_val* yyjson_mut_strbuf(yyjson_mut_doc* doc, const FFstrbuf* buf) {
|
||||
return yyjson_mut_strncpy(doc, buf->chars, buf->length);
|
||||
}
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_obj_add_strbuf(yyjson_mut_doc *doc,
|
||||
yyjson_mut_val *obj,
|
||||
const char *_key,
|
||||
const FFstrbuf* buf) {
|
||||
yyjson_api_inline bool yyjson_mut_obj_add_strbuf(yyjson_mut_doc* doc,
|
||||
yyjson_mut_val* obj,
|
||||
const char* _key,
|
||||
const FFstrbuf* buf) {
|
||||
return yyjson_mut_obj_add_strncpy(doc, obj, _key, buf->chars, buf->length);
|
||||
}
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_arr_add_strbuf(yyjson_mut_doc *doc,
|
||||
yyjson_mut_val *obj,
|
||||
const FFstrbuf* buf) {
|
||||
yyjson_api_inline bool yyjson_mut_arr_add_strbuf(yyjson_mut_doc* doc,
|
||||
yyjson_mut_val* obj,
|
||||
const FFstrbuf* buf) {
|
||||
return yyjson_mut_arr_add_strncpy(doc, obj, buf->chars, buf->length);
|
||||
}
|
||||
|
||||
|
||||
+66
-66
@@ -5,103 +5,103 @@
|
||||
|
||||
#ifndef FF_DISABLE_DLOPEN
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define FF_DLOPEN_FLAGS 0
|
||||
FF_C_NODISCARD void* dlopen(const char* path, int mode);
|
||||
FF_C_NODISCARD void* dlsym(void* handle, const char* symbol);
|
||||
int dlclose(void* handle);
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
# if defined(_WIN32)
|
||||
# define FF_DLOPEN_FLAGS 0
|
||||
FF_C_NODISCARD void* dlopen(const char* path, int mode);
|
||||
FF_C_NODISCARD void* dlsym(void* handle, const char* symbol);
|
||||
int dlclose(void* handle);
|
||||
# else
|
||||
# include <dlfcn.h>
|
||||
# endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FF_LIBRARY_EXTENSION ".dll"
|
||||
#elif defined(__APPLE__)
|
||||
#define FF_LIBRARY_EXTENSION ".dylib"
|
||||
#else
|
||||
#define FF_LIBRARY_EXTENSION ".so"
|
||||
#endif
|
||||
# ifdef _WIN32
|
||||
# define FF_LIBRARY_EXTENSION ".dll"
|
||||
# elif defined(__APPLE__)
|
||||
# define FF_LIBRARY_EXTENSION ".dylib"
|
||||
# else
|
||||
# define FF_LIBRARY_EXTENSION ".so"
|
||||
# endif
|
||||
|
||||
static inline void ffLibraryUnload(void** handle)
|
||||
{
|
||||
static inline void ffLibraryUnload(void** handle) {
|
||||
assert(handle);
|
||||
if (*handle)
|
||||
if (*handle) {
|
||||
dlclose(*handle);
|
||||
}
|
||||
}
|
||||
|
||||
#if __cplusplus
|
||||
#define __auto_type auto
|
||||
#endif
|
||||
# if __cplusplus
|
||||
# define __auto_type auto
|
||||
# endif
|
||||
|
||||
#define FF_LIBRARY_SYMBOL(symbolName) \
|
||||
__typeof__(&symbolName) ff ## symbolName;
|
||||
# define FF_LIBRARY_SYMBOL(symbolName) \
|
||||
__typeof__(&symbolName) ff##symbolName;
|
||||
|
||||
#define FF_LIBRARY_LOAD(libraryObjectName, returnValue, ...) \
|
||||
void* __attribute__((__cleanup__(ffLibraryUnload))) libraryObjectName = ffLibraryLoad(__VA_ARGS__, NULL);\
|
||||
if(libraryObjectName == NULL) \
|
||||
return returnValue;
|
||||
# define FF_LIBRARY_LOAD(libraryObjectName, returnValue, ...) \
|
||||
void* __attribute__((__cleanup__(ffLibraryUnload))) libraryObjectName = ffLibraryLoad(__VA_ARGS__, NULL); \
|
||||
if (libraryObjectName == NULL) \
|
||||
return returnValue;
|
||||
|
||||
#define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
|
||||
FF_LIBRARY_LOAD(libraryObjectName, "dlopen(" libraryFileName ") failed", libraryFileName, maxVersion, ##__VA_ARGS__)
|
||||
# define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
|
||||
FF_LIBRARY_LOAD(libraryObjectName, "dlopen(" libraryFileName ") failed", libraryFileName, maxVersion, ##__VA_ARGS__)
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
|
||||
symbolMapping = (__typeof__(&symbolName)) dlsym(library, #symbolName); \
|
||||
if(symbolMapping == NULL) \
|
||||
return returnValue;
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
|
||||
symbolMapping = (__typeof__(&symbolName)) dlsym(library, #symbolName); \
|
||||
if (symbolMapping == NULL) \
|
||||
return returnValue;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
# define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, returnValue);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
|
||||
__auto_type ff ## symbolName = (__typeof__(&symbolName)) dlsym(library, #symbolName);
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
|
||||
__auto_type ff##symbolName = (__typeof__(&symbolName)) dlsym(library, #symbolName);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
|
||||
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
|
||||
__auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, returnValue);
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, returnValue);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(library, varName, symbolName) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(library, varName, symbolName) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff ## symbolName, symbolName, returnValue);
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff##symbolName, symbolName, returnValue);
|
||||
|
||||
void* ffLibraryLoad(const char* path, int maxVersion, ...);
|
||||
|
||||
#else
|
||||
|
||||
#define FF_LIBRARY_EXTENSION ""
|
||||
# define FF_LIBRARY_EXTENSION ""
|
||||
|
||||
#define FF_LIBRARY_SYMBOL(symbolName) \
|
||||
__typeof__(&symbolName) ff ## symbolName;
|
||||
# define FF_LIBRARY_SYMBOL(symbolName) \
|
||||
__typeof__(&symbolName) ff##symbolName;
|
||||
|
||||
#define FF_LIBRARY_LOAD(libraryObjectName, returnValue, ...) \
|
||||
FF_MAYBE_UNUSED void* libraryObjectName = NULL; // Placeholder
|
||||
# define FF_LIBRARY_LOAD(libraryObjectName, returnValue, ...) \
|
||||
FF_MAYBE_UNUSED void* libraryObjectName = NULL; // Placeholder
|
||||
|
||||
#define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
|
||||
FF_LIBRARY_LOAD(libraryObjectName, , libraryFileName, maxVersion, ##__VA_ARGS__)
|
||||
# define FF_LIBRARY_LOAD_MESSAGE(libraryObjectName, libraryFileName, maxVersion, ...) \
|
||||
FF_LIBRARY_LOAD(libraryObjectName, , libraryFileName, maxVersion, ##__VA_ARGS__)
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
|
||||
symbolMapping = (__typeof__(&symbolName)) &symbolName;
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
|
||||
symbolMapping = (__typeof__(&symbolName)) &symbolName;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
# define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, returnValue);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
|
||||
FF_MAYBE_UNUSED __auto_type ff ## symbolName = (__typeof__(&symbolName)) &symbolName;
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_LAZY(library, symbolName) \
|
||||
FF_MAYBE_UNUSED __auto_type ff##symbolName = (__typeof__(&symbolName)) &symbolName;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
|
||||
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \
|
||||
FF_MAYBE_UNUSED __auto_type FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff##symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, returnValue);
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, returnValue);
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(library, varName, symbolName) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff ## symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(library, varName, symbolName) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName).ff##symbolName, symbolName, "dlsym " #symbolName " failed");
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff ## symbolName, symbolName, returnValue);
|
||||
# define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff##symbolName, symbolName, returnValue);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+21
-22
@@ -4,36 +4,35 @@
|
||||
#include <assert.h>
|
||||
|
||||
#if FF_HAVE_MALLOC_USABLE_SIZE || FF_HAVE_MSVC_MSIZE
|
||||
#if __has_include(<malloc.h>)
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <malloc_np.h> // For DragonFly BSD
|
||||
#endif
|
||||
# if __has_include(<malloc.h>)
|
||||
# include <malloc.h>
|
||||
# else
|
||||
# include <malloc_np.h> // For DragonFly BSD
|
||||
# endif
|
||||
#elif FF_HAVE_MALLOC_SIZE
|
||||
#include <malloc/malloc.h>
|
||||
# include <malloc/malloc.h>
|
||||
#endif
|
||||
|
||||
static inline void ffWrapFree(const void* pPtr)
|
||||
{
|
||||
static inline void ffWrapFree(const void* pPtr) {
|
||||
assert(pPtr);
|
||||
if(*(void**)pPtr)
|
||||
free(*(void**)pPtr);
|
||||
if (*(void**) pPtr) {
|
||||
free(*(void**) pPtr);
|
||||
}
|
||||
}
|
||||
|
||||
#define FF_AUTO_FREE __attribute__((__cleanup__(ffWrapFree)))
|
||||
|
||||
// ptr MUST be a malloc'ed pointer
|
||||
static inline size_t ffMallocUsableSize(const void* ptr)
|
||||
{
|
||||
static inline size_t ffMallocUsableSize(const void* ptr) {
|
||||
assert(ptr);
|
||||
#if FF_HAVE_MALLOC_USABLE_SIZE
|
||||
return malloc_usable_size((void*) ptr);
|
||||
#elif FF_HAVE_MALLOC_SIZE
|
||||
return malloc_size((void*) ptr);
|
||||
#elif FF_HAVE_MSVC_MSIZE
|
||||
return _msize((void*) ptr);
|
||||
#else
|
||||
(void) ptr;
|
||||
return 0; // Not supported
|
||||
#endif
|
||||
#if FF_HAVE_MALLOC_USABLE_SIZE
|
||||
return malloc_usable_size((void*) ptr);
|
||||
#elif FF_HAVE_MALLOC_SIZE
|
||||
return malloc_size((void*) ptr);
|
||||
#elif FF_HAVE_MSVC_MSIZE
|
||||
return _msize((void*) ptr);
|
||||
#else
|
||||
(void) ptr;
|
||||
return 0; // Not supported
|
||||
#endif
|
||||
}
|
||||
|
||||
+4
-4
@@ -3,8 +3,8 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
# include <net/if.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFNetifDefaultRouteResultStatus {
|
||||
@@ -16,10 +16,10 @@ typedef enum __attribute__((__packed__)) FFNetifDefaultRouteResultStatus {
|
||||
typedef struct FFNetifDefaultRouteResult {
|
||||
uint32_t ifIndex;
|
||||
|
||||
#ifndef _WIN32
|
||||
#ifndef _WIN32
|
||||
char ifName[IF_NAMESIZE + 1];
|
||||
uint32_t preferredSourceAddrV4;
|
||||
#endif
|
||||
#endif
|
||||
enum FFNetifDefaultRouteResultStatus status;
|
||||
} FFNetifDefaultRouteResult;
|
||||
|
||||
|
||||
+12
-12
@@ -4,29 +4,29 @@
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <minwindef.h>
|
||||
# include <minwindef.h>
|
||||
#endif
|
||||
|
||||
struct addrinfo;
|
||||
|
||||
typedef struct FFNetworkingState {
|
||||
#ifdef _WIN32
|
||||
uintptr_t sockfd;
|
||||
OVERLAPPED overlapped;
|
||||
#else
|
||||
int sockfd;
|
||||
struct addrinfo* addr;
|
||||
#ifdef _WIN32
|
||||
uintptr_t sockfd;
|
||||
OVERLAPPED overlapped;
|
||||
#else
|
||||
int sockfd;
|
||||
struct addrinfo* addr;
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
FFThreadType thread;
|
||||
#endif
|
||||
#endif
|
||||
# ifdef FF_HAVE_THREADS
|
||||
FFThreadType thread;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
FFstrbuf command;
|
||||
uint32_t timeout;
|
||||
bool ipv6;
|
||||
bool compression; // if true, HTTP content compression will be enabled if supported
|
||||
bool tfo; // if true, TCP Fast Open will be attempted first, and fallback to traditional connection if it fails
|
||||
bool tfo; // if true, TCP Fast Open will be attempted first, and fallback to traditional connection if it fails
|
||||
} FFNetworkingState;
|
||||
|
||||
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers);
|
||||
|
||||
+12
-21
@@ -6,23 +6,20 @@ struct yyjson_val;
|
||||
struct yyjson_mut_doc;
|
||||
struct yyjson_mut_val;
|
||||
|
||||
typedef struct FFModuleFormatArg
|
||||
{
|
||||
typedef struct FFModuleFormatArg {
|
||||
const char* desc;
|
||||
const char* name;
|
||||
} FFModuleFormatArg;
|
||||
|
||||
typedef struct FFModuleFormatArgList
|
||||
{
|
||||
typedef struct FFModuleFormatArgList {
|
||||
FFModuleFormatArg* args;
|
||||
uint32_t count;
|
||||
} FFModuleFormatArgList;
|
||||
|
||||
#define FF_FORMAT_ARG_LIST(list) { .args = list, .count = sizeof(list) / sizeof(FFModuleFormatArg) }
|
||||
#define FF_FORMAT_ARG_LIST(list) {.args = list, .count = sizeof(list) / sizeof(FFModuleFormatArg)}
|
||||
|
||||
// Must be the first field of FFModuleOptions
|
||||
typedef struct FFModuleBaseInfo
|
||||
{
|
||||
typedef struct FFModuleBaseInfo {
|
||||
const char* name;
|
||||
const char* description;
|
||||
// A dirty polymorphic implementation in C.
|
||||
@@ -32,15 +29,14 @@ typedef struct FFModuleBaseInfo
|
||||
|
||||
void (*initOptions)(void* options);
|
||||
void (*destroyOptions)(void* options);
|
||||
void (*parseJsonObject)(void* options, struct yyjson_val *module);
|
||||
bool (*printModule)(void* options); // true on success
|
||||
void (*parseJsonObject)(void* options, struct yyjson_val* module);
|
||||
bool (*printModule)(void* options); // true on success
|
||||
bool (*generateJsonResult)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module); // true on success
|
||||
void (*generateJsonConfig)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* obj);
|
||||
FFModuleFormatArgList formatArgs;
|
||||
} FFModuleBaseInfo;
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFModuleKeyType
|
||||
{
|
||||
typedef enum __attribute__((__packed__)) FFModuleKeyType {
|
||||
FF_MODULE_KEY_TYPE_NONE = 0,
|
||||
FF_MODULE_KEY_TYPE_STRING = 1 << 0,
|
||||
FF_MODULE_KEY_TYPE_ICON = 1 << 1,
|
||||
@@ -54,8 +50,7 @@ typedef enum __attribute__((__packed__)) FFModuleKeyType
|
||||
FF_MODULE_KEY_TYPE_FORCE_UNSIGNED = UINT8_MAX,
|
||||
} FFModuleKeyType;
|
||||
|
||||
typedef struct FFModuleArgs
|
||||
{
|
||||
typedef struct FFModuleArgs {
|
||||
FFstrbuf key;
|
||||
FFstrbuf keyColor;
|
||||
FFstrbuf keyIcon;
|
||||
@@ -64,8 +59,7 @@ typedef struct FFModuleArgs
|
||||
uint32_t keyWidth;
|
||||
} FFModuleArgs;
|
||||
|
||||
typedef struct FFKeyValuePair
|
||||
{
|
||||
typedef struct FFKeyValuePair {
|
||||
const char* key;
|
||||
int value;
|
||||
} FFKeyValuePair;
|
||||
@@ -77,14 +71,12 @@ FF_C_NODISCARD int32_t ffOptionParseInt32(const char* argumentKey, const char* v
|
||||
FF_C_NODISCARD int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]);
|
||||
FF_C_NODISCARD bool ffOptionParseBoolean(const char* str);
|
||||
void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer);
|
||||
static inline void ffOptionParseColor(const char* value, FFstrbuf* buffer)
|
||||
{
|
||||
static inline void ffOptionParseColor(const char* value, FFstrbuf* buffer) {
|
||||
ffStrbufClear(buffer);
|
||||
ffOptionParseColorNoClear(value, buffer);
|
||||
}
|
||||
|
||||
static inline void ffOptionInitModuleArg(FFModuleArgs* args, const char* icon)
|
||||
{
|
||||
static inline void ffOptionInitModuleArg(FFModuleArgs* args, const char* icon) {
|
||||
ffStrbufInit(&args->key);
|
||||
ffStrbufInit(&args->keyColor);
|
||||
ffStrbufInitStatic(&args->keyIcon, icon);
|
||||
@@ -93,8 +85,7 @@ static inline void ffOptionInitModuleArg(FFModuleArgs* args, const char* icon)
|
||||
args->keyWidth = 0;
|
||||
}
|
||||
|
||||
static inline void ffOptionDestroyModuleArg(FFModuleArgs* args)
|
||||
{
|
||||
static inline void ffOptionDestroyModuleArg(FFModuleArgs* args) {
|
||||
ffStrbufDestroy(&args->key);
|
||||
ffStrbufDestroy(&args->keyColor);
|
||||
ffStrbufDestroy(&args->keyIcon);
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct FFVersion
|
||||
{
|
||||
typedef struct FFVersion {
|
||||
uint32_t major;
|
||||
uint32_t minor;
|
||||
uint32_t patch;
|
||||
} FFVersion;
|
||||
|
||||
typedef struct FFColorRangeConfig
|
||||
{
|
||||
typedef struct FFColorRangeConfig {
|
||||
uint8_t green;
|
||||
uint8_t yellow;
|
||||
} FFColorRangeConfig;
|
||||
|
||||
+6
-7
@@ -4,19 +4,18 @@
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result);
|
||||
static inline bool ffIsAbsolutePath(const char* path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static inline bool ffIsAbsolutePath(const char* path) {
|
||||
#ifdef _WIN32
|
||||
return (ffCharIsEnglishAlphabet(path[0]) && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) // drive letter path
|
||||
|| (path[0] == '\\' && path[1] == '\\'); // UNC path
|
||||
#else
|
||||
|| (path[0] == '\\' && path[1] == '\\'); // UNC path
|
||||
#else
|
||||
return path[0] == '/';
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
char* frealpath(void* __restrict hFile, char* __restrict resolved_name /*MAX_PATH*/);
|
||||
char* realpath(const char* __restrict file_name, char* __restrict resolved_name /*MAX_PATH*/);
|
||||
char* realpath(const char* __restrict file_name, char* __restrict resolved_name /*MAX_PATH*/);
|
||||
ssize_t freadlink(void* hFile, char* buf, size_t bufsiz);
|
||||
ssize_t readlink(const char* path, char* buf, size_t bufsiz);
|
||||
#endif
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "common/parsing.h"
|
||||
#include "common/option.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFPercentageTypeFlags
|
||||
{
|
||||
typedef enum __attribute__((__packed__)) FFPercentageTypeFlags {
|
||||
FF_PERCENTAGE_TYPE_NONE = 0,
|
||||
FF_PERCENTAGE_TYPE_NUM_BIT = 1 << 0,
|
||||
FF_PERCENTAGE_TYPE_BAR_BIT = 1 << 1,
|
||||
@@ -16,8 +15,7 @@ typedef enum __attribute__((__packed__)) FFPercentageTypeFlags
|
||||
} FFPercentageTypeFlags;
|
||||
static_assert(sizeof(FFPercentageTypeFlags) == 1, "");
|
||||
|
||||
typedef struct FFPercentageModuleConfig
|
||||
{
|
||||
typedef struct FFPercentageModuleConfig {
|
||||
uint8_t green;
|
||||
uint8_t yellow;
|
||||
FFPercentageTypeFlags type;
|
||||
|
||||
@@ -16,6 +16,7 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments);
|
||||
#define FF_PRINT_FORMAT_CHECKED(moduleName, moduleIndex, moduleArgs, printType, arguments) \
|
||||
ffPrintFormat((moduleName), (moduleIndex), (moduleArgs), (printType), (sizeof(arguments) / sizeof(*arguments)), (arguments));
|
||||
FF_C_PRINTF(5, 6) void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...);
|
||||
FF_C_PRINTF(5, 6)
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...);
|
||||
void ffPrintColor(const FFstrbuf* colorValue);
|
||||
void ffPrintCharTimes(char c, uint32_t times);
|
||||
|
||||
+17
-13
@@ -3,43 +3,47 @@
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h> // pid_t
|
||||
# include <sys/types.h> // pid_t
|
||||
#endif
|
||||
|
||||
typedef struct FFProcessHandle {
|
||||
#if _WIN32
|
||||
void* pid; // HANDLE
|
||||
#if _WIN32
|
||||
void* pid; // HANDLE
|
||||
void* pipeRead; // HANDLE
|
||||
#else
|
||||
#else
|
||||
pid_t pid;
|
||||
int pipeRead;
|
||||
#endif
|
||||
#endif
|
||||
} FFProcessHandle;
|
||||
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle);
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer); // Destroys handle internally
|
||||
|
||||
static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[])
|
||||
{
|
||||
static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[]) {
|
||||
FFProcessHandle handle;
|
||||
const char* error = ffProcessSpawn(argv, false, &handle);
|
||||
if (error) return error;
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = ffProcessReadOutput(&handle, buffer);
|
||||
if (!error)
|
||||
if (!error) {
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static inline const char* ffProcessAppendStdErr(FFstrbuf* buffer, char* const argv[])
|
||||
{
|
||||
static inline const char* ffProcessAppendStdErr(FFstrbuf* buffer, char* const argv[]) {
|
||||
FFProcessHandle handle;
|
||||
const char* error = ffProcessSpawn(argv, true, &handle);
|
||||
if (error) return error;
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
error = ffProcessReadOutput(&handle, buffer);
|
||||
if (!error)
|
||||
if (!error) {
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
+14
-23
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
typedef struct FFpropquery
|
||||
{
|
||||
typedef struct FFpropquery {
|
||||
const char* start;
|
||||
FFstrbuf* buffer;
|
||||
} FFpropquery;
|
||||
@@ -15,42 +14,34 @@ bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uin
|
||||
|
||||
bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer);
|
||||
|
||||
static inline bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
static inline bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer) {
|
||||
return ffParsePropLinePointer(&line, start, buffer);
|
||||
}
|
||||
|
||||
static inline bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
|
||||
static inline bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer) {
|
||||
return ffParsePropFileValues(filename, 1, (FFpropquery[]) {{start, buffer}});
|
||||
}
|
||||
|
||||
static inline bool ffParsePropFileHome(const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileHomeValues(relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
static inline bool ffParsePropFileHome(const char* relativeFile, const char* start, FFstrbuf* buffer) {
|
||||
return ffParsePropFileHomeValues(relativeFile, 1, (FFpropquery[]) {{start, buffer}});
|
||||
}
|
||||
|
||||
static inline bool ffParsePropFileList(const FFlist* list, const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileListValues(list, relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
static inline bool ffParsePropFileList(const FFlist* list, const char* relativeFile, const char* start, FFstrbuf* buffer) {
|
||||
return ffParsePropFileListValues(list, relativeFile, 1, (FFpropquery[]) {{start, buffer}});
|
||||
}
|
||||
|
||||
static inline bool ffParsePropFileConfigValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
static inline bool ffParsePropFileConfigValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries) {
|
||||
return ffParsePropFileListValues(&instance.state.platform.configDirs, relativeFile, numQueries, queries);
|
||||
}
|
||||
|
||||
static inline bool ffParsePropFileConfig(const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileConfigValues(relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
static inline bool ffParsePropFileConfig(const char* relativeFile, const char* start, FFstrbuf* buffer) {
|
||||
return ffParsePropFileConfigValues(relativeFile, 1, (FFpropquery[]) {{start, buffer}});
|
||||
}
|
||||
|
||||
static inline bool ffParsePropFileDataValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
static inline bool ffParsePropFileDataValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries) {
|
||||
return ffParsePropFileListValues(&instance.state.platform.dataDirs, relativeFile, numQueries, queries);
|
||||
}
|
||||
|
||||
static inline bool ffParsePropFileData(const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileDataValues(relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
static inline bool ffParsePropFileData(const char* relativeFile, const char* start, FFstrbuf* buffer) {
|
||||
return ffParsePropFileDataValues(relativeFile, 1, (FFpropquery[]) {{start, buffer}});
|
||||
}
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFvarianttype
|
||||
{
|
||||
typedef enum __attribute__((__packed__)) FFvarianttype {
|
||||
FF_VARIANT_TYPE_STRING,
|
||||
FF_VARIANT_TYPE_BOOL,
|
||||
FF_VARIANT_TYPE_INT
|
||||
} FFvarianttype;
|
||||
|
||||
typedef union FFvariant
|
||||
{
|
||||
typedef union FFvariant {
|
||||
const char* strValue;
|
||||
int32_t intValue;
|
||||
struct
|
||||
@@ -20,7 +18,7 @@ typedef union FFvariant
|
||||
};
|
||||
} FFvariant;
|
||||
|
||||
#define FF_VARIANT_NULL ((FFvariant){.strValue = NULL})
|
||||
#define FF_VARIANT_NULL ((FFvariant) {.strValue = NULL})
|
||||
|
||||
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type);
|
||||
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type);
|
||||
|
||||
+10
-10
@@ -3,10 +3,10 @@
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
bool ffIsSmbiosValueSet(FFstrbuf* value);
|
||||
static inline void ffCleanUpSmbiosValue(FFstrbuf* value)
|
||||
{
|
||||
if (!ffIsSmbiosValueSet(value))
|
||||
static inline void ffCleanUpSmbiosValue(FFstrbuf* value) {
|
||||
if (!ffIsSmbiosValueSet(value)) {
|
||||
ffStrbufClear(value);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/KunYi/DumpSMBIOS
|
||||
@@ -20,7 +20,7 @@ typedef enum __attribute__((__packed__)) FFSmbiosType // : uint8_t
|
||||
FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE = 3,
|
||||
FF_SMBIOS_TYPE_PROCESSOR_INFO = 4,
|
||||
FF_SMBIOS_TYPE_MEMORY_CONTROLLER_INFO = 5, // obsolete
|
||||
FF_SMBIOS_TYPE_MEMORY_MODULE_INFO = 6, // obsolete
|
||||
FF_SMBIOS_TYPE_MEMORY_MODULE_INFO = 6, // obsolete
|
||||
FF_SMBIOS_TYPE_CACHE_INFO = 7,
|
||||
FF_SMBIOS_TYPE_PORT_CONNECTOR_INFO = 8,
|
||||
FF_SMBIOS_TYPE_SYSTEM_SLOTS = 9,
|
||||
@@ -68,8 +68,7 @@ typedef enum __attribute__((__packed__)) FFSmbiosType // : uint8_t
|
||||
} FFSmbiosType;
|
||||
static_assert(sizeof(FFSmbiosType) == 1, "FFSmbiosType should be 1 byte");
|
||||
|
||||
typedef struct FFSmbiosHeader
|
||||
{
|
||||
typedef struct FFSmbiosHeader {
|
||||
// Type of SMBIOS structure. Do NOT test `Type == FF_SMBIOS_END_OF_TABLE` to determine the end of the table,
|
||||
// as malformed tables may be missing the end-of-table marker.
|
||||
// **Use FFSmbiosHeaderTable[FF_SMBIOS_TYPE_END_OF_TABLE] pointer instead.**
|
||||
@@ -83,12 +82,13 @@ typedef struct FFSmbiosHeader
|
||||
} __attribute__((__packed__)) FFSmbiosHeader;
|
||||
static_assert(sizeof(FFSmbiosHeader) == 4, "FFSmbiosHeader should be 4 bytes");
|
||||
|
||||
static inline const char* ffSmbiosLocateString(const char* start, uint8_t index /* start from 1 */)
|
||||
{
|
||||
if (index == 0 || *start == '\0')
|
||||
static inline const char* ffSmbiosLocateString(const char* start, uint8_t index /* start from 1 */) {
|
||||
if (index == 0 || *start == '\0') {
|
||||
return NULL;
|
||||
while (--index)
|
||||
}
|
||||
while (--index) {
|
||||
start += strlen(start) + 1;
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
|
||||
+31
-40
@@ -5,102 +5,93 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static inline bool ffStrSet(const char* str)
|
||||
{
|
||||
if(str == NULL)
|
||||
static inline bool ffStrSet(const char* str) {
|
||||
if (str == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while(isspace(*str))
|
||||
while (isspace(*str)) {
|
||||
str++;
|
||||
}
|
||||
|
||||
return *str != '\0';
|
||||
}
|
||||
|
||||
|
||||
static inline bool ffStrStartsWithIgnCase(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrStartsWithIgnCase(const char* str, const char* compareTo) {
|
||||
return strncasecmp(str, compareTo, strlen(compareTo)) == 0;
|
||||
}
|
||||
|
||||
static inline bool ffStrEqualsIgnCase(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrEqualsIgnCase(const char* str, const char* compareTo) {
|
||||
return strcasecmp(str, compareTo) == 0;
|
||||
}
|
||||
|
||||
static inline bool ffStrStartsWith(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrStartsWith(const char* str, const char* compareTo) {
|
||||
return strncmp(str, compareTo, strlen(compareTo)) == 0;
|
||||
}
|
||||
|
||||
static inline bool ffStrEndsWith(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrEndsWith(const char* str, const char* compareTo) {
|
||||
size_t strLength = strlen(str);
|
||||
size_t compareToLength = strlen(compareTo);
|
||||
if (strLength < compareToLength)
|
||||
if (strLength < compareToLength) {
|
||||
return false;
|
||||
}
|
||||
return memcmp(str + strLength - compareToLength, compareTo, compareToLength) == 0;
|
||||
}
|
||||
|
||||
static inline bool ffStrEndsWithIgnCase(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrEndsWithIgnCase(const char* str, const char* compareTo) {
|
||||
size_t strLength = strlen(str);
|
||||
size_t compareToLength = strlen(compareTo);
|
||||
if (strLength < compareToLength)
|
||||
if (strLength < compareToLength) {
|
||||
return false;
|
||||
}
|
||||
return strncasecmp(str + strLength - compareToLength, compareTo, compareToLength) == 0;
|
||||
}
|
||||
|
||||
static inline bool ffStrEquals(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrEquals(const char* str, const char* compareTo) {
|
||||
return strcmp(str, compareTo) == 0;
|
||||
}
|
||||
|
||||
static inline bool ffStrContains(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrContains(const char* str, const char* compareTo) {
|
||||
return strstr(str, compareTo) != NULL;
|
||||
}
|
||||
|
||||
static inline bool ffStrContainsIgnCase(const char* str, const char* compareTo)
|
||||
{
|
||||
static inline bool ffStrContainsIgnCase(const char* str, const char* compareTo) {
|
||||
return strcasestr(str, compareTo) != NULL;
|
||||
}
|
||||
|
||||
static inline bool ffStrContainsC(const char* str, char compareTo)
|
||||
{
|
||||
static inline bool ffStrContainsC(const char* str, char compareTo) {
|
||||
return strchr(str, compareTo) != NULL;
|
||||
}
|
||||
|
||||
static inline bool ffCharIsEnglishAlphabet(char c)
|
||||
{
|
||||
static inline bool ffCharIsEnglishAlphabet(char c) {
|
||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
|
||||
}
|
||||
|
||||
static inline bool ffCharIsDigit(char c)
|
||||
{
|
||||
static inline bool ffCharIsDigit(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
static inline bool ffCharIsHexDigit(char c)
|
||||
{
|
||||
static inline bool ffCharIsHexDigit(char c) {
|
||||
return ffCharIsDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
|
||||
}
|
||||
|
||||
static inline int8_t ffHexCharToInt(char c)
|
||||
{
|
||||
if (ffCharIsDigit(c))
|
||||
static inline int8_t ffHexCharToInt(char c) {
|
||||
if (ffCharIsDigit(c)) {
|
||||
return (int8_t) (c - '0');
|
||||
else if ('a' <= c && c <= 'f')
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
return (int8_t) (c - 'a' + 10);
|
||||
else if ('A' <= c && c <= 'F')
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
return (int8_t) (c - 'A' + 10);
|
||||
else
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Copies at most (dstBufSiz - 1) bytes from src to dst; dst is always null-terminated
|
||||
static inline char* ffStrCopy(char* __restrict__ dst, const char* __restrict__ src, size_t dstBufSiz)
|
||||
{
|
||||
if (__builtin_expect(dst == NULL, false) || dstBufSiz == 0) return dst;
|
||||
static inline char* ffStrCopy(char* __restrict__ dst, const char* __restrict__ src, size_t dstBufSiz) {
|
||||
if (__builtin_expect(dst == NULL, false) || dstBufSiz == 0) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
size_t len = strnlen(src, dstBufSiz - 1);
|
||||
memcpy(dst, src, len);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define FASTFETCH_TEXT_MODIFIER_BOLT "\033[1m"
|
||||
#define FASTFETCH_TEXT_MODIFIER_BOLT "\033[1m"
|
||||
#define FASTFETCH_TEXT_MODIFIER_ERROR "\033[1;31m"
|
||||
#define FASTFETCH_TEXT_MODIFIER_RESET "\033[m"
|
||||
|
||||
+108
-80
@@ -3,87 +3,115 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#ifdef FF_HAVE_THREADS
|
||||
#if defined(_WIN32)
|
||||
#include <winternl.h>
|
||||
#include <synchapi.h>
|
||||
#include <process.h>
|
||||
#include <processthreadsapi.h>
|
||||
#define FF_THREAD_MUTEX_INITIALIZER SRWLOCK_INIT
|
||||
typedef SRWLOCK FFThreadMutex;
|
||||
typedef HANDLE FFThreadType;
|
||||
static inline void ffThreadMutexLock(FFThreadMutex* mutex) { AcquireSRWLockExclusive(mutex); }
|
||||
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) { ReleaseSRWLockExclusive(mutex); }
|
||||
static inline FFThreadType ffThreadCreate(unsigned (__stdcall* func)(void*), void* data) {
|
||||
return (FFThreadType)_beginthreadex(NULL, 0, func, data, 0, NULL);
|
||||
}
|
||||
#define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) static __stdcall unsigned fn ## ThreadMain (void* data) { fn((paramType)data); return 0; }
|
||||
#define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) static __stdcall unsigned fn ## ThreadMain () { fn(); return 0; }
|
||||
static inline void ffThreadDetach(FFThreadType thread) { NtClose(thread); }
|
||||
static inline bool ffThreadJoin(FFThreadType thread, uint32_t timeout)
|
||||
{
|
||||
if (NtWaitForSingleObject(thread, FALSE, timeout == 0 ? NULL : &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 }) != STATUS_WAIT_0)
|
||||
{
|
||||
TerminateThread(thread, (DWORD) -1);
|
||||
NtClose(thread);
|
||||
# if defined(_WIN32)
|
||||
# include <winternl.h>
|
||||
# include <synchapi.h>
|
||||
# include <process.h>
|
||||
# include <processthreadsapi.h>
|
||||
# define FF_THREAD_MUTEX_INITIALIZER SRWLOCK_INIT
|
||||
typedef SRWLOCK FFThreadMutex;
|
||||
typedef HANDLE FFThreadType;
|
||||
static inline void ffThreadMutexLock(FFThreadMutex* mutex) {
|
||||
AcquireSRWLockExclusive(mutex);
|
||||
}
|
||||
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) {
|
||||
ReleaseSRWLockExclusive(mutex);
|
||||
}
|
||||
static inline FFThreadType ffThreadCreate(unsigned(__stdcall* func)(void*), void* data) {
|
||||
return (FFThreadType) _beginthreadex(NULL, 0, func, data, 0, NULL);
|
||||
}
|
||||
# define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) \
|
||||
static __stdcall unsigned fn##ThreadMain(void* data) { \
|
||||
fn((paramType) data); \
|
||||
return 0; \
|
||||
}
|
||||
# define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) \
|
||||
static __stdcall unsigned fn##ThreadMain() { \
|
||||
fn(); \
|
||||
return 0; \
|
||||
}
|
||||
static inline void ffThreadDetach(FFThreadType thread) {
|
||||
NtClose(thread);
|
||||
}
|
||||
static inline bool ffThreadJoin(FFThreadType thread, uint32_t timeout) {
|
||||
if (NtWaitForSingleObject(thread, FALSE, timeout == 0 ? NULL : &(LARGE_INTEGER) {.QuadPart = (int64_t) timeout * -10000}) != STATUS_WAIT_0) {
|
||||
TerminateThread(thread, (DWORD) -1);
|
||||
NtClose(thread);
|
||||
return false;
|
||||
}
|
||||
NtClose(thread);
|
||||
return true;
|
||||
}
|
||||
# else
|
||||
# include <pthread.h>
|
||||
# include <signal.h>
|
||||
# if FF_HAVE_PTHREAD_NP
|
||||
# include <pthread_np.h>
|
||||
# endif
|
||||
typedef pthread_t FFThreadType;
|
||||
# if __APPLE__
|
||||
# include <os/lock.h>
|
||||
# define FF_THREAD_MUTEX_INITIALIZER OS_UNFAIR_LOCK_INIT
|
||||
typedef os_unfair_lock FFThreadMutex;
|
||||
static inline void ffThreadMutexLock(os_unfair_lock* mutex) {
|
||||
os_unfair_lock_lock(mutex);
|
||||
}
|
||||
static inline void ffThreadMutexUnlock(os_unfair_lock* mutex) {
|
||||
os_unfair_lock_unlock(mutex);
|
||||
}
|
||||
# else
|
||||
# define FF_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
typedef pthread_mutex_t FFThreadMutex;
|
||||
static inline void ffThreadMutexLock(FFThreadMutex* mutex) {
|
||||
pthread_mutex_lock(mutex);
|
||||
}
|
||||
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) {
|
||||
pthread_mutex_unlock(mutex);
|
||||
}
|
||||
# endif
|
||||
static inline FFThreadType ffThreadCreate(void* (*func)(void*), void* data) {
|
||||
FFThreadType newThread = 0;
|
||||
pthread_create(&newThread, NULL, func, data);
|
||||
return newThread;
|
||||
}
|
||||
# define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) \
|
||||
static void* fn##ThreadMain(void* data) { \
|
||||
fn((paramType) data); \
|
||||
return NULL; \
|
||||
}
|
||||
# define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) \
|
||||
static void* fn##ThreadMain() { \
|
||||
fn(); \
|
||||
return NULL; \
|
||||
}
|
||||
static inline void ffThreadDetach(FFThreadType thread) {
|
||||
pthread_detach(thread);
|
||||
}
|
||||
static inline bool ffThreadJoin(FFThreadType thread, FF_MAYBE_UNUSED uint32_t timeout) {
|
||||
# if HAVE_TIMEDJOIN_NP
|
||||
if (timeout > 0) {
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
|
||||
ts.tv_sec += timeout / 1000;
|
||||
ts.tv_nsec += (timeout % 1000) * 1000000;
|
||||
if (pthread_timedjoin_np(thread, NULL, &ts) != 0) {
|
||||
pthread_kill(thread, SIGTERM);
|
||||
return false;
|
||||
}
|
||||
NtClose(thread);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#if FF_HAVE_PTHREAD_NP
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
typedef pthread_t FFThreadType;
|
||||
#if __APPLE__
|
||||
#include <os/lock.h>
|
||||
#define FF_THREAD_MUTEX_INITIALIZER OS_UNFAIR_LOCK_INIT
|
||||
typedef os_unfair_lock FFThreadMutex;
|
||||
static inline void ffThreadMutexLock(os_unfair_lock* mutex) { os_unfair_lock_lock(mutex); }
|
||||
static inline void ffThreadMutexUnlock(os_unfair_lock* mutex) { os_unfair_lock_unlock(mutex); }
|
||||
#else
|
||||
#define FF_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
||||
typedef pthread_mutex_t FFThreadMutex;
|
||||
static inline void ffThreadMutexLock(FFThreadMutex* mutex) { pthread_mutex_lock(mutex); }
|
||||
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) { pthread_mutex_unlock(mutex); }
|
||||
#endif
|
||||
static inline FFThreadType ffThreadCreate(void* (* func)(void*), void* data) {
|
||||
FFThreadType newThread = 0;
|
||||
pthread_create(&newThread, NULL, func, data);
|
||||
return newThread;
|
||||
}
|
||||
#define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) static void* fn ## ThreadMain (void* data) { fn((paramType)data); return NULL; }
|
||||
#define FF_THREAD_ENTRY_DECL_WRAPPER_NOPARAM(fn) static void* fn ## ThreadMain () { fn(); return NULL; }
|
||||
static inline void ffThreadDetach(FFThreadType thread) { pthread_detach(thread); }
|
||||
static inline bool ffThreadJoin(FFThreadType thread, FF_MAYBE_UNUSED uint32_t timeout)
|
||||
{
|
||||
#if HAVE_TIMEDJOIN_NP
|
||||
if (timeout > 0)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
|
||||
{
|
||||
ts.tv_sec += timeout / 1000;
|
||||
ts.tv_nsec += (timeout % 1000) * 1000000;
|
||||
if (pthread_timedjoin_np(thread, NULL, &ts) != 0)
|
||||
{
|
||||
pthread_kill(thread, SIGTERM);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
pthread_join(thread, NULL);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#else //FF_HAVE_THREADS
|
||||
#define FF_THREAD_MUTEX_INITIALIZER 0
|
||||
typedef char FFThreadMutex;
|
||||
static inline void ffThreadMutexLock(FFThreadMutex* mutex) { FF_UNUSED(mutex) }
|
||||
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) { FF_UNUSED(mutex) }
|
||||
#define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType)
|
||||
#endif //FF_HAVE_THREADS
|
||||
}
|
||||
# endif
|
||||
pthread_join(thread, NULL);
|
||||
return true;
|
||||
}
|
||||
# endif
|
||||
#else // FF_HAVE_THREADS
|
||||
# define FF_THREAD_MUTEX_INITIALIZER 0
|
||||
typedef char FFThreadMutex;
|
||||
static inline void ffThreadMutexLock(FFThreadMutex* mutex) {
|
||||
FF_UNUSED(mutex)
|
||||
}
|
||||
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex){FF_UNUSED(mutex)}
|
||||
# define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType)
|
||||
#endif // FF_HAVE_THREADS
|
||||
|
||||
+40
-43
@@ -4,64 +4,62 @@
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#ifdef _WIN32
|
||||
#include <ntstatus.h>
|
||||
#include "common/windows/nt.h"
|
||||
#include <profileapi.h>
|
||||
# include <ntstatus.h>
|
||||
# include "common/windows/nt.h"
|
||||
# include <profileapi.h>
|
||||
#elif defined(__HAIKU__)
|
||||
#include <OS.h>
|
||||
# include <OS.h>
|
||||
#endif
|
||||
|
||||
#include "common/arrayUtils.h"
|
||||
|
||||
static inline double ffTimeGetTick(void) //In msec
|
||||
static inline double ffTimeGetTick(void) // In msec
|
||||
{
|
||||
#ifdef _WIN32
|
||||
extern double ffQpcMultiplier;
|
||||
LARGE_INTEGER start;
|
||||
RtlQueryPerformanceCounter(&start);
|
||||
return (double) start.QuadPart * ffQpcMultiplier;
|
||||
#elif defined(__HAIKU__)
|
||||
return (double) system_time() / 1000.;
|
||||
#else
|
||||
struct timespec timeNow;
|
||||
clock_gettime(CLOCK_MONOTONIC, &timeNow);
|
||||
return (double) timeNow.tv_sec * 1000. + (double) timeNow.tv_nsec / 1000000.;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
extern double ffQpcMultiplier;
|
||||
LARGE_INTEGER start;
|
||||
RtlQueryPerformanceCounter(&start);
|
||||
return (double) start.QuadPart * ffQpcMultiplier;
|
||||
#elif defined(__HAIKU__)
|
||||
return (double) system_time() / 1000.;
|
||||
#else
|
||||
struct timespec timeNow;
|
||||
clock_gettime(CLOCK_MONOTONIC, &timeNow);
|
||||
return (double) timeNow.tv_sec * 1000. + (double) timeNow.tv_nsec / 1000000.;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
static inline uint64_t ffFileTimeToUnixMs(uint64_t value)
|
||||
{
|
||||
if (__builtin_expect(__builtin_usubll_overflow(value, 116444736000000000ull, &value), false))
|
||||
static inline uint64_t ffFileTimeToUnixMs(uint64_t value) {
|
||||
if (__builtin_expect(__builtin_usubll_overflow(value, 116444736000000000ull, &value), false)) {
|
||||
return 0;
|
||||
}
|
||||
return value / 10000ull;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline uint64_t ffTimeGetNow(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
uint64_t timeNow = ffKSystemTimeToUInt64(&SharedUserData->SystemTime);
|
||||
return ffFileTimeToUnixMs((uint64_t) timeNow);
|
||||
#elif defined(__HAIKU__)
|
||||
return (uint64_t) real_time_clock_usecs() / 1000u;
|
||||
#else
|
||||
struct timespec timeNow;
|
||||
clock_gettime(CLOCK_REALTIME, &timeNow);
|
||||
return (uint64_t)(((uint64_t) timeNow.tv_sec * 1000u) + ((uint64_t) timeNow.tv_nsec / 1000000u));
|
||||
#endif
|
||||
static inline uint64_t ffTimeGetNow(void) {
|
||||
#ifdef _WIN32
|
||||
uint64_t timeNow = ffKSystemTimeToUInt64(&SharedUserData->SystemTime);
|
||||
return ffFileTimeToUnixMs((uint64_t) timeNow);
|
||||
#elif defined(__HAIKU__)
|
||||
return (uint64_t) real_time_clock_usecs() / 1000u;
|
||||
#else
|
||||
struct timespec timeNow;
|
||||
clock_gettime(CLOCK_REALTIME, &timeNow);
|
||||
return (uint64_t) (((uint64_t) timeNow.tv_sec * 1000u) + ((uint64_t) timeNow.tv_nsec / 1000000u));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns true if not interrupted
|
||||
static inline bool ffTimeSleep(uint32_t msec)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER interval;
|
||||
interval.QuadPart = -(int64_t) msec * 10000; // Relative time in 100-nanosecond intervals
|
||||
return NT_SUCCESS(NtDelayExecution(TRUE, &interval));
|
||||
#else
|
||||
return nanosleep(&(struct timespec){ msec / 1000, (long) (msec % 1000) * 1000000 }, NULL) == 0;
|
||||
#endif
|
||||
static inline bool ffTimeSleep(uint32_t msec) {
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER interval;
|
||||
interval.QuadPart = -(int64_t) msec * 10000; // Relative time in 100-nanosecond intervals
|
||||
return NT_SUCCESS(NtDelayExecution(TRUE, &interval));
|
||||
#else
|
||||
return nanosleep(&(struct timespec) {msec / 1000, (long) (msec % 1000) * 1000000}, NULL) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Not thread-safe
|
||||
@@ -73,8 +71,7 @@ const char* ffTimeToShortStr(uint64_t msec);
|
||||
// Not thread-safe
|
||||
const char* ffTimeToTimeStr(uint64_t msec);
|
||||
|
||||
typedef struct FFTimeGetAgeResult
|
||||
{
|
||||
typedef struct FFTimeGetAgeResult {
|
||||
uint32_t years;
|
||||
uint32_t daysOfYear;
|
||||
double yearsFraction;
|
||||
|
||||
+5
-3
@@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
static inline void ffUnused(int dummy, ...) { (void) dummy; }
|
||||
static inline void ffUnused(int dummy, ...) {
|
||||
(void) dummy;
|
||||
}
|
||||
#define FF_UNUSED(...) ffUnused(0, __VA_ARGS__);
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define FF_MAYBE_UNUSED __attribute__ ((__unused__))
|
||||
# define FF_MAYBE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define FF_MAYBE_UNUSED
|
||||
# define FF_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef FF_HAVE_WCWIDTH
|
||||
#include <wchar.h>
|
||||
# include <wchar.h>
|
||||
|
||||
// Should be char32_t but it's not defined on macOS
|
||||
static_assert(sizeof(wchar_t) == sizeof(uint32_t), "wcwidth implementation requires wchar_t to be 32 bits");
|
||||
|
||||
+10
-12
@@ -3,18 +3,17 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
//https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer
|
||||
//https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes
|
||||
static void CoUninitializeWrap(void)
|
||||
{
|
||||
// https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer
|
||||
// https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes
|
||||
static void CoUninitializeWrap(void) {
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
static const char* doInitCom()
|
||||
{
|
||||
static const char* doInitCom() {
|
||||
// Initialize COM
|
||||
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
|
||||
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) {
|
||||
return "CoInitializeEx() failed";
|
||||
}
|
||||
|
||||
// Set general COM security levels
|
||||
|
||||
@@ -30,8 +29,7 @@ static const char* doInitCom()
|
||||
NULL // Reserved
|
||||
);
|
||||
|
||||
if (FAILED(hRes) && hRes != RPC_E_TOO_LATE /* Has been set by a random dll */)
|
||||
{
|
||||
if (FAILED(hRes) && hRes != RPC_E_TOO_LATE /* Has been set by a random dll */) {
|
||||
CoUninitialize();
|
||||
return "CoInitializeSecurity() failed";
|
||||
}
|
||||
@@ -40,10 +38,10 @@ static const char* doInitCom()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffInitCom(void)
|
||||
{
|
||||
const char* ffInitCom(void) {
|
||||
static const char* error = "";
|
||||
if (error && error[0] == '\0')
|
||||
if (error && error[0] == '\0') {
|
||||
error = doInitCom();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <unknwn.h>
|
||||
# include <unknwn.h>
|
||||
|
||||
const char* ffInitCom(void);
|
||||
|
||||
static inline void ffReleaseComObject(void* ppUnknown)
|
||||
{
|
||||
static inline void ffReleaseComObject(void* ppUnknown) {
|
||||
IUnknown* pUnknown = *(IUnknown**) ppUnknown;
|
||||
if (pUnknown) pUnknown->Release();
|
||||
if (pUnknown) {
|
||||
pUnknown->Release();
|
||||
}
|
||||
}
|
||||
|
||||
#define FF_AUTO_RELEASE_COM_OBJECT __attribute__((__cleanup__(ffReleaseComObject)))
|
||||
# define FF_AUTO_RELEASE_COM_OBJECT __attribute__((__cleanup__(ffReleaseComObject)))
|
||||
|
||||
#else
|
||||
// Win32 COM headers requires C++ compiler
|
||||
#error Must be included in C++ source file
|
||||
// Win32 COM headers requires C++ compiler
|
||||
# error Must be included in C++ source file
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
ssize_t getline(char** lineptr, size_t* n, FILE* stream) {
|
||||
ssize_t pos = -1;
|
||||
int c;
|
||||
|
||||
@@ -28,13 +28,13 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
while(c != EOF) {
|
||||
if ((size_t)(pos + 1) >= *n) {
|
||||
while (c != EOF) {
|
||||
if ((size_t) (pos + 1) >= *n) {
|
||||
size_t new_size = *n + (*n >> 2);
|
||||
if (new_size < 128) {
|
||||
new_size = 128;
|
||||
}
|
||||
char *new_ptr = realloc(*lineptr, new_size);
|
||||
char* new_ptr = realloc(*lineptr, new_size);
|
||||
if (new_ptr == NULL) {
|
||||
pos = -1;
|
||||
goto exit;
|
||||
@@ -43,7 +43,7 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
|
||||
*lineptr = new_ptr;
|
||||
}
|
||||
|
||||
((char *)(*lineptr))[pos ++] = (char)c;
|
||||
((char*) (*lineptr))[pos++] = (char) c;
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
|
||||
ssize_t getline(char** lineptr, size_t* n, FILE* stream);
|
||||
|
||||
+148
-218
@@ -30,10 +30,8 @@ NTSYSAPI NTSTATUS NTAPI NtPowerInformation(
|
||||
OUT PVOID OutputBuffer OPTIONAL,
|
||||
IN ULONG OutputBufferLength);
|
||||
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI RtlGetVersion(
|
||||
_Inout_ PRTL_OSVERSIONINFOW lpVersionInformation
|
||||
);
|
||||
_Inout_ PRTL_OSVERSIONINFOW lpVersionInformation);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtQueryDirectoryFile(
|
||||
IN HANDLE FileHandle,
|
||||
@@ -49,29 +47,26 @@ NTSYSAPI NTSTATUS NTAPI NtQueryDirectoryFile(
|
||||
IN BOOLEAN RestartScan);
|
||||
|
||||
// https://ntdoc.m417z.com/process_devicemap_information_ex
|
||||
typedef struct _PROCESS_DEVICEMAP_INFORMATION_EX
|
||||
{
|
||||
union
|
||||
{
|
||||
typedef struct _PROCESS_DEVICEMAP_INFORMATION_EX {
|
||||
union {
|
||||
struct
|
||||
{
|
||||
HANDLE DirectoryHandle; // A handle to a directory object that can be set as the new device map for the process. This handle must have DIRECTORY_TRAVERSE access.
|
||||
} Set;
|
||||
struct
|
||||
{
|
||||
ULONG DriveMap; // A bitmask that indicates which drive letters are currently in use in the process's device map.
|
||||
UCHAR DriveType[32]; // A value that indicates the type of each drive (e.g., local disk, network drive, etc.). // DRIVE_* WinBase.h
|
||||
ULONG DriveMap; // A bitmask that indicates which drive letters are currently in use in the process's device map.
|
||||
UCHAR DriveType[32]; // A value that indicates the type of each drive (e.g., local disk, network drive, etc.). // DRIVE_* WinBase.h
|
||||
} Query;
|
||||
};
|
||||
ULONG Flags; // PROCESS_LUID_DOSDEVICES_ONLY
|
||||
} PROCESS_DEVICEMAP_INFORMATION_EX, *PPROCESS_DEVICEMAP_INFORMATION_EX;
|
||||
|
||||
#ifndef NtCurrentProcess
|
||||
#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
|
||||
# define NtCurrentProcess() ((HANDLE) (LONG_PTR) - 1)
|
||||
#endif
|
||||
|
||||
typedef struct _CURDIR
|
||||
{
|
||||
typedef struct _CURDIR {
|
||||
UNICODE_STRING DosPath;
|
||||
HANDLE Handle;
|
||||
} CURDIR, *PCURDIR;
|
||||
@@ -81,15 +76,13 @@ NTSYSAPI PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID BaseOfImage);
|
||||
/**
|
||||
* The SECTION_IMAGE_INFORMATION structure contains detailed information about an image section.
|
||||
*/
|
||||
typedef struct _SECTION_IMAGE_INFORMATION
|
||||
{
|
||||
PVOID TransferAddress; // The address of the image entry point function.
|
||||
ULONG ZeroBits; // The number of high-order address bits that must be zero in the image base address.
|
||||
SIZE_T MaximumStackSize; // The maximum stack size of threads from the PE file header.
|
||||
SIZE_T CommittedStackSize; // The initial stack size of threads from the PE file header.
|
||||
ULONG SubSystemType; // The image subsystem from the PE file header (e.g., Windows GUI, Windows CUI, POSIX).
|
||||
union
|
||||
{
|
||||
typedef struct _SECTION_IMAGE_INFORMATION {
|
||||
PVOID TransferAddress; // The address of the image entry point function.
|
||||
ULONG ZeroBits; // The number of high-order address bits that must be zero in the image base address.
|
||||
SIZE_T MaximumStackSize; // The maximum stack size of threads from the PE file header.
|
||||
SIZE_T CommittedStackSize; // The initial stack size of threads from the PE file header.
|
||||
ULONG SubSystemType; // The image subsystem from the PE file header (e.g., Windows GUI, Windows CUI, POSIX).
|
||||
union {
|
||||
struct
|
||||
{
|
||||
USHORT SubSystemMinorVersion;
|
||||
@@ -97,8 +90,7 @@ typedef struct _SECTION_IMAGE_INFORMATION
|
||||
};
|
||||
ULONG SubSystemVersion;
|
||||
};
|
||||
union
|
||||
{
|
||||
union {
|
||||
struct
|
||||
{
|
||||
USHORT MajorOperatingSystemVersion;
|
||||
@@ -106,35 +98,32 @@ typedef struct _SECTION_IMAGE_INFORMATION
|
||||
};
|
||||
ULONG OperatingSystemVersion;
|
||||
};
|
||||
USHORT ImageCharacteristics; // The image characteristics from the PE file header.
|
||||
USHORT DllCharacteristics; // The DLL characteristics flags (e.g., ASLR, NX compatibility).
|
||||
USHORT Machine; // The image architecture (e.g., x86, x64, ARM).
|
||||
BOOLEAN ImageContainsCode; // The image contains native executable code.
|
||||
union
|
||||
{
|
||||
USHORT ImageCharacteristics; // The image characteristics from the PE file header.
|
||||
USHORT DllCharacteristics; // The DLL characteristics flags (e.g., ASLR, NX compatibility).
|
||||
USHORT Machine; // The image architecture (e.g., x86, x64, ARM).
|
||||
BOOLEAN ImageContainsCode; // The image contains native executable code.
|
||||
union {
|
||||
UCHAR ImageFlags;
|
||||
struct
|
||||
{
|
||||
UCHAR ComPlusNativeReady : 1; // The image contains precompiled .NET assembly generated by NGEN (Native Image Generator).
|
||||
UCHAR ComPlusILOnly : 1; // the image contains only Microsoft Intermediate Language (IL) assembly.
|
||||
UCHAR ImageDynamicallyRelocated : 1; // The image was mapped using a random base address rather than the preferred base address.
|
||||
UCHAR ImageMappedFlat : 1; // The image was mapped using a single contiguous region, rather than separate regions for each section.
|
||||
UCHAR BaseBelow4gb : 1; // The image was mapped using a base address below the 4 GB boundary.
|
||||
UCHAR ComPlusPrefer32bit : 1; // The image prefers to run as a 32-bit process, even on a 64-bit system.
|
||||
UCHAR ComPlusNativeReady : 1; // The image contains precompiled .NET assembly generated by NGEN (Native Image Generator).
|
||||
UCHAR ComPlusILOnly : 1; // the image contains only Microsoft Intermediate Language (IL) assembly.
|
||||
UCHAR ImageDynamicallyRelocated : 1; // The image was mapped using a random base address rather than the preferred base address.
|
||||
UCHAR ImageMappedFlat : 1; // The image was mapped using a single contiguous region, rather than separate regions for each section.
|
||||
UCHAR BaseBelow4gb : 1; // The image was mapped using a base address below the 4 GB boundary.
|
||||
UCHAR ComPlusPrefer32bit : 1; // The image prefers to run as a 32-bit process, even on a 64-bit system.
|
||||
UCHAR Reserved : 2;
|
||||
};
|
||||
};
|
||||
ULONG LoaderFlags; // Reserved by ntdll.dll for the Windows loader.
|
||||
ULONG ImageFileSize; // The size of the image, in bytes, including all headers.
|
||||
ULONG CheckSum; // The image file checksum, from the PE optional header.
|
||||
ULONG LoaderFlags; // Reserved by ntdll.dll for the Windows loader.
|
||||
ULONG ImageFileSize; // The size of the image, in bytes, including all headers.
|
||||
ULONG CheckSum; // The image file checksum, from the PE optional header.
|
||||
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;
|
||||
|
||||
typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
|
||||
{
|
||||
typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION {
|
||||
GUID BootIdentifier;
|
||||
FIRMWARE_TYPE FirmwareType;
|
||||
union
|
||||
{
|
||||
union {
|
||||
ULONGLONG BootFlags;
|
||||
struct
|
||||
{
|
||||
@@ -146,15 +135,14 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
|
||||
ULONGLONG DbgSystemHiveReplace : 1;
|
||||
ULONGLONG DbgMeasuredLaunchSmmProtections : 1;
|
||||
ULONGLONG DbgMeasuredLaunchSmmLevel : 7; // 20H1
|
||||
ULONGLONG DbgBugCheckRecovery : 1; // 24H2
|
||||
ULONGLONG DbgBugCheckRecovery : 1; // 24H2
|
||||
ULONGLONG DbgFASR : 1;
|
||||
ULONGLONG DbgUseCachedBcd : 1;
|
||||
};
|
||||
};
|
||||
} SYSTEM_BOOT_ENVIRONMENT_INFORMATION;
|
||||
|
||||
typedef struct _RTL_PROCESS_MODULE_INFORMATION
|
||||
{
|
||||
typedef struct _RTL_PROCESS_MODULE_INFORMATION {
|
||||
PVOID Section;
|
||||
PVOID MappedBase;
|
||||
PVOID ImageBase;
|
||||
@@ -167,8 +155,7 @@ typedef struct _RTL_PROCESS_MODULE_INFORMATION
|
||||
UCHAR FullPathName[256];
|
||||
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
|
||||
|
||||
typedef struct _RTL_PROCESS_MODULES
|
||||
{
|
||||
typedef struct _RTL_PROCESS_MODULES {
|
||||
ULONG NumberOfModules;
|
||||
_Field_size_(NumberOfModules) RTL_PROCESS_MODULE_INFORMATION Modules[1];
|
||||
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
|
||||
@@ -184,8 +171,7 @@ NTSTATUS NTAPI NtQuerySystemEnvironmentValueEx(
|
||||
NTSTATUS NTAPI RtlGUIDFromString(IN PCUNICODE_STRING GuidString, OUT GUID* Guid);
|
||||
NTSTATUS NTAPI RtlStringFromGUIDEx(IN GUID* Guid, OUT PCUNICODE_STRING GuidString, _In_ BOOLEAN AllocateGuidString);
|
||||
|
||||
typedef struct _SYSTEM_SECUREBOOT_INFORMATION
|
||||
{
|
||||
typedef struct _SYSTEM_SECUREBOOT_INFORMATION {
|
||||
BOOLEAN SecureBootEnabled;
|
||||
BOOLEAN SecureBootCapable;
|
||||
} SYSTEM_SECUREBOOT_INFORMATION, *PSYSTEM_SECUREBOOT_INFORMATION;
|
||||
@@ -196,18 +182,15 @@ NTSTATUS NTAPI NtQuerySystemInformationEx(
|
||||
_In_ ULONG InputBufferLength,
|
||||
_Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
|
||||
_In_ ULONG SystemInformationLength,
|
||||
_Out_opt_ PULONG ReturnLength
|
||||
);
|
||||
_Out_opt_ PULONG ReturnLength);
|
||||
|
||||
typedef enum _SYSTEM_FIRMWARE_TABLE_ACTION
|
||||
{
|
||||
typedef enum _SYSTEM_FIRMWARE_TABLE_ACTION {
|
||||
SystemFirmwareTableEnumerate,
|
||||
SystemFirmwareTableGet,
|
||||
SystemFirmwareTableMax
|
||||
} SYSTEM_FIRMWARE_TABLE_ACTION;
|
||||
|
||||
typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION
|
||||
{
|
||||
typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION {
|
||||
ULONG ProviderSignature; // (same as the GetSystemFirmwareTable function)
|
||||
SYSTEM_FIRMWARE_TABLE_ACTION Action;
|
||||
ULONG TableID;
|
||||
@@ -220,8 +203,7 @@ NTSYSAPI NTSTATUS NTAPI NtDelayExecution(_In_ BOOLEAN Alertable, _In_ PLARGE_INT
|
||||
/**
|
||||
* The KSYSTEM_TIME structure represents interrupt time, system time, and time zone bias.
|
||||
*/
|
||||
typedef struct _KSYSTEM_TIME
|
||||
{
|
||||
typedef struct _KSYSTEM_TIME {
|
||||
ULONG LowPart;
|
||||
LONG High1Time;
|
||||
LONG High2Time;
|
||||
@@ -240,8 +222,7 @@ typedef struct _KSYSTEM_TIME
|
||||
* \remarks NEC98x86 represents the NEC PC-98 architecture,
|
||||
* supported only on very early Windows releases.
|
||||
*/
|
||||
typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
|
||||
{
|
||||
typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE {
|
||||
StandardDesign,
|
||||
NEC98x86,
|
||||
EndAlternatives
|
||||
@@ -252,8 +233,7 @@ typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE
|
||||
*
|
||||
* \sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
|
||||
*/
|
||||
typedef struct _KUSER_SHARED_DATA
|
||||
{
|
||||
typedef struct _KUSER_SHARED_DATA {
|
||||
//
|
||||
// Current low 32-bit of tick count and tick count multiplier.
|
||||
//
|
||||
@@ -344,14 +324,13 @@ typedef struct _KUSER_SHARED_DATA
|
||||
// This value controls Application Compatibility (AppCompat) switchback processing.
|
||||
//
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
ULONG AppCompatFlag;
|
||||
struct
|
||||
{
|
||||
ULONG SwitchbackEnabled : 1; // Basic switchback processing
|
||||
ULONG ExtendedHeuristics : 1; // Extended switchback heuristics
|
||||
ULONG TelemetryFallback : 1; // Telemetry-driven fallback
|
||||
ULONG SwitchbackEnabled : 1; // Basic switchback processing
|
||||
ULONG ExtendedHeuristics : 1; // Extended switchback heuristics
|
||||
ULONG TelemetryFallback : 1; // Telemetry-driven fallback
|
||||
ULONG Reserved : 29;
|
||||
} AppCompatFlags;
|
||||
};
|
||||
@@ -435,13 +414,12 @@ typedef struct _KUSER_SHARED_DATA
|
||||
|
||||
BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX];
|
||||
|
||||
|
||||
//
|
||||
// Reserved fields - do not use.
|
||||
//
|
||||
|
||||
ULONG MaximumUserModeAddressDeprecated; // Deprecated, use SystemBasicInformation instead.
|
||||
ULONG SystemRangeStartDeprecated; // Deprecated, use SystemRangeStartInformation instead.
|
||||
ULONG SystemRangeStartDeprecated; // Deprecated, use SystemRangeStartInformation instead.
|
||||
|
||||
//
|
||||
// Time slippage while in debugger.
|
||||
@@ -489,8 +467,7 @@ typedef struct _KUSER_SHARED_DATA
|
||||
// Mitigation policies.
|
||||
//
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
UCHAR MitigationPolicies;
|
||||
struct
|
||||
{
|
||||
@@ -562,8 +539,7 @@ typedef struct _KUSER_SHARED_DATA
|
||||
// Virtualization flags.
|
||||
//
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
UCHAR VirtualizationFlags;
|
||||
|
||||
#if defined(_ARM64_)
|
||||
@@ -580,7 +556,6 @@ typedef struct _KUSER_SHARED_DATA
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
@@ -598,8 +573,7 @@ typedef struct _KUSER_SHARED_DATA
|
||||
// API for an accurate result
|
||||
//
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
ULONG SharedDataFlags;
|
||||
struct
|
||||
{
|
||||
@@ -608,20 +582,20 @@ typedef struct _KUSER_SHARED_DATA
|
||||
// Use the bit definitions instead.
|
||||
//
|
||||
|
||||
ULONG DbgErrorPortPresent : 1;
|
||||
ULONG DbgElevationEnabled : 1;
|
||||
ULONG DbgVirtEnabled : 1;
|
||||
ULONG DbgErrorPortPresent : 1;
|
||||
ULONG DbgElevationEnabled : 1;
|
||||
ULONG DbgVirtEnabled : 1;
|
||||
ULONG DbgInstallerDetectEnabled : 1;
|
||||
ULONG DbgLkgEnabled : 1;
|
||||
ULONG DbgDynProcessorEnabled : 1;
|
||||
ULONG DbgConsoleBrokerEnabled : 1;
|
||||
ULONG DbgSecureBootEnabled : 1;
|
||||
ULONG DbgMultiSessionSku : 1;
|
||||
ULONG DbgLkgEnabled : 1;
|
||||
ULONG DbgDynProcessorEnabled : 1;
|
||||
ULONG DbgConsoleBrokerEnabled : 1;
|
||||
ULONG DbgSecureBootEnabled : 1;
|
||||
ULONG DbgMultiSessionSku : 1;
|
||||
ULONG DbgMultiUsersInSessionSku : 1;
|
||||
ULONG DbgStateSeparationEnabled : 1;
|
||||
ULONG DbgSplitTokenEnabled : 1;
|
||||
ULONG DbgShadowAdminEnabled : 1;
|
||||
ULONG SpareBits : 19;
|
||||
ULONG DbgSplitTokenEnabled : 1;
|
||||
ULONG DbgShadowAdminEnabled : 1;
|
||||
ULONG SpareBits : 19;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -630,63 +604,57 @@ typedef struct _KUSER_SHARED_DATA
|
||||
|
||||
#define SharedUserData ((const KUSER_SHARED_DATA*) 0x7FFE0000UL)
|
||||
|
||||
static inline uint64_t ffKSystemTimeToUInt64(const volatile KSYSTEM_TIME* pTime)
|
||||
{
|
||||
#if _WIN64
|
||||
static inline uint64_t ffKSystemTimeToUInt64(const volatile KSYSTEM_TIME* pTime) {
|
||||
#if _WIN64
|
||||
|
||||
// This is safe even if pTime is not 8-byte aligned
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/winprog64/fault-alignments
|
||||
return *(const volatile uint64_t*) pTime;
|
||||
|
||||
#else
|
||||
#else
|
||||
|
||||
uint32_t low, high1, high2;
|
||||
|
||||
do {
|
||||
high1 = pTime->High1Time;
|
||||
low = pTime->LowPart;
|
||||
low = pTime->LowPart;
|
||||
high2 = pTime->High2Time;
|
||||
} while (high1 != high2);
|
||||
|
||||
return ((uint64_t) high1 << 32) | low;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool ffIsWindows10OrGreater()
|
||||
{
|
||||
#if FF_WIN81_COMPAT
|
||||
static inline bool ffIsWindows10OrGreater() {
|
||||
#if FF_WIN81_COMPAT
|
||||
return SharedUserData->NtMajorVersion >= 10;
|
||||
#else
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool ffIsWindows11OrGreater()
|
||||
{
|
||||
static inline bool ffIsWindows11OrGreater() {
|
||||
return ffIsWindows10OrGreater() && SharedUserData->NtBuildNumber >= 22000;
|
||||
}
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtOpenProcessToken(
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_Out_ PHANDLE TokenHandle
|
||||
);
|
||||
_Out_ PHANDLE TokenHandle);
|
||||
NTSYSAPI NTSTATUS NTAPI NtAdjustPrivilegesToken(
|
||||
_In_ HANDLE TokenHandle,
|
||||
_In_ BOOLEAN DisableAllPrivileges,
|
||||
_In_opt_ PTOKEN_PRIVILEGES NewState,
|
||||
_In_ ULONG BufferLength,
|
||||
_Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState,
|
||||
_Out_opt_ PULONG ReturnLength
|
||||
);
|
||||
_Out_opt_ PULONG ReturnLength);
|
||||
NTSYSAPI NTSTATUS NTAPI NtQueryInformationToken(
|
||||
_In_ HANDLE TokenHandle,
|
||||
_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||
_Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) PVOID TokenInformation,
|
||||
_In_ ULONG TokenInformationLength,
|
||||
_Out_ PULONG ReturnLength
|
||||
);
|
||||
#define NtCurrentProcessToken() ((HANDLE)(LONG_PTR)-4) // for NtQueryInformationToken only; Windows 8+
|
||||
_Out_ PULONG ReturnLength);
|
||||
#define NtCurrentProcessToken() ((HANDLE) (LONG_PTR) - 4) // for NtQueryInformationToken only; Windows 8+
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtReadFile(
|
||||
_In_ HANDLE FileHandle,
|
||||
@@ -697,49 +665,42 @@ NTSYSAPI NTSTATUS NTAPI NtReadFile(
|
||||
_Out_writes_bytes_(Length) PVOID Buffer,
|
||||
_In_ ULONG Length,
|
||||
_In_opt_ PLARGE_INTEGER ByteOffset,
|
||||
_In_opt_ PULONG Key
|
||||
);
|
||||
_In_opt_ PULONG Key);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtCreateEvent(
|
||||
_Out_ PHANDLE EventHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_In_ EVENT_TYPE EventType,
|
||||
_In_ BOOLEAN InitialState
|
||||
);
|
||||
_In_ BOOLEAN InitialState);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtQueryAttributesFile(
|
||||
_In_ PCOBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_Out_ PFILE_BASIC_INFORMATION FileInformation
|
||||
);
|
||||
_Out_ PFILE_BASIC_INFORMATION FileInformation);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI RtlUnicodeToUTF8N(
|
||||
_Out_writes_bytes_to_(UTF8StringMaxByteCount, *UTF8StringActualByteCount) PCHAR UTF8StringDestination,
|
||||
_In_ ULONG UTF8StringMaxByteCount,
|
||||
_Out_opt_ PULONG UTF8StringActualByteCount,
|
||||
_In_reads_bytes_(UnicodeStringByteCount) PCWCH UnicodeStringSource,
|
||||
_In_ ULONG UnicodeStringByteCount
|
||||
);
|
||||
_In_ ULONG UnicodeStringByteCount);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI RtlUTF8ToUnicodeN(
|
||||
_Out_writes_bytes_to_(UnicodeStringMaxByteCount, *UnicodeStringActualByteCount) PWSTR UnicodeStringDestination,
|
||||
_In_ ULONG UnicodeStringMaxByteCount,
|
||||
_Out_opt_ PULONG UnicodeStringActualByteCount,
|
||||
_In_reads_bytes_(UTF8StringByteCount) PCCH UTF8StringSource,
|
||||
_In_ ULONG UTF8StringByteCount
|
||||
);
|
||||
_In_ ULONG UTF8StringByteCount);
|
||||
|
||||
#define RTL_MAX_DRIVE_LETTERS 32
|
||||
typedef struct _RTL_DRIVE_LETTER_CURDIR
|
||||
{
|
||||
typedef struct _RTL_DRIVE_LETTER_CURDIR {
|
||||
USHORT Flags;
|
||||
USHORT Length;
|
||||
ULONG TimeStamp;
|
||||
STRING DosPath;
|
||||
} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
|
||||
|
||||
typedef struct _RTL_USER_PROCESS_PARAMETERS_FULL
|
||||
{
|
||||
typedef struct _RTL_USER_PROCESS_PARAMETERS_FULL {
|
||||
ULONG MaximumLength;
|
||||
ULONG Length;
|
||||
|
||||
@@ -794,8 +755,7 @@ typedef struct CPTABLEINFO* PCPTABLEINFO;
|
||||
typedef struct NLSTABLEINFO* PNLSTABLEINFO;
|
||||
typedef struct GDI_HANDLE_ENTRY* PGDI_HANDLE_ENTRY;
|
||||
|
||||
typedef struct _PEB_FULL
|
||||
{
|
||||
typedef struct _PEB_FULL {
|
||||
//
|
||||
// The process was cloned with an inherited address space.
|
||||
//
|
||||
@@ -811,19 +771,18 @@ typedef struct _PEB_FULL
|
||||
//
|
||||
BOOLEAN BeingDebugged;
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
BOOLEAN BitField;
|
||||
struct
|
||||
{
|
||||
BOOLEAN ImageUsesLargePages : 1; // The process uses large image regions (4 MB).
|
||||
BOOLEAN IsProtectedProcess : 1; // The process is a protected process.
|
||||
BOOLEAN IsImageDynamicallyRelocated : 1; // The process image base address was relocated.
|
||||
BOOLEAN SkipPatchingUser32Forwarders : 1; // The process skipped forwarders for User32.dll functions. 1 for 64-bit, 0 for 32-bit.
|
||||
BOOLEAN IsPackagedProcess : 1; // The process is a packaged store process (APPX/MSIX).
|
||||
BOOLEAN IsAppContainerProcess : 1; // The process has an AppContainer token.
|
||||
BOOLEAN IsProtectedProcessLight : 1; // The process is a protected process (light).
|
||||
BOOLEAN IsLongPathAwareProcess : 1; // The process is long path aware.
|
||||
BOOLEAN ImageUsesLargePages : 1; // The process uses large image regions (4 MB).
|
||||
BOOLEAN IsProtectedProcess : 1; // The process is a protected process.
|
||||
BOOLEAN IsImageDynamicallyRelocated : 1; // The process image base address was relocated.
|
||||
BOOLEAN SkipPatchingUser32Forwarders : 1; // The process skipped forwarders for User32.dll functions. 1 for 64-bit, 0 for 32-bit.
|
||||
BOOLEAN IsPackagedProcess : 1; // The process is a packaged store process (APPX/MSIX).
|
||||
BOOLEAN IsAppContainerProcess : 1; // The process has an AppContainer token.
|
||||
BOOLEAN IsProtectedProcessLight : 1; // The process is a protected process (light).
|
||||
BOOLEAN IsLongPathAwareProcess : 1; // The process is long path aware.
|
||||
};
|
||||
};
|
||||
|
||||
@@ -875,19 +834,18 @@ typedef struct _PEB_FULL
|
||||
//
|
||||
// Cross process flags.
|
||||
//
|
||||
union
|
||||
{
|
||||
union {
|
||||
ULONG CrossProcessFlags;
|
||||
struct
|
||||
{
|
||||
ULONG ProcessInJob : 1; // The process is part of a job.
|
||||
ULONG ProcessInitializing : 1; // The process is initializing.
|
||||
ULONG ProcessUsingVEH : 1; // The process is using VEH.
|
||||
ULONG ProcessUsingVCH : 1; // The process is using VCH.
|
||||
ULONG ProcessUsingFTH : 1; // The process is using FTH.
|
||||
ULONG ProcessPreviouslyThrottled : 1; // The process was previously throttled.
|
||||
ULONG ProcessCurrentlyThrottled : 1; // The process is currently throttled.
|
||||
ULONG ProcessImagesHotPatched : 1; // The process images are hot patched. // RS5
|
||||
ULONG ProcessInJob : 1; // The process is part of a job.
|
||||
ULONG ProcessInitializing : 1; // The process is initializing.
|
||||
ULONG ProcessUsingVEH : 1; // The process is using VEH.
|
||||
ULONG ProcessUsingVCH : 1; // The process is using VCH.
|
||||
ULONG ProcessUsingFTH : 1; // The process is using FTH.
|
||||
ULONG ProcessPreviouslyThrottled : 1; // The process was previously throttled.
|
||||
ULONG ProcessCurrentlyThrottled : 1; // The process is currently throttled.
|
||||
ULONG ProcessImagesHotPatched : 1; // The process images are hot patched. // RS5
|
||||
ULONG ReservedBits0 : 24;
|
||||
};
|
||||
};
|
||||
@@ -895,8 +853,7 @@ typedef struct _PEB_FULL
|
||||
//
|
||||
// User32 KERNEL_CALLBACK_TABLE (ntuser.h)
|
||||
//
|
||||
union
|
||||
{
|
||||
union {
|
||||
PKERNEL_CALLBACK_TABLE KernelCallbackTable;
|
||||
PVOID UserSharedInfoPtr;
|
||||
};
|
||||
@@ -969,8 +926,7 @@ typedef struct _PEB_FULL
|
||||
//
|
||||
// Global flags for the system.
|
||||
//
|
||||
union
|
||||
{
|
||||
union {
|
||||
ULONG NtGlobalFlag;
|
||||
struct
|
||||
{
|
||||
@@ -1115,8 +1071,7 @@ typedef struct _PEB_FULL
|
||||
// ...
|
||||
} PEB_FULL, *PPEB_FULL;
|
||||
|
||||
typedef struct _TEB_FULL
|
||||
{
|
||||
typedef struct _TEB_FULL {
|
||||
//
|
||||
// Thread Information Block (TIB) contains the thread's stack, base and limit addresses, the current stack pointer, and the exception list.
|
||||
//
|
||||
@@ -1188,13 +1143,11 @@ typedef struct _TEB_FULL
|
||||
LCID CurrentLocale;
|
||||
} TEB_FULL, *PTEB_FULL;
|
||||
|
||||
static inline PTEB_FULL ffGetTeb()
|
||||
{
|
||||
static inline PTEB_FULL ffGetTeb() {
|
||||
return (PTEB_FULL) NtCurrentTeb();
|
||||
}
|
||||
|
||||
static inline PPEB_FULL ffGetPeb()
|
||||
{
|
||||
static inline PPEB_FULL ffGetPeb() {
|
||||
return ffGetTeb()->ProcessEnvironmentBlock;
|
||||
}
|
||||
|
||||
@@ -1204,23 +1157,20 @@ NTSYSAPI NTSTATUS NTAPI RtlExpandEnvironmentStrings(
|
||||
_In_ SIZE_T SourceLength,
|
||||
_Out_writes_(DestinationLength) PWSTR Destination,
|
||||
_In_ SIZE_T DestinationLength,
|
||||
_Out_opt_ PSIZE_T ReturnLength
|
||||
);
|
||||
_Out_opt_ PSIZE_T ReturnLength);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtOpenKey(
|
||||
_Out_ PHANDLE KeyHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_ POBJECT_ATTRIBUTES ObjectAttributes
|
||||
);
|
||||
_In_ POBJECT_ATTRIBUTES ObjectAttributes);
|
||||
|
||||
typedef enum _KEY_VALUE_INFORMATION_CLASS
|
||||
{
|
||||
KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION
|
||||
KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION
|
||||
KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION
|
||||
KeyValueFullInformationAlign64, // KEY_VALUE_FULL_INFORMATION_ALIGN64
|
||||
KeyValuePartialInformationAlign64, // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64
|
||||
KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION
|
||||
typedef enum _KEY_VALUE_INFORMATION_CLASS {
|
||||
KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION
|
||||
KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION
|
||||
KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION
|
||||
KeyValueFullInformationAlign64, // KEY_VALUE_FULL_INFORMATION_ALIGN64
|
||||
KeyValuePartialInformationAlign64, // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64
|
||||
KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION
|
||||
MaxKeyValueInfoClass
|
||||
} KEY_VALUE_INFORMATION_CLASS;
|
||||
|
||||
@@ -1230,34 +1180,30 @@ NTSYSAPI NTSTATUS NTAPI NtQueryValueKey(
|
||||
_In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
|
||||
_Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyValueInformation,
|
||||
_In_ ULONG Length,
|
||||
_Out_ PULONG ResultLength
|
||||
);
|
||||
_Out_ PULONG ResultLength);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI RtlOpenCurrentUser(
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_Out_ PHANDLE CurrentUserKey
|
||||
);
|
||||
_Out_ PHANDLE CurrentUserKey);
|
||||
|
||||
typedef struct _KEY_VALUE_PARTIAL_INFORMATION
|
||||
{
|
||||
typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
|
||||
ULONG TitleIndex;
|
||||
ULONG Type;
|
||||
ULONG DataLength;
|
||||
_Field_size_bytes_(DataLength) UCHAR Data[];
|
||||
} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;
|
||||
|
||||
typedef enum _KEY_INFORMATION_CLASS
|
||||
{
|
||||
KeyBasicInformation, // KEY_BASIC_INFORMATION
|
||||
KeyNodeInformation, // KEY_NODE_INFORMATION
|
||||
KeyFullInformation, // KEY_FULL_INFORMATION
|
||||
KeyNameInformation, // KEY_NAME_INFORMATION
|
||||
KeyCachedInformation, // KEY_CACHED_INFORMATION
|
||||
KeyFlagsInformation, // KEY_FLAGS_INFORMATION
|
||||
typedef enum _KEY_INFORMATION_CLASS {
|
||||
KeyBasicInformation, // KEY_BASIC_INFORMATION
|
||||
KeyNodeInformation, // KEY_NODE_INFORMATION
|
||||
KeyFullInformation, // KEY_FULL_INFORMATION
|
||||
KeyNameInformation, // KEY_NAME_INFORMATION
|
||||
KeyCachedInformation, // KEY_CACHED_INFORMATION
|
||||
KeyFlagsInformation, // KEY_FLAGS_INFORMATION
|
||||
KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION
|
||||
KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION
|
||||
KeyTrustInformation, // KEY_TRUST_INFORMATION
|
||||
KeyLayerInformation, // KEY_LAYER_INFORMATION
|
||||
KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION
|
||||
KeyTrustInformation, // KEY_TRUST_INFORMATION
|
||||
KeyLayerInformation, // KEY_LAYER_INFORMATION
|
||||
MaxKeyInfoClass
|
||||
} KEY_INFORMATION_CLASS;
|
||||
|
||||
@@ -1267,19 +1213,16 @@ NTSYSAPI NTSTATUS NTAPI NtEnumerateKey(
|
||||
_In_ KEY_INFORMATION_CLASS KeyInformationClass,
|
||||
_Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyInformation,
|
||||
_In_ ULONG Length,
|
||||
_Out_ PULONG ResultLength
|
||||
);
|
||||
_Out_ PULONG ResultLength);
|
||||
|
||||
typedef struct _KEY_BASIC_INFORMATION
|
||||
{
|
||||
LARGE_INTEGER LastWriteTime; // Number of 100-nanosecond intervals since this key or any of its values changed.
|
||||
ULONG TitleIndex; // Reserved // A legacy field originally intended for use with localization such as an index of a resource table.
|
||||
ULONG NameLength; // The size, in bytes, of the key name string in the Name array.
|
||||
_Field_size_bytes_(NameLength) WCHAR Name[]; // The name of the registry key. This string is not null-terminated.
|
||||
typedef struct _KEY_BASIC_INFORMATION {
|
||||
LARGE_INTEGER LastWriteTime; // Number of 100-nanosecond intervals since this key or any of its values changed.
|
||||
ULONG TitleIndex; // Reserved // A legacy field originally intended for use with localization such as an index of a resource table.
|
||||
ULONG NameLength; // The size, in bytes, of the key name string in the Name array.
|
||||
_Field_size_bytes_(NameLength) WCHAR Name[]; // The name of the registry key. This string is not null-terminated.
|
||||
} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;
|
||||
|
||||
typedef struct _KEY_FULL_INFORMATION
|
||||
{
|
||||
typedef struct _KEY_FULL_INFORMATION {
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
ULONG TitleIndex;
|
||||
ULONG ClassOffset;
|
||||
@@ -1298,40 +1241,34 @@ NTSYSAPI NTSTATUS NTAPI NtQueryKey(
|
||||
_In_ KEY_INFORMATION_CLASS KeyInformationClass,
|
||||
_Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyInformation,
|
||||
_In_ ULONG Length,
|
||||
_Out_ PULONG ResultLength
|
||||
);
|
||||
_Out_ PULONG ResultLength);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtOpenProcess(
|
||||
_Out_ PHANDLE ProcessHandle,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_In_ PCOBJECT_ATTRIBUTES ObjectAttributes,
|
||||
_In_opt_ PCLIENT_ID ClientId
|
||||
);
|
||||
_In_opt_ PCLIENT_ID ClientId);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI LdrLoadDll(
|
||||
_In_opt_ PCWSTR DllPath,
|
||||
_In_opt_ PULONG DllCharacteristics,
|
||||
_In_ PCUNICODE_STRING DllName,
|
||||
_Out_ PVOID *DllHandle
|
||||
);
|
||||
_Out_ PVOID* DllHandle);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI LdrUnloadDll(
|
||||
_In_ PVOID DllHandle
|
||||
);
|
||||
_In_ PVOID DllHandle);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI LdrGetDllHandle(
|
||||
_In_opt_ PCWSTR DllPath,
|
||||
_In_opt_ PULONG DllCharacteristics,
|
||||
_In_ PCUNICODE_STRING DllName,
|
||||
_Out_ PVOID *DllHandle
|
||||
);
|
||||
_Out_ PVOID* DllHandle);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI LdrGetProcedureAddress(
|
||||
_In_ PVOID DllHandle,
|
||||
_In_opt_ PCANSI_STRING ProcedureName,
|
||||
_In_opt_ ULONG ProcedureNumber,
|
||||
_Out_ PVOID *ProcedureAddress
|
||||
);
|
||||
_Out_ PVOID* ProcedureAddress);
|
||||
|
||||
typedef enum _SECTION_INHERIT {
|
||||
ViewShare = 1,
|
||||
@@ -1345,42 +1282,35 @@ NTSYSAPI NTSTATUS NTAPI NtCreateSection(
|
||||
_In_opt_ PLARGE_INTEGER MaximumSize,
|
||||
_In_ ULONG SectionPageProtection,
|
||||
_In_ ULONG AllocationAttributes,
|
||||
_In_opt_ HANDLE FileHandle
|
||||
);
|
||||
_In_opt_ HANDLE FileHandle);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtMapViewOfSection(
|
||||
_In_ HANDLE SectionHandle,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress,
|
||||
_Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID* BaseAddress,
|
||||
_In_ ULONG_PTR ZeroBits,
|
||||
_In_ SIZE_T CommitSize,
|
||||
_Inout_opt_ PLARGE_INTEGER SectionOffset,
|
||||
_Inout_ PSIZE_T ViewSize,
|
||||
_In_ SECTION_INHERIT InheritDisposition,
|
||||
_In_ ULONG AllocationType,
|
||||
_In_ ULONG PageProtection
|
||||
);
|
||||
_In_ ULONG PageProtection);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtUnmapViewOfSection(
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_opt_ PVOID BaseAddress
|
||||
);
|
||||
_In_opt_ PVOID BaseAddress);
|
||||
|
||||
NTSYSAPI LOGICAL NTAPI RtlQueryPerformanceCounter(
|
||||
_Out_ PLARGE_INTEGER PerformanceCounter
|
||||
);
|
||||
_Out_ PLARGE_INTEGER PerformanceCounter);
|
||||
|
||||
NTSYSAPI LOGICAL NTAPI RtlQueryPerformanceFrequency(
|
||||
_Out_ PLARGE_INTEGER PerformanceFrequency
|
||||
);
|
||||
_Out_ PLARGE_INTEGER PerformanceFrequency);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtCancelIoFileEx(
|
||||
_In_ HANDLE FileHandle,
|
||||
_In_opt_ PIO_STATUS_BLOCK IoRequestToCancel,
|
||||
_Out_ PIO_STATUS_BLOCK IoStatusBlock
|
||||
);
|
||||
_Out_ PIO_STATUS_BLOCK IoStatusBlock);
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtTerminateProcess(
|
||||
_In_opt_ HANDLE ProcessHandle,
|
||||
_In_ NTSTATUS ExitStatus
|
||||
);
|
||||
_In_ NTSTATUS ExitStatus);
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
// Missing from <perflib.h> of MinGW-w64 SDK
|
||||
|
||||
#define PERF_WILDCARD_COUNTER 0xFFFFFFFF
|
||||
#define PERF_WILDCARD_INSTANCE L"*"
|
||||
#define PERF_WILDCARD_COUNTER 0xFFFFFFFF
|
||||
#define PERF_WILDCARD_INSTANCE L"*"
|
||||
#define PERF_AGGREGATE_INSTANCE L"_Total"
|
||||
#define PERF_MAX_INSTANCE_NAME 1024
|
||||
#define PERF_MAX_INSTANCE_NAME 1024
|
||||
|
||||
typedef struct _PERF_INSTANCE_HEADER {
|
||||
ULONG Size; // = sizeof(PERF_INSTANCE_HEADER) + sizeof(InstanceName) + sizeof(Padding)
|
||||
@@ -19,28 +19,28 @@ typedef struct _PERF_INSTANCE_HEADER {
|
||||
} PERF_INSTANCE_HEADER, *PPERF_INSTANCE_HEADER;
|
||||
|
||||
typedef struct _PERF_COUNTER_IDENTIFIER {
|
||||
GUID CounterSetGuid; // The GUID of the counterset.
|
||||
ULONG Status; // Win32 error code indicating success/failure of the add/delete operation.
|
||||
ULONG Size; // sizeof(PERF_COUNTER_IDENTIFIER) + sizeof(InstanceName) + sizeof(Padding)
|
||||
ULONG CounterId; // CounterId, or PERF_WILDCARD_COUNTER for all counters.
|
||||
ULONG InstanceId; // InstanceId, or 0xFFFFFFFF to not filter on instance ID.
|
||||
ULONG Index; // Set by PerfQueryCounterInfo to the position in which the corresponding counter data is returned.
|
||||
ULONG Reserved; // Reserved.
|
||||
GUID CounterSetGuid; // The GUID of the counterset.
|
||||
ULONG Status; // Win32 error code indicating success/failure of the add/delete operation.
|
||||
ULONG Size; // sizeof(PERF_COUNTER_IDENTIFIER) + sizeof(InstanceName) + sizeof(Padding)
|
||||
ULONG CounterId; // CounterId, or PERF_WILDCARD_COUNTER for all counters.
|
||||
ULONG InstanceId; // InstanceId, or 0xFFFFFFFF to not filter on instance ID.
|
||||
ULONG Index; // Set by PerfQueryCounterInfo to the position in which the corresponding counter data is returned.
|
||||
ULONG Reserved; // Reserved.
|
||||
// Followed by:
|
||||
// WCHAR InstanceName[];
|
||||
// WCHAR Padding[];
|
||||
} PERF_COUNTER_IDENTIFIER, * PPERF_COUNTER_IDENTIFIER;
|
||||
} PERF_COUNTER_IDENTIFIER, *PPERF_COUNTER_IDENTIFIER;
|
||||
|
||||
typedef struct _PERF_DATA_HEADER {
|
||||
ULONG dwTotalSize; // = sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER blocks...)
|
||||
ULONG dwNumCounters; // The number of PERF_COUNTER_HEADER blocks.
|
||||
LONGLONG PerfTimeStamp; // Timestamp from a high-resolution clock.
|
||||
LONGLONG PerfTime100NSec; // The number of 100 nanosecond intervals since January 1, 1601, in Coordinated Universal Time (UTC).
|
||||
LONGLONG PerfFreq; // The frequency of a high-resolution clock.
|
||||
SYSTEMTIME SystemTime; // The time at which data is collected on the provider side.
|
||||
ULONG dwTotalSize; // = sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER blocks...)
|
||||
ULONG dwNumCounters; // The number of PERF_COUNTER_HEADER blocks.
|
||||
LONGLONG PerfTimeStamp; // Timestamp from a high-resolution clock.
|
||||
LONGLONG PerfTime100NSec; // The number of 100 nanosecond intervals since January 1, 1601, in Coordinated Universal Time (UTC).
|
||||
LONGLONG PerfFreq; // The frequency of a high-resolution clock.
|
||||
SYSTEMTIME SystemTime; // The time at which data is collected on the provider side.
|
||||
// Followed by:
|
||||
// PERF_COUNTER_HEADER blocks...;
|
||||
} PERF_DATA_HEADER, * PPERF_DATA_HEADER;
|
||||
} PERF_DATA_HEADER, *PPERF_DATA_HEADER;
|
||||
|
||||
typedef enum _PerfCounterDataType {
|
||||
PERF_ERROR_RETURN = 0, /* An error occurred when the performance counter value was queried. */
|
||||
@@ -51,90 +51,84 @@ typedef enum _PerfCounterDataType {
|
||||
} PerfCounterDataType;
|
||||
|
||||
typedef struct _PERF_COUNTER_HEADER {
|
||||
ULONG dwStatus; // Win32 error code indicating success/failure of the query operation.
|
||||
ULONG dwStatus; // Win32 error code indicating success/failure of the query operation.
|
||||
PerfCounterDataType dwType; // Result type - error, single/single, multi/single, single/multi, multi/multi.
|
||||
ULONG dwSize; // = sizeof(PERF_COUNTER_HEADER) + sizeof(Additional data)
|
||||
ULONG Reserved; // Reserved.
|
||||
ULONG dwSize; // = sizeof(PERF_COUNTER_HEADER) + sizeof(Additional data)
|
||||
ULONG Reserved; // Reserved.
|
||||
// Followed by additional data:
|
||||
// If dwType == PERF_ERROR_RETURN: nothing.
|
||||
// If dwType == PERF_SINGLE_COUNTER: PERF_COUNTER_DATA block.
|
||||
// If dwType == PERF_MULTIPLE_COUNTERS: PERF_MULTI_COUNTERS block + PERF_COUNTER_DATA blocks.
|
||||
// If dwType == PERF_MULTIPLE_INSTANCES: PERF_MULTI_INSTANCES block.
|
||||
// If dwType == PERF_COUNTERSET: PERF_MULTI_COUNTERS block + PERF_MULTI_INSTANCES block.
|
||||
} PERF_COUNTER_HEADER, * PPERF_COUNTER_HEADER;
|
||||
} PERF_COUNTER_HEADER, *PPERF_COUNTER_HEADER;
|
||||
|
||||
typedef struct _PERF_MULTI_INSTANCES {
|
||||
ULONG dwTotalSize; // = sizeof(PERF_MULTI_INSTANCES) + sizeof(instance data blocks...)
|
||||
ULONG dwInstances; // Number of instance data blocks.
|
||||
ULONG dwTotalSize; // = sizeof(PERF_MULTI_INSTANCES) + sizeof(instance data blocks...)
|
||||
ULONG dwInstances; // Number of instance data blocks.
|
||||
// Followed by:
|
||||
// Instance data blocks...;
|
||||
} PERF_MULTI_INSTANCES, * PPERF_MULTI_INSTANCES;
|
||||
} PERF_MULTI_INSTANCES, *PPERF_MULTI_INSTANCES;
|
||||
|
||||
typedef struct _PERF_MULTI_COUNTERS {
|
||||
ULONG dwSize; // sizeof(PERF_MULTI_COUNTERS) + sizeof(CounterIds)
|
||||
ULONG dwCounters; // Number of counter ids.
|
||||
ULONG dwSize; // sizeof(PERF_MULTI_COUNTERS) + sizeof(CounterIds)
|
||||
ULONG dwCounters; // Number of counter ids.
|
||||
// Followed by:
|
||||
// DWORD CounterIds[dwCounters];
|
||||
} PERF_MULTI_COUNTERS, * PPERF_MULTI_COUNTERS;
|
||||
} PERF_MULTI_COUNTERS, *PPERF_MULTI_COUNTERS;
|
||||
|
||||
typedef struct _PERF_COUNTER_DATA {
|
||||
ULONG dwDataSize; // Size of the counter data, in bytes.
|
||||
ULONG dwSize; // = sizeof(PERF_COUNTER_DATA) + sizeof(Data) + sizeof(Padding)
|
||||
ULONG dwDataSize; // Size of the counter data, in bytes.
|
||||
ULONG dwSize; // = sizeof(PERF_COUNTER_DATA) + sizeof(Data) + sizeof(Padding)
|
||||
// Followed by:
|
||||
// BYTE Data[dwDataSize];
|
||||
// BYTE Padding[];
|
||||
} PERF_COUNTER_DATA, * PPERF_COUNTER_DATA;
|
||||
} PERF_COUNTER_DATA, *PPERF_COUNTER_DATA;
|
||||
|
||||
_Success_(return == ERROR_SUCCESS)
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfEnumerateCounterSetInstances(
|
||||
_In_opt_z_ LPCWSTR szMachine,
|
||||
_In_ LPCGUID pCounterSetId,
|
||||
_Out_opt_bytecap_post_bytecount_(cbInstances, *pcbInstancesActual) PPERF_INSTANCE_HEADER pInstances,
|
||||
DWORD cbInstances,
|
||||
_Out_ LPDWORD pcbInstancesActual
|
||||
);
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfEnumerateCounterSetInstances(
|
||||
_In_opt_z_ LPCWSTR szMachine,
|
||||
_In_ LPCGUID pCounterSetId,
|
||||
_Out_opt_bytecap_post_bytecount_(cbInstances, *pcbInstancesActual) PPERF_INSTANCE_HEADER pInstances,
|
||||
DWORD cbInstances,
|
||||
_Out_ LPDWORD pcbInstancesActual);
|
||||
|
||||
_Success_(return == ERROR_SUCCESS)
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfOpenQueryHandle(
|
||||
_In_opt_z_ LPCWSTR szMachine,
|
||||
_Out_ HANDLE * phQuery
|
||||
);
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfOpenQueryHandle(
|
||||
_In_opt_z_ LPCWSTR szMachine,
|
||||
_Out_ HANDLE* phQuery);
|
||||
|
||||
_Success_(return == ERROR_SUCCESS)
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfCloseQueryHandle(
|
||||
_In_ HANDLE hQuery
|
||||
);
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfCloseQueryHandle(
|
||||
_In_ HANDLE hQuery);
|
||||
|
||||
_Success_(return == ERROR_SUCCESS)
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfAddCounters(
|
||||
_In_ HANDLE hQuery,
|
||||
_Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters,
|
||||
DWORD cbCounters
|
||||
);
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfAddCounters(
|
||||
_In_ HANDLE hQuery,
|
||||
_Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters,
|
||||
DWORD cbCounters);
|
||||
|
||||
_Success_(return == ERROR_SUCCESS)
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfDeleteCounters(
|
||||
_In_ HANDLE hQuery,
|
||||
_Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters,
|
||||
DWORD cbCounters
|
||||
);
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfDeleteCounters(
|
||||
_In_ HANDLE hQuery,
|
||||
_Inout_bytecount_(cbCounters) PPERF_COUNTER_IDENTIFIER pCounters,
|
||||
DWORD cbCounters);
|
||||
|
||||
_Success_(return == ERROR_SUCCESS)
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfQueryCounterData(
|
||||
_In_ HANDLE hQuery,
|
||||
_Out_opt_bytecap_post_bytecount_(cbCounterBlock, *pcbCounterBlockActual) PPERF_DATA_HEADER pCounterBlock,
|
||||
DWORD cbCounterBlock,
|
||||
_Out_ LPDWORD pcbCounterBlockActual
|
||||
);
|
||||
ULONG
|
||||
WINAPI
|
||||
PerfQueryCounterData(
|
||||
_In_ HANDLE hQuery,
|
||||
_Out_opt_bytecap_post_bytecount_(cbCounterBlock, *pcbCounterBlockActual) PPERF_DATA_HEADER pCounterBlock,
|
||||
DWORD cbCounterBlock,
|
||||
_Out_ LPDWORD pcbCounterBlockActual);
|
||||
|
||||
+113
-135
@@ -9,9 +9,9 @@
|
||||
|
||||
static HANDLE hRootKeys[8 /*(uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS - (uintptr_t) HKEY_CLASSES_ROOT + 1*/];
|
||||
|
||||
static const char* hKey2Str(HANDLE hRootKey)
|
||||
{
|
||||
#define HKEY_CASE(compareKey) if(hRootKey == hRootKeys[(uintptr_t)compareKey - (uintptr_t)HKEY_CLASSES_ROOT]) return #compareKey;
|
||||
static const char* hKey2Str(HANDLE hRootKey) {
|
||||
#define HKEY_CASE(compareKey) \
|
||||
if (hRootKey == hRootKeys[(uintptr_t) compareKey - (uintptr_t) HKEY_CLASSES_ROOT]) return #compareKey;
|
||||
HKEY_CASE(HKEY_CLASSES_ROOT)
|
||||
HKEY_CASE(HKEY_CURRENT_USER)
|
||||
HKEY_CASE(HKEY_LOCAL_MACHINE)
|
||||
@@ -20,31 +20,27 @@ static const char* hKey2Str(HANDLE hRootKey)
|
||||
HKEY_CASE(HKEY_CURRENT_CONFIG)
|
||||
HKEY_CASE(HKEY_DYN_DATA)
|
||||
HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS)
|
||||
#undef HKEY_CASE
|
||||
#undef HKEY_CASE
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
HANDLE ffRegGetRootKeyHandle(HKEY hKey)
|
||||
{
|
||||
HANDLE ffRegGetRootKeyHandle(HKEY hKey) {
|
||||
assert(hKey);
|
||||
assert((uintptr_t) hKey >= (uintptr_t) HKEY_CLASSES_ROOT && (uintptr_t) hKey <= (uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS);
|
||||
|
||||
FF_DEBUG("Getting root key handle for HKEY %08llx", (uint64_t)(uintptr_t) hKey);
|
||||
FF_DEBUG("Getting root key handle for HKEY %08llx", (uint64_t) (uintptr_t) hKey);
|
||||
|
||||
HANDLE result = hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT];
|
||||
if (result)
|
||||
{
|
||||
if (result) {
|
||||
FF_DEBUG("Found cached root key handle for %s -> %p", hKey2Str(result), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
switch ((uintptr_t) hKey)
|
||||
{
|
||||
switch ((uintptr_t) hKey) {
|
||||
case (uintptr_t) HKEY_CURRENT_USER: {
|
||||
NTSTATUS status = RtlOpenCurrentUser(KEY_READ, &result);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("RtlOpenCurrentUser() failed: %s", ffDebugNtStatus(status));
|
||||
return NULL;
|
||||
}
|
||||
@@ -54,13 +50,12 @@ HANDLE ffRegGetRootKeyHandle(HKEY hKey)
|
||||
case (uintptr_t) HKEY_LOCAL_MACHINE: {
|
||||
UNICODE_STRING path = RTL_CONSTANT_STRING(L"\\Registry\\Machine");
|
||||
NTSTATUS status = NtOpenKey(&result, KEY_READ, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = NULL,
|
||||
.ObjectName = &path,
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
});
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = NULL,
|
||||
.ObjectName = &path,
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
});
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("NtOpenKey(%ls) failed: %s (0x%08lx)", path.Buffer, ffDebugNtStatus(status), status);
|
||||
return NULL;
|
||||
}
|
||||
@@ -77,8 +72,7 @@ HANDLE ffRegGetRootKeyHandle(HKEY hKey)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error)
|
||||
{
|
||||
bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error) {
|
||||
assert(hKey);
|
||||
assert(subKeyW);
|
||||
assert(result);
|
||||
@@ -87,18 +81,16 @@ bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result,
|
||||
|
||||
USHORT subKeyLen = (USHORT) (wcslen(subKeyW) * sizeof(wchar_t));
|
||||
if (!NT_SUCCESS(NtOpenKey(result, KEY_READ, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = hKey,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Length = subKeyLen,
|
||||
.MaximumLength = subKeyLen + (USHORT) sizeof(wchar_t),
|
||||
.Buffer = (wchar_t*) subKeyW,
|
||||
},
|
||||
})))
|
||||
{
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = hKey,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Length = subKeyLen,
|
||||
.MaximumLength = subKeyLen + (USHORT) sizeof(wchar_t),
|
||||
.Buffer = (wchar_t*) subKeyW,
|
||||
},
|
||||
}))) {
|
||||
FF_DEBUG("NtOpenKey(%s\\<subkey>) failed", hKey2Str(hKey));
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW);
|
||||
ffStrbufAppendF(error, "NtOpenKey(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars);
|
||||
}
|
||||
@@ -108,24 +100,22 @@ bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const void* regData, ULONG regDataLen, FFstrbuf* error)
|
||||
{
|
||||
switch (arg->type)
|
||||
{
|
||||
case FF_ARG_TYPE_STRBUF:
|
||||
{
|
||||
if (regType != REG_SZ && regType != REG_EXPAND_SZ)
|
||||
static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const void* regData, ULONG regDataLen, FFstrbuf* error) {
|
||||
switch (arg->type) {
|
||||
case FF_ARG_TYPE_STRBUF: {
|
||||
if (regType != REG_SZ && regType != REG_EXPAND_SZ) {
|
||||
goto type_mismatch;
|
||||
}
|
||||
|
||||
FFstrbuf* strbuf = (FFstrbuf*) arg->value;
|
||||
uint32_t strLen = regDataLen / sizeof(wchar_t);
|
||||
if (strLen == 0)
|
||||
if (strLen == 0) {
|
||||
ffStrbufClear(strbuf);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
const wchar_t* ws = (const wchar_t*) regData;
|
||||
if (ws[strLen - 1] == L'\0')
|
||||
if (ws[strLen - 1] == L'\0') {
|
||||
--strLen;
|
||||
}
|
||||
ffStrbufSetNWS(strbuf, strLen, ws);
|
||||
}
|
||||
break;
|
||||
@@ -135,59 +125,61 @@ static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const
|
||||
case FF_ARG_TYPE_UINT64:
|
||||
case FF_ARG_TYPE_UINT16:
|
||||
case FF_ARG_TYPE_UINT8:
|
||||
case FF_ARG_TYPE_BOOL:
|
||||
{
|
||||
case FF_ARG_TYPE_BOOL: {
|
||||
uint64_t value = 0;
|
||||
|
||||
if (regType == REG_DWORD)
|
||||
{
|
||||
if (regDataLen < sizeof(uint32_t))
|
||||
if (regType == REG_DWORD) {
|
||||
if (regDataLen < sizeof(uint32_t)) {
|
||||
goto type_mismatch;
|
||||
}
|
||||
value = *(uint32_t*) regData;
|
||||
}
|
||||
else if (regType == REG_QWORD)
|
||||
{
|
||||
if (regDataLen < sizeof(uint64_t))
|
||||
} else if (regType == REG_QWORD) {
|
||||
if (regDataLen < sizeof(uint64_t)) {
|
||||
goto type_mismatch;
|
||||
}
|
||||
value = *(uint64_t*) regData;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
goto type_mismatch;
|
||||
}
|
||||
|
||||
if (arg->type == FF_ARG_TYPE_UINT) *(uint32_t*) arg->value = (uint32_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_UINT64) *(uint64_t*) arg->value = (uint64_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_UINT16) *(uint16_t*) arg->value = (uint16_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_UINT8) *(uint8_t*) arg->value = (uint8_t) value;
|
||||
else if (arg->type == FF_ARG_TYPE_BOOL) *(bool*) arg->value = value != 0;
|
||||
if (arg->type == FF_ARG_TYPE_UINT) {
|
||||
*(uint32_t*) arg->value = (uint32_t) value;
|
||||
} else if (arg->type == FF_ARG_TYPE_UINT64) {
|
||||
*(uint64_t*) arg->value = (uint64_t) value;
|
||||
} else if (arg->type == FF_ARG_TYPE_UINT16) {
|
||||
*(uint16_t*) arg->value = (uint16_t) value;
|
||||
} else if (arg->type == FF_ARG_TYPE_UINT8) {
|
||||
*(uint8_t*) arg->value = (uint8_t) value;
|
||||
} else if (arg->type == FF_ARG_TYPE_BOOL) {
|
||||
*(bool*) arg->value = value != 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_FLOAT:
|
||||
{
|
||||
if (regDataLen < sizeof(float))
|
||||
case FF_ARG_TYPE_FLOAT: {
|
||||
if (regDataLen < sizeof(float)) {
|
||||
goto type_mismatch;
|
||||
}
|
||||
*(float*) arg->value = *(float*) regData;
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_DOUBLE:
|
||||
{
|
||||
if (regDataLen < sizeof(double))
|
||||
case FF_ARG_TYPE_DOUBLE: {
|
||||
if (regDataLen < sizeof(double)) {
|
||||
goto type_mismatch;
|
||||
}
|
||||
*(double*) arg->value = *(double*) regData;
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_LIST:
|
||||
{
|
||||
if (regType != REG_MULTI_SZ)
|
||||
case FF_ARG_TYPE_LIST: {
|
||||
if (regType != REG_MULTI_SZ) {
|
||||
goto type_mismatch;
|
||||
}
|
||||
|
||||
FFlist* list = (FFlist*) arg->value;
|
||||
if (list->elementSize != sizeof(FFstrbuf))
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
if (list->elementSize != sizeof(FFstrbuf)) {
|
||||
if (error) {
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: expected list of strbuf for REG_MULTI_SZ", nameA.chars);
|
||||
}
|
||||
@@ -199,9 +191,7 @@ static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const
|
||||
for (
|
||||
const wchar_t* ptr = (const wchar_t*) regData;
|
||||
(const uint8_t*) ptr < (const uint8_t*) regData + regDataLen && *ptr;
|
||||
ptr++
|
||||
)
|
||||
{
|
||||
ptr++) {
|
||||
uint32_t strLen = (uint32_t) wcsnlen(ptr, regDataLen / sizeof(wchar_t) - (size_t) (ptr - (const wchar_t*) regData));
|
||||
ffStrbufInitNWS(FF_LIST_ADD(FFstrbuf, *list), strLen, ptr);
|
||||
ptr += strLen;
|
||||
@@ -209,20 +199,16 @@ static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const
|
||||
break;
|
||||
}
|
||||
|
||||
case FF_ARG_TYPE_BUFFER:
|
||||
{
|
||||
if (regType != REG_BINARY)
|
||||
case FF_ARG_TYPE_BUFFER: {
|
||||
if (regType != REG_BINARY) {
|
||||
goto type_mismatch;
|
||||
}
|
||||
|
||||
FFArgBuffer* buffer = (FFArgBuffer*) arg->value;
|
||||
if (buffer->length == 0)
|
||||
{
|
||||
if (buffer->length == 0) {
|
||||
buffer->data = malloc(regDataLen);
|
||||
}
|
||||
else if (buffer->length < regDataLen)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
} else if (buffer->length < regDataLen) {
|
||||
if (error) {
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "ffRegReadValues(%s) buffer too small (%u): expected %u", nameA.chars, (unsigned) buffer->length, (unsigned) regDataLen);
|
||||
}
|
||||
@@ -237,8 +223,7 @@ static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const
|
||||
case FF_ARG_TYPE_STRING:
|
||||
case FF_ARG_TYPE_NULL:
|
||||
default:
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "processRegValue(%s) unsupported FFArgType %u", nameA.chars, (unsigned) arg->type);
|
||||
}
|
||||
@@ -249,18 +234,18 @@ static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const
|
||||
|
||||
type_mismatch:
|
||||
FF_DEBUG("ffRegReadValues(%ls) type mismatch: regType=%u, argType=%u, dataLen=%u",
|
||||
arg->name ?: L"(default)", (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen);
|
||||
if (error)
|
||||
{
|
||||
arg->name ?: L"(default)",
|
||||
(unsigned) regType,
|
||||
(unsigned) arg->type,
|
||||
(unsigned) regDataLen);
|
||||
if (error) {
|
||||
FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: regType=%u, argType=%u, dataLen=%u",
|
||||
nameA.chars, (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen);
|
||||
ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: regType=%u, argType=%u, dataLen=%u", nameA.chars, (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error)
|
||||
{
|
||||
bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error) {
|
||||
UNICODE_STRING* valueNameU = &(UNICODE_STRING) {
|
||||
.Length = arg->name ? (USHORT) (wcslen(arg->name) * sizeof(wchar_t)) : 0 /*(default)*/,
|
||||
.MaximumLength = 0,
|
||||
@@ -272,14 +257,13 @@ bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error)
|
||||
|
||||
KEY_VALUE_PARTIAL_INFORMATION* buffer = (KEY_VALUE_PARTIAL_INFORMATION*) &staticBuffer;
|
||||
DWORD bufSize = sizeof(staticBuffer);
|
||||
if (NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize)))
|
||||
if (NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize))) {
|
||||
goto process_value;
|
||||
}
|
||||
|
||||
if (bufSize == 0)
|
||||
{
|
||||
if (bufSize == 0) {
|
||||
FF_DEBUG("NtQueryValueKey(%p, %ls) failed (bufSize=0)", hKey, arg->name ?: L"(default)");
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "NtQueryValueKey(%p, %s) failed", hKey, valueNameA.chars);
|
||||
}
|
||||
@@ -289,11 +273,9 @@ bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error)
|
||||
dynamicBuffer = (uint8_t*) malloc(bufSize);
|
||||
buffer = (KEY_VALUE_PARTIAL_INFORMATION*) dynamicBuffer;
|
||||
|
||||
if (!NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize)))
|
||||
{
|
||||
if (!NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize))) {
|
||||
FF_DEBUG("NtQueryValueKey(%p, %ls, buffer=%u) failed", hKey, arg->name ?: L"(default)", (unsigned) bufSize);
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)");
|
||||
ffStrbufAppendF(error, "NtQueryValueKey(%p, %s, buffer) failed", hKey, valueNameA.chars);
|
||||
}
|
||||
@@ -305,22 +287,22 @@ process_value:
|
||||
return processRegValue(arg, buffer->Type, buffer->Data, buffer->DataLength, error);
|
||||
}
|
||||
|
||||
bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error)
|
||||
{
|
||||
if (__builtin_expect(argc == 0, false))
|
||||
bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error) {
|
||||
if (__builtin_expect(argc == 0, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(argv);
|
||||
|
||||
FF_AUTO_FREE UNICODE_STRING* names = (UNICODE_STRING*) calloc(argc, sizeof(*names));
|
||||
FF_AUTO_FREE KEY_VALUE_ENTRY* entries = (KEY_VALUE_ENTRY*) calloc(argc, sizeof(*entries));
|
||||
|
||||
for (uint32_t i = 0; i < argc; ++i)
|
||||
{
|
||||
if (__builtin_expect(!argv[i].value, false))
|
||||
{
|
||||
for (uint32_t i = 0; i < argc; ++i) {
|
||||
if (__builtin_expect(!argv[i].value, false)) {
|
||||
FF_DEBUG("ffRegReadValues(argv[%u].value) is NULL", (unsigned) i);
|
||||
if (error) ffStrbufAppendF(error, "ffRegReadValues(argv[%u].pVar) is NULL", (unsigned) i);
|
||||
if (error) {
|
||||
ffStrbufAppendF(error, "ffRegReadValues(argv[%u].pVar) is NULL", (unsigned) i);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -333,54 +315,51 @@ bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFs
|
||||
}
|
||||
|
||||
ULONG bufferSize = argc * 128;
|
||||
if (bufferSize < 512)
|
||||
if (bufferSize < 512) {
|
||||
bufferSize = 512;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE uint8_t* buffer = NULL;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
buffer = (uint8_t*) realloc(buffer, bufferSize);
|
||||
|
||||
ULONG writtenSize = bufferSize;
|
||||
ULONG requiredSize = 0;
|
||||
NTSTATUS status = NtQueryMultipleValueKey(hKey, entries, argc, buffer, &writtenSize, &requiredSize);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (!NT_SUCCESS(status)) {
|
||||
// Buffer too small: docs guarantee requiredSize is returned when provided.
|
||||
if (requiredSize > bufferSize)
|
||||
{
|
||||
if (requiredSize > bufferSize) {
|
||||
FF_DEBUG("NtQueryMultipleValueKey(%p) resize buffer: %u -> %u", hKey, (unsigned) bufferSize, (unsigned) requiredSize);
|
||||
bufferSize = requiredSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_DEBUG("NtQueryMultipleValueKey(%p, argc=%u) failed, status=0x%08X", hKey, (unsigned) argc, (unsigned) status);
|
||||
if (error)
|
||||
ffStrbufAppendF(error, "NtQueryMultipleValueKey(%p, argc=%u) failed, status=0x%08X",
|
||||
hKey, (unsigned) argc, (unsigned) status);
|
||||
if (error) {
|
||||
ffStrbufAppendF(error, "NtQueryMultipleValueKey(%p, argc=%u) failed, status=0x%08X", hKey, (unsigned) argc, (unsigned) status);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < argc; ++i)
|
||||
{
|
||||
for (uint32_t i = 0; i < argc; ++i) {
|
||||
const FFRegValueArg* arg = &argv[i];
|
||||
const KEY_VALUE_ENTRY* entry = &entries[i];
|
||||
|
||||
FF_DEBUG("Read value[%u] from %p: type=%u, len=%u", (unsigned) i, hKey, (unsigned) entry->Type, (unsigned) entry->DataLength);
|
||||
if (!processRegValue(arg, entry->Type, buffer + entry->DataOffset, entry->DataLength, error))
|
||||
if (!processRegValue(arg, entry->Type, buffer + entry->DataOffset, entry->DataLength, error)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error)
|
||||
{
|
||||
bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error) {
|
||||
assert(hKey);
|
||||
assert(result);
|
||||
|
||||
@@ -388,11 +367,11 @@ bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* err
|
||||
ULONG bufSize = (ULONG) sizeof(buffer);
|
||||
KEY_BASIC_INFORMATION* keyInfo = (KEY_BASIC_INFORMATION*) buffer;
|
||||
|
||||
if (!NT_SUCCESS(NtEnumerateKey(hKey, index, KeyBasicInformation, keyInfo, bufSize, &bufSize)))
|
||||
{
|
||||
if (!NT_SUCCESS(NtEnumerateKey(hKey, index, KeyBasicInformation, keyInfo, bufSize, &bufSize))) {
|
||||
FF_DEBUG("NtEnumerateKey(hKey=%p, index=%u) failed", hKey, (unsigned) index);
|
||||
if (error)
|
||||
if (error) {
|
||||
ffStrbufAppendF(error, "NtEnumerateKey(hKey=%p, %u, keyInfo) failed", hKey, (unsigned) index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -400,8 +379,7 @@ bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* err
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error)
|
||||
{
|
||||
bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error) {
|
||||
assert(hKey);
|
||||
assert(result);
|
||||
|
||||
@@ -409,11 +387,11 @@ bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error)
|
||||
ULONG bufSize = sizeof(buffer);
|
||||
KEY_FULL_INFORMATION* keyInfo = (KEY_FULL_INFORMATION*) buffer;
|
||||
|
||||
if (!NT_SUCCESS(NtQueryKey(hKey, KeyFullInformation, keyInfo, bufSize, &bufSize)))
|
||||
{
|
||||
if (!NT_SUCCESS(NtQueryKey(hKey, KeyFullInformation, keyInfo, bufSize, &bufSize))) {
|
||||
FF_DEBUG("NtQueryKey(hKey=%p, KeyFullInformation) failed", hKey);
|
||||
if (error)
|
||||
if (error) {
|
||||
ffStrbufAppendF(error, "NtQueryKey(hKey=%p, KeyFullInformation, keyInfo) failed", hKey);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user