diff --git a/src/detection/packages/packages_linux.c b/src/detection/packages/packages_linux.c
index e2f4a6b232..2b2b902543 100644
--- a/src/detection/packages/packages_linux.c
+++ b/src/detection/packages/packages_linux.c
@@ -1,562 +1,601 @@
-#include "packages.h"
+#include "common/FFstrbuf.h"
#include "common/io.h"
#include "common/parsing.h"
#include "common/properties.h"
#include "common/settings.h"
#include "common/stringUtils.h"
#include "detection/os/os.h"
+#include "packages.h"
-static uint32_t getNumElements(FFstrbuf* baseDir, const char* dirname, bool isdir)
-{
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, dirname);
- uint32_t num_elements = ffPackagesGetNumElements(baseDir->chars, isdir);
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return num_elements;
+static uint32_t getNumElements(FFstrbuf *baseDir, const char *dirname,
+ bool isdir) {
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, dirname);
+ uint32_t num_elements = ffPackagesGetNumElements(baseDir->chars, isdir);
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
+ return num_elements;
}
-static uint32_t getNumStringsImpl(const char* filename, const char* needle)
-{
- FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
- if (!ffReadFileBuffer(filename, &content))
- return 0;
-
- uint32_t count = 0;
- char *iter = content.chars;
- size_t needleLength = strlen(needle);
- while ((iter = memmem(iter, content.length - (size_t)(iter - content.chars), needle, needleLength)) != NULL)
- {
- ++count;
- iter += needleLength;
- }
-
- return count;
+static uint32_t getNumStringsImpl(const char *filename, const char *needle) {
+ FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
+ if (!ffReadFileBuffer(filename, &content))
+ return 0;
+
+ uint32_t count = 0;
+ char *iter = content.chars;
+ size_t needleLength = strlen(needle);
+ while ((iter = memmem(iter, content.length - (size_t)(iter - content.chars),
+ needle, needleLength)) != NULL) {
+ ++count;
+ iter += needleLength;
+ }
+
+ return count;
}
-static uint32_t getNumStrings(FFstrbuf* baseDir, const char* filename, const char* needle, const char* packageId)
-{
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, filename);
+static uint32_t getNumStrings(FFstrbuf *baseDir, const char *filename,
+ const char *needle, const char *packageId) {
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, filename);
- FF_STRBUF_AUTO_DESTROY cacheDir = ffStrbufCreate();
- FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreate();
-
- uint32_t num_elements;
- if (ffPackagesReadCache(&cacheDir, &cacheContent, baseDir->chars, packageId, &num_elements))
- {
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return num_elements;
- }
+ FF_STRBUF_AUTO_DESTROY cacheDir = ffStrbufCreate();
+ FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreate();
- num_elements = getNumStringsImpl(baseDir->chars, needle);
+ uint32_t num_elements;
+ if (ffPackagesReadCache(&cacheDir, &cacheContent, baseDir->chars, packageId,
+ &num_elements)) {
ffStrbufSubstrBefore(baseDir, baseDirLength);
+ return num_elements;
+ }
- ffPackagesWriteCache(&cacheDir, &cacheContent, num_elements);
+ num_elements = getNumStringsImpl(baseDir->chars, needle);
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
- return num_elements;
-}
+ ffPackagesWriteCache(&cacheDir, &cacheContent, num_elements);
-static uint32_t getSQLite3Int(FFstrbuf* baseDir, const char* dbPath, const char* query, const char* packageId)
-{
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, dbPath);
+ return num_elements;
+}
- FF_STRBUF_AUTO_DESTROY cacheDir = ffStrbufCreate();
- FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreate();
+static uint32_t getSQLite3Int(FFstrbuf *baseDir, const char *dbPath,
+ const char *query, const char *packageId) {
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, dbPath);
- uint32_t num_elements;
- if (ffPackagesReadCache(&cacheDir, &cacheContent, baseDir->chars, packageId, &num_elements))
- {
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return num_elements;
- }
+ FF_STRBUF_AUTO_DESTROY cacheDir = ffStrbufCreate();
+ FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreate();
- num_elements = (uint32_t) ffSettingsGetSQLite3Int(baseDir->chars, query);
+ uint32_t num_elements;
+ if (ffPackagesReadCache(&cacheDir, &cacheContent, baseDir->chars, packageId,
+ &num_elements)) {
ffStrbufSubstrBefore(baseDir, baseDirLength);
+ return num_elements;
+ }
- ffPackagesWriteCache(&cacheDir, &cacheContent, num_elements);
+ num_elements = (uint32_t)ffSettingsGetSQLite3Int(baseDir->chars, query);
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
- return num_elements;
+ ffPackagesWriteCache(&cacheDir, &cacheContent, num_elements);
+
+ return num_elements;
}
-static uint32_t countFilesRecursiveImpl(FFstrbuf* baseDirPath, const char* filename)
-{
- uint32_t baseDirPathLength = baseDirPath->length;
+static uint32_t countFilesRecursiveImpl(FFstrbuf *baseDirPath,
+ const char *filename) {
+ uint32_t baseDirPathLength = baseDirPath->length;
- ffStrbufAppendC(baseDirPath, '/');
- ffStrbufAppendS(baseDirPath, filename);
- bool exists = ffPathExists(baseDirPath->chars, FF_PATHTYPE_FILE);
- ffStrbufSubstrBefore(baseDirPath, baseDirPathLength);
- if(exists)
- return 1;
+ ffStrbufAppendC(baseDirPath, '/');
+ ffStrbufAppendS(baseDirPath, filename);
+ bool exists = ffPathExists(baseDirPath->chars, FF_PATHTYPE_FILE);
+ ffStrbufSubstrBefore(baseDirPath, baseDirPathLength);
+ if (exists)
+ return 1;
- DIR* dirp = opendir(baseDirPath->chars);
- if(dirp == NULL)
- return 0;
+ DIR *dirp = opendir(baseDirPath->chars);
+ if (dirp == NULL)
+ return 0;
- ffStrbufAppendC(baseDirPath, '/');
- baseDirPathLength = baseDirPath->length;
+ ffStrbufAppendC(baseDirPath, '/');
+ baseDirPathLength = baseDirPath->length;
- uint32_t sum = 0;
+ uint32_t sum = 0;
- struct dirent *entry;
- while((entry = readdir(dirp)) != NULL) {
- // According to the PMS, neither category nor package name can begin with '.', so no need to check for . or .. specifically
- if(entry->d_type != DT_DIR || entry->d_name[0] == '.')
- continue;
+ struct dirent *entry;
+ while ((entry = readdir(dirp)) != NULL) {
+ // According to the PMS, neither category nor package name can begin with
+ // '.', so no need to check for . or .. specifically
+ if (entry->d_type != DT_DIR || entry->d_name[0] == '.')
+ continue;
- ffStrbufAppendS(baseDirPath, entry->d_name);
- sum += countFilesRecursiveImpl(baseDirPath, filename);
- ffStrbufSubstrBefore(baseDirPath, baseDirPathLength);
- }
+ ffStrbufAppendS(baseDirPath, entry->d_name);
+ sum += countFilesRecursiveImpl(baseDirPath, filename);
+ ffStrbufSubstrBefore(baseDirPath, baseDirPathLength);
+ }
- closedir(dirp);
- return sum;
+ closedir(dirp);
+ return sum;
}
-static uint32_t countFilesRecursive(FFstrbuf* baseDir, const char* dirname, const char* filename)
-{
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, dirname);
- uint32_t sum = countFilesRecursiveImpl(baseDir, filename);
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return sum;
+static uint32_t countFilesRecursive(FFstrbuf *baseDir, const char *dirname,
+ const char *filename) {
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, dirname);
+ uint32_t sum = countFilesRecursiveImpl(baseDir, filename);
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
+ return sum;
}
-static uint32_t getXBPSImpl(FFstrbuf* baseDir)
-{
- DIR* dir = opendir(baseDir->chars);
- if(dir == NULL)
- return 0;
+static uint32_t getXBPSImpl(FFstrbuf *baseDir) {
+ DIR *dir = opendir(baseDir->chars);
+ if (dir == NULL)
+ return 0;
- uint32_t result = 0;
+ uint32_t result = 0;
- struct dirent *entry;
- while((entry = readdir(dir)) != NULL)
- {
- if(entry->d_type != DT_REG || !ffStrStartsWithIgnCase(entry->d_name, "pkgdb-"))
- continue;
+ struct dirent *entry;
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_type != DT_REG ||
+ !ffStrStartsWithIgnCase(entry->d_name, "pkgdb-"))
+ continue;
- ffStrbufAppendC(baseDir, '/');
- ffStrbufAppendS(baseDir, entry->d_name);
- result = getNumStringsImpl(baseDir->chars, "installed");
- break;
- }
+ ffStrbufAppendC(baseDir, '/');
+ ffStrbufAppendS(baseDir, entry->d_name);
+ result = getNumStringsImpl(baseDir->chars, "installed");
+ break;
+ }
- closedir(dir);
- return result;
+ closedir(dir);
+ return result;
}
-static uint32_t getXBPS(FFstrbuf* baseDir, const char* dirname)
-{
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, dirname);
- uint32_t result = getXBPSImpl(baseDir);
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return result;
+static uint32_t getXBPS(FFstrbuf *baseDir, const char *dirname) {
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, dirname);
+ uint32_t result = getXBPSImpl(baseDir);
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
+ return result;
}
-static uint32_t getSnap(FFstrbuf* baseDir)
-{
- uint32_t result = getNumElements(baseDir, "/snap", true);
+static uint32_t getSnap(FFstrbuf *baseDir) {
+ uint32_t result = getNumElements(baseDir, "/snap", true);
- if (result == 0)
- result = getNumElements(baseDir, "/var/lib/snapd/snap", true);
+ if (result == 0)
+ result = getNumElements(baseDir, "/var/lib/snapd/snap", true);
- //Accounting for the /snap/bin folder
- return result > 0 ? result - 1 : 0;
+ // Accounting for the /snap/bin folder
+ return result > 0 ? result - 1 : 0;
}
#ifdef FF_HAVE_RPM
#include "common/library.h"
-#include
-#include
#include
+#include
#include
+#include
-static uint32_t getRpmFromLibrpm(void)
-{
- FF_LIBRARY_LOAD(rpm, 0, "librpm" FF_LIBRARY_EXTENSION, 12)
- FF_LIBRARY_LOAD_SYMBOL(rpm, rpmReadConfigFiles, 0)
- FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsCreate, 0)
- FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsInitIterator, 0)
- FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbGetIteratorCount, 0)
- FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbFreeIterator, 0)
- FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsFree, 0)
- FF_LIBRARY_LOAD_SYMBOL(rpm, rpmlogSetMask, 0)
-
- // Don't print any error messages
- ffrpmlogSetMask(RPMLOG_MASK(RPMLOG_EMERG));
-
- if(ffrpmReadConfigFiles(NULL, NULL) != 0)
- return 0;
-
- rpmts ts = ffrpmtsCreate();
- if(ts == NULL)
- return 0;
-
- rpmdbMatchIterator mi = ffrpmtsInitIterator(ts, RPMDBI_LABEL, NULL, 0);
- if(mi == NULL)
- {
- ffrpmtsFree(ts);
- return 0;
- }
+static uint32_t getRpmFromLibrpm(void) {
+ FF_LIBRARY_LOAD(rpm, 0, "librpm" FF_LIBRARY_EXTENSION, 12)
+ FF_LIBRARY_LOAD_SYMBOL(rpm, rpmReadConfigFiles, 0)
+ FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsCreate, 0)
+ FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsInitIterator, 0)
+ FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbGetIteratorCount, 0)
+ FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbFreeIterator, 0)
+ FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsFree, 0)
+ FF_LIBRARY_LOAD_SYMBOL(rpm, rpmlogSetMask, 0)
+
+ // Don't print any error messages
+ ffrpmlogSetMask(RPMLOG_MASK(RPMLOG_EMERG));
+
+ if (ffrpmReadConfigFiles(NULL, NULL) != 0)
+ return 0;
- int count = ffrpmdbGetIteratorCount(mi);
+ rpmts ts = ffrpmtsCreate();
+ if (ts == NULL)
+ return 0;
- ffrpmdbFreeIterator(mi);
+ rpmdbMatchIterator mi = ffrpmtsInitIterator(ts, RPMDBI_LABEL, NULL, 0);
+ if (mi == NULL) {
ffrpmtsFree(ts);
+ return 0;
+ }
- return count > 0 ? (uint32_t) count : 0;
+ int count = ffrpmdbGetIteratorCount(mi);
+
+ ffrpmdbFreeIterator(mi);
+ ffrpmtsFree(ts);
+
+ return count > 0 ? (uint32_t)count : 0;
}
-#endif //FF_HAVE_RPM
-
-static uint32_t getAMPackages(FFstrbuf* baseDir)
-{
- uint32_t baseLength = baseDir->length;
- FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
- if (!dirp) return 0;
-
- uint32_t result = 0;
- struct dirent *entry;
- while ((entry = readdir(dirp)) != NULL)
- {
- if (entry->d_name[0] == '.') continue;
- if (entry->d_type == DT_DIR)
- {
- ffStrbufAppendF(baseDir, "/%s/remove", entry->d_name);
- if (ffPathExists(baseDir->chars, FF_PATHTYPE_FILE))
- ++result;
- ffStrbufSubstrBefore(baseDir, baseLength);
- }
+#endif // FF_HAVE_RPM
+
+static uint32_t getAMPackages(FFstrbuf *baseDir) {
+ uint32_t baseLength = baseDir->length;
+ FF_AUTO_CLOSE_DIR DIR *dirp = opendir(baseDir->chars);
+ if (!dirp)
+ return 0;
+
+ uint32_t result = 0;
+ struct dirent *entry;
+ while ((entry = readdir(dirp)) != NULL) {
+ if (entry->d_name[0] == '.')
+ continue;
+ if (entry->d_type == DT_DIR) {
+ ffStrbufAppendF(baseDir, "/%s/remove", entry->d_name);
+ if (ffPathExists(baseDir->chars, FF_PATHTYPE_FILE))
+ ++result;
+ ffStrbufSubstrBefore(baseDir, baseLength);
}
- return result;
+ }
+ return result;
}
-static uint32_t getAMSystem(FFstrbuf* baseDir)
-{
- // #771
- uint32_t baseDirLength = baseDir->length;
+static uint32_t getAMSystem(FFstrbuf *baseDir) {
+ // #771
+ uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, "/opt");
- uint32_t optDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, "/opt");
+ uint32_t optDirLength = baseDir->length;
- uint32_t result = 0;
+ uint32_t result = 0;
- ffStrbufAppendS(baseDir, "/am/APP-MANAGER");
- if (ffPathExists(baseDir->chars, FF_PATHTYPE_FILE))
- {
- ++result; // `am` itself is counted as a package too
- ffStrbufSubstrBefore(baseDir, optDirLength);
- result = getAMPackages(baseDir);
- }
+ ffStrbufAppendS(baseDir, "/am/APP-MANAGER");
+ if (ffPathExists(baseDir->chars, FF_PATHTYPE_FILE)) {
+ ++result; // `am` itself is counted as a package too
+ ffStrbufSubstrBefore(baseDir, optDirLength);
+ result = getAMPackages(baseDir);
+ }
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return result;
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
+ return result;
}
-static uint32_t getAMUser(void)
-{
- if (instance.state.platform.configDirs.length == 0) return 0;
-
- // check if $XDG_CONFIG_HOME/appman/appman-config exists
- FFstrbuf* baseDir = FF_LIST_FIRST(FFstrbuf, instance.state.platform.configDirs);
- uint32_t baseLen = baseDir->length;
- ffStrbufAppendS(baseDir, "appman/appman-config");
- FF_STRBUF_AUTO_DESTROY packagesPath = ffStrbufCreate();
- if (ffReadFileBuffer(baseDir->chars, &packagesPath))
- ffStrbufTrimRightSpace(&packagesPath);
- ffStrbufSubstrBefore(baseDir, baseLen);
-
- return packagesPath.length > 0 ? getAMPackages(&packagesPath) : 0;
+static uint32_t getAMUser(void) {
+ if (instance.state.platform.configDirs.length == 0)
+ return 0;
+
+ // check if $XDG_CONFIG_HOME/appman/appman-config exists
+ FFstrbuf *baseDir =
+ FF_LIST_FIRST(FFstrbuf, instance.state.platform.configDirs);
+ uint32_t baseLen = baseDir->length;
+ ffStrbufAppendS(baseDir, "appman/appman-config");
+ FF_STRBUF_AUTO_DESTROY packagesPath = ffStrbufCreate();
+ if (ffReadFileBuffer(baseDir->chars, &packagesPath))
+ ffStrbufTrimRightSpace(&packagesPath);
+ ffStrbufSubstrBefore(baseDir, baseLen);
+
+ return packagesPath.length > 0 ? getAMPackages(&packagesPath) : 0;
}
-static int compareHash(const void* a, const void* b)
-{
- return memcmp(a, b, 32);
+static int compareHash(const void *a, const void *b) {
+ return memcmp(a, b, 32);
}
-static uint32_t getGuixPackagesImpl(char* filename)
-{
- FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
- if (!ffAppendFileBuffer(filename, &content))
- return 0;
-
- // Count number of unique /gnu/store/ paths in PROFILE/manifest based on their hash value.
- // Contains packages explicitly installed and their propagated inputs.
- char* pend = content.chars;
-
- for (const char* pattern = content.chars; (pattern = strstr(pattern, "/gnu/store/")); pattern += 32)
- {
- pattern += strlen("/gnu/store/");
- memmove(pend, pattern, 32);
- pend += 32;
- }
+static uint32_t getGuixPackagesImpl(char *filename) {
+ FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
+ if (!ffAppendFileBuffer(filename, &content))
+ return 0;
+
+ // Count number of unique /gnu/store/ paths in PROFILE/manifest based on their
+ // hash value. Contains packages explicitly installed and their propagated
+ // inputs.
+ char *pend = content.chars;
+
+ for (const char *pattern = content.chars;
+ (pattern = strstr(pattern, "/gnu/store/")); pattern += 32) {
+ pattern += strlen("/gnu/store/");
+ memmove(pend, pattern, 32);
+ pend += 32;
+ }
- if (pend == content.chars)
- return 0;
+ if (pend == content.chars)
+ return 0;
- qsort(content.chars, (size_t) (pend - content.chars) / 32, 32, compareHash);
+ qsort(content.chars, (size_t)(pend - content.chars) / 32, 32, compareHash);
- uint32_t count = 1;
- for (const char* p = content.chars + 32; p < pend; p += 32)
- count += compareHash(p - 32, p) != 0;
+ uint32_t count = 1;
+ for (const char *p = content.chars + 32; p < pend; p += 32)
+ count += compareHash(p - 32, p) != 0;
- return count;
+ return count;
}
-static uint32_t getGuixPackages(FFstrbuf* baseDir, const char* dirname)
-{
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, dirname);
- ffStrbufAppendS(baseDir, "/manifest");
- uint32_t num_elements = getGuixPackagesImpl(baseDir->chars);
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return num_elements;
+static uint32_t getGuixPackages(FFstrbuf *baseDir, const char *dirname) {
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, dirname);
+ ffStrbufAppendS(baseDir, "/manifest");
+ uint32_t num_elements = getGuixPackagesImpl(baseDir->chars);
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
+ return num_elements;
}
-static inline uint32_t getFlatpakRuntimePackagesArch(FFstrbuf* baseDir)
-{
- FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
- if (dirp == NULL)
- return 0;
-
- uint32_t num_elements = 0;
-
- struct dirent *entry;
- while ((entry = readdir(dirp)) != NULL)
- {
- if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
- {
- num_elements += getNumElements(baseDir, entry->d_name, true);
- }
+static inline uint32_t getFlatpakRuntimePackagesArch(FFstrbuf *baseDir) {
+ FF_AUTO_CLOSE_DIR DIR *dirp = opendir(baseDir->chars);
+ if (dirp == NULL)
+ return 0;
+
+ uint32_t num_elements = 0;
+
+ struct dirent *entry;
+ while ((entry = readdir(dirp)) != NULL) {
+ if (entry->d_type == DT_DIR && entry->d_name[0] != '.') {
+ num_elements += getNumElements(baseDir, entry->d_name, true);
}
+ }
- return num_elements;
+ return num_elements;
}
-static inline uint32_t getFlatpakRuntimePackages(FFstrbuf* baseDir)
-{
- ffStrbufAppendS(baseDir, "runtime/");
- FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
- if (dirp == NULL)
- return 0;
-
- uint32_t runtimeDirLength = baseDir->length;
- uint32_t num_elements = 0;
-
- struct dirent *entry;
- while ((entry = readdir(dirp)) != NULL)
- {
- if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
- {
- // `flatpak list` ignores `.Locale` and `.Debug` packages, and maybe others
- const char* dot = strrchr(entry->d_name, '.');
- if (__builtin_expect(!dot, false)) continue;
- dot++;
-
- if (ffStrEquals(dot, "Locale") || ffStrEquals(dot, "Debug"))
- continue;
-
- ffStrbufAppendS(baseDir, entry->d_name);
- ffStrbufAppendC(baseDir, '/');
- num_elements += getFlatpakRuntimePackagesArch(baseDir);
- ffStrbufSubstrBefore(baseDir, runtimeDirLength);
- }
+static inline uint32_t getFlatpakRuntimePackages(FFstrbuf *baseDir) {
+ ffStrbufAppendS(baseDir, "runtime/");
+ FF_AUTO_CLOSE_DIR DIR *dirp = opendir(baseDir->chars);
+ if (dirp == NULL)
+ return 0;
+
+ uint32_t runtimeDirLength = baseDir->length;
+ uint32_t num_elements = 0;
+
+ struct dirent *entry;
+ while ((entry = readdir(dirp)) != NULL) {
+ if (entry->d_type == DT_DIR && entry->d_name[0] != '.') {
+ // `flatpak list` ignores `.Locale` and `.Debug` packages, and maybe
+ // others
+ const char *dot = strrchr(entry->d_name, '.');
+ if (__builtin_expect(!dot, false))
+ continue;
+ dot++;
+
+ if (ffStrEquals(dot, "Locale") || ffStrEquals(dot, "Debug"))
+ continue;
+
+ ffStrbufAppendS(baseDir, entry->d_name);
+ ffStrbufAppendC(baseDir, '/');
+ num_elements += getFlatpakRuntimePackagesArch(baseDir);
+ ffStrbufSubstrBefore(baseDir, runtimeDirLength);
}
+ }
- return num_elements;
+ return num_elements;
}
-static inline uint32_t getFlatpakAppPackages(FFstrbuf* baseDir)
-{
- ffStrbufAppendS(baseDir, "app/");
- FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
- if (dirp == NULL)
- return 0;
-
- uint32_t appDirLength = baseDir->length;
- uint32_t num_elements = 0;
-
- struct dirent *entry;
- while ((entry = readdir(dirp)) != NULL)
- {
- if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
- {
- ffStrbufAppendS(baseDir, entry->d_name);
- ffStrbufAppendS(baseDir, "/current");
- if (ffPathExists(baseDir->chars, FF_PATHTYPE_ANY)) // Exclude deleted apps, #1856
- ++num_elements;
- ffStrbufSubstrBefore(baseDir, appDirLength);
- }
+static inline uint32_t getFlatpakAppPackages(FFstrbuf *baseDir) {
+ ffStrbufAppendS(baseDir, "app/");
+ FF_AUTO_CLOSE_DIR DIR *dirp = opendir(baseDir->chars);
+ if (dirp == NULL)
+ return 0;
+
+ uint32_t appDirLength = baseDir->length;
+ uint32_t num_elements = 0;
+
+ struct dirent *entry;
+ while ((entry = readdir(dirp)) != NULL) {
+ if (entry->d_type == DT_DIR && entry->d_name[0] != '.') {
+ ffStrbufAppendS(baseDir, entry->d_name);
+ ffStrbufAppendS(baseDir, "/current");
+ if (ffPathExists(baseDir->chars,
+ FF_PATHTYPE_ANY)) // Exclude deleted apps, #1856
+ ++num_elements;
+ ffStrbufSubstrBefore(baseDir, appDirLength);
}
- return num_elements;
+ }
+ return num_elements;
}
-static uint32_t getFlatpakPackages(FFstrbuf* baseDir, const char* dirname)
-{
- uint32_t num_elements = 0;
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, dirname);
- ffStrbufAppendS(baseDir, "/flatpak/");
- uint32_t flatpakDirLength = baseDir->length;
+static uint32_t getFlatpakPackages(FFstrbuf *baseDir, const char *dirname) {
+ uint32_t num_elements = 0;
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, dirname);
+ ffStrbufAppendS(baseDir, "/flatpak/");
+ uint32_t flatpakDirLength = baseDir->length;
- num_elements += getFlatpakAppPackages(baseDir);
- ffStrbufSubstrBefore(baseDir, flatpakDirLength);
+ num_elements += getFlatpakAppPackages(baseDir);
+ ffStrbufSubstrBefore(baseDir, flatpakDirLength);
- num_elements += getFlatpakRuntimePackages(baseDir);
+ num_elements += getFlatpakRuntimePackages(baseDir);
- ffStrbufSubstrBefore(baseDir, baseDirLength);
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
- return num_elements;
+ return num_elements;
}
-static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options)
-{
- if (!(options->disabled & FF_PACKAGES_FLAG_APK_BIT)) packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q", "apk");
- if (!(options->disabled & FF_PACKAGES_FLAG_DPKG_BIT)) packageCounts->dpkg += getNumStrings(baseDir, "/var/lib/dpkg/status", "Status: install ok installed", "dpkg");
- if (!(options->disabled & FF_PACKAGES_FLAG_LPKG_BIT)) packageCounts->lpkg += getNumStrings(baseDir, "/opt/Loc-OS-LPKG/installed-lpkg/Listinstalled-lpkg.list", "\n", "lpkg");
- if (!(options->disabled & FF_PACKAGES_FLAG_EMERGE_BIT)) packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE");
- if (!(options->disabled & FF_PACKAGES_FLAG_EOPKG_BIT)) packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", true);
- if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT)) packageCounts->flatpakSystem += getFlatpakPackages(baseDir, "/var/lib");
- if (!(options->disabled & FF_PACKAGES_FLAG_KISS_BIT)) packageCounts->kiss += getNumElements(baseDir, "/var/db/kiss/installed", true);
- if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
- {
- packageCounts->nixDefault += ffPackagesGetNix(baseDir, "/nix/var/nix/profiles/default");
- packageCounts->nixSystem += ffPackagesGetNix(baseDir, "/run/current-system");
- }
- if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true);
- if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
- if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
- if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT))
- {
- // `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package
- packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm");
- }
- if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
- if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
- if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
- {
- packageCounts->brewCask += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", true);
- packageCounts->brew += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", true);
- }
- if (!(options->disabled & FF_PACKAGES_FLAG_PALUDIS_BIT)) packageCounts->paludis += countFilesRecursive(baseDir, "/var/db/paludis/repositories", "environment.bz2");
- if (!(options->disabled & FF_PACKAGES_FLAG_OPKG_BIT)) packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status", "Package:", "opkg"); // openwrt
- if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT)) packageCounts->amSystem = getAMSystem(baseDir);
- if (!(options->disabled & FF_PACKAGES_FLAG_SORCERY_BIT)) packageCounts->sorcery += getNumStrings(baseDir, "/var/state/sorcery/packages", ":installed:", "sorcery");
- if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT))
- {
- packageCounts->guixSystem += getGuixPackages(baseDir, "/run/current-system/profile");
- }
- if (!(options->disabled & FF_PACKAGES_FLAG_LINGLONG_BIT)) packageCounts->linglong += getNumElements(baseDir, "/var/lib/linglong/layers", true);
- if (!(options->disabled & FF_PACKAGES_FLAG_PACSTALL_BIT)) packageCounts->pacstall += getNumElements(baseDir, "/var/lib/pacstall/metadata", false);
- if (!(options->disabled & FF_PACKAGES_FLAG_PISI_BIT)) packageCounts->pisi += getNumElements(baseDir, "/var/lib/pisi/package", true);
- if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT)) packageCounts->pkgsrc += getNumElements(baseDir, "/usr/pkg/pkgdb", DT_DIR);
+static uint32_t getPacmanPackages(FFstrbuf *baseDir) {
+ FF_STRBUF_AUTO_DESTROY pacmanDir = ffStrbufCreate();
+
+ uint32_t baseDirLen = baseDir->length;
+ ffStrbufAppendS(&pacmanDir, "/etc/pacman.conf");
+ if (!ffParsePropFile(baseDir->chars, "DBPath =", &pacmanDir))
+ ffStrbufSetS(&pacmanDir, "/var/lib/pacman");
+ ffStrbufSubstrBefore(&pacmanDir, baseDirLen);
+ ffStrbufTrimRight(&pacmanDir, '/');
+ ffStrbufAppendS(&pacmanDir, "/local");
+ return getNumElements(baseDir, pacmanDir.chars, true);
}
-static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options)
-{
- getPackageCounts(baseDir, packageCounts, options);
-
- if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT))
- {
- uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendS(baseDir, FASTFETCH_TARGET_DIR_ETC "/pacman-mirrors.conf");
- if(ffParsePropFile(baseDir->chars, "Branch =", &packageCounts->pacmanBranch) && packageCounts->pacmanBranch.length == 0)
- ffStrbufAppendS(&packageCounts->pacmanBranch, "stable");
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- }
+static void getPackageCounts(FFstrbuf *baseDir, FFPackagesResult *packageCounts,
+ FFPackagesOptions *options) {
+ if (!(options->disabled & FF_PACKAGES_FLAG_APK_BIT))
+ packageCounts->apk +=
+ getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q", "apk");
+ if (!(options->disabled & FF_PACKAGES_FLAG_DPKG_BIT))
+ packageCounts->dpkg +=
+ getNumStrings(baseDir, "/var/lib/dpkg/status",
+ "Status: install ok installed", "dpkg");
+ if (!(options->disabled & FF_PACKAGES_FLAG_LPKG_BIT))
+ packageCounts->lpkg += getNumStrings(
+ baseDir, "/opt/Loc-OS-LPKG/installed-lpkg/Listinstalled-lpkg.list",
+ "\n", "lpkg");
+ if (!(options->disabled & FF_PACKAGES_FLAG_EMERGE_BIT))
+ packageCounts->emerge +=
+ countFilesRecursive(baseDir, "/var/db/pkg", "SIZE");
+ if (!(options->disabled & FF_PACKAGES_FLAG_EOPKG_BIT))
+ packageCounts->eopkg +=
+ getNumElements(baseDir, "/var/lib/eopkg/package", true);
+ if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT))
+ packageCounts->flatpakSystem += getFlatpakPackages(baseDir, "/var/lib");
+ if (!(options->disabled & FF_PACKAGES_FLAG_KISS_BIT))
+ packageCounts->kiss +=
+ getNumElements(baseDir, "/var/db/kiss/installed", true);
+ if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT)) {
+ packageCounts->nixDefault +=
+ ffPackagesGetNix(baseDir, "/nix/var/nix/profiles/default");
+ packageCounts->nixSystem +=
+ ffPackagesGetNix(baseDir, "/run/current-system");
+ }
+ // TODO: change to getPacmanPackages():
+ if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT))
+ packageCounts->pacman += getPacmanPackages(baseDir);
+ if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT))
+ packageCounts->lpkgbuild +=
+ getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
+ if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT))
+ packageCounts->pkgtool +=
+ getNumElements(baseDir, "/var/log/packages", false);
+ if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) {
+ // `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey`
+ // package
+ packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite",
+ "SELECT count(*) FROM Sigmd5", "rpm");
+ }
+ if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT))
+ packageCounts->snap += getSnap(baseDir);
+ if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT))
+ packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
+ if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT)) {
+ packageCounts->brewCask +=
+ getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", true);
+ packageCounts->brew +=
+ getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", true);
+ }
+ if (!(options->disabled & FF_PACKAGES_FLAG_PALUDIS_BIT))
+ packageCounts->paludis += countFilesRecursive(
+ baseDir, "/var/db/paludis/repositories", "environment.bz2");
+ if (!(options->disabled & FF_PACKAGES_FLAG_OPKG_BIT))
+ packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status",
+ "Package:", "opkg"); // openwrt
+ if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT))
+ packageCounts->amSystem = getAMSystem(baseDir);
+ if (!(options->disabled & FF_PACKAGES_FLAG_SORCERY_BIT))
+ packageCounts->sorcery += getNumStrings(
+ baseDir, "/var/state/sorcery/packages", ":installed:", "sorcery");
+ if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT)) {
+ packageCounts->guixSystem +=
+ getGuixPackages(baseDir, "/run/current-system/profile");
+ }
+ if (!(options->disabled & FF_PACKAGES_FLAG_LINGLONG_BIT))
+ packageCounts->linglong +=
+ getNumElements(baseDir, "/var/lib/linglong/layers", true);
+ if (!(options->disabled & FF_PACKAGES_FLAG_PACSTALL_BIT))
+ packageCounts->pacstall +=
+ getNumElements(baseDir, "/var/lib/pacstall/metadata", false);
+ if (!(options->disabled & FF_PACKAGES_FLAG_PISI_BIT))
+ packageCounts->pisi +=
+ getNumElements(baseDir, "/var/lib/pisi/package", true);
+ if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
+ packageCounts->pkgsrc += getNumElements(baseDir, "/usr/pkg/pkgdb", DT_DIR);
}
-static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options)
-{
- uint32_t baseDirLength = baseDir->length;
+static void getPackageCountsRegular(FFstrbuf *baseDir,
+ FFPackagesResult *packageCounts,
+ FFPackagesOptions *options) {
+ getPackageCounts(baseDir, packageCounts, options);
- ffStrbufAppendS(baseDir, "/bedrock/strata");
+ if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) {
+ uint32_t baseDirLength = baseDir->length;
+ ffStrbufAppendS(baseDir, FASTFETCH_TARGET_DIR_ETC "/pacman-mirrors.conf");
+ if (ffParsePropFile(baseDir->chars,
+ "Branch =", &packageCounts->pacmanBranch) &&
+ packageCounts->pacmanBranch.length == 0)
+ ffStrbufAppendS(&packageCounts->pacmanBranch, "stable");
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
+ }
+}
- FF_AUTO_CLOSE_DIR DIR* dir = opendir(baseDir->chars);
- if(dir == NULL)
- {
- ffStrbufSubstrBefore(baseDir, baseDirLength);
- return;
- }
+static void getPackageCountsBedrock(FFstrbuf *baseDir,
+ FFPackagesResult *packageCounts,
+ FFPackagesOptions *options) {
+ uint32_t baseDirLength = baseDir->length;
- ffStrbufAppendC(baseDir, '/');
- uint32_t baseDirLength2 = baseDir->length;
-
- struct dirent* entry;
- while((entry = readdir(dir)) != NULL)
- {
- if(entry->d_type != DT_DIR)
- continue;
- if(entry->d_name[0] == '.')
- continue;
-
- ffStrbufAppendS(baseDir, entry->d_name);
- getPackageCounts(baseDir, packageCounts, options);
- ffStrbufSubstrBefore(baseDir, baseDirLength2);
- }
+ ffStrbufAppendS(baseDir, "/bedrock/strata");
+ FF_AUTO_CLOSE_DIR DIR *dir = opendir(baseDir->chars);
+ if (dir == NULL) {
ffStrbufSubstrBefore(baseDir, baseDirLength);
-}
+ return;
+ }
-void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
-{
- FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(512);
- ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT);
-
- if(ffStrbufIgnCaseEqualS(&ffDetectOS()->id, "bedrock"))
- getPackageCountsBedrock(&baseDir, result, options);
- else
- getPackageCountsRegular(&baseDir, result, options);
-
- // If SQL failed, we can still try with librpm.
- // This is needed on openSUSE, which seems to use a proprietary database file
- // This method doesn't work on bedrock, so we do it here.
- #ifdef FF_HAVE_RPM
- if(!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT) && result->rpm == 0)
- result->rpm = getRpmFromLibrpm();
- #endif
-
- ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
- if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
- {
- // Count packages from $HOME/.nix-profile
- result->nixUser += ffPackagesGetNix(&baseDir, ".nix-profile");
-
- // Check in $XDG_STATE_HOME/nix/profile
- FF_STRBUF_AUTO_DESTROY stateHome = ffStrbufCreate();
- const char* stateHomeEnv = getenv("XDG_STATE_HOME");
- if (ffStrSet(stateHomeEnv))
- {
- ffStrbufSetS(&stateHome, stateHomeEnv);
- ffStrbufEnsureEndsWithC(&stateHome, '/');
- }
- else
- {
- ffStrbufSet(&stateHome, &instance.state.platform.homeDir);
- ffStrbufAppendS(&stateHome, ".local/state/");
- }
- result->nixUser += ffPackagesGetNix(&stateHome, "nix/profile");
-
- // Check in /etc/profiles/per-user/$USER
- FF_STRBUF_AUTO_DESTROY userPkgsDir = ffStrbufCreateStatic("/etc/profiles/per-user/");
- result->nixUser += ffPackagesGetNix(&userPkgsDir, instance.state.platform.userName.chars);
- }
+ ffStrbufAppendC(baseDir, '/');
+ uint32_t baseDirLength2 = baseDir->length;
- if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT))
- {
- result->guixUser += getGuixPackages(&baseDir, ".guix-profile");
- result->guixHome += getGuixPackages(&baseDir, ".guix-home/profile");
- }
+ struct dirent *entry;
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_type != DT_DIR)
+ continue;
+ if (entry->d_name[0] == '.')
+ continue;
- if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT))
- result->flatpakUser = getFlatpakPackages(&baseDir, "/.local/share");
+ ffStrbufAppendS(baseDir, entry->d_name);
+ getPackageCounts(baseDir, packageCounts, options);
+ ffStrbufSubstrBefore(baseDir, baseDirLength2);
+ }
- if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT))
- result->amUser = getAMUser();
+ ffStrbufSubstrBefore(baseDir, baseDirLength);
+}
- if (!(options->disabled & FF_PACKAGES_FLAG_SOAR_BIT))
- result->soar += getSQLite3Int(&baseDir, ".local/share/soar/db/soar.db", "SELECT COUNT(DISTINCT pkg_id || pkg_name) FROM packages WHERE is_installed = true", "soar");
+void ffDetectPackagesImpl(FFPackagesResult *result,
+ FFPackagesOptions *options) {
+ FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(512);
+ ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT);
+
+ if (ffStrbufIgnCaseEqualS(&ffDetectOS()->id, "bedrock"))
+ getPackageCountsBedrock(&baseDir, result, options);
+ else
+ getPackageCountsRegular(&baseDir, result, options);
+
+// If SQL failed, we can still try with librpm.
+// This is needed on openSUSE, which seems to use a proprietary database file
+// This method doesn't work on bedrock, so we do it here.
+#ifdef FF_HAVE_RPM
+ if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT) && result->rpm == 0)
+ result->rpm = getRpmFromLibrpm();
+#endif
+
+ ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
+ if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT)) {
+ // Count packages from $HOME/.nix-profile
+ result->nixUser += ffPackagesGetNix(&baseDir, ".nix-profile");
+
+ // Check in $XDG_STATE_HOME/nix/profile
+ FF_STRBUF_AUTO_DESTROY stateHome = ffStrbufCreate();
+ const char *stateHomeEnv = getenv("XDG_STATE_HOME");
+ if (ffStrSet(stateHomeEnv)) {
+ ffStrbufSetS(&stateHome, stateHomeEnv);
+ ffStrbufEnsureEndsWithC(&stateHome, '/');
+ } else {
+ ffStrbufSet(&stateHome, &instance.state.platform.homeDir);
+ ffStrbufAppendS(&stateHome, ".local/state/");
+ }
+ result->nixUser += ffPackagesGetNix(&stateHome, "nix/profile");
+
+ // Check in /etc/profiles/per-user/$USER
+ FF_STRBUF_AUTO_DESTROY userPkgsDir =
+ ffStrbufCreateStatic("/etc/profiles/per-user/");
+ result->nixUser +=
+ ffPackagesGetNix(&userPkgsDir, instance.state.platform.userName.chars);
+ }
+
+ if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT)) {
+ result->guixUser += getGuixPackages(&baseDir, ".guix-profile");
+ result->guixHome += getGuixPackages(&baseDir, ".guix-home/profile");
+ }
+
+ if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT))
+ result->flatpakUser = getFlatpakPackages(&baseDir, "/.local/share");
+
+ if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT))
+ result->amUser = getAMUser();
+
+ if (!(options->disabled & FF_PACKAGES_FLAG_SOAR_BIT))
+ result->soar += getSQLite3Int(&baseDir, ".local/share/soar/db/soar.db",
+ "SELECT COUNT(DISTINCT pkg_id || pkg_name) "
+ "FROM packages WHERE is_installed = true",
+ "soar");
}
diff --git a/src/fastfetch.c b/src/fastfetch.c
index 60df8051f4..429be32d1c 100644
--- a/src/fastfetch.c
+++ b/src/fastfetch.c
@@ -1,191 +1,188 @@
#include "fastfetch.h"
-#include "common/ffdata.h"
-#include "detection/version/version.h"
-#include "logo/logo.h"
#include "common/commandoption.h"
+#include "common/ffdata.h"
#include "common/init.h"
#include "common/io.h"
#include "common/jsonconfig.h"
-#include "common/time.h"
-#include "common/stringUtils.h"
#include "common/mallocHelper.h"
+#include "common/stringUtils.h"
+#include "common/time.h"
+#include "detection/version/version.h"
#include "fastfetch_datatext.h"
+#include "logo/logo.h"
-#include
#include
+#include
#include
#ifdef _WIN32
- #include "common/windows/getline.h"
+#include "common/windows/getline.h"
#endif
-static void printCommandFormatHelpJson(void)
-{
- yyjson_mut_doc* doc = yyjson_mut_doc_new(NULL);
- yyjson_mut_val* root = yyjson_mut_obj(doc);
- yyjson_mut_doc_set_root(doc, root);
-
- for (uint32_t i = 0; i <= 'Z' - 'A'; ++i)
- {
- for (FFModuleBaseInfo** modules = ffModuleInfos[i]; *modules; ++modules)
- {
- FFModuleBaseInfo* baseInfo = *modules;
- if (!baseInfo->formatArgs.count) continue;
-
- FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
- ffStrbufLowerCase(&type);
- ffStrbufAppendS(&type, "Format");
-
- yyjson_mut_val* obj = yyjson_mut_obj(doc);
- if (yyjson_mut_obj_add(root, yyjson_mut_strbuf(doc, &type), obj))
- {
- FF_STRBUF_AUTO_DESTROY content = ffStrbufCreateF("Output format of the module `%s`. See Wiki for formatting syntax\n", baseInfo->name);
- for (unsigned i = 0; i < baseInfo->formatArgs.count; i++)
- {
- const FFModuleFormatArg* arg = &baseInfo->formatArgs.args[i];
- ffStrbufAppendF(&content, " %u. {%s}: %s\n", i + 1, arg->name, arg->desc);
- }
- ffStrbufTrimRight(&content, '\n');
- yyjson_mut_obj_add_strbuf(doc, obj, "description", &content);
- yyjson_mut_obj_add_str(doc, obj, "type", "string");
- }
+static void printCommandFormatHelpJson(void) {
+ yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
+ yyjson_mut_val *root = yyjson_mut_obj(doc);
+ yyjson_mut_doc_set_root(doc, root);
+
+ for (uint32_t i = 0; i <= 'Z' - 'A'; ++i) {
+ for (FFModuleBaseInfo **modules = ffModuleInfos[i]; *modules; ++modules) {
+ FFModuleBaseInfo *baseInfo = *modules;
+ if (!baseInfo->formatArgs.count)
+ continue;
+
+ FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
+ ffStrbufLowerCase(&type);
+ ffStrbufAppendS(&type, "Format");
+
+ yyjson_mut_val *obj = yyjson_mut_obj(doc);
+ if (yyjson_mut_obj_add(root, yyjson_mut_strbuf(doc, &type), obj)) {
+ FF_STRBUF_AUTO_DESTROY content =
+ ffStrbufCreateF("Output format of the module `%s`. See Wiki for "
+ "formatting syntax\n",
+ baseInfo->name);
+ for (unsigned i = 0; i < baseInfo->formatArgs.count; i++) {
+ const FFModuleFormatArg *arg = &baseInfo->formatArgs.args[i];
+ ffStrbufAppendF(&content, " %u. {%s}: %s\n", i + 1, arg->name,
+ arg->desc);
}
- }
- yyjson_mut_write_fp(stdout, doc, YYJSON_WRITE_PRETTY, NULL, NULL);
- putchar('\n');
- yyjson_mut_doc_free(doc);
+ ffStrbufTrimRight(&content, '\n');
+ yyjson_mut_obj_add_strbuf(doc, obj, "description", &content);
+ yyjson_mut_obj_add_str(doc, obj, "type", "string");
+ }
+ }
+ }
+ yyjson_mut_write_fp(stdout, doc, YYJSON_WRITE_PRETTY, NULL, NULL);
+ putchar('\n');
+ yyjson_mut_doc_free(doc);
}
-static void printCommandFormatHelp(const char* command)
-{
- FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateNS((uint32_t) (strlen(command) - strlen("-format")), command);
- ffStrbufLowerCase(&type);
- for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(command[0]) - 'A']; *modules; ++modules)
- {
- FFModuleBaseInfo* baseInfo = *modules;
- if (ffStrbufIgnCaseEqualS(&type, baseInfo->name))
- {
- if (baseInfo->formatArgs.count > 0)
- {
- FF_STRBUF_AUTO_DESTROY variable = ffStrbufCreate();
- printf("-- In config file: { \"type\": \"%s\", \"format\": \"{}\" }\n", type.chars);
- printf("Sets the format string for %s output.\n", baseInfo->name);
- puts("To see how a format string is constructed, take a look at https://github.com/fastfetch-cli/fastfetch/wiki/Format-String-Guide.");
- puts("The following variables are passed:");
-
- for (unsigned i = 0; i < baseInfo->formatArgs.count; i++)
- {
- const FFModuleFormatArg* arg = &baseInfo->formatArgs.args[i];
- ffStrbufSetF(&variable, "{%s}", arg->name);
- printf("%20s: %s\n", variable.chars, arg->desc);
- }
- }
- else
- fprintf(stderr, "Error: Module '%s' doesn't support output formatting\n", baseInfo->name);
- return;
+static void printCommandFormatHelp(const char *command) {
+ FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateNS(
+ (uint32_t)(strlen(command) - strlen("-format")), command);
+ ffStrbufLowerCase(&type);
+ for (FFModuleBaseInfo **modules = ffModuleInfos[toupper(command[0]) - 'A'];
+ *modules; ++modules) {
+ FFModuleBaseInfo *baseInfo = *modules;
+ if (ffStrbufIgnCaseEqualS(&type, baseInfo->name)) {
+ if (baseInfo->formatArgs.count > 0) {
+ FF_STRBUF_AUTO_DESTROY variable = ffStrbufCreate();
+ printf("-- In config file: { \"type\": \"%s\", \"format\": "
+ "\"{}\" }\n",
+ type.chars);
+ printf("Sets the format string for %s output.\n", baseInfo->name);
+ puts("To see how a format string is constructed, take a look at "
+ "https://github.com/fastfetch-cli/fastfetch/wiki/"
+ "Format-String-Guide.");
+ puts("The following variables are passed:");
+
+ for (unsigned i = 0; i < baseInfo->formatArgs.count; i++) {
+ const FFModuleFormatArg *arg = &baseInfo->formatArgs.args[i];
+ ffStrbufSetF(&variable, "{%s}", arg->name);
+ printf("%20s: %s\n", variable.chars, arg->desc);
}
+ } else
+ fprintf(stderr,
+ "Error: Module '%s' doesn't support output formatting\n",
+ baseInfo->name);
+ return;
}
+ }
- fprintf(stderr, "Error: Module '%s' is not supported\n", type.chars);
+ fprintf(stderr, "Error: Module '%s' is not supported\n", type.chars);
}
-static void printFullHelp()
-{
- fputs("Fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way\n\n", stdout);
+static void printFullHelp() {
+ fputs("Fastfetch is a neofetch-like tool for fetching system information and "
+ "displaying them in a pretty way\n\n",
+ stdout);
+ if (!instance.config.display.pipe)
+ fputs("\e[1;4mUsage:\e[m \e[1mfastfetch\e[m \e[3m\e[m\n\n",
+ stdout);
+ else
+ fputs("Usage: fastfetch \n\n", stdout);
+
+ yyjson_doc *doc =
+ yyjson_read(FASTFETCH_DATATEXT_JSON_HELP,
+ strlen(FASTFETCH_DATATEXT_JSON_HELP), YYJSON_READ_NOFLAG);
+ assert(doc);
+ yyjson_val *groupKey, *flagArr;
+ size_t groupIdx, groupMax;
+ yyjson_obj_foreach(yyjson_doc_get_root(doc), groupIdx, groupMax, groupKey,
+ flagArr) {
if (!instance.config.display.pipe)
- fputs("\e[1;4mUsage:\e[m \e[1mfastfetch\e[m \e[3m\e[m\n\n", stdout);
- else
- fputs("Usage: fastfetch \n\n", stdout);
-
- yyjson_doc* doc = yyjson_read(FASTFETCH_DATATEXT_JSON_HELP, strlen(FASTFETCH_DATATEXT_JSON_HELP), YYJSON_READ_NOFLAG);
- assert(doc);
- yyjson_val *groupKey, *flagArr;
- size_t groupIdx, groupMax;
- yyjson_obj_foreach(yyjson_doc_get_root(doc), groupIdx, groupMax, groupKey, flagArr)
- {
+ fputs("\e[1;4m", stdout);
+ printf("%s options:", yyjson_get_str(groupKey));
+ if (!instance.config.display.pipe)
+ fputs("\e[m", stdout);
+ putchar('\n');
+
+ yyjson_val *flagObj;
+ size_t flagIdx, flagMax;
+ yyjson_arr_foreach(flagArr, flagIdx, flagMax, flagObj) {
+ yyjson_val *shortKey = yyjson_obj_get(flagObj, "short");
+ if (shortKey) {
+ fputs(" ", stdout);
if (!instance.config.display.pipe)
- fputs("\e[1;4m", stdout);
- printf("%s options:", yyjson_get_str(groupKey));
+ fputs("\e[1m", stdout);
+ printf("-%s", yyjson_get_str(shortKey));
if (!instance.config.display.pipe)
- fputs("\e[m", stdout);
- putchar('\n');
-
- yyjson_val* flagObj;
- size_t flagIdx, flagMax;
- yyjson_arr_foreach(flagArr, flagIdx, flagMax, flagObj)
- {
- yyjson_val* shortKey = yyjson_obj_get(flagObj, "short");
- if (shortKey)
- {
- fputs(" ", stdout);
- if (!instance.config.display.pipe)
- fputs("\e[1m", stdout);
- printf("-%s", yyjson_get_str(shortKey));
- if (!instance.config.display.pipe)
- fputs("\e[m", stdout);
- fputs(", ", stdout);
- }
- else
- {
- fputs(" ", stdout);
- }
- yyjson_val* longKey = yyjson_obj_get(flagObj, "long");
- assert(longKey);
- if (!instance.config.display.pipe)
- fputs("\e[1m", stdout);
- printf("--%s", yyjson_get_str(longKey));
- if (!instance.config.display.pipe)
- fputs("\e[m", stdout);
-
- yyjson_val* argObj = yyjson_obj_get(flagObj, "arg");
- if (argObj)
- {
- yyjson_val* typeKey = yyjson_obj_get(argObj, "type");
- assert(typeKey);
- yyjson_val* optionalKey = yyjson_obj_get(argObj, "optional");
- bool optional = optionalKey && yyjson_get_bool(optionalKey);
- putchar(' ');
- if (!instance.config.display.pipe)
- fputs("\e[3m", stdout);
- printf("<%s%s>", optional ? "?" : "", yyjson_get_str(typeKey));
- if (!instance.config.display.pipe)
- fputs("\e[m", stdout);
- }
-
- yyjson_val* descKey = yyjson_obj_get(flagObj, "desc");
- assert(descKey);
- if (yyjson_is_arr(descKey))
- {
- if (instance.config.display.pipe)
- putchar(':');
-
- yyjson_val* descStr;
- size_t descIdx, descMax;
- yyjson_arr_foreach(descKey, descIdx, descMax, descStr)
- {
- if (!instance.config.display.pipe)
- printf("\e[46G%s\n", yyjson_get_str(descStr));
- else
- printf(" %s", yyjson_get_str(descStr));
- }
- if (instance.config.display.pipe)
- putchar('\n');
- }
- else
- {
- if (!instance.config.display.pipe)
- fputs("\e[46G", stdout);
- else
- fputs(": ", stdout);
- puts(yyjson_get_str(descKey));
- }
+ fputs("\e[m", stdout);
+ fputs(", ", stdout);
+ } else {
+ fputs(" ", stdout);
+ }
+ yyjson_val *longKey = yyjson_obj_get(flagObj, "long");
+ assert(longKey);
+ if (!instance.config.display.pipe)
+ fputs("\e[1m", stdout);
+ printf("--%s", yyjson_get_str(longKey));
+ if (!instance.config.display.pipe)
+ fputs("\e[m", stdout);
+
+ yyjson_val *argObj = yyjson_obj_get(flagObj, "arg");
+ if (argObj) {
+ yyjson_val *typeKey = yyjson_obj_get(argObj, "type");
+ assert(typeKey);
+ yyjson_val *optionalKey = yyjson_obj_get(argObj, "optional");
+ bool optional = optionalKey && yyjson_get_bool(optionalKey);
+ putchar(' ');
+ if (!instance.config.display.pipe)
+ fputs("\e[3m", stdout);
+ printf("<%s%s>", optional ? "?" : "", yyjson_get_str(typeKey));
+ if (!instance.config.display.pipe)
+ fputs("\e[m", stdout);
+ }
+
+ yyjson_val *descKey = yyjson_obj_get(flagObj, "desc");
+ assert(descKey);
+ if (yyjson_is_arr(descKey)) {
+ if (instance.config.display.pipe)
+ putchar(':');
+
+ yyjson_val *descStr;
+ size_t descIdx, descMax;
+ yyjson_arr_foreach(descKey, descIdx, descMax, descStr) {
+ if (!instance.config.display.pipe)
+ printf("\e[46G%s\n", yyjson_get_str(descStr));
+ else
+ printf(" %s", yyjson_get_str(descStr));
}
-
- putchar('\n');
+ if (instance.config.display.pipe)
+ putchar('\n');
+ } else {
+ if (!instance.config.display.pipe)
+ fputs("\e[46G", stdout);
+ else
+ fputs(": ", stdout);
+ puts(yyjson_get_str(descKey));
+ }
}
- yyjson_doc_free(doc);
- puts("\n\
+ putchar('\n');
+ }
+ yyjson_doc_free(doc);
+
+ puts("\n\
Command flags are not case sensitive. E.g. `--print-logos` is equal to `--Print-Logos`\n\
If a value starts with a ?, it is optional. An optional boolean value defaults to true if not specified.\n\
More detailed help messages for each options can be printed with `-h `\n\
@@ -193,714 +190,695 @@ For detailed information on logo options, module configuration, and formatting,
https://github.com/fastfetch-cli/fastfetch/wiki/Configuration");
}
-static bool printSpecificCommandHelp(const char* command)
-{
- yyjson_doc* doc = yyjson_read(FASTFETCH_DATATEXT_JSON_HELP, strlen(FASTFETCH_DATATEXT_JSON_HELP), YYJSON_READ_NOFLAG);
- assert(doc);
- yyjson_val *groupKey, *flagArr;
- size_t groupIdx, groupMax;
- yyjson_obj_foreach(yyjson_doc_get_root(doc), groupIdx, groupMax, groupKey, flagArr)
- {
- yyjson_val* flagObj;
- size_t flagIdx, flagMax;
- yyjson_arr_foreach(flagArr, flagIdx, flagMax, flagObj)
- {
- yyjson_val* pseudo = yyjson_obj_get(flagObj, "pseudo");
- if (pseudo && yyjson_get_bool(pseudo))
- continue;
-
- yyjson_val* longKey = yyjson_obj_get(flagObj, "long");
- assert(longKey);
- if (ffStrEqualsIgnCase(command, yyjson_get_str(longKey)))
- {
- puts(yyjson_get_str(yyjson_obj_get(flagObj, "desc")));
-
- printf("%10s: ", "Usage");
- yyjson_val* shortKey = yyjson_obj_get(flagObj, "short");
- if (shortKey)
- {
- if (!instance.config.display.pipe)
- fputs("\e[1m", stdout);
- printf("-%s", yyjson_get_str(shortKey));
- if (!instance.config.display.pipe)
- fputs("\e[m", stdout);
- fputs(", ", stdout);
- }
- if (!instance.config.display.pipe)
- fputs("\e[1m", stdout);
- printf("--%s", yyjson_get_str(longKey));
- if (!instance.config.display.pipe)
- fputs("\e[m", stdout);
-
- yyjson_val* argObj = yyjson_obj_get(flagObj, "arg");
- if (argObj)
- {
- yyjson_val* typeKey = yyjson_obj_get(argObj, "type");
- assert(typeKey);
- yyjson_val* optionalKey = yyjson_obj_get(argObj, "optional");
- bool optional = optionalKey && yyjson_get_bool(optionalKey);
- putchar(' ');
- if (!instance.config.display.pipe)
- fputs("\e[3m", stdout);
- printf("<%s%s>", optional ? "?" : "", yyjson_get_str(typeKey));
- if (!instance.config.display.pipe)
- fputs("\e[m", stdout);
- putchar('\n');
-
- yyjson_val* defaultKey = yyjson_obj_get(argObj, "default");
- if (defaultKey)
- {
- if (ffStrEqualsIgnCase(yyjson_get_str(typeKey), "structure"))
- printf("%10s: %s\n", "Default", FASTFETCH_DATATEXT_STRUCTURE);
- else if (yyjson_is_bool(defaultKey))
- printf("%10s: %s\n", "Default", yyjson_get_bool(defaultKey) ? "true" : "false");
- else if (yyjson_is_num(defaultKey))
- printf("%10s: %d\n", "Default", yyjson_get_int(defaultKey));
- else if (yyjson_is_str(defaultKey))
- printf("%10s: %s\n", "Default", yyjson_get_str(defaultKey));
- else
- printf("%10s: Unknown\n", "Default");
- }
-
- yyjson_val* enumKey = yyjson_obj_get(argObj, "enum");
- if (enumKey)
- {
- printf("%10s:\n", "Options");
- yyjson_val *optKey, *optVal;
- size_t optIdx, optMax;
- yyjson_obj_foreach(enumKey, optIdx, optMax, optKey, optVal)
- printf("%12s: %s\n", yyjson_get_str(optKey), yyjson_get_str(optVal));
- }
- }
- else
- putchar('\n');
-
- yyjson_val* remarkKey = yyjson_obj_get(flagObj, "remark");
- if (remarkKey)
- {
- if (yyjson_is_str(remarkKey))
- printf("%10s: %s\n", "Remark", yyjson_get_str(remarkKey));
- else if (yyjson_is_arr(remarkKey) && yyjson_arr_size(remarkKey) > 0)
- {
- yyjson_val* remarkStr;
- size_t remarkIdx, remarkMax;
- yyjson_arr_foreach(remarkKey, remarkIdx, remarkMax, remarkStr)
- {
- if (remarkIdx == 0)
- printf("%10s: %s\n", "Remark", yyjson_get_str(remarkStr));
- else
- printf(" %s\n", yyjson_get_str(remarkStr));
- }
- }
- }
-
- yyjson_doc_free(doc);
- return true;
+static bool printSpecificCommandHelp(const char *command) {
+ yyjson_doc *doc =
+ yyjson_read(FASTFETCH_DATATEXT_JSON_HELP,
+ strlen(FASTFETCH_DATATEXT_JSON_HELP), YYJSON_READ_NOFLAG);
+ assert(doc);
+ yyjson_val *groupKey, *flagArr;
+ size_t groupIdx, groupMax;
+ yyjson_obj_foreach(yyjson_doc_get_root(doc), groupIdx, groupMax, groupKey,
+ flagArr) {
+ yyjson_val *flagObj;
+ size_t flagIdx, flagMax;
+ yyjson_arr_foreach(flagArr, flagIdx, flagMax, flagObj) {
+ yyjson_val *pseudo = yyjson_obj_get(flagObj, "pseudo");
+ if (pseudo && yyjson_get_bool(pseudo))
+ continue;
+
+ yyjson_val *longKey = yyjson_obj_get(flagObj, "long");
+ assert(longKey);
+ if (ffStrEqualsIgnCase(command, yyjson_get_str(longKey))) {
+ puts(yyjson_get_str(yyjson_obj_get(flagObj, "desc")));
+
+ printf("%10s: ", "Usage");
+ yyjson_val *shortKey = yyjson_obj_get(flagObj, "short");
+ if (shortKey) {
+ if (!instance.config.display.pipe)
+ fputs("\e[1m", stdout);
+ printf("-%s", yyjson_get_str(shortKey));
+ if (!instance.config.display.pipe)
+ fputs("\e[m", stdout);
+ fputs(", ", stdout);
+ }
+ if (!instance.config.display.pipe)
+ fputs("\e[1m", stdout);
+ printf("--%s", yyjson_get_str(longKey));
+ if (!instance.config.display.pipe)
+ fputs("\e[m", stdout);
+
+ yyjson_val *argObj = yyjson_obj_get(flagObj, "arg");
+ if (argObj) {
+ yyjson_val *typeKey = yyjson_obj_get(argObj, "type");
+ assert(typeKey);
+ yyjson_val *optionalKey = yyjson_obj_get(argObj, "optional");
+ bool optional = optionalKey && yyjson_get_bool(optionalKey);
+ putchar(' ');
+ if (!instance.config.display.pipe)
+ fputs("\e[3m", stdout);
+ printf("<%s%s>", optional ? "?" : "", yyjson_get_str(typeKey));
+ if (!instance.config.display.pipe)
+ fputs("\e[m", stdout);
+ putchar('\n');
+
+ yyjson_val *defaultKey = yyjson_obj_get(argObj, "default");
+ if (defaultKey) {
+ if (ffStrEqualsIgnCase(yyjson_get_str(typeKey), "structure"))
+ printf("%10s: %s\n", "Default", FASTFETCH_DATATEXT_STRUCTURE);
+ else if (yyjson_is_bool(defaultKey))
+ printf("%10s: %s\n", "Default",
+ yyjson_get_bool(defaultKey) ? "true" : "false");
+ else if (yyjson_is_num(defaultKey))
+ printf("%10s: %d\n", "Default", yyjson_get_int(defaultKey));
+ else if (yyjson_is_str(defaultKey))
+ printf("%10s: %s\n", "Default", yyjson_get_str(defaultKey));
+ else
+ printf("%10s: Unknown\n", "Default");
+ }
+
+ yyjson_val *enumKey = yyjson_obj_get(argObj, "enum");
+ if (enumKey) {
+ printf("%10s:\n", "Options");
+ yyjson_val *optKey, *optVal;
+ size_t optIdx, optMax;
+ yyjson_obj_foreach(enumKey, optIdx, optMax, optKey, optVal) printf(
+ "%12s: %s\n", yyjson_get_str(optKey), yyjson_get_str(optVal));
+ }
+ } else
+ putchar('\n');
+
+ yyjson_val *remarkKey = yyjson_obj_get(flagObj, "remark");
+ if (remarkKey) {
+ if (yyjson_is_str(remarkKey))
+ printf("%10s: %s\n", "Remark", yyjson_get_str(remarkKey));
+ else if (yyjson_is_arr(remarkKey) && yyjson_arr_size(remarkKey) > 0) {
+ yyjson_val *remarkStr;
+ size_t remarkIdx, remarkMax;
+ yyjson_arr_foreach(remarkKey, remarkIdx, remarkMax, remarkStr) {
+ if (remarkIdx == 0)
+ printf("%10s: %s\n", "Remark", yyjson_get_str(remarkStr));
+ else
+ printf(" %s\n", yyjson_get_str(remarkStr));
}
+ }
}
- }
-
- yyjson_doc_free(doc);
- return false;
-}
-
-static void printCommandHelp(const char* command)
-{
- if(command == NULL)
- printFullHelp();
- else if(ffStrEqualsIgnCase(command, "format-json"))
- printCommandFormatHelpJson();
- else if(ffCharIsEnglishAlphabet(command[0]) && ffStrEndsWithIgnCase(command, "-format")) // -format
- printCommandFormatHelp(command);
- else if(!printSpecificCommandHelp(command))
- fprintf(stderr, "Error: No specific help for command '%s' provided\n", command);
-}
-static void listAvailablePresets(bool pretty)
-{
- FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.dataDirs)
- {
- ffStrbufAppendS(path, "fastfetch/presets/");
- ffListFilesRecursively(path->chars, pretty);
+ yyjson_doc_free(doc);
+ return true;
+ }
}
+ }
- if (instance.state.platform.exePath.length)
- {
- FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateCopy(&instance.state.platform.exePath);
- ffStrbufSubstrBeforeLastC(&absolutePath, '/');
- ffStrbufAppendS(&absolutePath, "/presets/");
- ffListFilesRecursively(absolutePath.chars, pretty);
- }
+ yyjson_doc_free(doc);
+ return false;
}
-static void listAvailableLogos(void)
-{
- FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.dataDirs)
- {
- ffStrbufAppendS(path, "fastfetch/logos/");
- ffListFilesRecursively(path->chars, true);
- }
+static void printCommandHelp(const char *command) {
+ if (command == NULL)
+ printFullHelp();
+ else if (ffStrEqualsIgnCase(command, "format-json"))
+ printCommandFormatHelpJson();
+ else if (ffCharIsEnglishAlphabet(command[0]) &&
+ ffStrEndsWithIgnCase(command, "-format")) // -format
+ printCommandFormatHelp(command);
+ else if (!printSpecificCommandHelp(command))
+ fprintf(stderr, "Error: No specific help for command '%s' provided\n",
+ command);
}
-static void listConfigPaths(void)
-{
- FF_LIST_FOR_EACH(FFstrbuf, folder, instance.state.platform.configDirs)
- {
- bool exists = false;
- uint32_t length = folder->length + (uint32_t) strlen("fastfetch") + 1 /* trailing slash */;
- ffStrbufAppendS(folder, "fastfetch/config.jsonc");
- exists = ffPathExists(folder->chars, FF_PATHTYPE_FILE);
- ffStrbufSubstrBefore(folder, length);
- printf("%s%s\n", folder->chars, exists ? " (*)" : "");
- }
+static void listAvailablePresets(bool pretty) {
+ FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.dataDirs) {
+ ffStrbufAppendS(path, "fastfetch/presets/");
+ ffListFilesRecursively(path->chars, pretty);
+ }
+
+ if (instance.state.platform.exePath.length) {
+ FF_STRBUF_AUTO_DESTROY absolutePath =
+ ffStrbufCreateCopy(&instance.state.platform.exePath);
+ ffStrbufSubstrBeforeLastC(&absolutePath, '/');
+ ffStrbufAppendS(&absolutePath, "/presets/");
+ ffListFilesRecursively(absolutePath.chars, pretty);
+ }
}
-static void listDataPaths(void)
-{
- FF_LIST_FOR_EACH(FFstrbuf, folder, instance.state.platform.dataDirs)
- {
- ffStrbufAppendS(folder, "fastfetch/");
- puts(folder->chars);
- }
+static void listAvailableLogos(void) {
+ FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.dataDirs) {
+ ffStrbufAppendS(path, "fastfetch/logos/");
+ ffListFilesRecursively(path->chars, true);
+ }
}
-static void listModules(bool pretty)
-{
- unsigned count = 0;
- for (int i = 0; i <= 'Z' - 'A'; ++i)
- {
- for (FFModuleBaseInfo** modules = ffModuleInfos[i]; *modules; ++modules)
- {
- ++count;
- if (pretty)
- printf("%d)%s%-14s: %s\n", count, count > 9 ? " " : " ", (*modules)->name, (*modules)->description);
- else
- printf("%s:%s\n", (*modules)->name, (*modules)->description);
- }
- }
+static void listConfigPaths(void) {
+ FF_LIST_FOR_EACH(FFstrbuf, folder, instance.state.platform.configDirs) {
+ bool exists = false;
+ uint32_t length =
+ folder->length + (uint32_t)strlen("fastfetch") + 1 /* trailing slash */;
+ ffStrbufAppendS(folder, "fastfetch/config.jsonc");
+ exists = ffPathExists(folder->chars, FF_PATHTYPE_FILE);
+ ffStrbufSubstrBefore(folder, length);
+ printf("%s%s\n", folder->chars, exists ? " (*)" : "");
+ }
}
-static bool parseJsoncFile(FFdata* data, const char* path, yyjson_read_flag flg)
-{
- assert(!data->configDoc);
-
- {
- yyjson_read_err error;
- data->configDoc = path
- ? yyjson_read_file(path, flg, NULL, &error)
- : yyjson_read_fp(stdin, flg, NULL, &error);
- if (!data->configDoc)
- {
- if (error.code != YYJSON_READ_ERROR_FILE_OPEN)
- {
- if (path)
- {
- size_t row = 0, col = error.pos;
- FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
- if (ffAppendFileBuffer(path, &content))
- yyjson_locate_pos(content.chars, content.length, error.pos, &row, &col, NULL);
- fprintf(stderr, "Error: failed to parse JSON config file `%s` at (%zu, %zu): %s\n", path, row, col, error.msg);
- }
- else
- fprintf(stderr, "Error: failed to parse JSON from stdin at %zu: %s\n", error.pos, error.msg);
-
- exit(477);
- }
- return false;
- }
- }
-
- {
- const char* error = NULL;
-
- yyjson_val* const root = yyjson_doc_get_root(data->configDoc);
- if (!yyjson_is_obj(root))
- error = "Invalid JSON config format. Root value must be an object";
-
- if (
- error ||
- (error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) ||
- (error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) ||
- (error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) ||
- false
- ) {
- fprintf(stderr, "JsonConfig Error: %s\n", error);
- exit(477);
- }
- }
+static void listDataPaths(void) {
+ FF_LIST_FOR_EACH(FFstrbuf, folder, instance.state.platform.dataDirs) {
+ ffStrbufAppendS(folder, "fastfetch/");
+ puts(folder->chars);
+ }
+}
- return true;
+static void listModules(bool pretty) {
+ unsigned count = 0;
+ for (int i = 0; i <= 'Z' - 'A'; ++i) {
+ for (FFModuleBaseInfo **modules = ffModuleInfos[i]; *modules; ++modules) {
+ ++count;
+ if (pretty)
+ printf("%d)%s%-14s: %s\n", count, count > 9 ? " " : " ",
+ (*modules)->name, (*modules)->description);
+ else
+ printf("%s:%s\n", (*modules)->name, (*modules)->description);
+ }
+ }
}
+static bool parseJsoncFile(FFdata *data, const char *path,
+ yyjson_read_flag flg) {
+ assert(!data->configDoc);
+
+ {
+ yyjson_read_err error;
+ data->configDoc = path ? yyjson_read_file(path, flg, NULL, &error)
+ : yyjson_read_fp(stdin, flg, NULL, &error);
+ if (!data->configDoc) {
+ if (error.code != YYJSON_READ_ERROR_FILE_OPEN) {
+ if (path) {
+ size_t row = 0, col = error.pos;
+ FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
+ if (ffAppendFileBuffer(path, &content))
+ yyjson_locate_pos(content.chars, content.length, error.pos, &row,
+ &col, NULL);
+ fprintf(stderr,
+ "Error: failed to parse JSON config file `%s` at (%zu, %zu): "
+ "%s\n",
+ path, row, col, error.msg);
+ } else
+ fprintf(stderr, "Error: failed to parse JSON from stdin at %zu: %s\n",
+ error.pos, error.msg);
-static void generateConfigFile(FFdata* data, bool force, const char* filePath, bool fullConfig)
-{
- if (data->resultDoc)
- {
- fprintf(stderr, "Error: duplicated `--gen-config` or `--format json` flags found\n");
exit(477);
+ }
+ return false;
}
+ }
- if (!filePath)
- {
- if (instance.state.platform.configDirs.length == 0)
- {
- fprintf(stderr, "Error: No config directory found to generate config file in. Use --gen-config to specify a path\n");
- exit(477);
- }
+ {
+ const char *error = NULL;
- FFstrbuf* configDir = FF_LIST_FIRST(FFstrbuf, instance.state.platform.configDirs);
- ffStrbufEnsureFixedLengthFree(&data->genConfigPath, configDir->length + strlen("fastfetch/config.jsonc"));
- ffStrbufSet(&data->genConfigPath, configDir);
- ffStrbufAppendS(&data->genConfigPath, "fastfetch/config.jsonc");
- }
- else
- {
- ffStrbufSetS(&data->genConfigPath, filePath);
- }
+ yyjson_val *const root = yyjson_doc_get_root(data->configDoc);
+ if (!yyjson_is_obj(root))
+ error = "Invalid JSON config format. Root value must be an object";
- if (!force && ffPathExists(data->genConfigPath.chars, FF_PATHTYPE_ANY))
- {
- fprintf(stderr, "Error: file `%s` exists. Use `--gen-config%s-force` to overwrite\n", data->genConfigPath.chars, fullConfig ? "-full" : "");
- exit(477);
+ if (error ||
+ (error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) ||
+ (error =
+ ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) ||
+ (error =
+ ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) ||
+ false) {
+ fprintf(stderr, "JsonConfig Error: %s\n", error);
+ exit(477);
}
+ }
- data->docType = fullConfig ? FF_RESULT_DOC_TYPE_CONFIG_FULL : FF_RESULT_DOC_TYPE_CONFIG;
- data->resultDoc = yyjson_mut_doc_new(NULL);
+ return true;
}
-static void optionParseConfigFile(FFdata* data, const char* key, const char* value)
-{
- if (data->configLoaded)
- {
- fprintf(stderr, "Error: only one config file can be loaded\n");
- exit(413);
- }
-
- data->configLoaded = true;
-
- if(value == NULL)
- {
- fprintf(stderr, "Error: usage: %s \n", key);
- exit(413);
- }
-
- if (value[0] == '\0' || ffStrEqualsIgnCase(value, "none"))
- return;
-
- if (value[0] == '-' && value[1] == '\0')
- {
- parseJsoncFile(data, NULL, false);
- return;
- }
-
- //Try to load as an absolute path
+static void generateConfigFile(FFdata *data, bool force, const char *filePath,
+ bool fullConfig) {
+ if (data->resultDoc) {
+ fprintf(
+ stderr,
+ "Error: duplicated `--gen-config` or `--format json` flags found\n");
+ exit(477);
+ }
+
+ if (!filePath) {
+ if (instance.state.platform.configDirs.length == 0) {
+ fprintf(stderr, "Error: No config directory found to generate config "
+ "file in. Use --gen-config to specify a path\n");
+ exit(477);
+ }
+
+ FFstrbuf *configDir =
+ FF_LIST_FIRST(FFstrbuf, instance.state.platform.configDirs);
+ ffStrbufEnsureFixedLengthFree(&data->genConfigPath,
+ configDir->length +
+ strlen("fastfetch/config.jsonc"));
+ ffStrbufSet(&data->genConfigPath, configDir);
+ ffStrbufAppendS(&data->genConfigPath, "fastfetch/config.jsonc");
+ } else {
+ ffStrbufSetS(&data->genConfigPath, filePath);
+ }
+
+ if (!force && ffPathExists(data->genConfigPath.chars, FF_PATHTYPE_ANY)) {
+ fprintf(
+ stderr,
+ "Error: file `%s` exists. Use `--gen-config%s-force` to overwrite\n",
+ data->genConfigPath.chars, fullConfig ? "-full" : "");
+ exit(477);
+ }
+
+ data->docType =
+ fullConfig ? FF_RESULT_DOC_TYPE_CONFIG_FULL : FF_RESULT_DOC_TYPE_CONFIG;
+ data->resultDoc = yyjson_mut_doc_new(NULL);
+}
- FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(128);
- ffStrbufSetS(&absolutePath, value);
- bool strictJson = ffStrbufEndsWithIgnCaseS(&absolutePath, ".json");
- bool jsonc = !strictJson && ffStrbufEndsWithIgnCaseS(&absolutePath, ".jsonc");
- bool json5 = !strictJson && !jsonc && ffStrbufEndsWithIgnCaseS(&absolutePath, ".json5");
- bool needExtension = !strictJson && !jsonc && !json5;
+static void optionParseConfigFile(FFdata *data, const char *key,
+ const char *value) {
+ if (data->configLoaded) {
+ fprintf(stderr, "Error: only one config file can be loaded\n");
+ exit(413);
+ }
+
+ data->configLoaded = true;
+
+ if (value == NULL) {
+ fprintf(stderr, "Error: usage: %s \n", key);
+ exit(413);
+ }
+
+ if (value[0] == '\0' || ffStrEqualsIgnCase(value, "none"))
+ return;
+
+ if (value[0] == '-' && value[1] == '\0') {
+ parseJsoncFile(data, NULL, false);
+ return;
+ }
+
+ // Try to load as an absolute path
+
+ FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(128);
+ ffStrbufSetS(&absolutePath, value);
+ bool strictJson = ffStrbufEndsWithIgnCaseS(&absolutePath, ".json");
+ bool jsonc = !strictJson && ffStrbufEndsWithIgnCaseS(&absolutePath, ".jsonc");
+ bool json5 = !strictJson && !jsonc &&
+ ffStrbufEndsWithIgnCaseS(&absolutePath, ".json5");
+ bool needExtension = !strictJson && !jsonc && !json5;
+ if (needExtension)
+ ffStrbufAppendS(&absolutePath, ".jsonc");
+
+ yyjson_read_flag flag =
+ strictJson ? 0
+ : jsonc ? YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS
+ : YYJSON_READ_JSON5;
+
+ if (parseJsoncFile(data, absolutePath.chars, flag))
+ return;
+
+ // Try to load as a relative path with the config directory
+
+ FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.configDirs) {
+ ffStrbufSet(&absolutePath, path);
+ ffStrbufAppendS(&absolutePath, "fastfetch/");
+ ffStrbufAppendS(&absolutePath, value);
if (needExtension)
- ffStrbufAppendS(&absolutePath, ".jsonc");
-
- yyjson_read_flag flag = strictJson
- ? 0
- : jsonc
- ? YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS
- : YYJSON_READ_JSON5;
+ ffStrbufAppendS(&absolutePath, ".jsonc");
- if (parseJsoncFile(data, absolutePath.chars, flag)) return;
+ if (parseJsoncFile(data, absolutePath.chars, flag))
+ return;
+ }
- //Try to load as a relative path with the config directory
+ // Try to load as a preset
- FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.configDirs)
- {
- ffStrbufSet(&absolutePath, path);
- ffStrbufAppendS(&absolutePath, "fastfetch/");
- ffStrbufAppendS(&absolutePath, value);
- if (needExtension)
- ffStrbufAppendS(&absolutePath, ".jsonc");
-
- if (parseJsoncFile(data, absolutePath.chars, flag)) return;
- }
+ FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.dataDirs) {
+ ffStrbufSet(&absolutePath, path);
+ ffStrbufAppendS(&absolutePath, "fastfetch/presets/");
+ ffStrbufAppendS(&absolutePath, value);
+ if (needExtension)
+ ffStrbufAppendS(&absolutePath, ".jsonc");
- //Try to load as a preset
+ if (parseJsoncFile(data, absolutePath.chars, flag))
+ return;
+ }
- FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.dataDirs)
- {
- ffStrbufSet(&absolutePath, path);
- ffStrbufAppendS(&absolutePath, "fastfetch/presets/");
- ffStrbufAppendS(&absolutePath, value);
- if (needExtension)
- ffStrbufAppendS(&absolutePath, ".jsonc");
+ // Try to load as a relative path with the directory of fastfetch binary, for
+ // Windows support
- if (parseJsoncFile(data, absolutePath.chars, flag)) return;
- }
+ if (instance.state.platform.exePath.length) {
+ uint32_t lastSlash =
+ ffStrbufLastIndexC(&instance.state.platform.exePath, '/') + 1;
+ assert(lastSlash < instance.state.platform.exePath.length);
- //Try to load as a relative path with the directory of fastfetch binary, for Windows support
-
- if (instance.state.platform.exePath.length)
- {
- uint32_t lastSlash = ffStrbufLastIndexC(&instance.state.platform.exePath, '/') + 1;
- assert(lastSlash < instance.state.platform.exePath.length);
-
- // Try {exePath}/
- ffStrbufSetNS(&absolutePath, lastSlash, instance.state.platform.exePath.chars);
- ffStrbufAppendS(&absolutePath, value);
- if (needExtension)
- ffStrbufAppendS(&absolutePath, ".jsonc");
- if (parseJsoncFile(data, absolutePath.chars, flag)) return;
-
- // Try {exePath}/presets/
- ffStrbufSubstrBefore(&absolutePath, lastSlash);
- ffStrbufAppendS(&absolutePath, "presets/");
- ffStrbufAppendS(&absolutePath, value);
- if (needExtension)
- ffStrbufAppendS(&absolutePath, ".jsonc");
- if (parseJsoncFile(data, absolutePath.chars, flag)) return;
- }
+ // Try {exePath}/
+ ffStrbufSetNS(&absolutePath, lastSlash,
+ instance.state.platform.exePath.chars);
+ ffStrbufAppendS(&absolutePath, value);
+ if (needExtension)
+ ffStrbufAppendS(&absolutePath, ".jsonc");
+ if (parseJsoncFile(data, absolutePath.chars, flag))
+ return;
+
+ // Try {exePath}/presets/
+ ffStrbufSubstrBefore(&absolutePath, lastSlash);
+ ffStrbufAppendS(&absolutePath, "presets/");
+ ffStrbufAppendS(&absolutePath, value);
+ if (needExtension)
+ ffStrbufAppendS(&absolutePath, ".jsonc");
+ if (parseJsoncFile(data, absolutePath.chars, flag))
+ return;
+ }
- //File not found
+ // File not found
- fprintf(stderr, "Error: couldn't find config: %s\n", value);
- exit(414);
+ fprintf(stderr, "Error: couldn't find config: %s\n", value);
+ exit(414);
}
-static void printVersion()
-{
- FFVersionResult* result = &ffVersionResult;
- printf("%s %s%s%s (%s)\n", result->projectName, result->version, result->versionTweak, result->debugMode ? "-debug" : "", result->architecture);
+static void printVersion() {
+ FFVersionResult *result = &ffVersionResult;
+ printf("%s %s%s%s (%s)\n", result->projectName, result->version,
+ result->versionTweak, result->debugMode ? "-debug" : "",
+ result->architecture);
}
-static void enableJsonOutput(FFdata* data)
-{
- if (data->resultDoc)
- {
- fprintf(stderr, "Error: duplicated `--gen-config` or `--format json` flags found\n");
- exit(477);
- }
-
- data->resultDoc = yyjson_mut_doc_new(NULL);
- data->docType = FF_RESULT_DOC_TYPE_JSON;
- yyjson_mut_doc_set_root(data->resultDoc, yyjson_mut_arr(data->resultDoc));
+static void enableJsonOutput(FFdata *data) {
+ if (data->resultDoc) {
+ fprintf(
+ stderr,
+ "Error: duplicated `--gen-config` or `--format json` flags found\n");
+ exit(477);
+ }
+
+ data->resultDoc = yyjson_mut_doc_new(NULL);
+ data->docType = FF_RESULT_DOC_TYPE_JSON;
+ yyjson_mut_doc_set_root(data->resultDoc, yyjson_mut_arr(data->resultDoc));
}
-static void parseCommand(FFdata* data, char* key, char* value)
-{
- if(ffStrEqualsIgnCase(key, "-h") || ffStrEqualsIgnCase(key, "--help"))
- {
- printCommandHelp(value);
- exit(0);
- }
- if(ffStrEqualsIgnCase(key, "--help-raw"))
- {
- puts(FASTFETCH_DATATEXT_JSON_HELP);
- exit(0);
- }
- else if(ffStrEqualsIgnCase(key, "-v") || ffStrEqualsIgnCase(key, "--version"))
- {
- printVersion();
- exit(0);
- }
- else if(ffStrEqualsIgnCase(key, "--version-raw"))
- {
- puts(FASTFETCH_PROJECT_VERSION);
- exit(0);
- }
- else if(ffStrStartsWithIgnCase(key, "--print-"))
- {
- const char* subkey = key + strlen("--print-");
- if(ffStrEndsWithIgnCase(subkey, "structure"))
- puts(FASTFETCH_DATATEXT_STRUCTURE);
- else if(ffStrEqualsIgnCase(subkey, "logos"))
- ffLogoBuiltinPrint();
- else
- {
- fprintf(stderr, "Error: unsupported print option: %s\n", key);
- exit(415);
- }
- exit(0);
- }
- else if(ffStrStartsWithIgnCase(key, "--list-"))
- {
- const char* subkey = key + strlen("--list-");
- if(ffStrEqualsIgnCase(subkey, "modules"))
- listModules(!value || !ffStrEqualsIgnCase(value, "autocompletion"));
- else if(ffStrEqualsIgnCase(subkey, "presets"))
- listAvailablePresets(!value || !ffStrEqualsIgnCase(value, "autocompletion"));
- else if(ffStrEqualsIgnCase(subkey, "config-paths"))
- listConfigPaths();
- else if(ffStrEqualsIgnCase(subkey, "data-paths"))
- listDataPaths();
- else if(ffStrEqualsIgnCase(subkey, "features"))
- ffListFeatures();
- else if(ffStrEqualsIgnCase(subkey, "logos"))
- {
- if (value)
- {
- if (ffStrEqualsIgnCase(value, "autocompletion"))
- ffLogoBuiltinListAutocompletion();
- else if (ffStrEqualsIgnCase(value, "builtin"))
- ffLogoBuiltinList();
- else if (ffStrEqualsIgnCase(value, "custom"))
- listAvailableLogos();
- else
- {
- fprintf(stderr, "Error: unsupported logo type: %s\n", value);
- exit(415);
- }
- }
- else
- {
- puts("Builtin logos:");
- ffLogoBuiltinList();
- puts("\nCustom logos:");
- listAvailableLogos();
- }
- }
- else
- {
- fprintf(stderr, "Error: unsupported list option: %s\n", key);
- exit(415);
+static void parseCommand(FFdata *data, char *key, char *value) {
+ if (ffStrEqualsIgnCase(key, "-h") || ffStrEqualsIgnCase(key, "--help")) {
+ printCommandHelp(value);
+ exit(0);
+ }
+ if (ffStrEqualsIgnCase(key, "--help-raw")) {
+ puts(FASTFETCH_DATATEXT_JSON_HELP);
+ exit(0);
+ } else if (ffStrEqualsIgnCase(key, "-v") ||
+ ffStrEqualsIgnCase(key, "--version")) {
+ printVersion();
+ exit(0);
+ } else if (ffStrEqualsIgnCase(key, "--version-raw")) {
+ puts(FASTFETCH_PROJECT_VERSION);
+ exit(0);
+ } else if (ffStrStartsWithIgnCase(key, "--print-")) {
+ const char *subkey = key + strlen("--print-");
+ if (ffStrEndsWithIgnCase(subkey, "structure"))
+ puts(FASTFETCH_DATATEXT_STRUCTURE);
+ else if (ffStrEqualsIgnCase(subkey, "logos"))
+ ffLogoBuiltinPrint();
+ else {
+ fprintf(stderr, "Error: unsupported print option: %s\n", key);
+ exit(415);
+ }
+ exit(0);
+ } else if (ffStrStartsWithIgnCase(key, "--list-")) {
+ const char *subkey = key + strlen("--list-");
+ if (ffStrEqualsIgnCase(subkey, "modules"))
+ listModules(!value || !ffStrEqualsIgnCase(value, "autocompletion"));
+ else if (ffStrEqualsIgnCase(subkey, "presets"))
+ listAvailablePresets(!value ||
+ !ffStrEqualsIgnCase(value, "autocompletion"));
+ else if (ffStrEqualsIgnCase(subkey, "config-paths"))
+ listConfigPaths();
+ else if (ffStrEqualsIgnCase(subkey, "data-paths"))
+ listDataPaths();
+ else if (ffStrEqualsIgnCase(subkey, "features"))
+ ffListFeatures();
+ else if (ffStrEqualsIgnCase(subkey, "logos")) {
+ if (value) {
+ if (ffStrEqualsIgnCase(value, "autocompletion"))
+ ffLogoBuiltinListAutocompletion();
+ else if (ffStrEqualsIgnCase(value, "builtin"))
+ ffLogoBuiltinList();
+ else if (ffStrEqualsIgnCase(value, "custom"))
+ listAvailableLogos();
+ else {
+ fprintf(stderr, "Error: unsupported logo type: %s\n", value);
+ exit(415);
}
-
- exit(0);
- }
- else if(ffStrEqualsIgnCase(key, "--gen-config"))
- generateConfigFile(data, false, value, false);
- else if(ffStrEqualsIgnCase(key, "--gen-config-force"))
- generateConfigFile(data, true, value, false);
- else if(ffStrEqualsIgnCase(key, "--gen-config-full"))
- generateConfigFile(data, false, value, true);
- else if(ffStrEqualsIgnCase(key, "--gen-config-full-force"))
- generateConfigFile(data, true, value, true);
- else if(ffStrEqualsIgnCase(key, "-c") || ffStrEqualsIgnCase(key, "--config"))
- optionParseConfigFile(data, key, value);
- else if(ffStrEqualsIgnCase(key, "-j") || ffStrEqualsIgnCase(key, "--json"))
- {
- if (ffOptionParseBoolean(value)) enableJsonOutput(data);
- }
- else if(ffStrEqualsIgnCase(key, "--format"))
- {
- if (!!ffOptionParseEnum(key, value, (FFKeyValuePair[]) {
- { "default", false},
- { "json", true },
- {},
- })) enableJsonOutput(data);
- }
- else if(ffStrEqualsIgnCase(key, "--dynamic-interval"))
- instance.state.dynamicInterval = ffOptionParseUInt32(key, value); // seconds to milliseconds
- else
- return;
-
- // Don't parse it again in parseOption.
- // This is necessary because parseOption doesn't understand this option and will result in an unknown option error.
- key[0] = '\0';
- if (value) value[0] = '\0';
+ } else {
+ puts("Builtin logos:");
+ ffLogoBuiltinList();
+ puts("\nCustom logos:");
+ listAvailableLogos();
+ }
+ } else {
+ fprintf(stderr, "Error: unsupported list option: %s\n", key);
+ exit(415);
+ }
+
+ exit(0);
+ } else if (ffStrEqualsIgnCase(key, "--gen-config"))
+ generateConfigFile(data, false, value, false);
+ else if (ffStrEqualsIgnCase(key, "--gen-config-force"))
+ generateConfigFile(data, true, value, false);
+ else if (ffStrEqualsIgnCase(key, "--gen-config-full"))
+ generateConfigFile(data, false, value, true);
+ else if (ffStrEqualsIgnCase(key, "--gen-config-full-force"))
+ generateConfigFile(data, true, value, true);
+ else if (ffStrEqualsIgnCase(key, "-c") || ffStrEqualsIgnCase(key, "--config"))
+ optionParseConfigFile(data, key, value);
+ else if (ffStrEqualsIgnCase(key, "-j") || ffStrEqualsIgnCase(key, "--json")) {
+ if (ffOptionParseBoolean(value))
+ enableJsonOutput(data);
+ } else if (ffStrEqualsIgnCase(key, "--format")) {
+ if (!!ffOptionParseEnum(key, value,
+ (FFKeyValuePair[]){
+ {"default", false},
+ {"json", true},
+ {},
+ }))
+ enableJsonOutput(data);
+ } else if (ffStrEqualsIgnCase(key, "--dynamic-interval"))
+ instance.state.dynamicInterval =
+ ffOptionParseUInt32(key, value); // seconds to milliseconds
+ else
+ return;
+
+ // Don't parse it again in parseOption.
+ // This is necessary because parseOption doesn't understand this option and
+ // will result in an unknown option error.
+ key[0] = '\0';
+ if (value)
+ value[0] = '\0';
}
-static void parseOption(FFdata* data, const char* key, const char* value)
-{
- if(ffStrEqualsIgnCase(key, "-s") || ffStrEqualsIgnCase(key, "--structure"))
- ffOptionParseString(key, value, &data->structure);
-
- else if(
- ffOptionsParseGeneralCommandLine(&instance.config.general, key, value) ||
- ffOptionsParseLogoCommandLine(&instance.config.logo, key, value) ||
- ffOptionsParseDisplayCommandLine(&instance.config.display, key, value) ||
- ffParseModuleOptions(key, value)
- ) {}
-
- else if(ffStrEqualsIgnCase(key, "--structure-disabled"))
- ffOptionParseString(key, value, &data->structureDisabled);
-
- else
- {
- fprintf(stderr, "Error: unknown option: %s\n", key);
- exit(400);
- }
+static void parseOption(FFdata *data, const char *key, const char *value) {
+ if (ffStrEqualsIgnCase(key, "-s") || ffStrEqualsIgnCase(key, "--structure"))
+ ffOptionParseString(key, value, &data->structure);
+
+ else if (ffOptionsParseGeneralCommandLine(&instance.config.general, key,
+ value) ||
+ ffOptionsParseLogoCommandLine(&instance.config.logo, key, value) ||
+ ffOptionsParseDisplayCommandLine(&instance.config.display, key,
+ value) ||
+ ffParseModuleOptions(key, value)) {
+ }
+
+ else if (ffStrEqualsIgnCase(key, "--structure-disabled"))
+ ffOptionParseString(key, value, &data->structureDisabled);
+
+ else {
+ fprintf(stderr, "Error: unknown option: %s\n", key);
+ exit(400);
+ }
}
-static void parseConfigFiles(FFdata* data)
-{
- if (__builtin_expect(data->genConfigPath.length == 0, true))
- {
- FF_LIST_FOR_EACH(FFstrbuf, dir, instance.state.platform.configDirs)
- {
- uint32_t dirLength = dir->length;
-
- ffStrbufAppendS(dir, "fastfetch/config.jsonc");
- bool success = parseJsoncFile(data, dir->chars, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS);
- ffStrbufSubstrBefore(dir, dirLength);
- if (success) return;
-
- ffStrbufAppendS(dir, "fastfetch/config.json5");
- success = parseJsoncFile(data, dir->chars, YYJSON_READ_JSON5);
- ffStrbufSubstrBefore(dir, dirLength);
- if (success) return;
- }
+static void parseConfigFiles(FFdata *data) {
+ if (__builtin_expect(data->genConfigPath.length == 0, true)) {
+ FF_LIST_FOR_EACH(FFstrbuf, dir, instance.state.platform.configDirs) {
+ uint32_t dirLength = dir->length;
+
+ ffStrbufAppendS(dir, "fastfetch/config.jsonc");
+ bool success = parseJsoncFile(data, dir->chars,
+ YYJSON_READ_ALLOW_COMMENTS |
+ YYJSON_READ_ALLOW_TRAILING_COMMAS);
+ ffStrbufSubstrBefore(dir, dirLength);
+ if (success)
+ return;
+
+ ffStrbufAppendS(dir, "fastfetch/config.json5");
+ success = parseJsoncFile(data, dir->chars, YYJSON_READ_JSON5);
+ ffStrbufSubstrBefore(dir, dirLength);
+ if (success)
+ return;
}
+ }
}
-static void parseArguments(FFdata* data, int argc, char** argv, void (*parser)(FFdata* data, char* key, char* value))
-{
- for(int i = 1; i < argc; i++)
- {
- const char* key = argv[i];
- if(*key == '\0')
- continue; // has been handled by parseCommand
-
- if(*key != '-')
- {
- fprintf(stderr, "Error: invalid option: %s. An option must start with `-`\n", key);
- exit(400);
- }
-
- if(i == argc - 1 || (
- argv[i + 1][0] == '-' &&
- argv[i + 1][1] != '\0' && // `-` is used as an alias for `/dev/stdin`
- !ffStrEqualsIgnCase(argv[i], "--separator-string") // Separator string can start with a -
- )) {
- parser(data, argv[i], NULL);
- }
- else
- {
- parser(data, argv[i], argv[i + 1]);
- ++i;
- }
- }
+static void parseArguments(FFdata *data, int argc, char **argv,
+ void (*parser)(FFdata *data, char *key,
+ char *value)) {
+ for (int i = 1; i < argc; i++) {
+ const char *key = argv[i];
+ if (*key == '\0')
+ continue; // has been handled by parseCommand
+
+ if (*key != '-') {
+ fprintf(stderr,
+ "Error: invalid option: %s. An option must start with `-`\n",
+ key);
+ exit(400);
+ }
+
+ if (i == argc - 1 ||
+ (argv[i + 1][0] == '-' &&
+ argv[i + 1][1] != '\0' && // `-` is used as an alias for `/dev/stdin`
+ !ffStrEqualsIgnCase(
+ argv[i],
+ "--separator-string") // Separator string can start with a -
+ )) {
+ parser(data, argv[i], NULL);
+ } else {
+ parser(data, argv[i], argv[i + 1]);
+ ++i;
+ }
+ }
}
-static void run(FFdata* data)
-{
- const bool useJsonConfig = data->structure.length == 0 && data->configDoc;
+static void run(FFdata *data) {
+ const bool useJsonConfig = data->structure.length == 0 && data->configDoc;
+
+ if (useJsonConfig)
+ ffPrintJsonConfig(data, true /* prepare */);
+ else {
+ // If we don't have a custom structure, use the default one
+ if (data->structure.length == 0)
+ ffStrbufAppendS(
+ &data->structure,
+ FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here
+ // because we will modify the string
+ ffPrepareCommandOption(data);
+ }
+
+ ffStart();
+
+ if (!data->resultDoc)
+ ffLogoPrint();
+
+#if defined(_WIN32)
+ if (!instance.config.display.noBuffer)
+ fflush(stdout);
+#endif
+ while (true) {
if (useJsonConfig)
- ffPrintJsonConfig(data, true /* prepare */);
+ ffPrintJsonConfig(data, false);
else
- {
- //If we don't have a custom structure, use the default one
- if(data->structure.length == 0)
- ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
- ffPrepareCommandOption(data);
- }
-
- ffStart();
-
- if (!data->resultDoc)
- ffLogoPrint();
-
- #if defined(_WIN32)
- if (!instance.config.display.noBuffer) fflush(stdout);
- #endif
-
- while (true)
- {
- if (useJsonConfig)
- ffPrintJsonConfig(data, false);
- else
- ffPrintCommandOption(data);
-
- if (instance.state.dynamicInterval > 0)
- {
- fflush(stdout);
- ffTimeSleep(instance.state.dynamicInterval);
- fputs("\e[H", stdout);
- }
- else
- break;
+ ffPrintCommandOption(data);
- if (useJsonConfig)
- ffPrintJsonConfig(data, true /* prepare */);
- else
- ffPrepareCommandOption(data);
- }
+ if (instance.state.dynamicInterval > 0) {
+ fflush(stdout);
+ ffTimeSleep(instance.state.dynamicInterval);
+ fputs("\e[H", stdout);
+ } else
+ break;
- if (data->resultDoc)
- yyjson_mut_write_fp(stdout, data->resultDoc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_NEWLINE_AT_END, NULL, NULL);
+ if (useJsonConfig)
+ ffPrintJsonConfig(data, true /* prepare */);
else
- {
- if (instance.config.logo.printRemaining)
- ffLogoPrintRemaining();
- ffFinish();
- }
+ ffPrepareCommandOption(data);
+ }
+
+ if (data->resultDoc)
+ yyjson_mut_write_fp(stdout, data->resultDoc,
+ YYJSON_WRITE_INF_AND_NAN_AS_NULL |
+ YYJSON_WRITE_PRETTY_TWO_SPACES |
+ YYJSON_WRITE_NEWLINE_AT_END,
+ NULL, NULL);
+ else {
+ if (instance.config.logo.printRemaining)
+ ffLogoPrintRemaining();
+ ffFinish();
+ }
}
-static void writeConfigFile(FFdata* data)
-{
- const FFstrbuf* filename = &data->genConfigPath;
-
- yyjson_mut_doc* doc = data->resultDoc;
- yyjson_mut_val* root = yyjson_mut_obj(doc);
- yyjson_mut_doc_set_root(doc, root);
- yyjson_mut_obj_add_str(doc, root, "$schema", "https://github.com/fastfetch-cli/fastfetch/raw/master/doc/json_schema.json");
-
- if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL)
- {
- ffOptionsGenerateLogoJsonConfig(data, &instance.config.logo);
- ffOptionsGenerateDisplayJsonConfig(data, &instance.config.display);
- ffOptionsGenerateGeneralJsonConfig(data, &instance.config.general);
- }
- ffMigrateCommandOptionToJsonc(data);
-
- if (ffStrbufEqualS(filename, "-"))
- yyjson_mut_write_fp(stdout, doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_NEWLINE_AT_END, NULL, NULL);
- else
- {
- size_t len;
- FF_AUTO_FREE const char* str = yyjson_mut_write(doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_NEWLINE_AT_END, &len);
- if (!str)
- {
- printf("Error: failed to generate config file\n");
- exit(1);
- }
- if (ffWriteFileData(filename->chars, len, str))
- {
- printf("✓ Configuration file generated: `%s`\n"
- "* Tip: Use a JSON schema-aware editor for better editing experience\n"
- "* Documentation: https://github.com/fastfetch-cli/fastfetch/wiki/Configuration\n", filename->chars);
- }
- else
- {
- printf("Error: failed to write file in `%s`\n", filename->chars);
- exit(1);
- }
- }
+static void writeConfigFile(FFdata *data) {
+ const FFstrbuf *filename = &data->genConfigPath;
+
+ yyjson_mut_doc *doc = data->resultDoc;
+ yyjson_mut_val *root = yyjson_mut_obj(doc);
+ yyjson_mut_doc_set_root(doc, root);
+ yyjson_mut_obj_add_str(doc, root, "$schema",
+ "https://github.com/fastfetch-cli/fastfetch/raw/"
+ "master/doc/json_schema.json");
+
+ if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL) {
+ ffOptionsGenerateLogoJsonConfig(data, &instance.config.logo);
+ ffOptionsGenerateDisplayJsonConfig(data, &instance.config.display);
+ ffOptionsGenerateGeneralJsonConfig(data, &instance.config.general);
+ }
+ ffMigrateCommandOptionToJsonc(data);
+
+ if (ffStrbufEqualS(filename, "-"))
+ yyjson_mut_write_fp(stdout, doc,
+ YYJSON_WRITE_INF_AND_NAN_AS_NULL |
+ YYJSON_WRITE_PRETTY_TWO_SPACES |
+ YYJSON_WRITE_NEWLINE_AT_END,
+ NULL, NULL);
+ else {
+ size_t len;
+ FF_AUTO_FREE const char *str = yyjson_mut_write(
+ doc,
+ YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES |
+ YYJSON_WRITE_NEWLINE_AT_END,
+ &len);
+ if (!str) {
+ printf("Error: failed to generate config file\n");
+ exit(1);
+ }
+ if (ffWriteFileData(filename->chars, len, str)) {
+ printf("✓ Configuration file generated: `%s`\n"
+ "* Tip: Use a JSON schema-aware editor for better editing "
+ "experience\n"
+ "* Documentation: "
+ "https://github.com/fastfetch-cli/fastfetch/wiki/Configuration\n",
+ filename->chars);
+ } else {
+ printf("Error: failed to write file in `%s`\n", filename->chars);
+ exit(1);
+ }
+ }
}
-int main(int argc, char** argv)
-{
- ffInitInstance();
- atexit(ffDestroyInstance);
-
- //Data stores things only needed for the configuration of fastfetch
- FFdata data = {
- .structure = ffStrbufCreate(),
- .structureDisabled = ffStrbufCreate(),
- .genConfigPath = ffStrbufCreate(),
- };
-
- parseArguments(&data, argc, argv, parseCommand);
- if(instance.state.dynamicInterval && data.resultDoc)
- {
- fprintf(stderr, "Error: --dynamic-interval cannot be used with --json\n");
- exit(400);
- }
-
- if(!data.configLoaded && !getenv("NO_CONFIG"))
- parseConfigFiles(&data);
- parseArguments(&data, argc, argv, (void*) parseOption);
-
- if (__builtin_expect(data.genConfigPath.length == 0, true))
- run(&data);
- else
- writeConfigFile(&data);
-
- ffStrbufDestroy(&data.structure);
- ffStrbufDestroy(&data.structureDisabled);
- yyjson_doc_free(data.configDoc);
- yyjson_mut_doc_free(data.resultDoc);
- ffStrbufDestroy(&data.genConfigPath);
+int main(int argc, char **argv) {
+ ffInitInstance();
+ atexit(ffDestroyInstance);
+
+ // Data stores things only needed for the configuration of fastfetch
+ FFdata data = {
+ .structure = ffStrbufCreate(),
+ .structureDisabled = ffStrbufCreate(),
+ .genConfigPath = ffStrbufCreate(),
+ };
+
+ parseArguments(&data, argc, argv, parseCommand);
+ if (instance.state.dynamicInterval && data.resultDoc) {
+ fprintf(stderr, "Error: --dynamic-interval cannot be used with --json\n");
+ exit(400);
+ }
+
+ if (!data.configLoaded && !getenv("NO_CONFIG"))
+ parseConfigFiles(&data);
+ parseArguments(&data, argc, argv, (void *)parseOption);
+
+ if (__builtin_expect(data.genConfigPath.length == 0, true))
+ run(&data);
+ else
+ writeConfigFile(&data);
+
+ ffStrbufDestroy(&data.structure);
+ ffStrbufDestroy(&data.structureDisabled);
+ yyjson_doc_free(data.configDoc);
+ yyjson_mut_doc_free(data.resultDoc);
+ ffStrbufDestroy(&data.genConfigPath);
}
diff --git a/src/modules/packages/packages.c b/src/modules/packages/packages.c
index c9d3d55802..e17c1e6c3a 100644
--- a/src/modules/packages/packages.c
+++ b/src/modules/packages/packages.c
@@ -1,158 +1,138 @@
-#include "common/printing.h"
+#include "detection/packages/packages.h"
#include "common/jsonconfig.h"
+#include "common/printing.h"
#include "common/stringUtils.h"
-#include "detection/packages/packages.h"
#include "modules/packages/packages.h"
-bool ffPrintPackages(FFPackagesOptions* options)
-{
- FFPackagesResult counts = {};
- ffStrbufInit(&counts.pacmanBranch);
-
- const char* error = ffDetectPackages(&counts, options);
-
- if(error)
- {
- ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
- return false;
+bool ffPrintPackages(FFPackagesOptions *options) {
+ FFPackagesResult counts = {};
+ ffStrbufInit(&counts.pacmanBranch);
+
+ const char *error = ffDetectPackages(&counts, options);
+
+ if (error) {
+ ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs,
+ FF_PRINT_TYPE_DEFAULT, "%s", error);
+ return false;
+ }
+
+ uint32_t nixAll = counts.nixDefault + counts.nixSystem + counts.nixUser;
+ uint32_t flatpakAll = counts.flatpakSystem + counts.flatpakUser;
+ uint32_t brewAll = counts.brew + counts.brewCask;
+ uint32_t guixAll = counts.guixSystem + counts.guixUser + counts.guixHome;
+ uint32_t hpkgAll = counts.hpkgSystem + counts.hpkgUser;
+ uint32_t amAll = counts.amSystem + counts.amUser;
+ uint32_t scoopAll = counts.scoopUser + counts.scoopGlobal;
+
+ if (options->moduleArgs.outputFormat.length == 0) {
+ ffPrintLogoAndKey(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs,
+ FF_PRINT_TYPE_DEFAULT);
+
+#define FF_PRINT_PACKAGE_NAME(var, name) \
+ { \
+ if (counts.var > 0) { \
+ printf("%u (%s)", counts.var, (name)); \
+ if ((all -= counts.var) > 0) \
+ fputs(", ", stdout); \
+ } \
+ }
+
+#define FF_PRINT_PACKAGE(name) FF_PRINT_PACKAGE_NAME(name, #name)
+
+#define FF_PRINT_PACKAGE_ALL(name) \
+ { \
+ if (name##All > 0) { \
+ printf("%u (%s)", name##All, #name); \
+ if ((all -= name##All) > 0) \
+ fputs(", ", stdout); \
+ } \
+ }
+
+ uint32_t all = counts.all;
+ if (counts.pacman > 0) {
+ printf("%u (pacman)", counts.pacman);
+ if (counts.pacmanBranch.length > 0)
+ printf("[%s]", counts.pacmanBranch.chars);
+ if ((all -= counts.pacman) > 0)
+ printf(", ");
+ };
+ FF_PRINT_PACKAGE(dpkg)
+ FF_PRINT_PACKAGE(rpm)
+ FF_PRINT_PACKAGE(emerge)
+ FF_PRINT_PACKAGE(eopkg)
+ FF_PRINT_PACKAGE(xbps)
+ if (options->combined) {
+ FF_PRINT_PACKAGE_ALL(nix);
+ } else {
+ FF_PRINT_PACKAGE_NAME(nixSystem, "nix-system")
+ FF_PRINT_PACKAGE_NAME(nixUser, "nix-user")
+ FF_PRINT_PACKAGE_NAME(nixDefault, "nix-default")
}
-
- uint32_t nixAll = counts.nixDefault + counts.nixSystem + counts.nixUser;
- uint32_t flatpakAll = counts.flatpakSystem + counts.flatpakUser;
- uint32_t brewAll = counts.brew + counts.brewCask;
- uint32_t guixAll = counts.guixSystem + counts.guixUser + counts.guixHome;
- uint32_t hpkgAll = counts.hpkgSystem + counts.hpkgUser;
- uint32_t amAll = counts.amSystem + counts.amUser;
- uint32_t scoopAll = counts.scoopUser + counts.scoopGlobal;
-
- if(options->moduleArgs.outputFormat.length == 0)
- {
- ffPrintLogoAndKey(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
-
- #define FF_PRINT_PACKAGE_NAME(var, name) {\
- if(counts.var > 0) \
- { \
- printf("%u (%s)", counts.var, (name)); \
- if((all -= counts.var) > 0) \
- fputs(", ", stdout); \
- } \
- }
-
- #define FF_PRINT_PACKAGE(name) FF_PRINT_PACKAGE_NAME(name, #name)
-
- #define FF_PRINT_PACKAGE_ALL(name) {\
- if(name ## All > 0) \
- { \
- printf("%u (%s)", name ## All, #name); \
- if((all -= name ## All) > 0) \
- fputs(", ", stdout); \
- } \
- }
-
- uint32_t all = counts.all;
- if(counts.pacman > 0)
- {
- printf("%u (pacman)", counts.pacman);
- if(counts.pacmanBranch.length > 0)
- printf("[%s]", counts.pacmanBranch.chars);
- if((all -= counts.pacman) > 0)
- printf(", ");
- };
- FF_PRINT_PACKAGE(dpkg)
- FF_PRINT_PACKAGE(rpm)
- FF_PRINT_PACKAGE(emerge)
- FF_PRINT_PACKAGE(eopkg)
- FF_PRINT_PACKAGE(xbps)
- if (options->combined)
- {
- FF_PRINT_PACKAGE_ALL(nix);
- }
- else
- {
- FF_PRINT_PACKAGE_NAME(nixSystem, "nix-system")
- FF_PRINT_PACKAGE_NAME(nixUser, "nix-user")
- FF_PRINT_PACKAGE_NAME(nixDefault, "nix-default")
- }
- FF_PRINT_PACKAGE(apk)
- FF_PRINT_PACKAGE(pkg)
- FF_PRINT_PACKAGE(pkgsrc)
- FF_PRINT_PACKAGE(kiss)
- if (options->combined)
- {
- FF_PRINT_PACKAGE_ALL(hpkg)
- }
- else
- {
- FF_PRINT_PACKAGE_NAME(hpkgSystem, counts.hpkgUser ? "hpkg-system" : "hpkg")
- FF_PRINT_PACKAGE_NAME(hpkgUser, "hpkg-user")
- }
- if (options->combined)
- {
- FF_PRINT_PACKAGE_ALL(flatpak);
- }
- else
- {
- FF_PRINT_PACKAGE_NAME(flatpakSystem, counts.flatpakUser ? "flatpak-system" : "flatpak")
- FF_PRINT_PACKAGE_NAME(flatpakUser, "flatpak-user")
- }
- FF_PRINT_PACKAGE(snap)
- if (options->combined)
- {
- FF_PRINT_PACKAGE_ALL(brew);
- }
- else
- {
- FF_PRINT_PACKAGE_NAME(brew, "brew")
- FF_PRINT_PACKAGE_NAME(brewCask, "brew-cask")
- }
- FF_PRINT_PACKAGE(macports)
- if (options->combined)
- {
- FF_PRINT_PACKAGE_ALL(scoop);
- }
- else
- {
- FF_PRINT_PACKAGE_NAME(scoopUser, counts.scoopGlobal ? "scoop-user" : "scoop")
- FF_PRINT_PACKAGE_NAME(scoopGlobal, "scoop-global")
- }
- FF_PRINT_PACKAGE(choco)
- FF_PRINT_PACKAGE(pkgtool)
- FF_PRINT_PACKAGE(paludis)
- FF_PRINT_PACKAGE(winget)
- FF_PRINT_PACKAGE(opkg)
- if (options->combined)
- {
- FF_PRINT_PACKAGE_ALL(am);
- }
- else
- {
- FF_PRINT_PACKAGE_NAME(amSystem, "am")
- FF_PRINT_PACKAGE_NAME(amUser, "appman")
- }
- FF_PRINT_PACKAGE(sorcery)
- FF_PRINT_PACKAGE(lpkg)
- FF_PRINT_PACKAGE(lpkgbuild)
- if (options->combined)
- {
- FF_PRINT_PACKAGE_ALL(guix);
- }
- else
- {
- FF_PRINT_PACKAGE_NAME(guixSystem, "guix-system")
- FF_PRINT_PACKAGE_NAME(guixUser, "guix-user")
- FF_PRINT_PACKAGE_NAME(guixHome, "guix-home")
- }
- FF_PRINT_PACKAGE(linglong)
- FF_PRINT_PACKAGE(pacstall)
- FF_PRINT_PACKAGE(mport)
- FF_PRINT_PACKAGE(pisi)
- FF_PRINT_PACKAGE(soar)
-
- putchar('\n');
+ FF_PRINT_PACKAGE(apk)
+ FF_PRINT_PACKAGE(pkg)
+ FF_PRINT_PACKAGE(pkgsrc)
+ FF_PRINT_PACKAGE(kiss)
+ if (options->combined) {
+ FF_PRINT_PACKAGE_ALL(hpkg)
+ } else {
+ FF_PRINT_PACKAGE_NAME(hpkgSystem,
+ counts.hpkgUser ? "hpkg-system" : "hpkg")
+ FF_PRINT_PACKAGE_NAME(hpkgUser, "hpkg-user")
+ }
+ if (options->combined) {
+ FF_PRINT_PACKAGE_ALL(flatpak);
+ } else {
+ FF_PRINT_PACKAGE_NAME(flatpakSystem,
+ counts.flatpakUser ? "flatpak-system" : "flatpak")
+ FF_PRINT_PACKAGE_NAME(flatpakUser, "flatpak-user")
+ }
+ FF_PRINT_PACKAGE(snap)
+ if (options->combined) {
+ FF_PRINT_PACKAGE_ALL(brew);
+ } else {
+ FF_PRINT_PACKAGE_NAME(brew, "brew")
+ FF_PRINT_PACKAGE_NAME(brewCask, "brew-cask")
}
- else
- {
- FF_PRINT_FORMAT_CHECKED(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]){
+ FF_PRINT_PACKAGE(macports)
+ if (options->combined) {
+ FF_PRINT_PACKAGE_ALL(scoop);
+ } else {
+ FF_PRINT_PACKAGE_NAME(scoopUser,
+ counts.scoopGlobal ? "scoop-user" : "scoop")
+ FF_PRINT_PACKAGE_NAME(scoopGlobal, "scoop-global")
+ }
+ FF_PRINT_PACKAGE(choco)
+ FF_PRINT_PACKAGE(pkgtool)
+ FF_PRINT_PACKAGE(paludis)
+ FF_PRINT_PACKAGE(winget)
+ FF_PRINT_PACKAGE(opkg)
+ if (options->combined) {
+ FF_PRINT_PACKAGE_ALL(am);
+ } else {
+ FF_PRINT_PACKAGE_NAME(amSystem, "am")
+ FF_PRINT_PACKAGE_NAME(amUser, "appman")
+ }
+ FF_PRINT_PACKAGE(sorcery)
+ FF_PRINT_PACKAGE(lpkg)
+ FF_PRINT_PACKAGE(lpkgbuild)
+ if (options->combined) {
+ FF_PRINT_PACKAGE_ALL(guix);
+ } else {
+ FF_PRINT_PACKAGE_NAME(guixSystem, "guix-system")
+ FF_PRINT_PACKAGE_NAME(guixUser, "guix-user")
+ FF_PRINT_PACKAGE_NAME(guixHome, "guix-home")
+ }
+ FF_PRINT_PACKAGE(linglong)
+ FF_PRINT_PACKAGE(pacstall)
+ FF_PRINT_PACKAGE(mport)
+ FF_PRINT_PACKAGE(pisi)
+ FF_PRINT_PACKAGE(soar)
+
+ putchar('\n');
+ } else {
+ FF_PRINT_FORMAT_CHECKED(
+ FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT,
+ ((FFformatarg[]){
FF_FORMAT_ARG(counts.all, "all"),
FF_FORMAT_ARG(counts.pacman, "pacman"),
FF_FORMAT_ARG(counts.pacmanBranch, "pacman-branch"),
@@ -202,267 +182,304 @@ bool ffPrintPackages(FFPackagesOptions* options)
FF_FORMAT_ARG(guixAll, "guix-all"),
FF_FORMAT_ARG(hpkgAll, "hpkg-all"),
}));
- }
+ }
- ffStrbufDestroy(&counts.pacmanBranch);
+ ffStrbufDestroy(&counts.pacmanBranch);
- return true;
+ return true;
}
-void ffParsePackagesJsonObject(FFPackagesOptions* options, yyjson_val* module)
-{
- yyjson_val *key, *val;
- size_t idx, max;
- yyjson_obj_foreach(module, idx, max, key, val)
- {
- if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
- continue;
-
- if (unsafe_yyjson_equals_str(key, "disabled"))
- {
- if (!yyjson_is_null(val) && !yyjson_is_arr(val))
- {
- ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Invalid JSON value for %s", unsafe_yyjson_get_str(key));
- continue;
- }
-
- options->disabled = FF_PACKAGES_FLAG_NONE;
-
- if (yyjson_is_arr(val))
- {
- yyjson_val* flagObj;
- size_t flagIdx, flagMax;
- yyjson_arr_foreach(val, flagIdx, flagMax, flagObj)
- {
- if (!yyjson_is_str(flagObj))
- {
- ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Invalid JSON value for %s", unsafe_yyjson_get_str(key));
- continue;
- }
- const char* flag = unsafe_yyjson_get_str(flagObj);
-
- #define FF_TEST_PACKAGE_NAME(name) else if (ffStrEqualsIgnCase(flag, #name)) { options->disabled |= FF_PACKAGES_FLAG_ ## name ## _BIT; }
- switch (toupper(flag[0]))
- {
- case 'A': if (false);
- FF_TEST_PACKAGE_NAME(APK)
- FF_TEST_PACKAGE_NAME(AM)
- break;
- case 'B': if (false);
- FF_TEST_PACKAGE_NAME(BREW)
- break;
- case 'C': if (false);
- FF_TEST_PACKAGE_NAME(CHOCO)
- break;
- case 'D': if (false);
- FF_TEST_PACKAGE_NAME(DPKG)
- break;
- case 'E': if (false);
- FF_TEST_PACKAGE_NAME(EMERGE)
- FF_TEST_PACKAGE_NAME(EOPKG)
- break;
- case 'F': if (false);
- FF_TEST_PACKAGE_NAME(FLATPAK)
- break;
- case 'G': if (false);
- FF_TEST_PACKAGE_NAME(GUIX)
- break;
- case 'H': if (false);
- FF_TEST_PACKAGE_NAME(HPKG)
- break;
- case 'K': if (false);
- FF_TEST_PACKAGE_NAME(KISS)
- break;
- case 'L': if (false);
- FF_TEST_PACKAGE_NAME(LPKG)
- FF_TEST_PACKAGE_NAME(LPKGBUILD)
- FF_TEST_PACKAGE_NAME(LINGLONG)
- break;
- case 'M': if (false);
- FF_TEST_PACKAGE_NAME(MACPORTS)
- FF_TEST_PACKAGE_NAME(MPORT)
- break;
- case 'N': if (false);
- FF_TEST_PACKAGE_NAME(NIX)
- break;
- case 'O': if (false);
- FF_TEST_PACKAGE_NAME(OPKG)
- break;
- case 'P': if (false);
- FF_TEST_PACKAGE_NAME(PACMAN)
- FF_TEST_PACKAGE_NAME(PACSTALL)
- FF_TEST_PACKAGE_NAME(PALUDIS)
- FF_TEST_PACKAGE_NAME(PISI)
- FF_TEST_PACKAGE_NAME(PKG)
- FF_TEST_PACKAGE_NAME(PKGTOOL)
- FF_TEST_PACKAGE_NAME(PKGSRC)
- break;
- case 'R': if (false);
- FF_TEST_PACKAGE_NAME(RPM)
- break;
- case 'S': if (false);
- FF_TEST_PACKAGE_NAME(SCOOP)
- FF_TEST_PACKAGE_NAME(SNAP)
- FF_TEST_PACKAGE_NAME(SOAR)
- FF_TEST_PACKAGE_NAME(SORCERY)
- break;
- case 'W': if (false);
- FF_TEST_PACKAGE_NAME(WINGET)
- break;
- case 'X': if (false);
- FF_TEST_PACKAGE_NAME(XBPS)
- break;
- }
- #undef FF_TEST_PACKAGE_NAME
- }
- continue;
- }
- }
-
- if (unsafe_yyjson_equals_str(key, "combined"))
- {
- options->combined = yyjson_get_bool(val);
+void ffParsePackagesJsonObject(FFPackagesOptions *options, yyjson_val *module) {
+ yyjson_val *key, *val;
+ size_t idx, max;
+ yyjson_obj_foreach(module, idx, max, key, val) {
+ if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
+ continue;
+
+ if (unsafe_yyjson_equals_str(key, "disabled")) {
+ if (!yyjson_is_null(val) && !yyjson_is_arr(val)) {
+ ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs,
+ FF_PRINT_TYPE_DEFAULT, "Invalid JSON value for %s",
+ unsafe_yyjson_get_str(key));
+ continue;
+ }
+
+ options->disabled = FF_PACKAGES_FLAG_NONE;
+
+ if (yyjson_is_arr(val)) {
+ yyjson_val *flagObj;
+ size_t flagIdx, flagMax;
+ yyjson_arr_foreach(val, flagIdx, flagMax, flagObj) {
+ if (!yyjson_is_str(flagObj)) {
+ ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs,
+ FF_PRINT_TYPE_DEFAULT, "Invalid JSON value for %s",
+ unsafe_yyjson_get_str(key));
continue;
+ }
+ const char *flag = unsafe_yyjson_get_str(flagObj);
+
+#define FF_TEST_PACKAGE_NAME(name) \
+ else if (ffStrEqualsIgnCase(flag, #name)) { \
+ options->disabled |= FF_PACKAGES_FLAG_##name##_BIT; \
+ }
+ switch (toupper(flag[0])) {
+ case 'A':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(APK)
+ FF_TEST_PACKAGE_NAME(AM)
+ break;
+ case 'B':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(BREW)
+ break;
+ case 'C':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(CHOCO)
+ break;
+ case 'D':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(DPKG)
+ break;
+ case 'E':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(EMERGE)
+ FF_TEST_PACKAGE_NAME(EOPKG)
+ break;
+ case 'F':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(FLATPAK)
+ break;
+ case 'G':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(GUIX)
+ break;
+ case 'H':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(HPKG)
+ break;
+ case 'K':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(KISS)
+ break;
+ case 'L':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(LPKG)
+ FF_TEST_PACKAGE_NAME(LPKGBUILD)
+ FF_TEST_PACKAGE_NAME(LINGLONG)
+ break;
+ case 'M':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(MACPORTS)
+ FF_TEST_PACKAGE_NAME(MPORT)
+ break;
+ case 'N':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(NIX)
+ break;
+ case 'O':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(OPKG)
+ break;
+ case 'P':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(PACMAN)
+ FF_TEST_PACKAGE_NAME(PACSTALL)
+ FF_TEST_PACKAGE_NAME(PALUDIS)
+ FF_TEST_PACKAGE_NAME(PISI)
+ FF_TEST_PACKAGE_NAME(PKG)
+ FF_TEST_PACKAGE_NAME(PKGTOOL)
+ FF_TEST_PACKAGE_NAME(PKGSRC)
+ break;
+ case 'R':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(RPM)
+ break;
+ case 'S':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(SCOOP)
+ FF_TEST_PACKAGE_NAME(SNAP)
+ FF_TEST_PACKAGE_NAME(SOAR)
+ FF_TEST_PACKAGE_NAME(SORCERY)
+ break;
+ case 'W':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(WINGET)
+ break;
+ case 'X':
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(XBPS)
+ break;
+ }
+#undef FF_TEST_PACKAGE_NAME
}
-
- ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
+ continue;
+ }
}
-}
-
-void ffGeneratePackagesJsonConfig(FFPackagesOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
-{
- ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
- FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
- yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "disabled");
- #define FF_TEST_PACKAGE_NAME(name) else if ((options->disabled & FF_PACKAGES_FLAG_ ## name ## _BIT)) { \
- ffStrbufSetS(&buf, #name); \
- ffStrbufLowerCase(&buf); \
- yyjson_mut_arr_add_strbuf(doc, arr, &buf); \
+ if (unsafe_yyjson_equals_str(key, "combined")) {
+ options->combined = yyjson_get_bool(val);
+ continue;
}
- if (false);
- FF_TEST_PACKAGE_NAME(AM)
- FF_TEST_PACKAGE_NAME(APK)
- FF_TEST_PACKAGE_NAME(BREW)
- FF_TEST_PACKAGE_NAME(CHOCO)
- FF_TEST_PACKAGE_NAME(DPKG)
- FF_TEST_PACKAGE_NAME(EMERGE)
- FF_TEST_PACKAGE_NAME(EOPKG)
- FF_TEST_PACKAGE_NAME(FLATPAK)
- FF_TEST_PACKAGE_NAME(GUIX)
- FF_TEST_PACKAGE_NAME(HPKG)
- FF_TEST_PACKAGE_NAME(KISS)
- FF_TEST_PACKAGE_NAME(LINGLONG)
- FF_TEST_PACKAGE_NAME(LPKG)
- FF_TEST_PACKAGE_NAME(LPKGBUILD)
- FF_TEST_PACKAGE_NAME(MACPORTS)
- FF_TEST_PACKAGE_NAME(MPORT)
- FF_TEST_PACKAGE_NAME(NIX)
- FF_TEST_PACKAGE_NAME(OPKG)
- FF_TEST_PACKAGE_NAME(PACMAN)
- FF_TEST_PACKAGE_NAME(PACSTALL)
- FF_TEST_PACKAGE_NAME(PALUDIS)
- FF_TEST_PACKAGE_NAME(PISI)
- FF_TEST_PACKAGE_NAME(PKG)
- FF_TEST_PACKAGE_NAME(PKGTOOL)
- FF_TEST_PACKAGE_NAME(PKGSRC)
- FF_TEST_PACKAGE_NAME(RPM)
- FF_TEST_PACKAGE_NAME(SCOOP)
- FF_TEST_PACKAGE_NAME(SNAP)
- FF_TEST_PACKAGE_NAME(SOAR)
- FF_TEST_PACKAGE_NAME(SORCERY)
- FF_TEST_PACKAGE_NAME(WINGET)
- FF_TEST_PACKAGE_NAME(XBPS)
- #undef FF_TEST_PACKAGE_NAME
-
- yyjson_mut_obj_add_bool(doc, module, "combined", options->combined);
-}
-
-bool ffGeneratePackagesJsonResult(FF_MAYBE_UNUSED FFPackagesOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
-{
- FFPackagesResult counts = {};
- ffStrbufInit(&counts.pacmanBranch);
- const char* error = ffDetectPackages(&counts, options);
+ ffPrintError(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs,
+ FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s",
+ unsafe_yyjson_get_str(key));
+ }
+}
- if(error)
- {
- yyjson_mut_obj_add_str(doc, module, "error", error);
- return false;
- }
+void ffGeneratePackagesJsonConfig(FFPackagesOptions *options,
+ yyjson_mut_doc *doc, yyjson_mut_val *module) {
+ ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
+
+ FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
+ yyjson_mut_val *arr = yyjson_mut_obj_add_arr(doc, module, "disabled");
+#define FF_TEST_PACKAGE_NAME(name) \
+ else if ((options->disabled & FF_PACKAGES_FLAG_##name##_BIT)) { \
+ ffStrbufSetS(&buf, #name); \
+ ffStrbufLowerCase(&buf); \
+ yyjson_mut_arr_add_strbuf(doc, arr, &buf); \
+ }
+ if (false)
+ ;
+ FF_TEST_PACKAGE_NAME(AM)
+ FF_TEST_PACKAGE_NAME(APK)
+ FF_TEST_PACKAGE_NAME(BREW)
+ FF_TEST_PACKAGE_NAME(CHOCO)
+ FF_TEST_PACKAGE_NAME(DPKG)
+ FF_TEST_PACKAGE_NAME(EMERGE)
+ FF_TEST_PACKAGE_NAME(EOPKG)
+ FF_TEST_PACKAGE_NAME(FLATPAK)
+ FF_TEST_PACKAGE_NAME(GUIX)
+ FF_TEST_PACKAGE_NAME(HPKG)
+ FF_TEST_PACKAGE_NAME(KISS)
+ FF_TEST_PACKAGE_NAME(LINGLONG)
+ FF_TEST_PACKAGE_NAME(LPKG)
+ FF_TEST_PACKAGE_NAME(LPKGBUILD)
+ FF_TEST_PACKAGE_NAME(MACPORTS)
+ FF_TEST_PACKAGE_NAME(MPORT)
+ FF_TEST_PACKAGE_NAME(NIX)
+ FF_TEST_PACKAGE_NAME(OPKG)
+ FF_TEST_PACKAGE_NAME(PACMAN)
+ FF_TEST_PACKAGE_NAME(PACSTALL)
+ FF_TEST_PACKAGE_NAME(PALUDIS)
+ FF_TEST_PACKAGE_NAME(PISI)
+ FF_TEST_PACKAGE_NAME(PKG)
+ FF_TEST_PACKAGE_NAME(PKGTOOL)
+ FF_TEST_PACKAGE_NAME(PKGSRC)
+ FF_TEST_PACKAGE_NAME(RPM)
+ FF_TEST_PACKAGE_NAME(SCOOP)
+ FF_TEST_PACKAGE_NAME(SNAP)
+ FF_TEST_PACKAGE_NAME(SOAR)
+ FF_TEST_PACKAGE_NAME(SORCERY)
+ FF_TEST_PACKAGE_NAME(WINGET)
+ FF_TEST_PACKAGE_NAME(XBPS)
+#undef FF_TEST_PACKAGE_NAME
+
+ yyjson_mut_obj_add_bool(doc, module, "combined", options->combined);
+}
- yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result");
-
- #define FF_APPEND_PACKAGE_COUNT(name) yyjson_mut_obj_add_uint(doc, obj, #name, counts.name);
-
- FF_APPEND_PACKAGE_COUNT(all)
- FF_APPEND_PACKAGE_COUNT(amSystem)
- FF_APPEND_PACKAGE_COUNT(amUser)
- FF_APPEND_PACKAGE_COUNT(apk)
- FF_APPEND_PACKAGE_COUNT(brew)
- FF_APPEND_PACKAGE_COUNT(brewCask)
- FF_APPEND_PACKAGE_COUNT(choco)
- FF_APPEND_PACKAGE_COUNT(dpkg)
- FF_APPEND_PACKAGE_COUNT(emerge)
- FF_APPEND_PACKAGE_COUNT(eopkg)
- FF_APPEND_PACKAGE_COUNT(flatpakSystem)
- FF_APPEND_PACKAGE_COUNT(flatpakUser)
- FF_APPEND_PACKAGE_COUNT(guixSystem)
- FF_APPEND_PACKAGE_COUNT(guixUser)
- FF_APPEND_PACKAGE_COUNT(guixHome)
- FF_APPEND_PACKAGE_COUNT(hpkgSystem)
- FF_APPEND_PACKAGE_COUNT(hpkgUser)
- FF_APPEND_PACKAGE_COUNT(linglong)
- FF_APPEND_PACKAGE_COUNT(mport)
- FF_APPEND_PACKAGE_COUNT(nixDefault)
- FF_APPEND_PACKAGE_COUNT(nixSystem)
- FF_APPEND_PACKAGE_COUNT(nixUser)
- FF_APPEND_PACKAGE_COUNT(opkg)
- FF_APPEND_PACKAGE_COUNT(pacman)
- FF_APPEND_PACKAGE_COUNT(pacstall)
- FF_APPEND_PACKAGE_COUNT(paludis)
- FF_APPEND_PACKAGE_COUNT(pisi)
- FF_APPEND_PACKAGE_COUNT(pkg)
- FF_APPEND_PACKAGE_COUNT(pkgtool)
- FF_APPEND_PACKAGE_COUNT(pkgsrc)
- FF_APPEND_PACKAGE_COUNT(macports)
- FF_APPEND_PACKAGE_COUNT(rpm)
- FF_APPEND_PACKAGE_COUNT(scoopUser)
- FF_APPEND_PACKAGE_COUNT(scoopGlobal)
- FF_APPEND_PACKAGE_COUNT(snap)
- FF_APPEND_PACKAGE_COUNT(soar)
- FF_APPEND_PACKAGE_COUNT(kiss)
- FF_APPEND_PACKAGE_COUNT(sorcery)
- FF_APPEND_PACKAGE_COUNT(winget)
- FF_APPEND_PACKAGE_COUNT(xbps)
- yyjson_mut_obj_add_strbuf(doc, obj, "pacmanBranch", &counts.pacmanBranch);
-
- return true;
+bool ffGeneratePackagesJsonResult(FF_MAYBE_UNUSED FFPackagesOptions *options,
+ yyjson_mut_doc *doc, yyjson_mut_val *module) {
+ FFPackagesResult counts = {};
+ ffStrbufInit(&counts.pacmanBranch);
+
+ const char *error = ffDetectPackages(&counts, options);
+
+ if (error) {
+ yyjson_mut_obj_add_str(doc, module, "error", error);
+ return false;
+ }
+
+ yyjson_mut_val *obj = yyjson_mut_obj_add_obj(doc, module, "result");
+
+#define FF_APPEND_PACKAGE_COUNT(name) \
+ yyjson_mut_obj_add_uint(doc, obj, #name, counts.name);
+
+ FF_APPEND_PACKAGE_COUNT(all)
+ FF_APPEND_PACKAGE_COUNT(amSystem)
+ FF_APPEND_PACKAGE_COUNT(amUser)
+ FF_APPEND_PACKAGE_COUNT(apk)
+ FF_APPEND_PACKAGE_COUNT(brew)
+ FF_APPEND_PACKAGE_COUNT(brewCask)
+ FF_APPEND_PACKAGE_COUNT(choco)
+ FF_APPEND_PACKAGE_COUNT(dpkg)
+ FF_APPEND_PACKAGE_COUNT(emerge)
+ FF_APPEND_PACKAGE_COUNT(eopkg)
+ FF_APPEND_PACKAGE_COUNT(flatpakSystem)
+ FF_APPEND_PACKAGE_COUNT(flatpakUser)
+ FF_APPEND_PACKAGE_COUNT(guixSystem)
+ FF_APPEND_PACKAGE_COUNT(guixUser)
+ FF_APPEND_PACKAGE_COUNT(guixHome)
+ FF_APPEND_PACKAGE_COUNT(hpkgSystem)
+ FF_APPEND_PACKAGE_COUNT(hpkgUser)
+ FF_APPEND_PACKAGE_COUNT(linglong)
+ FF_APPEND_PACKAGE_COUNT(mport)
+ FF_APPEND_PACKAGE_COUNT(nixDefault)
+ FF_APPEND_PACKAGE_COUNT(nixSystem)
+ FF_APPEND_PACKAGE_COUNT(nixUser)
+ FF_APPEND_PACKAGE_COUNT(opkg)
+ FF_APPEND_PACKAGE_COUNT(pacman)
+ FF_APPEND_PACKAGE_COUNT(pacstall)
+ FF_APPEND_PACKAGE_COUNT(paludis)
+ FF_APPEND_PACKAGE_COUNT(pisi)
+ FF_APPEND_PACKAGE_COUNT(pkg)
+ FF_APPEND_PACKAGE_COUNT(pkgtool)
+ FF_APPEND_PACKAGE_COUNT(pkgsrc)
+ FF_APPEND_PACKAGE_COUNT(macports)
+ FF_APPEND_PACKAGE_COUNT(rpm)
+ FF_APPEND_PACKAGE_COUNT(scoopUser)
+ FF_APPEND_PACKAGE_COUNT(scoopGlobal)
+ FF_APPEND_PACKAGE_COUNT(snap)
+ FF_APPEND_PACKAGE_COUNT(soar)
+ FF_APPEND_PACKAGE_COUNT(kiss)
+ FF_APPEND_PACKAGE_COUNT(sorcery)
+ FF_APPEND_PACKAGE_COUNT(winget)
+ FF_APPEND_PACKAGE_COUNT(xbps)
+ yyjson_mut_obj_add_strbuf(doc, obj, "pacmanBranch", &counts.pacmanBranch);
+
+ return true;
}
-void ffInitPackagesOptions(FFPackagesOptions* options)
-{
- ffOptionInitModuleArg(&options->moduleArgs, "");
+void ffInitPackagesOptions(FFPackagesOptions *options) {
+ ffOptionInitModuleArg(&options->moduleArgs, "");
- options->disabled = FF_PACKAGES_DISABLE_LIST;
- options->combined = false;
+ options->disabled = FF_PACKAGES_DISABLE_LIST;
+ options->combined = false;
}
-void ffDestroyPackagesOptions(FFPackagesOptions* options)
-{
- ffOptionDestroyModuleArg(&options->moduleArgs);
+void ffDestroyPackagesOptions(FFPackagesOptions *options) {
+ ffOptionDestroyModuleArg(&options->moduleArgs);
}
FFModuleBaseInfo ffPackagesModuleInfo = {
.name = FF_PACKAGES_MODULE_NAME,
- .description = "List installed package managers and count of installed packages",
- .initOptions = (void*) ffInitPackagesOptions,
- .destroyOptions = (void*) ffDestroyPackagesOptions,
- .parseJsonObject = (void*) ffParsePackagesJsonObject,
- .printModule = (void*) ffPrintPackages,
- .generateJsonResult = (void*) ffGeneratePackagesJsonResult,
- .generateJsonConfig = (void*) ffGeneratePackagesJsonConfig,
- .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
+ .description =
+ "List installed package managers and count of installed packages",
+ .initOptions = (void *)ffInitPackagesOptions,
+ .destroyOptions = (void *)ffDestroyPackagesOptions,
+ .parseJsonObject = (void *)ffParsePackagesJsonObject,
+ .printModule = (void *)ffPrintPackages,
+ .generateJsonResult = (void *)ffGeneratePackagesJsonResult,
+ .generateJsonConfig = (void *)ffGeneratePackagesJsonConfig,
+ .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]){
{"Number of all packages", "all"},
{"Number of pacman packages", "pacman"},
{"Pacman branch on manjaro", "pacman-branch"},
@@ -511,5 +528,4 @@ FFModuleBaseInfo ffPackagesModuleInfo = {
{"Total number of all brew packages", "brew-all"},
{"Total number of all guix packages", "guix-all"},
{"Total number of all hpkg packages", "hpkg-all"},
- }))
-};
+ }))};