master ohmu/fastfetch-openbsd / src / common / option.h
ohmu  ·  2026-10-15
  1#pragma once
  2
  3#include "common/FFstrbuf.h"
  4
  5struct yyjson_val;
  6struct yyjson_mut_doc;
  7struct yyjson_mut_val;
  8
  9typedef struct FFModuleFormatArg {
 10    const char* desc;
 11    const char* name;
 12} FFModuleFormatArg;
 13
 14typedef struct FFModuleFormatArgList {
 15    FFModuleFormatArg* args;
 16    uint32_t count;
 17} FFModuleFormatArgList;
 18
 19#define FF_FORMAT_ARG_LIST(list) { .args = list, .count = sizeof(list) / sizeof(FFModuleFormatArg) }
 20
 21typedef struct FFModuleDisplayName {
 22    const char* en; // English
 23
 24    const char* ar;    // Arabic
 25    const char* cs;    // Czech
 26    const char* de;    // German
 27    const char* es;    // Spanish
 28    const char* fi;    // Finnish
 29    const char* fr;    // French
 30    const char* gl;    // Galician
 31    const char* he;    // Hebrew
 32    const char* id;    // Indonesian
 33    const char* it;    // Italian
 34    const char* ja;    // Japanese
 35    const char* ko;    // Korean
 36    const char* pl;    // Polish
 37    const char* pt;    // (Brazilian) Portuguese
 38    const char* ru;    // Russian
 39    const char* tr;    // Turkish
 40    const char* uk;    // Ukrainian
 41    const char* vi;    // Vietnamese
 42    const char* zh_CN; // Simplified Chinese
 43    const char* zh_TW; // Traditional Chinese
 44} FFModuleDisplayName;
 45
 46// Must be the first field of FFModuleOptions
 47typedef struct FFModuleBaseInfo {
 48    const char* name;
 49    const char* description;
 50    FFModuleDisplayName displayName;
 51    // A dirty polymorphic implementation in C.
 52    // This is UB, because `void*` is not compatible with `FF*Options*`.
 53    // However we can't do it better unless we move to C++, so that `option` becomes a `this` pointer
 54    // https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type
 55
 56    void (*initOptions)(void* options);
 57    void (*destroyOptions)(void* options);
 58    void (*parseJsonObject)(void* options, struct yyjson_val* module);
 59    bool (*printModule)(void* options);                                                                   // true on success
 60    bool (*generateJsonResult)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module); // true on success
 61    void (*generateJsonConfig)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* obj);
 62    FFModuleFormatArgList formatArgs;
 63    const uint8_t defaultOrder;
 64} FFModuleBaseInfo;
 65
 66typedef enum FFModuleKeyType: uint8_t {
 67    FF_MODULE_KEY_TYPE_NONE = 0,
 68    FF_MODULE_KEY_TYPE_STRING = 1 << 0,
 69    FF_MODULE_KEY_TYPE_ICON = 1 << 1,
 70    FF_MODULE_KEY_TYPE_SPACE_SHIFT = 4,
 71    FF_MODULE_KEY_TYPE_BOTH_0 = FF_MODULE_KEY_TYPE_STRING | FF_MODULE_KEY_TYPE_ICON,
 72    FF_MODULE_KEY_TYPE_BOTH_1 = FF_MODULE_KEY_TYPE_BOTH_0 | (1 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
 73    FF_MODULE_KEY_TYPE_BOTH = FF_MODULE_KEY_TYPE_BOTH_1, // alias
 74    FF_MODULE_KEY_TYPE_BOTH_2 = FF_MODULE_KEY_TYPE_BOTH_0 | (2 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
 75    FF_MODULE_KEY_TYPE_BOTH_3 = FF_MODULE_KEY_TYPE_BOTH_0 | (3 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
 76    FF_MODULE_KEY_TYPE_BOTH_4 = FF_MODULE_KEY_TYPE_BOTH_0 | (4 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
 77} FFModuleKeyType;
 78
 79typedef struct FFModuleArgs {
 80    FFstrbuf key;
 81    FFstrbuf keyColor;
 82    FFstrbuf keyIcon;
 83    FFstrbuf outputFormat;
 84    FFstrbuf outputColor;
 85    uint32_t keyWidth;
 86} FFModuleArgs;
 87
 88typedef struct FFKeyValuePair {
 89    const char* key;
 90    int value;
 91} FFKeyValuePair;
 92
 93// `moduleName` and `argumentKey` are both dereferenced unconditionally; reads no global state, so `pure`
 94[[gnu::nonnull(1, 2), gnu::pure, nodiscard]] const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName);
 95// `value` is optional (null exits with a usage error), `argumentKey` and `buffer` are not
 96[[gnu::nonnull(1, 3)]] void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer);
 97[[gnu::nonnull(1), nodiscard]] uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value);
 98[[gnu::nonnull(1), nodiscard]] int32_t ffOptionParseInt32(const char* argumentKey, const char* value);
 99// `requestedKey` is optional (null exits with a usage error); `pairs` is walked until its null key
100[[gnu::nonnull(1, 3), nodiscard]] int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]);
101// `str` is optional: a null or empty value is reported as `true`
102[[gnu::pure, nodiscard]] bool ffOptionParseBoolean(const char* str);
103// `value` is optional (a null or empty value is a no-op); `buffer` is not
104[[gnu::nonnull(2)]] void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer);
105[[gnu::nonnull(2)]] static inline void ffOptionParseColor(const char* value, FFstrbuf* buffer) {
106    ffStrbufClear(buffer);
107    ffOptionParseColorNoClear(value, buffer);
108}
109
110// `icon` is optional, `args` is not
111[[gnu::nonnull(1)]] static inline void ffOptionInitModuleArg(FFModuleArgs* args, const char* icon) {
112    ffStrbufInit(&args->key);
113    ffStrbufInit(&args->keyColor);
114    ffStrbufInitStatic(&args->keyIcon, icon);
115    ffStrbufInit(&args->outputFormat);
116    ffStrbufInit(&args->outputColor);
117    args->keyWidth = 0;
118}
119
120[[gnu::nonnull(1)]] static inline void ffOptionDestroyModuleArg(FFModuleArgs* args) {
121    ffStrbufDestroy(&args->key);
122    ffStrbufDestroy(&args->keyColor);
123    ffStrbufDestroy(&args->keyIcon);
124    ffStrbufDestroy(&args->outputFormat);
125    ffStrbufDestroy(&args->outputColor);
126}
127
128enum { FF_OPTION_MAX_SIZE = 1 << 8 }; // Maximum size of a single option value, used for static allocation
129
130#define FF_MODULE_GET_DISPLAY_NAME(moduleName) (*(const char**) ((uint8_t*) &ff ## moduleName ## ModuleInfo.displayName + instance.config.display.keyLanguage))