master ohmu/fastfetch-openbsd / src / modules / swap / swap.c
ohmu  ·  2026-10-15
  1#include "common/printing.h"
  2#include "common/jsonconfig.h"
  3#include "common/percent.h"
  4#include "common/size.h"
  5#include "common/strutil.h"
  6#include "detection/swap/swap.h"
  7#include "modules/swap/swap.h"
  8
  9void printSwap(FFSwapOptions* options, uint8_t index, uint32_t totalCount, FFSwapResult* storage) {
 10    FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
 11
 12    if (options->moduleArgs.key.length == 0) {
 13        if (storage->name.length > 0) {
 14            ffStrbufSetF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Swap), storage->name.chars);
 15        } else {
 16            ffStrbufSetS(&key, FF_MODULE_GET_DISPLAY_NAME(Swap));
 17        }
 18    } else {
 19        ffStrbufClear(&key);
 20        FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]) {
 21                                                                           FF_ARG(index, "index"),
 22                                                                           FF_ARG(storage->name, "name"),
 23                                                                           FF_ARG(options->moduleArgs.keyIcon, "icon"),
 24                                                                           FF_ARG(FF_MODULE_GET_DISPLAY_NAME(Swap), "module-name"),
 25                                                                       }));
 26    }
 27
 28    FF_STRBUF_AUTO_DESTROY usedPretty = ffStrbufCreate();
 29    ffSizeAppendNum(storage->bytesUsed, &usedPretty);
 30
 31    FF_STRBUF_AUTO_DESTROY totalPretty = ffStrbufCreate();
 32    ffSizeAppendNum(storage->bytesTotal, &totalPretty);
 33
 34    double percentage = storage->bytesTotal == 0
 35        ? 0
 36        : (double) storage->bytesUsed / (double) storage->bytesTotal * 100.0;
 37
 38    FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
 39    if (options->moduleArgs.outputFormat.length == 0) {
 40        ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY);
 41        FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate();
 42
 43        if (storage->bytesTotal == 0) {
 44            if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 45                ffPercentAppendBar(&str, 0, options->percent, &options->moduleArgs);
 46                ffStrbufAppendC(&str, ' ');
 47            }
 48            if (!(percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) {
 49                ffStrbufAppendS(&str, totalCount ? "Unused" : "Disabled");
 50            } else {
 51                ffPercentAppendNum(&str, 0, options->percent, str.length > 0, &options->moduleArgs);
 52            }
 53        } else {
 54            if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 55                ffPercentAppendBar(&str, percentage, options->percent, &options->moduleArgs);
 56                ffStrbufAppendC(&str, ' ');
 57            }
 58
 59            if (!(percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) {
 60                ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars);
 61            }
 62
 63            if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
 64                ffPercentAppendNum(&str, percentage, options->percent, str.length > 0, &options->moduleArgs);
 65            }
 66        }
 67
 68        ffStrbufTrimRight(&str, ' ');
 69        ffStrbufPutTo(&str, stdout);
 70    } else {
 71        FF_STRBUF_AUTO_DESTROY percentageNum = ffStrbufCreate();
 72        if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
 73            ffPercentAppendNum(&percentageNum, percentage, options->percent, false, &options->moduleArgs);
 74        }
 75        FF_STRBUF_AUTO_DESTROY percentageBar = ffStrbufCreate();
 76        if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 77            ffPercentAppendBar(&percentageBar, percentage, options->percent, &options->moduleArgs);
 78        }
 79        FF_PRINT_FORMAT_CHECKED(key.chars, index, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) {
 80                                                                                                         FF_ARG(usedPretty, "used"),
 81                                                                                                         FF_ARG(totalPretty, "total"),
 82                                                                                                         FF_ARG(percentageNum, "percentage"),
 83                                                                                                         FF_ARG(percentageBar, "percentage-bar"),
 84                                                                                                         FF_ARG(storage->name, "name"),
 85                                                                                                     }));
 86    }
 87}
 88
 89bool ffPrintSwap(FFSwapOptions* options) {
 90    FF_LIST_AUTO_DESTROY result = ffListCreate();
 91    const char* error = ffDetectSwap(&result);
 92
 93    if (error) {
 94        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Swap), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
 95        return false;
 96    }
 97
 98    if (options->separate && result.length > 0) {
 99        uint8_t index = 0;
100        FF_LIST_FOR_EACH (FFSwapResult, storage, result) {
101            ++index;
102            printSwap(options, index, result.length, storage);
103        }
104    } else {
105        FFSwapResult total = {
106            .name = ffStrbufCreate(),
107        };
108        FF_LIST_FOR_EACH (FFSwapResult, storage, result) {
109            total.bytesUsed += storage->bytesUsed;
110            total.bytesTotal += storage->bytesTotal;
111        }
112        printSwap(options, 0, result.length, &total);
113        ffStrbufDestroy(&total.name);
114    }
115
116    FF_LIST_FOR_EACH (FFSwapResult, storage, result) {
117        ffStrbufDestroy(&storage->name);
118    }
119
120    return true;
121}
122
123void ffParseSwapJsonObject(FFSwapOptions* options, yyjson_val* module) {
124    yyjson_val *key, *val;
125    size_t idx, max;
126    yyjson_obj_foreach (module, idx, max, key, val) {
127        if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
128            continue;
129        }
130
131        if (ffPercentParseJsonObject(key, val, &options->percent)) {
132            continue;
133        }
134
135        if (unsafe_yyjson_equals_str(key, "separate")) {
136            options->separate = yyjson_get_bool(val);
137            continue;
138        }
139
140        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Swap), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
141    }
142}
143
144[[gnu::cold]]
145void ffGenerateSwapJsonConfig(FFSwapOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
146    ffPercentGenerateJsonConfig(doc, module, options->percent);
147
148    ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
149    yyjson_mut_obj_add_bool(doc, module, "separate", options->separate);
150}
151
152bool ffGenerateSwapJsonResult([[maybe_unused]] FFSwapOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
153    FF_LIST_AUTO_DESTROY result = ffListCreate();
154    const char* error = ffDetectSwap(&result);
155
156    if (error) {
157        yyjson_mut_obj_add_str(doc, module, "error", error);
158        return false;
159    }
160
161    yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
162    FF_LIST_FOR_EACH (FFSwapResult, storage, result) {
163        yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
164        yyjson_mut_obj_add_strbuf(doc, obj, "name", &storage->name);
165        yyjson_mut_obj_add_uint(doc, obj, "used", storage->bytesUsed);
166        yyjson_mut_obj_add_uint(doc, obj, "total", storage->bytesTotal);
167    }
168
169    FF_LIST_FOR_EACH (FFSwapResult, storage, result) {
170        ffStrbufDestroy(&storage->name);
171    }
172
173    return true;
174}
175
176void ffInitSwapOptions(FFSwapOptions* options) {
177    ffOptionInitModuleArg(&options->moduleArgs, "󰓡");
178    options->percent = (FFPercentageModuleConfig) { 50, 80, 0 };
179    options->separate = false;
180}
181
182void ffDestroySwapOptions(FFSwapOptions* options) {
183    ffOptionDestroyModuleArg(&options->moduleArgs);
184}
185
186FFModuleBaseInfo ffSwapModuleInfo = {
187    .name = "Swap",
188    .description = "Print swap (paging file) space usage",
189    .displayName = {
190        .en = "Swap",
191        .ar = "الذاكرة التبادلية",
192        .cs = "Odkládací prostor",
193        .de = "Swap",
194        .es = "Swap",
195        .fi = "Swap",
196        .fr = "Swap",
197        .gl = "Swap",
198        .he = "זיכרון החלפה",
199        .id = "Swap",
200        .it = "Swap",
201        .ja = "スワップ",
202        .ko = "스왑",
203        .pl = "Swap",
204        .pt = "Swap",
205        .ru = "Подкачка",
206        .tr = "Takas",
207        .uk = "Своп",
208        .vi = "Swap",
209        .zh_CN = "交换空间",
210        .zh_TW = "交換空間",
211    },
212    .initOptions = (void*) ffInitSwapOptions,
213    .destroyOptions = (void*) ffDestroySwapOptions,
214    .parseJsonObject = (void*) ffParseSwapJsonObject,
215    .printModule = (void*) ffPrintSwap,
216    .generateJsonResult = (void*) ffGenerateSwapJsonResult,
217    .generateJsonConfig = (void*) ffGenerateSwapJsonConfig,
218    .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
219        { "Used size", "used" },
220        { "Total size", "total" },
221        { "Percentage used (num)", "percentage" },
222        { "Percentage used (bar)", "percentage-bar" },
223        { "Name *", "name" },
224    })),
225    .defaultOrder = 41,
226};