Common: adds more gcc constrants

This commit is contained in:
李通洲
2026-09-17 21:00:36 +08:00
parent 6ff7f2772b
commit 97ac94eb44
29 changed files with 344 additions and 285 deletions
+18 -15
View File
@@ -15,17 +15,18 @@ typedef struct FFlist {
} FFlist;
// Removes the first element, and copy its value to `*result`
bool ffListShift(FFlist* list, uint32_t elementSize, void* __restrict result);
// `result` is only written when the list is not empty, so it may be null for an empty list
[[gnu::nonnull(1), nodiscard]] bool ffListShift(FFlist* list, uint32_t elementSize, void* __restrict result);
// Removes the last element, and copy its value to `*result`
bool ffListPop(FFlist* list, uint32_t elementSize, void* __restrict result);
[[gnu::nonnull(1), nodiscard]] bool ffListPop(FFlist* list, uint32_t elementSize, void* __restrict result);
static inline void ffListInit(FFlist* list) {
[[gnu::nonnull(1)]] static inline void ffListInit(FFlist* list) {
list->capacity = 0;
list->length = 0;
list->data = nullptr;
}
static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) {
[[gnu::nonnull(1)]] static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) {
ffListInit(list);
list->capacity = capacity;
list->data = __builtin_expect(capacity == 0, 0) ? nullptr : (uint8_t*) malloc((size_t) capacity * elementSize);
@@ -43,12 +44,13 @@ static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capa
return result;
}
[[nodiscard]] static inline void* ffListGet(const FFlist* list, uint32_t elementSize, uint32_t index) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline void* ffListGet(const FFlist* list, uint32_t elementSize, uint32_t index) {
assert(list->capacity > index);
return list->data + (index * elementSize);
}
[[nodiscard]] static inline uint32_t ffListFirstIndexComp(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
// Not `pure`: `compFunc` is caller-supplied and may have side effects
[[gnu::nonnull(1, 3, 4), nodiscard]] static inline uint32_t ffListFirstIndexComp(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
for (uint32_t i = 0; i < list->length; i++) {
if (compFunc(ffListGet(list, elementSize, i), compElement)) {
return i;
@@ -58,16 +60,17 @@ static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capa
return list->length;
}
[[nodiscard]] static inline bool ffListContains(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
// Not `pure`, same reason as ffListFirstIndexComp
[[gnu::nonnull(1, 3, 4), nodiscard]] static inline bool ffListContains(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
return ffListFirstIndexComp(list, elementSize, compElement, compFunc) != list->length;
}
static inline void ffListSort(FFlist* list, uint32_t elementSize, int (*compar)(const void*, const void*)) {
[[gnu::nonnull(1, 3)]] static inline void ffListSort(FFlist* list, uint32_t elementSize, int (*compar)(const void*, const void*)) {
qsort(list->data, list->length, elementSize, compar);
}
// Move the contents of `src` into `list`, and left `src` empty
static inline void ffListInitMove(FFlist* list, FFlist* src) {
[[gnu::nonnull(1)]] static inline void ffListInitMove(FFlist* list, FFlist* src) {
if (src) {
list->capacity = src->capacity;
list->length = src->length;
@@ -78,7 +81,7 @@ static inline void ffListInitMove(FFlist* list, FFlist* src) {
}
}
static inline void ffListDestroy(FFlist* list) {
[[gnu::nonnull(1)]] static inline void ffListDestroy(FFlist* list) {
if (!list->data) {
return;
}
@@ -89,11 +92,11 @@ static inline void ffListDestroy(FFlist* list) {
list->data = nullptr;
}
static inline void ffListClear(FFlist* list) {
[[gnu::nonnull(1)]] static inline void ffListClear(FFlist* list) {
list->length = 0;
}
static inline void ffListReserve(FFlist* list, uint32_t elementSize, uint32_t newCapacity) {
[[gnu::nonnull(1)]] static inline void ffListReserve(FFlist* list, uint32_t elementSize, uint32_t newCapacity) {
if (__builtin_expect(newCapacity <= list->capacity, false)) {
return;
}
@@ -102,7 +105,7 @@ static inline void ffListReserve(FFlist* list, uint32_t elementSize, uint32_t ne
list->capacity = newCapacity;
}
static inline void* ffListAdd(FFlist* list, uint32_t elementSize) {
[[gnu::nonnull(1)]] static inline void* ffListAdd(FFlist* list, uint32_t elementSize) {
if (__builtin_expect(list->length == list->capacity, false)) {
ffListReserve(list, elementSize, list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2);
}
@@ -111,13 +114,13 @@ static inline void* ffListAdd(FFlist* list, uint32_t elementSize) {
return ffListGet(list, elementSize, list->length - 1);
}
static inline void ffListRemoveAt(FFlist* list, uint32_t elementSize, uint32_t index) {
[[gnu::nonnull(1)]] static inline void ffListRemoveAt(FFlist* list, uint32_t elementSize, uint32_t index) {
assert(list->length > index);
memmove(list->data + (index * elementSize), list->data + ((index + 1) * elementSize), (size_t) (list->length - index - 1) * elementSize);
--list->length;
}
static inline void ffListInsertAt(FFlist* list, uint32_t elementSize, uint32_t index, const void* element) {
[[gnu::nonnull(1, 4)]] static inline void ffListInsertAt(FFlist* list, uint32_t elementSize, uint32_t index, const void* element) {
assert(list->length >= index);
ffListAdd(list, elementSize);
memmove(list->data + ((index + 1) * elementSize), list->data + (index * elementSize), (size_t) (list->length - index - 1) * elementSize);
+162 -132
View File
@@ -24,6 +24,29 @@ __stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch);
#define FASTFETCH_STRBUF_DEFAULT_ALLOC 32
// ---------------------------------------------------------------------------------------------
// Contract attributes used throughout this header:
//
// `gnu::pure` marks a function that reads memory (through its arguments and through globals) but
// writes nothing observable, so the compiler may cache and reorder calls to it. It is applied to
// the comparison / search accessors, and deliberately NOT to:
// * the `To*` converters -- `strtod` / `strtoull` / `strtoll` write `errno`;
// * `ffStrbufEndsWithFn` -- the caller-supplied `fn` may have side effects;
// * `ffStrbufWriteTo` / `ffStrbufPutTo` -- they write to a `FILE*`.
//
// `gnu::nonnull(N)` is added wherever the function dereferences argument N unconditionally. The
// two cannot be combined with a null check: clang reports `-Wtautological-pointer-compare` /
// `-Wpointer-bool-conversion` (both in `-Wall`) when a `nonnull` parameter is compared against
// null, so a redundant `assert(p != nullptr)` is dropped in favour of the attribute. Asserts that
// state something `nonnull` cannot express -- pointer aliasing (`value != strbuf`), index ranges
// (`start <= strbuf->length`), or a non-pointer invariant -- are kept.
//
// `nodiscard` is NOT applied to the "was the buffer modified" boolean returns
// (`ffStrbufSubstr*`, `ffStrbufRemoveSubstr`, `ffStrbufEnsureEndsWithC`, ...). Ignoring that
// result is a normal, intended use of those functions -- `ffStrbufSubstrBefore` alone has 153 call
// sites and ~147 of them discard the result -- so `nodiscard` would only produce noise.
// ---------------------------------------------------------------------------------------------
// static string (allocated == 0), chars points to a string literal
// dynamic string (allocated > 0), chars points to a heap allocated buffer
typedef struct FFstrbuf {
@@ -32,67 +55,70 @@ typedef struct FFstrbuf {
char* chars;
} FFstrbuf;
static inline void ffStrbufInit(FFstrbuf* strbuf);
void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate);
void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments);
void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr);
[[gnu::format(printf, 2, 3)]] void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::format(printf, 1, 2)]] [[nodiscard]] FFstrbuf ffStrbufCreateF(const char* format, ...);
[[gnu::nonnull(1)]] static inline void ffStrbufInit(FFstrbuf* strbuf);
[[gnu::nonnull(1)]] void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate);
[[gnu::nonnull(1, 2), gnu::format(printf, 2, 0)]] void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments);
[[gnu::nonnull(1, 3)]] void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr);
[[gnu::format(printf, 2, 3), gnu::nonnull(1, 2)]] void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::format(printf, 1, 2), gnu::nonnull(1), nodiscard]] FFstrbuf ffStrbufCreateF(const char* format, ...);
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free);
void ffStrbufEnsureFreeNoCheck(FFstrbuf* strbuf, uint32_t free);
[[gnu::nonnull(1)]] void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free);
[[gnu::nonnull(1)]] void ffStrbufEnsureFreeNoCheck(FFstrbuf* strbuf, uint32_t free);
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value);
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transformFunc)(int));
[[gnu::format(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);
[[gnu::nonnull(1)]] static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value);
[[gnu::nonnull(1, 3)]] void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transformFunc)(int));
[[gnu::format(printf, 2, 3), gnu::nonnull(1, 2)]] void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::nonnull(1, 2), gnu::format(printf, 2, 0)]] void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments);
// Returns the pointer to the terminator, or nullptr if `value` was nullptr; callers are free to
// ignore it, so not `nodiscard`.
[[gnu::nonnull(1)]] const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until);
void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value);
void ffStrbufPrependC(FFstrbuf* strbuf, char c);
[[gnu::nonnull(1)]] void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value);
[[gnu::nonnull(1)]] void ffStrbufPrependC(FFstrbuf* strbuf, char c);
void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c);
[[gnu::nonnull(1)]] void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c);
// Clear the content of strbuf and set new value
// 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);
[[gnu::format(printf, 2, 3)]] void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::nonnull(1, 2)]] void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value);
[[gnu::nonnull(1, 3)]] void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value);
[[gnu::format(printf, 2, 3), gnu::nonnull(1, 2)]] void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
void ffStrbufTrimLeftSpace(FFstrbuf* strbuf);
void ffStrbufTrimRightSpace(FFstrbuf* strbuf);
[[gnu::nonnull(1)]] void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
[[gnu::nonnull(1)]] void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
[[gnu::nonnull(1)]] void ffStrbufTrimLeftSpace(FFstrbuf* strbuf);
[[gnu::nonnull(1)]] void ffStrbufTrimRightSpace(FFstrbuf* strbuf);
bool ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex);
void ffStrbufRemoveS(FFstrbuf* strbuf, const char* str);
void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, const char* strings[]);
[[gnu::nonnull(1)]] bool ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex);
[[gnu::nonnull(1, 2)]] void ffStrbufRemoveS(FFstrbuf* strbuf, const char* str);
// `strings` is only dereferenced when `numStrings > 0`, so it is intentionally not `nonnull(3)`
[[gnu::nonnull(1)]] void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, const char* strings[]);
void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace);
[[gnu::nonnull(1)]] void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace);
// Returns true if the strbuf is modified
bool ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index);
bool ffStrbufSubstrAfter(FFstrbuf* strbuf, uint32_t index); // Not including the index
bool ffStrbufSubstrAfterFirstC(FFstrbuf* strbuf, char c);
bool ffStrbufSubstrAfterFirstS(FFstrbuf* strbuf, const char* str);
bool ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c);
bool ffStrbufSubstr(FFstrbuf* strbuf, uint32_t start, uint32_t end);
[[gnu::nonnull(1)]] bool ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index);
[[gnu::nonnull(1)]] bool ffStrbufSubstrAfter(FFstrbuf* strbuf, uint32_t index); // Not including the index
[[gnu::nonnull(1)]] bool ffStrbufSubstrAfterFirstC(FFstrbuf* strbuf, char c);
[[gnu::nonnull(1, 2)]] bool ffStrbufSubstrAfterFirstS(FFstrbuf* strbuf, const char* str);
[[gnu::nonnull(1)]] bool ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c);
[[gnu::nonnull(1)]] bool ffStrbufSubstr(FFstrbuf* strbuf, uint32_t start, uint32_t end);
[[nodiscard]] uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c);
[[gnu::nonnull(1), gnu::pure, nodiscard]] uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c);
bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end);
[[gnu::nonnull(1, 2)]] bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end);
bool ffStrbufEnsureEndsWithC(FFstrbuf* strbuf, char c);
[[gnu::nonnull(1)]] bool ffStrbufEnsureEndsWithC(FFstrbuf* strbuf, char c);
void ffStrbufUpperCase(FFstrbuf* strbuf);
void ffStrbufLowerCase(FFstrbuf* strbuf);
[[gnu::nonnull(1)]] void ffStrbufUpperCase(FFstrbuf* strbuf);
[[gnu::nonnull(1)]] void ffStrbufLowerCase(FFstrbuf* strbuf);
// Function alters the buffer to extract lines or delimited segments (replaces the delimiter with '\0')
// so that buffer MUST be heap allocated (NOT a static string)
// `lineptr` must be `nullptr` and `n` MUST be `0` for the first call
// Caller MUST NOT free `*lineptr`
bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
[[gnu::nonnull(1, 2, 4)]] bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
[[gnu::nonnull(1, 2, 4)]] void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
/**
* @brief Read a line from a FFstrbuf.
@@ -110,29 +136,31 @@ 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) {
[[gnu::nonnull(1, 2, 3), nodiscard]] 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) {
[[gnu::nonnull(1, 2, 3)]] static inline void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer) {
ffStrbufGetdelimRestore(lineptr, n, '\n', buffer);
}
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf);
bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
[[gnu::nonnull(1)]] bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf);
// `comp` is only dereferenced when `compLength > 0` in the first pair, and is never dereferenced
// when `strbuf` is empty in the second pair, so neither takes `nonnull(3)`
[[gnu::nonnull(1), gnu::pure, nodiscard]] bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
[[gnu::nonnull(1), gnu::pure, nodiscard]] bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
[[gnu::nonnull(1), gnu::pure, nodiscard]] bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
[[gnu::nonnull(1), gnu::pure, nodiscard]] bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint);
[[gnu::nonnull(1)]] int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint);
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value);
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
[[gnu::nonnull(1)]] void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value);
[[gnu::nonnull(1)]] void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
// Appends a double value to the string buffer with the specified precision (0~15).
// if `precision < 0`, let yyjson decide the precision
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros);
[[gnu::nonnull(1)]] void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros);
[[nodiscard]] static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) {
FFstrbuf strbuf;
@@ -140,7 +168,7 @@ void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool
return strbuf;
}
static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict src) {
[[gnu::nonnull(1, 2)]] static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict src) {
if (src->allocated == 0) { // static string
*strbuf = *src;
} else {
@@ -149,14 +177,14 @@ static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf*
}
}
[[nodiscard]] static inline FFstrbuf ffStrbufCreateCopy(const FFstrbuf* src) {
[[gnu::nonnull(1), 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) {
[[gnu::nonnull(1)]] static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src) {
if (src) {
*strbuf = *src;
ffStrbufInit(src);
@@ -171,12 +199,12 @@ static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src) {
return strbuf;
}
static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr) {
[[gnu::nonnull(1, 2)]] 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) {
[[gnu::nonnull(1)]] static inline void ffStrbufDestroy(FFstrbuf* strbuf) {
if (strbuf->allocated > 0) {
free(strbuf->chars);
}
@@ -184,8 +212,7 @@ static inline void ffStrbufDestroy(FFstrbuf* strbuf) {
ffStrbufInit(strbuf);
}
[[nodiscard]] static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf) {
assert(strbuf != nullptr);
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf) {
if (strbuf->allocated == 0) {
return 0;
}
@@ -193,7 +220,7 @@ static inline void ffStrbufDestroy(FFstrbuf* strbuf) {
return strbuf->allocated - strbuf->length - 1; // - 1 for the null byte
}
static inline void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) {
[[gnu::nonnull(1)]] static inline void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) {
if (__builtin_expect(free == 0, false)) {
if (__builtin_expect(!(strbuf->allocated == 0 && strbuf->length > 0), true)) {
return;
@@ -208,8 +235,7 @@ static inline void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) {
}
static inline void ffStrbufClear(FFstrbuf* strbuf) {
assert(strbuf != nullptr);
[[gnu::nonnull(1)]] static inline void ffStrbufClear(FFstrbuf* strbuf) {
extern char* CHAR_NULL_PTR;
if (strbuf->allocated == 0) {
@@ -221,13 +247,13 @@ static inline void ffStrbufClear(FFstrbuf* strbuf) {
strbuf->length = 0;
}
static inline void ffStrbufAppendC(FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1)]] static inline void ffStrbufAppendC(FFstrbuf* strbuf, char c) {
ffStrbufEnsureFree(strbuf, 1);
strbuf->chars[strbuf->length++] = c;
strbuf->chars[strbuf->length] = '\0';
}
static inline void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c) {
[[gnu::nonnull(1)]] static inline void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c) {
if (__builtin_expect(num == 0, false)) {
return;
}
@@ -238,7 +264,7 @@ static inline void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c) {
strbuf->chars[strbuf->length] = '\0';
}
static inline void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
[[gnu::nonnull(1)]] static inline void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
if (__builtin_expect(value == nullptr || length == 0, false)) {
return;
}
@@ -249,7 +275,7 @@ static inline void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const cha
strbuf->chars[strbuf->length] = '\0';
}
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value) {
[[gnu::nonnull(1)]] static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value) {
assert(value != strbuf);
if (value == nullptr) {
return;
@@ -257,13 +283,12 @@ static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* _
ffStrbufAppendNS(strbuf, value->length, value->chars);
}
static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf) {
[[gnu::nonnull(1)]] static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf) {
strbuf->length = (uint32_t) strlen(strbuf->chars);
}
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value) {
assert(strbuf != nullptr);
// `value` may be null (clears the buffer); `strbuf` may not
[[gnu::nonnull(1)]] static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value) {
if (value == nullptr) {
ffStrbufClear(strbuf);
} else {
@@ -271,9 +296,7 @@ static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value) {
}
}
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
assert(strbuf != nullptr);
[[gnu::nonnull(1)]] static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
if (yyjson_is_str(jsonVal)) {
ffStrbufSetNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
return true;
@@ -283,13 +306,15 @@ static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
return false;
}
static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value) {
[[gnu::nonnull(1)]] static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value) {
if (value == nullptr) {
return;
}
ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value);
}
// Returns whether `jsonVal` was a string. Callers routinely pre-check with `yyjson_is_str`, so the
// result is not `nodiscard`.
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));
@@ -298,7 +323,7 @@ static inline bool ffStrbufAppendJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
return false;
}
static inline void ffStrbufInit(FFstrbuf* strbuf) {
[[gnu::nonnull(1)]] static inline void ffStrbufInit(FFstrbuf* strbuf) {
extern char* CHAR_NULL_PTR;
strbuf->allocated = strbuf->length = 0;
strbuf->chars = CHAR_NULL_PTR;
@@ -327,7 +352,7 @@ static inline void ffStrbufInitStatic(FFstrbuf* strbuf, const char* str) {
return strbuf;
}
static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value) {
[[gnu::nonnull(1)]] static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value) {
if (strbuf->allocated > 0) {
free(strbuf->chars);
}
@@ -339,7 +364,7 @@ static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value) {
}
}
static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str) {
[[gnu::nonnull(1)]] static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str) {
ffStrbufInit(strbuf);
ffStrbufAppendNS(strbuf, length, str);
}
@@ -350,12 +375,13 @@ static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char*
return strbuf;
}
// Returns whether `jsonVal` was a string; not `nodiscard`, same reason as ffStrbufAppendJsonVal
static inline bool ffStrbufInitJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
ffStrbufInit(strbuf);
return ffStrbufAppendJsonVal(strbuf, jsonVal);
}
static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) {
[[gnu::nonnull(1)]] static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) {
ffStrbufInit(strbuf);
ffStrbufAppendS(strbuf, str);
}
@@ -366,107 +392,107 @@ static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) {
return strbuf;
}
static inline void ffStrbufPrepend(FFstrbuf* strbuf, FFstrbuf* value) {
[[gnu::nonnull(1)]] static inline void ffStrbufPrepend(FFstrbuf* strbuf, FFstrbuf* value) {
if (value == nullptr) {
return;
}
ffStrbufPrependNS(strbuf, value->length, value->chars);
}
static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) {
[[gnu::nonnull(1)]] static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) {
if (value == nullptr) {
return;
}
ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value);
}
[[nodiscard]] static inline int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline 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);
}
[[nodiscard]] static inline bool ffStrbufEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
return ffStrbufComp(strbuf, comp) == 0;
}
[[nodiscard]] static inline int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp) {
return strcmp(strbuf->chars, comp);
}
[[nodiscard]] static inline bool ffStrbufEqualS(const FFstrbuf* strbuf, const char* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufEqualS(const FFstrbuf* strbuf, const char* comp) {
return ffStrbufCompS(strbuf, comp) == 0;
}
[[nodiscard]] static inline int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp) {
return strcasecmp(strbuf->chars, comp);
}
[[nodiscard]] static inline bool ffStrbufIgnCaseEqualS(const FFstrbuf* strbuf, const char* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufIgnCaseEqualS(const FFstrbuf* strbuf, const char* comp) {
return ffStrbufIgnCaseCompS(strbuf, comp) == 0;
}
[[nodiscard]] static inline int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
return ffStrbufIgnCaseCompS(strbuf, comp->chars);
}
[[nodiscard]] static inline bool ffStrbufIgnCaseEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufIgnCaseEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
return ffStrbufIgnCaseComp(strbuf, comp) == 0;
}
[[nodiscard]] static inline bool ffStrbufContainC(const FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline bool ffStrbufContainC(const FFstrbuf* strbuf, char c) {
return memchr(strbuf->chars, c, strbuf->length) != nullptr;
}
[[nodiscard]] static inline bool ffStrbufContainS(const FFstrbuf* strbuf, const char* str) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufContainS(const FFstrbuf* strbuf, const char* str) {
return strstr(strbuf->chars, str) != nullptr;
}
[[nodiscard]] static inline bool ffStrbufContain(const FFstrbuf* strbuf, const FFstrbuf* str) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufContain(const FFstrbuf* strbuf, const FFstrbuf* str) {
return ffStrbufContainS(strbuf, str->chars);
}
[[nodiscard]] static inline bool ffStrbufContainIgnCaseS(const FFstrbuf* strbuf, const char* str) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufContainIgnCaseS(const FFstrbuf* strbuf, const char* str) {
return strcasestr(strbuf->chars, str) != nullptr;
}
[[nodiscard]] static inline bool ffStrbufContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* str) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* str) {
return ffStrbufContainIgnCaseS(strbuf, str->chars);
}
[[nodiscard]] static inline uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
assert(start <= strbuf->length);
const char* ptr = (const char*) memchr(strbuf->chars + start, c, strbuf->length - start);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
[[nodiscard]] static inline uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
[[gnu::nonnull(1, 3), gnu::pure, nodiscard]] static inline uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
assert(start <= strbuf->length);
const char* ptr = strstr(strbuf->chars + start, str);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
[[nodiscard]] static inline uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
assert(start <= strbuf->length);
const char* ptr = (const char*) memrchr(strbuf->chars, c, start + 1);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
[[nodiscard]] static inline uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) {
return ffStrbufNextIndexC(strbuf, 0, c);
}
[[nodiscard]] static inline uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched) {
return ffStrbufNextIndexS(strbuf, 0, searched->chars);
}
[[nodiscard]] static inline uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str) {
return ffStrbufNextIndexS(strbuf, 0, str);
}
[[nodiscard]] static inline uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c) {
if (strbuf->length == 0) {
return 0;
}
@@ -474,19 +500,19 @@ static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) {
return ffStrbufPreviousIndexC(strbuf, strbuf->length - 1, c);
}
static inline bool ffStrbufSubstrBeforeFirstC(FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1)]] static inline bool ffStrbufSubstrBeforeFirstC(FFstrbuf* strbuf, char c) {
return ffStrbufSubstrBefore(strbuf, ffStrbufFirstIndexC(strbuf, c));
}
static inline bool ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1)]] static inline bool ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c) {
return ffStrbufSubstrBefore(strbuf, ffStrbufLastIndexC(strbuf, c));
}
[[nodiscard]] static inline bool ffStrbufStartsWithC(const FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline bool ffStrbufStartsWithC(const FFstrbuf* strbuf, char c) {
return strbuf->chars[0] == c;
}
[[nodiscard]] static inline bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, const char* start, uint32_t length) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, const char* start, uint32_t length) {
if (length > strbuf->length) {
return false;
}
@@ -494,34 +520,34 @@ static inline bool ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c) {
return memcmp(strbuf->chars, start, length) == 0;
}
[[nodiscard]] static inline bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start) {
return ffStrbufStartsWithSN(strbuf, start, (uint32_t) strlen(start));
}
[[nodiscard]] static inline bool ffStrbufStartsWith(const FFstrbuf* strbuf, const FFstrbuf* start) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufStartsWith(const FFstrbuf* strbuf, const FFstrbuf* start) {
return ffStrbufStartsWithSN(strbuf, start->chars, start->length);
}
[[nodiscard]] static inline bool ffStrbufStartsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t length, const char* start) {
[[gnu::nonnull(1, 3), gnu::pure, nodiscard]] static inline bool ffStrbufStartsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t length, const char* start) {
if (length > strbuf->length) {
return false;
}
return strncasecmp(strbuf->chars, start, length) == 0;
}
[[nodiscard]] static inline bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) {
return ffStrbufStartsWithIgnCaseNS(strbuf, (uint32_t) strlen(start), start);
}
[[nodiscard]] static inline bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) {
return ffStrbufStartsWithIgnCaseNS(strbuf, start->length, start->chars);
}
[[nodiscard]] static inline bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) {
return strbuf->length == 0 ? false : strbuf->chars[strbuf->length - 1] == c;
}
[[nodiscard]] static inline bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
[[gnu::nonnull(1, 3), gnu::pure, nodiscard]] static inline bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
if (endLength > strbuf->length) {
return false;
}
@@ -529,104 +555,108 @@ static inline bool ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c) {
return memcmp(strbuf->chars + strbuf->length - endLength, end, endLength) == 0;
}
[[nodiscard]] static inline bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) {
return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end);
}
[[nodiscard]] static inline bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int)) {
// Not `pure`: the caller-supplied `fn` may have side effects
[[gnu::nonnull(1, 2), nodiscard]] static inline bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int)) {
return strbuf->length == 0 ? false : fn(strbuf->chars[strbuf->length - 1]);
}
[[nodiscard]] static inline bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end) {
return ffStrbufEndsWithNS(strbuf, end->length, end->chars);
}
[[nodiscard]] static inline bool ffStrbufEndsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
[[gnu::nonnull(1, 3), gnu::pure, nodiscard]] static inline 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;
}
[[nodiscard]] static inline bool ffStrbufEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end) {
return ffStrbufEndsWithIgnCaseNS(strbuf, (uint32_t) strlen(end), end);
}
[[nodiscard]] static inline bool ffStrbufEndsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* end) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufEndsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* end) {
return ffStrbufEndsWithIgnCaseNS(strbuf, end->length, end->chars);
}
static inline void ffStrbufTrim(FFstrbuf* strbuf, char c) {
[[gnu::nonnull(1)]] static inline void ffStrbufTrim(FFstrbuf* strbuf, char c) {
ffStrbufTrimRight(strbuf, c);
ffStrbufTrimLeft(strbuf, c);
}
static inline void ffStrbufTrimSpace(FFstrbuf* strbuf) {
[[gnu::nonnull(1)]] static inline void ffStrbufTrimSpace(FFstrbuf* strbuf) {
ffStrbufTrimRightSpace(strbuf);
ffStrbufTrimLeftSpace(strbuf);
}
static inline bool ffStrbufMatchSeparatedS(const FFstrbuf* strbuf, const char* comp, char separator) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] 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) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] 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) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] 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) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] 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) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] 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) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] 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) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] 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) {
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator) {
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
}
static inline void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file) {
[[gnu::nonnull(1, 2)]] static inline void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file) {
fwrite(strbuf->chars, sizeof(*strbuf->chars), strbuf->length, file);
}
static inline void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file) {
[[gnu::nonnull(1, 2)]] static inline void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file) {
ffStrbufWriteTo(strbuf, file);
fputc('\n', file);
}
[[nodiscard]] static inline double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue) {
// Not `pure`: `strtod` reads the LC_NUMERIC locale and writes errno
[[gnu::nonnull(1), nodiscard]] static inline double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue) {
char* str_end;
double result = strtod(strbuf->chars, &str_end);
return str_end == strbuf->chars ? defaultValue : result;
}
[[nodiscard]] static inline uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue) {
// Not `pure`: `strtoull` reads the LC_NUMERIC locale and writes errno
[[gnu::nonnull(1), nodiscard]] static inline uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue) {
char* str_end;
unsigned long long result = strtoull(strbuf->chars, &str_end, 10);
return str_end == strbuf->chars ? defaultValue : (uint64_t) result;
}
[[nodiscard]] static inline int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue) {
// Not `pure`: `strtoll` reads the LC_NUMERIC locale and writes errno
[[gnu::nonnull(1), nodiscard]] static inline int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue) {
char* str_end;
long long result = strtoll(strbuf->chars, &str_end, 10);
return str_end == strbuf->chars ? defaultValue : (int64_t) result;
}
// Returns true if the strbuf is modified
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf);
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]] bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf);
#define FF_STRBUF_AUTO_DESTROY [[gnu::cleanup(ffStrbufDestroy)]] FFstrbuf
#define FF_STRBUF_STATIC(str) { .allocated = 0, .length = (uint32_t) sizeof(str) - 1, .chars = str }
+5 -4
View File
@@ -2,8 +2,9 @@
#include "fastfetch.h"
void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output);
static inline FFstrbuf ffBase64EncodeStrbuf(const FFstrbuf* in) {
// `str`, `out_size` and `output` are dereferenced unconditionally
[[gnu::nonnull(2, 3, 4)]] void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output);
[[gnu::nonnull(1), nodiscard]] 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);
@@ -11,8 +12,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) {
[[gnu::nonnull(2, 3, 4)]] void ffBase64DecodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output);
[[gnu::nonnull(1), nodiscard]] 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);
+1 -1
View File
@@ -3,7 +3,7 @@
#include "fastfetch.h"
#include "common/time.h"
static inline const char* ffFindFileName(const char* file) {
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline const char* ffFindFileName(const char* file) {
const char* lastSlash = __builtin_strrchr(file, '/');
#ifdef _WIN32
if (lastSlash == nullptr) {
+1 -1
View File
@@ -2,4 +2,4 @@
#include "fastfetch.h"
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result);
[[gnu::nonnull(2)]] void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result);
+3 -1
View File
@@ -2,4 +2,6 @@
#include "fastfetch.h"
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result);
// Returns false when nothing was appended (e.g. `mhz == 0`); callers routinely discard that, so it
// is not `nodiscard`.
[[gnu::nonnull(2)]] bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result);
+2 -19
View File
@@ -21,8 +21,6 @@ void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate) {
}
void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
assert(format != nullptr);
char* buffer = nullptr;
int len = vasprintf(&buffer, format, arguments);
assert(len >= 0);
@@ -33,8 +31,6 @@ void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
// Takes ownership of `heapStr`. The caller must not free `heapStr` after calling this
// function; the memory will be managed and freed via the associated FFstrbuf.
void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr) {
assert(heapStr != nullptr);
strbuf->length = length;
size_t allocSize = ffMallocUsableSize(heapStr);
if (allocSize == 0) {
@@ -157,8 +153,6 @@ void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transfo
}
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
assert(format != nullptr);
va_list copy;
va_copy(copy, arguments);
@@ -192,8 +186,6 @@ const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char unti
}
void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...) {
assert(format != nullptr);
va_list arguments;
va_start(arguments, format);
@@ -209,8 +201,6 @@ void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...) {
}
void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...) {
assert(format != nullptr);
va_list arguments;
va_start(arguments, format);
ffStrbufAppendVF(strbuf, format, arguments);
@@ -236,15 +226,11 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c) {
}
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
assert(strbuf != nullptr);
if (length == 0) {
ffStrbufClear(strbuf);
return;
}
assert(value != nullptr);
if (strbuf->allocated <= length) {
char* newBuf = malloc(sizeof(char) * (length + 1));
memcpy(newBuf, value, length);
@@ -262,7 +248,8 @@ void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
}
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value) {
assert(value && value != strbuf);
// `value` is non-null per the `nonnull(2)` contract; the aliasing check cannot be expressed by an attribute
assert(value != strbuf);
if (value->length == 0) {
ffStrbufClear(strbuf);
@@ -647,7 +634,6 @@ void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c) {
}
bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer) {
assert(lineptr && n && buffer);
assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0));
assert(!*lineptr || (*lineptr >= buffer->chars && *lineptr <= buffer->chars + buffer->length));
@@ -678,7 +664,6 @@ bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffe
}
void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer) {
assert(buffer && lineptr && n);
assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0));
assert(!*lineptr || (*lineptr >= buffer->chars && *lineptr <= buffer->chars + buffer->length));
@@ -842,8 +827,6 @@ bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLeng
}
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf) {
assert(strbuf);
if (strbuf->length < 4) {
return false;
}
+1 -2
View File
@@ -66,7 +66,7 @@ static void init_decode_table() {
#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) {
void ffBase64DecodeRaw(uint32_t size, const char* str, uint32_t* out_size, char* output) {
if (*(uint64_t*) decode_table == 0) {
init_decode_table();
}
@@ -113,5 +113,4 @@ bool ffBase64DecodeRaw(uint32_t size, const char* str, uint32_t* out_size, char*
*out = '\0';
*out_size = (uint32_t) (out - output);
return true;
}
+2 -2
View File
@@ -161,8 +161,8 @@ void* dlsym(void* handle, const char* symbol) {
}
void* ffLibraryGetModule(const wchar_t* libraryFileName) {
assert(libraryFileName != nullptr && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
// `libraryFileName` is non-null per the `nonnull(1)` contract.
// Prefer `ffGetPeb()->ImageBaseAddress` over looking the main module up by name.
void* module = nullptr;
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t) + sizeof(wchar_t));
NTSTATUS status = LdrGetDllHandle(nullptr, nullptr, &(UNICODE_STRING) {
+2 -7
View File
@@ -64,7 +64,8 @@ static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize) {
// Decompress gzip content
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd) {
assert(headerEnd != nullptr && *headerEnd == '\r');
// `headerEnd` itself is non-null per the `nonnull(2)` contract; what it points to is not expressible as an attribute
assert(*headerEnd == '\r');
// Calculate header size
uint32_t headerSize = (uint32_t) (headerEnd - buffer->chars);
@@ -192,8 +193,6 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd) {
#endif // FF_HAVE_ZLIB
const char* ffNetworkingFindHeader(const char* headers, uint32_t headerEnd, const char* name, uint32_t* valueLen) {
assert(headers != nullptr && valueLen != nullptr);
uint32_t nameLen = (uint32_t) strlen(name);
uint32_t pos = 0;
@@ -225,8 +224,6 @@ const char* ffNetworkingFindHeader(const char* headers, uint32_t headerEnd, cons
}
FFNetworkingTransferEncoding ffNetworkingParseTransferEncoding(const char* value, uint32_t valueLen) {
assert(value != nullptr);
// The value is a comma-separated list of transfer codings (RFC 9112 6.1)
uint32_t codingCount = 0;
const char* coding = nullptr;
@@ -267,8 +264,6 @@ FFNetworkingTransferEncoding ffNetworkingParseTransferEncoding(const char* value
}
int ffNetworkingChunkedComplete(const char* body, uint32_t bodyLen, uint32_t* consumed) {
assert(body != nullptr && consumed != nullptr);
uint32_t pos = 0;
for (;;) {
-2
View File
@@ -7,8 +7,6 @@
// Return start position of the inner key if the argument key belongs to the module specified, nullptr otherwise
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName) {
assert(argumentKey && moduleName);
const char* subKey = argumentKey;
if (!(subKey[0] == '-' && subKey[1] == '-')) {
return nullptr;
+6 -9
View File
@@ -36,8 +36,8 @@ typedef int FFNativeFD;
#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);
[[gnu::nonnull(2)]] HANDLE openat(HANDLE dfd, const char* fileName, int oflag);
[[gnu::nonnull(2)]] HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
#endif
static inline bool ffIsValidNativeFD(FFNativeFD fd) {
@@ -51,8 +51,6 @@ static inline bool ffIsValidNativeFD(FFNativeFD fd) {
[[gnu::always_inline, gnu::nonnull(1)]]
static inline void wrapClose(FFNativeFD* pfd) {
assert(pfd);
if (ffIsValidNativeFD(*pfd)) {
#ifndef _WIN32
close(*pfd);
@@ -235,6 +233,7 @@ typedef enum FFPathType: uint8_t {
[[gnu::format(scanf, 3, 4), gnu::nonnull(1, 3)]] const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);
// Not thread safe!
// Returns the previous state, which callers routinely discard (see ffUnsuppressIO), so not `nodiscard`
bool ffSuppressIO(bool suppress);
static inline void ffUnsuppressIO(bool* suppressed) {
@@ -247,10 +246,9 @@ static inline void ffUnsuppressIO(bool* suppressed) {
#define FF_SUPPRESS_IO() [[maybe_unused, gnu::cleanup(ffUnsuppressIO)]] bool io_suppressed__ = ffSuppressIO(true)
void ffListFilesRecursively(const char* path, bool pretty);
[[gnu::nonnull(1)]] void ffListFilesRecursively(const char* path, bool pretty);
[[gnu::nonnull(1), gnu::always_inline]] static inline void wrapFclose(FILE** pfile) {
assert(pfile);
if (*pfile) {
fclose(*pfile);
}
@@ -260,14 +258,12 @@ void ffListFilesRecursively(const char* path, bool pretty);
[[gnu::nonnull(1), gnu::always_inline]]
#ifndef _WIN32
static inline void wrapClosedir(DIR** pdir) {
assert(pdir);
if (*pdir) {
closedir(*pdir);
}
}
#else
static inline void wrapClosedir(HANDLE* pdir) {
assert(pdir);
if (*pdir) {
FindClose(*pdir);
}
@@ -290,7 +286,8 @@ static inline void wrapClosedir(HANDLE* pdir) {
}
FFNativeFD ffGetNullFD(void);
bool ffRemoveFile(const char* fileName);
// Returns whether the file was removed; callers that only want it gone discard that, so not `nodiscard`
[[gnu::nonnull(1)]] bool ffRemoveFile(const char* fileName);
// Modification time of a file, in milliseconds since the Unix epoch, or 0 if it can not be read.
// The representation is uniform across platforms so that a value derived from it means the
// same thing everywhere, which matters for callers that store it as a cache key.
+12 -7
View File
@@ -3,25 +3,30 @@
#include "common/ffdata.h"
#include "common/option.h"
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs);
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[]);
// `key` / `val` may be null when the JSON object has no such member; `moduleArgs` is always real
[[gnu::nonnull(3)]] bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs);
// `val` may be null (yyjson predicates tolerate it); `result` and `pairs` may not.
// Returns an error string, null on success, so it is `nodiscard`.
[[gnu::nonnull(2, 3), nodiscard]] 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) {
// The three helpers below are routinely called as statements, to add a key to a document, so their
// result is not `nodiscard`.
[[gnu::nonnull(1, 2)]] 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,
[[gnu::nonnull(1, 2, 3, 4)]] 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,
[[gnu::nonnull(1, 2, 3)]] 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);
}
void ffPrintJsonConfig(FFdata* data, bool prepare);
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs);
[[gnu::nonnull(1)]] void ffPrintJsonConfig(FFdata* data, bool prepare);
[[gnu::nonnull(1, 2, 3)]] void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs);
+5 -6
View File
@@ -21,8 +21,7 @@ int dlclose(void* handle);
#define FF_LIBRARY_EXTENSION ".so"
#endif
static inline void ffLibraryUnload(void** handle) {
assert(handle);
[[gnu::nonnull(1)]] static inline void ffLibraryUnload(void** handle) {
if (*handle) {
dlclose(*handle);
}
@@ -66,8 +65,8 @@ static inline void ffLibraryUnload(void** handle) {
#define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \
FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, (varName)->ff##symbolName, symbolName, returnValue);
void* ffLibraryLoadSingle(const char* path, int maxVersion);
void* ffLibraryLoadMulti(const char* path, int maxVersion, ...);
[[gnu::nonnull(1), nodiscard]] void* ffLibraryLoadSingle(const char* path, int maxVersion);
[[gnu::nonnull(1), nodiscard]] void* ffLibraryLoadMulti(const char* path, int maxVersion, ...);
#else
@@ -109,10 +108,10 @@ void* ffLibraryLoadMulti(const char* path, int maxVersion, ...);
#endif
#if _WIN32
void* ffLibraryGetModule(const wchar_t* libraryFileName);
[[gnu::nonnull(1), nodiscard]] void* ffLibraryGetModule(const wchar_t* libraryFileName);
#endif
// Return false to stop iterating, true to continue
typedef bool (*FFLibraryIterateCallback)(const char* name, void* userData);
// Iterate over all loaded dynamic libraries. Returns true on success, false on failure.
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData);
[[nodiscard]] bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData);
+1 -2
View File
@@ -15,7 +15,6 @@
[[gnu::always_inline, gnu::nonnull(1)]]
static inline void ffWrapFree(const void* pPtr) {
assert(pPtr);
if (*(void**) pPtr) {
free(*(void**) pPtr);
}
@@ -24,8 +23,8 @@ static inline void ffWrapFree(const void* pPtr) {
#define FF_AUTO_FREE [[gnu::cleanup(ffWrapFree)]]
// ptr MUST be a malloc'ed pointer
[[gnu::nonnull(1), nodiscard]]
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
+10 -7
View File
@@ -29,14 +29,16 @@ typedef struct FFNetworkingState {
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, uint16_t port, const char* path, const char* headers);
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer);
// `headers` is optional and may be null; the other pointer arguments are dereferenced unconditionally.
// Both functions report failure through their return value, which must be checked.
[[gnu::nonnull(1, 2, 4), nodiscard]] const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, uint16_t port, const char* path, const char* headers);
[[gnu::nonnull(1, 2), nodiscard]] const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer);
// Case-insensitive header lookup restricted to the header block [0, headerEnd).
// Restricting the range matters because the body may already share the same buffer.
// Returns a pointer to the first character of the value; `valueLen` receives its
// length excluding the terminating CRLF. Returns nullptr when the header is absent.
const char* ffNetworkingFindHeader(const char* headers, uint32_t headerEnd, const char* name, uint32_t* valueLen);
[[gnu::nonnull(1, 3, 4), gnu::pure, nodiscard]] const char* ffNetworkingFindHeader(const char* headers, uint32_t headerEnd, const char* name, uint32_t* valueLen);
// Checks whether a `Transfer-Encoding: chunked` body has been received in full, so that
// framing does not have to rely on the server closing the connection.
@@ -44,11 +46,12 @@ const char* ffNetworkingFindHeader(const char* headers, uint32_t headerEnd, cons
// 0 when more data is needed, and -1 when the body is malformed.
// The caller must not wait for a fixed amount of data (e.g. `MSG_WAITALL`) while the
// response length is still unknown, otherwise this check never gets to run.
int ffNetworkingChunkedComplete(const char* body, uint32_t bodyLen, uint32_t* consumed);
// Not `pure`: the `strtoul` it calls writes `errno`.
[[gnu::nonnull(1, 3), nodiscard]] int ffNetworkingChunkedComplete(const char* body, uint32_t bodyLen, uint32_t* consumed);
// Decodes a `Transfer-Encoding: chunked` body in place and rewrites the response with a
// `Content-Length` header in place of `Transfer-Encoding`.
bool ffNetworkingDecodeChunked(FFstrbuf* buffer, uint32_t headerEnd);
[[gnu::nonnull(1), nodiscard]] bool ffNetworkingDecodeChunked(FFstrbuf* buffer, uint32_t headerEnd);
// Result of parsing a `Transfer-Encoding` header value
typedef enum FFNetworkingTransferEncoding {
@@ -62,9 +65,9 @@ typedef enum FFNetworkingTransferEncoding {
// and any other coding (e.g. `gzip, chunked`) leaves the payload encoded, which this
// client cannot decode. Only a lone `chunked` is accepted; everything else is reported
// as unsupported so that the caller fails the response instead of returning garbage.
FFNetworkingTransferEncoding ffNetworkingParseTransferEncoding(const char* value, uint32_t valueLen);
[[gnu::nonnull(1), gnu::pure, nodiscard]] FFNetworkingTransferEncoding ffNetworkingParseTransferEncoding(const char* value, uint32_t valueLen);
#ifdef FF_HAVE_ZLIB
const char* ffNetworkingLoadZlibLibrary(void);
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd);
[[gnu::nonnull(1, 2), nodiscard]] bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd);
#endif
+16 -10
View File
@@ -89,19 +89,25 @@ typedef struct FFKeyValuePair {
int value;
} FFKeyValuePair;
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName);
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer);
[[nodiscard]] uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value);
[[nodiscard]] int32_t ffOptionParseInt32(const char* argumentKey, const char* value);
[[nodiscard]] int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]);
[[nodiscard]] bool ffOptionParseBoolean(const char* str);
void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer);
static inline void ffOptionParseColor(const char* value, FFstrbuf* buffer) {
// `moduleName` and `argumentKey` are both dereferenced unconditionally; reads no global state, so `pure`
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName);
// `value` is optional (null exits with a usage error), `argumentKey` and `buffer` are not
[[gnu::nonnull(1, 3)]] void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer);
[[gnu::nonnull(1), nodiscard]] uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value);
[[gnu::nonnull(1), nodiscard]] int32_t ffOptionParseInt32(const char* argumentKey, const char* value);
// `requestedKey` is optional (null exits with a usage error); `pairs` is walked until its null key
[[gnu::nonnull(1, 3), nodiscard]] int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]);
// `str` is optional: a null or empty value is reported as `true`
[[gnu::pure, nodiscard]] bool ffOptionParseBoolean(const char* str);
// `value` is optional (a null or empty value is a no-op); `buffer` is not
[[gnu::nonnull(2)]] void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer);
[[gnu::nonnull(2)]] static inline void ffOptionParseColor(const char* value, FFstrbuf* buffer) {
ffStrbufClear(buffer);
ffOptionParseColorNoClear(value, buffer);
}
static inline void ffOptionInitModuleArg(FFModuleArgs* args, const char* icon) {
// `icon` is optional, `args` is not
[[gnu::nonnull(1)]] static inline void ffOptionInitModuleArg(FFModuleArgs* args, const char* icon) {
ffStrbufInit(&args->key);
ffStrbufInit(&args->keyColor);
ffStrbufInitStatic(&args->keyIcon, icon);
@@ -110,7 +116,7 @@ static inline void ffOptionInitModuleArg(FFModuleArgs* args, const char* icon) {
args->keyWidth = 0;
}
static inline void ffOptionDestroyModuleArg(FFModuleArgs* args) {
[[gnu::nonnull(1)]] static inline void ffOptionDestroyModuleArg(FFModuleArgs* args) {
ffStrbufDestroy(&args->key);
ffStrbufDestroy(&args->keyColor);
ffStrbufDestroy(&args->keyIcon);
+5 -4
View File
@@ -17,8 +17,9 @@ typedef struct FFColorRangeConfig {
#define FF_VERSION_INIT ((FFVersion) { 0 })
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
// Every argument is dereferenced unconditionally
[[gnu::nonnull(1, 2, 3, 4)]] void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
[[gnu::nonnull(1, 2, 3, 4)]] void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
[[gnu::nonnull(1, 2)]] void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
+3 -3
View File
@@ -4,8 +4,8 @@
#include "common/strutil.h"
#include "fastfetch_config.h"
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result);
static inline bool ffIsAbsolutePath(const char* path) {
[[gnu::nonnull(1, 2), nodiscard]] const char* ffFindExecutableInPath(const char* name, FFstrbuf* result);
[[gnu::nonnull(1), gnu::pure, nodiscard]] 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
@@ -34,4 +34,4 @@ ssize_t readlink(const char* path, char* buf, size_t bufsiz);
#define FF_PATH_PKG_BASE "/usr/pkg"
#else
#define FF_PATH_PKG_BASE FASTFETCH_TARGET_DIR_USR
#endif
#endif
+4 -3
View File
@@ -30,13 +30,14 @@ typedef struct FFPercentageModuleConfig {
// [yellow, green): print yellow
// [0, yellow): print red
void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, const FFModuleArgs* module);
void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, bool parentheses, const FFModuleArgs* module);
// `buffer` and `module` are dereferenced unconditionally; `module` carries the key/color formatting
[[gnu::nonnull(1, 4)]] void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, const FFModuleArgs* module);
[[gnu::nonnull(1, 5)]] void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConfig config, bool parentheses, const FFModuleArgs* module);
typedef struct yyjson_val yyjson_val;
typedef struct yyjson_mut_doc yyjson_mut_doc;
typedef struct yyjson_mut_val yyjson_mut_val;
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentageModuleConfig* config);
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config);
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config);
[[gnu::nonnull(1, 2)]] void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config);
const char* ffPercentParseTypeJsonConfig(yyjson_val* value, FFPercentageTypeFlags* result);
+9 -2
View File
@@ -11,10 +11,17 @@ typedef enum FFPrintType: uint8_t {
FF_PRINT_TYPE_NO_CUSTOM_OUTPUT_FORMAT = 1 << 3, // reserved
} FFPrintType;
// Both `moduleName` and `moduleArgs` are optional and explicitly handled: a null `moduleName` is what
// `--set-keyless` relies on, and a null `moduleArgs` (used by ffPrintError callers) skips the custom
// key entirely. So neither takes `nonnull`.
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType);
// Same for `moduleArgs`; `numArgs` / `arguments` are only read when `moduleArgs` is non-null, so
// `arguments` is not `nonnull(6)` either. At least one caller discards the result, so not `nodiscard`.
bool 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));
[[gnu::format(printf, 5, 6)]] void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...);
void ffPrintColor(const FFstrbuf* colorValue);
// `moduleName` / `moduleArgs` are forwarded to ffPrintLogoAndKey, which accepts null for both;
// only `message` is dereferenced here (by `vprintf`).
[[gnu::format(printf, 5, 6), gnu::nonnull(5)]] void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...);
[[gnu::nonnull(1)]] void ffPrintColor(const FFstrbuf* colorValue);
void ffPrintCharTimes(char c, uint32_t times);
+17 -13
View File
@@ -7,41 +7,45 @@ typedef struct FFpropquery {
FFstrbuf* buffer;
} FFpropquery;
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer);
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFileHomeValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
// These report "was the file/property found", which callers routinely discard, so they are not
// `nodiscard`.
//
// `queries` is only walked when `numQueries > 0`, so it is intentionally not `nonnull(3)`.
[[gnu::nonnull(1, 2, 3)]] bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer);
[[gnu::nonnull(1)]] bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries);
[[gnu::nonnull(1)]] bool ffParsePropFileHomeValues(const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
[[gnu::nonnull(1, 2)]] bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer);
[[gnu::nonnull(1, 2, 3)]] bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer);
static inline bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer) {
[[gnu::nonnull(1, 2, 3)]] 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) {
[[gnu::nonnull(1, 2, 3)]] 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) {
[[gnu::nonnull(1, 2, 3)]] 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) {
[[gnu::nonnull(1, 2, 3, 4)]] 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) {
[[gnu::nonnull(1)]] 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) {
[[gnu::nonnull(1, 2, 3)]] 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) {
[[gnu::nonnull(1)]] 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) {
[[gnu::nonnull(1, 2, 3)]] static inline bool ffParsePropFileData(const char* relativeFile, const char* start, FFstrbuf* buffer) {
return ffParsePropFileDataValues(relativeFile, 1, (FFpropquery[]) { { start, buffer } });
}
+1 -1
View File
@@ -2,4 +2,4 @@
#include "fastfetch.h"
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result);
[[gnu::nonnull(2)]] void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result);
+8 -6
View File
@@ -2,8 +2,9 @@
#include "common/FFstrbuf.h"
bool ffIsSmbiosValueSet(FFstrbuf* value);
static inline void ffCleanUpSmbiosValue(FFstrbuf* value) {
// Not `pure`: it trims the trailing spaces of `value` before reporting whether it is set
[[gnu::nonnull(1), nodiscard]] bool ffIsSmbiosValueSet(FFstrbuf* value);
[[gnu::nonnull(1)]] static inline void ffCleanUpSmbiosValue(FFstrbuf* value) {
if (!ffIsSmbiosValueSet(value)) {
ffStrbufClear(value);
}
@@ -82,7 +83,8 @@ typedef struct [[gnu::packed]] FFSmbiosHeader {
} 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 */) {
// `start` points into the unformatted string section and is walked with `strlen`, so it may not be null
[[gnu::nonnull(1), gnu::pure, nodiscard]] static inline const char* ffSmbiosLocateString(const char* start, uint8_t index /* start from 1 */) {
if (index == 0 || *start == '\0') {
return nullptr;
}
@@ -94,9 +96,9 @@ static inline const char* ffSmbiosLocateString(const char* start, uint8_t index
typedef const FFSmbiosHeader* FFSmbiosHeaderTable[FF_SMBIOS_TYPE__MAX];
const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header);
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable(void);
[[gnu::nonnull(1), gnu::pure, nodiscard]] const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header);
[[nodiscard]] const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable(void);
#ifdef __linux__
bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer);
[[gnu::nonnull(1, 2, 3), nodiscard]] bool ffGetSmbiosValue(const char* devicesPath, const char* classPath, FFstrbuf* buffer);
#endif
+28 -10
View File
@@ -14,6 +14,15 @@ __stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch);
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
// Everything below is a leaf predicate over the bytes it is given: it reads memory through its
// arguments and nothing else, so `gnu::pure` is accurate. `gnu::const` is deliberately not used --
// these are already `always_inline`, so it would buy no optimization, and it would become a lie the
// day one of them is rewritten around a lookup table.
//
// The `gnu::nonnull` indexes name the arguments that are dereferenced unconditionally. `ffStrSet`
// and `ffStrCopy` are not listed: both handle a null pointer explicitly.
[[nodiscard, gnu::pure]]
static inline bool ffStrSet(const char* str) {
if (str == nullptr) {
return false;
@@ -26,21 +35,22 @@ static inline bool ffStrSet(const char* str) {
return *str != '\0';
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrStartsWithIgnCase(const char* str, const char* compareTo) {
return strncasecmp(str, compareTo, strlen(compareTo)) == 0;
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrEqualsIgnCase(const char* str, const char* compareTo) {
return strcasecmp(str, compareTo) == 0;
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrStartsWith(const char* str, const char* compareTo) {
return strncmp(str, compareTo, strlen(compareTo)) == 0;
}
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrEndsWith(const char* str, const char* compareTo) {
size_t strLength = strlen(str);
size_t compareToLength = strlen(compareTo);
@@ -50,6 +60,7 @@ static inline bool ffStrEndsWith(const char* str, const char* compareTo) {
return memcmp(str + strLength - compareToLength, compareTo, compareToLength) == 0;
}
[[gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrEndsWithIgnCase(const char* str, const char* compareTo) {
size_t strLength = strlen(str);
size_t compareToLength = strlen(compareTo);
@@ -59,32 +70,32 @@ static inline bool ffStrEndsWithIgnCase(const char* str, const char* compareTo)
return strncasecmp(str + strLength - compareToLength, compareTo, compareToLength) == 0;
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrEquals(const char* str, const char* compareTo) {
return strcmp(str, compareTo) == 0;
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrContains(const char* str, const char* compareTo) {
return strstr(str, compareTo) != nullptr;
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::nonnull(1, 2), gnu::pure, nodiscard]]
static inline bool ffStrContainsIgnCase(const char* str, const char* compareTo) {
return strcasestr(str, compareTo) != nullptr;
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::nonnull(1), gnu::pure, nodiscard]]
static inline bool ffStrContainsC(const char* str, char compareTo) {
return strchr(str, compareTo) != nullptr;
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::pure, nodiscard]]
static inline bool ffCharIsEnglishAlphabet(char c) {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
[[gnu::always_inline]]
[[gnu::always_inline, gnu::pure, nodiscard]]
static inline bool ffCharIsDigit(char c) {
return '0' <= c && c <= '9';
}
@@ -92,15 +103,19 @@ static inline bool ffCharIsDigit(char c) {
// Parse one UTF-8 character, returning consumed byte count and display width.
// Invalid / incomplete sequence falls back to one-byte width=1.
// If the Unicode codepoint is non-printable, width becomes 0.
// Not `pure`: it stores the width through `width` when that is not null.
[[gnu::nonnull(1)]]
uint8_t ffUtf8CharLenWidth(const char* str, uint32_t length, uint8_t* width);
[[gnu::nonnull(1), gnu::pure, nodiscard]]
uint32_t ffUtf8StrWidth(const char* str, uint32_t length);
[[gnu::always_inline]]
[[gnu::always_inline, gnu::pure, nodiscard]]
static inline bool ffCharIsHexDigit(char c) {
return ffCharIsDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
}
[[gnu::always_inline, gnu::pure, nodiscard]]
static inline int8_t ffHexCharToInt(char c) {
if (ffCharIsDigit(c)) {
return (int8_t) (c - '0');
@@ -114,6 +129,9 @@ static inline int8_t ffHexCharToInt(char c) {
}
// Copies at most (dstBufSiz - 1) bytes from src to dst; dst is always null-terminated
// Returns a pointer to the end of the copy, which callers are free to ignore, so not `nodiscard`.
// Not `pure`: it writes through `dst`. `dst` may be null, `src` may not.
[[gnu::nonnull(2)]]
static inline char* ffStrCopy(char* __restrict__ dst, const char* __restrict__ src, size_t dstBufSiz) {
if (__builtin_expect(dst == nullptr, false) || dstBufSiz == 0) {
return dst;
+5 -4
View File
@@ -5,12 +5,13 @@
#include <sys/types.h>
#include <sys/sysctl.h>
// `result` is always written to, and `propName` is always read by the sysctl wrapper.
#ifdef __OpenBSD__
const char* ffSysctlGetString(int mib1, int mib2, FFstrbuf* result);
[[gnu::nonnull(3)]] const char* ffSysctlGetString(int mib1, int mib2, FFstrbuf* result);
[[nodiscard]] int ffSysctlGetInt(int mib1, int mib2, int defaultValue);
[[nodiscard]] int64_t ffSysctlGetInt64(int mib1, int mib2, int64_t defaultValue);
#else
const char* ffSysctlGetString(const char* propName, FFstrbuf* result);
[[nodiscard]] int ffSysctlGetInt(const char* propName, int defaultValue);
[[nodiscard]] int64_t ffSysctlGetInt64(const char* propName, int64_t defaultValue);
[[gnu::nonnull(1, 2)]] const char* ffSysctlGetString(const char* propName, FFstrbuf* result);
[[gnu::nonnull(1), nodiscard]] int ffSysctlGetInt(const char* propName, int defaultValue);
[[gnu::nonnull(1), nodiscard]] int64_t ffSysctlGetInt64(const char* propName, int64_t defaultValue);
#endif
+3 -2
View File
@@ -3,7 +3,8 @@
#include "common/parsing.h"
#include "common/option.h"
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module);
// `buffer` and `module` are dereferenced unconditionally; `module` carries the key/color formatting
[[gnu::nonnull(2, 4)]] void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module);
bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config);
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config);
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config);
[[gnu::nonnull(1, 2)]] void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config);
+11 -8
View File
@@ -11,13 +11,14 @@
#define FF_THREAD_MUTEX_INITIALIZER SRWLOCK_INIT
typedef SRWLOCK FFThreadMutex;
typedef HANDLE FFThreadType;
static inline void ffThreadMutexLock(FFThreadMutex* mutex) {
[[gnu::nonnull(1)]] static inline void ffThreadMutexLock(FFThreadMutex* mutex) {
AcquireSRWLockExclusive(mutex);
}
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) {
[[gnu::nonnull(1)]] static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) {
ReleaseSRWLockExclusive(mutex);
}
static inline FFThreadType ffThreadCreate(unsigned(__stdcall* func)(void*), void* data) {
// `data` is the thread argument and may be null; `func` may not
[[gnu::nonnull(1)]] static inline FFThreadType ffThreadCreate(unsigned(__stdcall* func)(void*), void* data) {
return (FFThreadType) _beginthreadex(nullptr, 0, func, data, 0, nullptr);
}
#define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType) \
@@ -56,23 +57,24 @@ typedef pthread_t FFThreadType;
#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) {
[[gnu::nonnull(1)]] static inline void ffThreadMutexLock(os_unfair_lock* mutex) {
os_unfair_lock_lock(mutex);
}
static inline void ffThreadMutexUnlock(os_unfair_lock* mutex) {
[[gnu::nonnull(1)]] 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) {
[[gnu::nonnull(1)]] static inline void ffThreadMutexLock(FFThreadMutex* mutex) {
pthread_mutex_lock(mutex);
}
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) {
[[gnu::nonnull(1)]] static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) {
pthread_mutex_unlock(mutex);
}
#endif
static inline FFThreadType ffThreadCreate(void* (*func)(void*), void* data) {
// `data` is the thread argument and may be null; `func` may not
[[gnu::nonnull(1)]] static inline FFThreadType ffThreadCreate(void* (*func)(void*), void* data) {
FFThreadType newThread = 0;
pthread_create(&newThread, nullptr, func, data);
return newThread;
@@ -115,6 +117,7 @@ static inline uintptr_t ffThreadGetCurrentId() {
#else // FF_HAVE_THREADS
#define FF_THREAD_MUTEX_INITIALIZER 0
typedef char FFThreadMutex;
// The stubs deliberately ignore their argument, so no `nonnull` here
static inline void ffThreadMutexLock([[maybe_unused]] FFThreadMutex* mutex) {}
static inline void ffThreadMutexUnlock([[maybe_unused]] FFThreadMutex* mutex) {}
#define FF_THREAD_ENTRY_DECL_WRAPPER(fn, paramType)
+3 -2
View File
@@ -3,9 +3,10 @@
#include <stdint.h>
#if FF_ENABLE_WCWIDTH
int mk_wcwidth(uint32_t wc);
// A pure table lookup: the width depends only on the code point
[[gnu::pure, nodiscard]] int mk_wcwidth(uint32_t wc);
#else
static inline int mk_wcwidth(uint32_t wc) {
[[gnu::pure, nodiscard]] static inline int mk_wcwidth(uint32_t wc) {
(void) wc;
return 1;
}