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:
李通洲
2026-03-29 09:28:49 +08:00
parent cdd4cee968
commit e0eba8ce21
690 changed files with 28093 additions and 30062 deletions
+5 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+86 -87
View File
@@ -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;
+8 -9
View File
@@ -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
View File
@@ -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 -4
View File
@@ -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
View File
@@ -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)}
+8 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+8 -6
View File
@@ -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;
}
+22 -19
View File
@@ -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
View File
@@ -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);
+114 -133
View File
@@ -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);
+9 -9
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+45 -47
View File
@@ -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';
+94 -81
View File
@@ -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, &section, 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, &section, 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, &section, 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, &section, 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);
}
}
+41 -29
View File
@@ -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";
}
+22 -19
View File
@@ -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;
}
+85 -99
View File
@@ -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
View File
@@ -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
+8 -10
View File
@@ -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
View File
@@ -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");
}
}
}
+58 -69
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
}
}
+1 -2
View File
@@ -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);
+1 -2
View File
@@ -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;
}
+8 -6
View File
@@ -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
View File
@@ -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 -2
View File
@@ -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 -5
View File
@@ -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);
+8 -7
View File
@@ -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
View File
@@ -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;
}
+8 -6
View File
@@ -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;
+4 -6
View File
@@ -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;
+66 -69
View File
@@ -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
View File
@@ -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';
+9 -8
View File
@@ -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;
+41 -28
View File
@@ -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;
}
+68 -79
View File
@@ -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;
+18 -25
View File
@@ -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;
+31 -41
View File
@@ -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
View File
@@ -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;
}
+78 -104
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+96 -111
View File
@@ -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;
+64 -64
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -2
View File
@@ -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
View File
@@ -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;
+8 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+2 -4
View File
@@ -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
View File
@@ -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
+2 -4
View File
@@ -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;
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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}});
}
+3 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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;
}
+8 -7
View File
@@ -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
+5 -5
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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);
+67 -73
View File
@@ -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
View File
@@ -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