mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
1178 lines
40 KiB
C
1178 lines
40 KiB
C
#include "fastfetch.h"
|
|
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
|
|
// Things only needed by fastfetch
|
|
typedef struct FFdata
|
|
{
|
|
FFvaluestore valuestore;
|
|
FFstrbuf structure;
|
|
bool multithreading;
|
|
} FFdata;
|
|
|
|
static void constructAndPrintCommandHelpFormat(const char* name, const char* def, uint32_t numArgs, ...)
|
|
{
|
|
va_list argp;
|
|
va_start(argp, numArgs);
|
|
|
|
printf("--%s-format:\n", name);
|
|
printf("Sets the format string for %s output.\n", name);
|
|
puts("To see how a format string is constructed, take a look at \"fastfetch --help format\".");
|
|
puts("The following values are passed:");
|
|
|
|
for(uint32_t i = 1; i <= numArgs; i++)
|
|
printf(" {%u}: %s\n", i, va_arg(argp, const char*));
|
|
|
|
printf("The default is something like \"%s\".\n", def);
|
|
|
|
va_end(argp);
|
|
}
|
|
|
|
static inline void printCommandHelp(const char* command)
|
|
{
|
|
if(command == NULL)
|
|
fputs(FASTFETCH_DATATEXT_HELP, stdout);
|
|
else if(strcasecmp(command, "c") == 0 || strcasecmp(command, "color") == 0)
|
|
fputs(FASTFETCH_DATATEXT_HELP_COLOR, stdout);
|
|
else if(strcasecmp(command, "format") == 0)
|
|
fputs(FASTFETCH_DATATEXT_HELP_FORMAT, stdout);
|
|
else if(strcasecmp(command, "load-config") == 0 || strcasecmp(command, "loadconfig") == 0 || strcasecmp(command, "config") == 0)
|
|
fputs(FASTFETCH_DATATEXT_HELP_CONFIG, stdout);
|
|
else if(strcasecmp(command, "os-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("os", "{3} {12}", 12,
|
|
"System name (typically just Linux)",
|
|
"Name of the OS",
|
|
"Pretty name of the OS",
|
|
"ID of the OS",
|
|
"ID like of the OS",
|
|
"Variant of the OS",
|
|
"Variant ID of the OS",
|
|
"Version of the OS",
|
|
"Version ID of the OS",
|
|
"Version codename of the OS",
|
|
"Build ID of the OS",
|
|
"Architecture of the OS"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "host-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("host", "{2} {3}", 3,
|
|
"Host family",
|
|
"Host name",
|
|
"Host version"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "kernel-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("kernel", "{2}", 3,
|
|
"Kernel sysname",
|
|
"Kernel release",
|
|
"Kernel version"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "uptime-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("uptime", "{} days {} hours {} mins", 4,
|
|
"Days",
|
|
"Hours",
|
|
"Minutes",
|
|
"Seconds"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "processes-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("processes", "{}", 1,
|
|
"Count"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "packages-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("packages", "{2} (pacman){?3}[{3}]{?}, {4} (dpkg), {5} (rpm), {6} (emerge), {7} (xps), {8}, (flatpak), {9} (snap)", 9,
|
|
"Number of all packages",
|
|
"Number of pacman packages",
|
|
"Pacman branch on manjaro",
|
|
"Number of dpkg packages",
|
|
"Number of rpm packages",
|
|
"Number of emerge packages",
|
|
"Number of xbps packages",
|
|
"Number of flatpak packages",
|
|
"Number of snap packages"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "shell-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("shell", "{3} {4}", 7,
|
|
"Shell process name",
|
|
"Shell path with exe name",
|
|
"Shell exe name",
|
|
"Shell version",
|
|
"User shell path with exe name",
|
|
"User shell exe name",
|
|
"User shell version"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "resolution-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("resolution", "{}x{} @ {}Hz", 3,
|
|
"Screen width",
|
|
"Screen height",
|
|
"Screen refresh rate"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "de-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("de", "{2} {3}", 3,
|
|
"DE process name",
|
|
"DE pretty name",
|
|
"DE version"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "wm-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("wm", "{2} ({3})", 3,
|
|
"WM process name",
|
|
"WM pretty name",
|
|
"WM protocol name"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "wm-theme-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("wm-theme", "{}", 1,
|
|
"WM theme name"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "theme-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("theme", "{} ({3}) [Plasma], {7}", 7,
|
|
"Plasma theme",
|
|
"Plasma color scheme",
|
|
"Plasma color scheme pretty",
|
|
"GTK2 theme",
|
|
"GTK3 theme",
|
|
"GTK4 theme",
|
|
"Combined GTK themes"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "icons-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("icons", "{} [Plasma], {5}", 5,
|
|
"Plasma icons",
|
|
"GTK2 icons",
|
|
"GTK3 icons",
|
|
"GTK4 icons",
|
|
"Combined GTK icons"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "font-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("font", "{5} [Plasma], {21}", 21,
|
|
"Plasma raw",
|
|
"Plasma name",
|
|
"Plasma size",
|
|
"Plasma styles",
|
|
"Plasma pretty",
|
|
"GTK2 raw",
|
|
"GTK2 name",
|
|
"GTK2 size",
|
|
"GTK2 styles",
|
|
"GTK2 pretty",
|
|
"GTK3 raw",
|
|
"GTK3 name",
|
|
"GTK3 size",
|
|
"GTK3 styles",
|
|
"GTK3 pretty",
|
|
"GTK4 raw",
|
|
"GTK4 name",
|
|
"GTK4 size",
|
|
"GTK4 styles",
|
|
"GTK4 pretty",
|
|
"GTK2/3/4 pretty"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "cursor-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("cursor", "{} ({}pt)", 2,
|
|
"Cursor theme",
|
|
"Cursor size"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "terminal-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("terminal", "{3}", 3,
|
|
"Terminal process name",
|
|
"Terminal path with exe name",
|
|
"Terminal exe name"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "terminal-font-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("terminal-font", "{5}", 5,
|
|
"Terminal font raw",
|
|
"Terminal font name",
|
|
"Termianl font size",
|
|
"Terminal font styles"
|
|
"Terminal font pretty"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "cpu-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("cpu", "{2} ({7}) @ {14}GHz", 14,
|
|
"CPU name",
|
|
"Prettified CPU name",
|
|
"CPU Vendor name (Vendor ID)",
|
|
"CPU logical core count online",
|
|
"CPU logical core count configured",
|
|
"CPU physical core count",
|
|
"Always set core count",
|
|
"frequency bios limit",
|
|
"frequency scaling max",
|
|
"frequency scaling min",
|
|
"frequency info max",
|
|
"frequency info min",
|
|
"frequeny from /proc/cpuinfo",
|
|
"most accurate frequeny"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "cpu-usage-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("cpu-usage", "{0}%", 1,
|
|
"CPU usage without percent mark"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "gpu-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("gpu", "{2} {4}", 5,
|
|
"GPU vendor",
|
|
"GPU vendor pretty",
|
|
"GPU name",
|
|
"GPU name pretty",
|
|
"GPU driver"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "memory-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("memory", "{}MiB / {}MiB ({}%)", 3,
|
|
"Used memory",
|
|
"Total memory",
|
|
"Used memory percentage"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "disk-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("disk", "{}GB / {}GB ({4}%)", 4,
|
|
"Used disk space",
|
|
"Total disk space",
|
|
"Number of files",
|
|
"Used disk space percentage"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "battery-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("battery", "{}%, {}", 5,
|
|
"Battery manufactor",
|
|
"Battery model",
|
|
"Battery technology",
|
|
"Battery capacity",
|
|
"Battery status"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "locale-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("locale", "{}", 1,
|
|
"Locale code"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "local-ip-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("local-ip", "{}", 1,
|
|
"Local IP address"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "public-ip-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("public-ip", "{}", 1,
|
|
"Public IP address"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "player-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("player", "{}", 3,
|
|
"Pretty player name",
|
|
"Player name",
|
|
"DBus bus name"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "song-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("song", "{3} - {4} - {1}", 5,
|
|
"Song name pretty",
|
|
"Song name",
|
|
"Artist name",
|
|
"Album name",
|
|
"Song url"
|
|
);
|
|
}
|
|
else if(strcasecmp(command, "datetime-format") == 0 || strcasecmp(command, "date-format") == 0 || strcasecmp(command, "time-format") == 0)
|
|
{
|
|
constructAndPrintCommandHelpFormat("[date][time]", "{1}-{4}-{11} {14}:{18}:{20}", 20,
|
|
"year",
|
|
"last two digits of year",
|
|
"month",
|
|
"month with leading zero",
|
|
"month name",
|
|
"month name short",
|
|
"week number on year",
|
|
"weekday",
|
|
"weekday short",
|
|
"day in year",
|
|
"day in month",
|
|
"day in Week",
|
|
"hour",
|
|
"hout with leading zero",
|
|
"hour 12h format",
|
|
"hour 12h format with leading zero",
|
|
"minute",
|
|
"minute with leading zero",
|
|
"second",
|
|
"second with leading zero"
|
|
);
|
|
}
|
|
else
|
|
fprintf(stderr, "No specific help for command %s provided\n", command);
|
|
}
|
|
|
|
static inline void listAvailablePresetsFromFolder(FFstrbuf* folder, uint8_t indentation, const char* folderName)
|
|
{
|
|
DIR* dir = opendir(folder->chars);
|
|
if(dir == NULL)
|
|
return;
|
|
|
|
uint32_t folderLength = folder->length;
|
|
|
|
if(folderName != NULL)
|
|
printf("%s/\n", folderName);
|
|
|
|
struct dirent* entry;
|
|
|
|
while((entry = readdir(dir)) != NULL)
|
|
{
|
|
if(entry->d_type == DT_DIR)
|
|
{
|
|
|
|
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
|
continue;
|
|
|
|
ffStrbufAppendS(folder, entry->d_name);
|
|
ffStrbufAppendC(folder, '/');
|
|
listAvailablePresetsFromFolder(folder, (uint8_t) (indentation + 1), entry->d_name);
|
|
ffStrbufSubstrBefore(folder, folderLength);
|
|
continue;
|
|
}
|
|
|
|
for(uint8_t i = 0; i < indentation; i++)
|
|
fputs(" | ", stdout);
|
|
|
|
puts(entry->d_name);
|
|
}
|
|
|
|
closedir(dir);
|
|
}
|
|
|
|
static inline void listAvailablePresets(FFinstance* instance)
|
|
{
|
|
FFstrbuf folder;
|
|
ffStrbufInitA(&folder, 64);
|
|
|
|
ffStrbufSetS(&folder, instance->state.passwd->pw_dir);
|
|
ffStrbufAppendS(&folder, "/.local/share/fastfetch/presets/");
|
|
listAvailablePresetsFromFolder(&folder, 0, NULL);
|
|
|
|
ffStrbufSetS(&folder, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
|
|
listAvailablePresetsFromFolder(&folder, 0, NULL);
|
|
|
|
ffStrbufDestroy(&folder);
|
|
}
|
|
|
|
static void parseOption(FFinstance* instance, FFdata* data, const char* key, const char* value);
|
|
|
|
static void parseConfigFile(FFinstance* instance, FFdata* data, FILE* file)
|
|
{
|
|
char* lineStart = NULL;
|
|
size_t len = 0;
|
|
ssize_t read;
|
|
|
|
FFstrbuf line;
|
|
ffStrbufInitA(&line, 256); //The default structure line needs this size
|
|
|
|
while ((read = getline(&lineStart, &len, file)) != -1)
|
|
{
|
|
ffStrbufSetS(&line, lineStart);
|
|
ffStrbufTrimRight(&line, '\n');
|
|
ffStrbufTrim(&line, ' ');
|
|
|
|
if(line.length == 0 || line.chars[0] == '#')
|
|
continue;
|
|
|
|
uint32_t firstSpace = ffStrbufFirstIndexC(&line, ' ');
|
|
|
|
if(firstSpace >= line.length)
|
|
{
|
|
parseOption(instance, data, line.chars, NULL);
|
|
continue;
|
|
}
|
|
|
|
//Separate key and value by simply replacing the first space with a \0
|
|
char* valueStart = &line.chars[firstSpace];
|
|
*valueStart = '\0';
|
|
++valueStart;
|
|
|
|
//Trim whitespace at beginning of value
|
|
while(*valueStart == ' ')
|
|
++valueStart;
|
|
|
|
//If we want whitespace in values, we need to quote it. This is done to keep consistency with shell.
|
|
if(*valueStart == '"')
|
|
{
|
|
char* last = line.chars + line.length - 1;
|
|
if(*last == '"')
|
|
{
|
|
++valueStart;
|
|
*last = '\0';
|
|
--line.length;
|
|
}
|
|
}
|
|
|
|
parseOption(instance, data, line.chars, valueStart);
|
|
}
|
|
|
|
ffStrbufDestroy(&line);
|
|
|
|
if(lineStart != NULL)
|
|
free(lineStart);
|
|
}
|
|
|
|
static void optionParseConfigFile(FFinstance* instance, FFdata* data, const char* key, const char* value)
|
|
{
|
|
if(value == NULL)
|
|
{
|
|
fprintf(stderr, "Error: usage: %s <file>\n", key);
|
|
exit(413);
|
|
}
|
|
|
|
FILE* file = fopen(value, "r");
|
|
if(file != NULL)
|
|
{
|
|
parseConfigFile(instance, data, file);
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
FFstrbuf filename;
|
|
ffStrbufInitA(&filename, 64);
|
|
|
|
ffStrbufAppendS(&filename, instance->state.passwd->pw_dir);
|
|
ffStrbufAppendS(&filename, "/.local/share/fastfetch/presets/");
|
|
ffStrbufAppendS(&filename, value);
|
|
|
|
file = fopen(filename.chars, "r");
|
|
if(file != NULL)
|
|
{
|
|
parseConfigFile(instance, data, file);
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
ffStrbufSetS(&filename, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
|
|
ffStrbufAppendS(&filename, value);
|
|
|
|
file = fopen(filename.chars, "r");
|
|
if(file != NULL)
|
|
{
|
|
parseConfigFile(instance, data, file);
|
|
fclose(file);
|
|
return;
|
|
}
|
|
|
|
fprintf(stderr, "Error: couldn't find config: %s\n", value);
|
|
exit(414);
|
|
}
|
|
|
|
static bool optionParseBoolean(const char* str)
|
|
{
|
|
return (
|
|
!ffStrSet(str) ||
|
|
strcasecmp(str, "true") == 0 ||
|
|
strcasecmp(str, "yes") == 0 ||
|
|
strcasecmp(str, "on") == 0 ||
|
|
strcasecmp(str, "1") == 0
|
|
);
|
|
}
|
|
|
|
static inline void optionCheckString(const char* key, const char* value, FFstrbuf* buffer)
|
|
{
|
|
if(value == NULL)
|
|
{
|
|
fprintf(stderr, "Error: usage: %s <str>\n", key);
|
|
exit(477);
|
|
}
|
|
ffStrbufEnsureFree(buffer, 63); //This is not needed, as ffStrbufSetS will resize capacity if needed, but giving a higher start should improve performance
|
|
}
|
|
|
|
static void optionParseString(const char* key, const char* value, FFstrbuf* buffer)
|
|
{
|
|
optionCheckString(key, value, buffer);
|
|
ffStrbufSetS(buffer, value);
|
|
}
|
|
|
|
static void optionParseColor(const char* key, const char* value, FFstrbuf* buffer)
|
|
{
|
|
optionCheckString(key, value, buffer);
|
|
|
|
static const char reset[] = "reset_";
|
|
static const char bright[] = "bright_";
|
|
|
|
static const char black[] = "black";
|
|
static const char red[] = "red";
|
|
static const char green[] = "green";
|
|
static const char yellow[] = "yellow";
|
|
static const char blue[] = "blue";
|
|
static const char magenta[] = "magenta";
|
|
static const char cyan[] = "cyan";
|
|
static const char white[] = "white";
|
|
|
|
while(*value != '\0')
|
|
{
|
|
if(strncasecmp(value, reset, sizeof(reset) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "0;");
|
|
value += sizeof(reset) - 1;
|
|
}
|
|
else if(strncasecmp(value, bright, sizeof(bright) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "1;");
|
|
value += sizeof(bright) - 1;
|
|
}
|
|
else if(strncasecmp(value, black, sizeof(black) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "30");
|
|
value += sizeof(black) - 1;
|
|
}
|
|
else if(strncasecmp(value, red, sizeof(red) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "31");
|
|
value += sizeof(red) - 1;
|
|
}
|
|
else if(strncasecmp(value, green, sizeof(green) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "32");
|
|
value += sizeof(green) - 1;
|
|
}
|
|
else if(strncasecmp(value, yellow, sizeof(yellow) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "33");
|
|
value += sizeof(yellow) - 1;
|
|
}
|
|
else if(strncasecmp(value, blue, sizeof(blue) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "34");
|
|
value += sizeof(blue) - 1;
|
|
}
|
|
else if(strncasecmp(value, magenta, sizeof(magenta) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "35");
|
|
value += sizeof(magenta) - 1;
|
|
}
|
|
else if(strncasecmp(value, cyan, sizeof(cyan) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "36");
|
|
value += sizeof(cyan) - 1;
|
|
}
|
|
else if(strncasecmp(value, white, sizeof(white) - 1) == 0)
|
|
{
|
|
ffStrbufAppendS(buffer, "37");
|
|
value += sizeof(white) - 1;
|
|
}
|
|
else
|
|
{
|
|
ffStrbufAppendC(buffer, *value);
|
|
++value;
|
|
}
|
|
}
|
|
}
|
|
|
|
static uint32_t optionParseUInt32(const char* key, const char* value)
|
|
{
|
|
if(value == NULL)
|
|
{
|
|
fprintf(stderr, "Error: usage: %s <num>\n", key);
|
|
exit(480);
|
|
}
|
|
|
|
char* end;
|
|
uint32_t num = (uint32_t) strtoul(value, &end, 10);
|
|
if(*end != '\0')
|
|
{
|
|
fprintf(stderr, "Error: usage: %s <num>\n", key);
|
|
exit(479);
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
static void parseOption(FFinstance* instance, FFdata* data, const char* key, const char* value)
|
|
{
|
|
///////////////////////
|
|
//Informative options//
|
|
///////////////////////
|
|
|
|
if(strcasecmp(key, "-h") == 0 || strcasecmp(key, "--help") == 0)
|
|
{
|
|
printCommandHelp(value);
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "-v") == 0 || strcasecmp(key, "--version") == 0)
|
|
{
|
|
puts("fastfetch "FASTFETCH_PROJECT_VERSION""FASTFETCH_PROJECT_VERSION_TWEAK);
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--version-raw") == 0)
|
|
{
|
|
puts(FASTFETCH_PROJECT_VERSION);
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--print-config") == 0)
|
|
{
|
|
fputs(FASTFETCH_DATATEXT_CONFIG, stdout);
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--print-structure") == 0)
|
|
{
|
|
puts(FASTFETCH_DATATEXT_STRUCTURE);
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--list-modules") == 0)
|
|
{
|
|
fputs(FASTFETCH_DATATEXT_MODULES, stdout);
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--list-presets") == 0)
|
|
{
|
|
listAvailablePresets(instance);
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--list-features") == 0)
|
|
{
|
|
ffListFeatures();
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--list-logos") == 0)
|
|
{
|
|
ffListBuiltinLogos();
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--list-logos-autocompletion") == 0)
|
|
{
|
|
ffListBuiltinLogosAutocompletion();
|
|
exit(0);
|
|
}
|
|
else if(strcasecmp(key, "--print-logos") == 0)
|
|
{
|
|
ffPrintBuiltinLogos(instance);
|
|
exit(0);
|
|
}
|
|
|
|
///////////////////
|
|
//General options//
|
|
///////////////////
|
|
|
|
else if(strcasecmp(key, "-r") == 0 || strcasecmp(key, "--recache") == 0)
|
|
{
|
|
//Set cacheSave as well, because the user expects the values to be cached when expliciting using --recache
|
|
instance->config.recache = optionParseBoolean(value);
|
|
instance->config.cacheSave = instance->config.recache;
|
|
}
|
|
else if(strcasecmp(key, "--nocache") == 0)
|
|
{
|
|
instance->config.recache = optionParseBoolean(value);
|
|
instance->config.cacheSave = false;
|
|
}
|
|
else if(strcasecmp(key, "--load-config") == 0)
|
|
optionParseConfigFile(instance, data, key, value);
|
|
else if(strcasecmp(key, "--multithreading") == 0)
|
|
data->multithreading = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "--allow-slow-operations") == 0)
|
|
instance->config.allowSlowOperations = optionParseBoolean(value);
|
|
|
|
////////////////
|
|
//Logo options//
|
|
////////////////
|
|
|
|
else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0)
|
|
optionParseString(key, value, &instance->config.logoName);
|
|
else if(strcasecmp(key, "--logo-type") == 0)
|
|
{
|
|
if(value == NULL)
|
|
{
|
|
fprintf(stderr, "Error: usage: %s <type>\n", key);
|
|
exit(476);
|
|
}
|
|
|
|
if(strcasecmp(value, "auto") == 0)
|
|
instance->config.logoType = FF_LOGO_TYPE_AUTO;
|
|
else if(strcasecmp(value, "builtin") == 0)
|
|
instance->config.logoType = FF_LOGO_TYPE_BUILTIN;
|
|
else if(strcasecmp(value, "file") == 0)
|
|
instance->config.logoType = FF_LOGO_TYPE_FILE;
|
|
else if(strcasecmp(value, "raw") == 0)
|
|
instance->config.logoType = FF_LOGO_TYPE_RAW;
|
|
else if(strcasecmp(value, "sixel") == 0)
|
|
instance->config.logoType = FF_LOGO_TYPE_SIXEL;
|
|
else
|
|
{
|
|
fprintf(stderr, "Error: unknown logo type: %s\n", value);
|
|
exit(478);
|
|
}
|
|
}
|
|
else if(strncasecmp(key, "--logo-color-", 13) == 0 && key[13] != '\0' && key[14] == '\0') // matches "--logo-color-*"
|
|
{
|
|
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
|
|
int index = (int)key[13] - 49;
|
|
|
|
//Match only --logo-color-[1-9]
|
|
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
|
|
{
|
|
fprintf(stderr, "Error: invalid --color-[1-9] index: %c\n", key[13]);
|
|
exit(472);
|
|
}
|
|
|
|
optionParseColor(key, value, &instance->config.logoColors[index]);
|
|
}
|
|
else if(strcasecmp(key, "--logo-width") == 0)
|
|
instance->config.logoWidth = optionParseUInt32(key, value);
|
|
else if(strcasecmp(key, "--logo-padding") == 0)
|
|
{
|
|
uint32_t padding = optionParseUInt32(key, value);
|
|
instance->config.logoPaddingLeft = padding;
|
|
instance->config.logoPaddingRight = padding;
|
|
}
|
|
else if(strcasecmp(key, "--logo-padding-left") == 0)
|
|
instance->config.logoPaddingLeft = optionParseUInt32(key, value);
|
|
else if(strcasecmp(key, "--logo-padding-right") == 0)
|
|
instance->config.logoPaddingRight = optionParseUInt32(key, value);
|
|
else if(strcasecmp(key, "--logo-print-remaining") == 0)
|
|
instance->config.logoPrintRemaining = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "--sixel") == 0)
|
|
{
|
|
optionParseString(key, value, &instance->config.logoName);
|
|
instance->config.logoType = FF_LOGO_TYPE_SIXEL;
|
|
}
|
|
|
|
///////////////////
|
|
//Display options//
|
|
///////////////////
|
|
|
|
else if(strcasecmp(key, "--show-errors") == 0)
|
|
instance->config.showErrors = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "--disable-linewrap") == 0)
|
|
instance->config.disableLinewrap = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "--hide-cursor") == 0)
|
|
instance->config.hideCursor = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "-s") == 0 || strcasecmp(key, "--structure") == 0)
|
|
optionParseString(key, value, &data->structure);
|
|
else if(strcasecmp(key, "--separator") == 0)
|
|
optionParseString(key, value, &instance->config.separator);
|
|
else if(strcasecmp(key, "-c") == 0 || strcasecmp(key, "--color") == 0)
|
|
optionParseColor(key, value, &instance->config.mainColor);
|
|
else if(strcasecmp(key, "--set") == 0)
|
|
{
|
|
if(value == NULL)
|
|
{
|
|
fprintf(stderr, "Error: usage: %s <key=value>\n", key);
|
|
exit(411);
|
|
}
|
|
|
|
char* separator = strchr(value, '=');
|
|
|
|
if(separator == NULL)
|
|
{
|
|
fprintf(stderr, "Error: usage: %s <key=value>, '=' missing\n", key);
|
|
exit(412);
|
|
}
|
|
|
|
*separator = '\0';
|
|
|
|
ffValuestoreSet(&data->valuestore, value, separator + 1);
|
|
}
|
|
|
|
////////////////////////
|
|
//Format + Key options//
|
|
////////////////////////
|
|
|
|
else if(strcasecmp(key, "--os-format") == 0)
|
|
optionParseString(key, value, &instance->config.osFormat);
|
|
else if(strcasecmp(key, "--os-key") == 0)
|
|
optionParseString(key, value, &instance->config.osKey);
|
|
else if(strcasecmp(key, "--host-format") == 0)
|
|
optionParseString(key, value, &instance->config.hostFormat);
|
|
else if(strcasecmp(key, "--host-key") == 0)
|
|
optionParseString(key, value, &instance->config.hostKey);
|
|
else if(strcasecmp(key, "--kernel-format") == 0)
|
|
optionParseString(key, value, &instance->config.kernelFormat);
|
|
else if(strcasecmp(key, "--kernel-key") == 0)
|
|
optionParseString(key, value, &instance->config.kernelKey);
|
|
else if(strcasecmp(key, "--uptime-format") == 0)
|
|
optionParseString(key, value, &instance->config.uptimeFormat);
|
|
else if(strcasecmp(key, "--uptime-key") == 0)
|
|
optionParseString(key, value, &instance->config.uptimeKey);
|
|
else if(strcasecmp(key, "--processes-format") == 0)
|
|
optionParseString(key, value, &instance->config.processesFormat);
|
|
else if(strcasecmp(key, "--processes-key") == 0)
|
|
optionParseString(key, value, &instance->config.processesKey);
|
|
else if(strcasecmp(key, "--packages-format") == 0)
|
|
optionParseString(key, value, &instance->config.packagesFormat);
|
|
else if(strcasecmp(key, "--packages-key") == 0)
|
|
optionParseString(key, value, &instance->config.packagesKey);
|
|
else if(strcasecmp(key, "--shell-format") == 0)
|
|
optionParseString(key, value, &instance->config.shellFormat);
|
|
else if(strcasecmp(key, "--shell-key") == 0)
|
|
optionParseString(key, value, &instance->config.shellKey);
|
|
else if(strcasecmp(key, "--resolution-format") == 0)
|
|
optionParseString(key, value, &instance->config.resolutionFormat);
|
|
else if(strcasecmp(key, "--resolution-key") == 0)
|
|
optionParseString(key, value, &instance->config.resolutionKey);
|
|
else if(strcasecmp(key, "--de-format") == 0)
|
|
optionParseString(key, value, &instance->config.deFormat);
|
|
else if(strcasecmp(key, "--de-key") == 0)
|
|
optionParseString(key, value, &instance->config.deKey);
|
|
else if(strcasecmp(key, "--wm-format") == 0)
|
|
optionParseString(key, value, &instance->config.wmFormat);
|
|
else if(strcasecmp(key, "--wm-key") == 0)
|
|
optionParseString(key, value, &instance->config.wmKey);
|
|
else if(strcasecmp(key, "--wm-theme-format") == 0)
|
|
optionParseString(key, value, &instance->config.wmThemeFormat);
|
|
else if(strcasecmp(key, "--wm-theme-key") == 0)
|
|
optionParseString(key, value, &instance->config.wmThemeKey);
|
|
else if(strcasecmp(key, "--theme-format") == 0)
|
|
optionParseString(key, value, &instance->config.themeFormat);
|
|
else if(strcasecmp(key, "--theme-key") == 0)
|
|
optionParseString(key, value, &instance->config.themeKey);
|
|
else if(strcasecmp(key, "--icons-format") == 0)
|
|
optionParseString(key, value, &instance->config.iconsFormat);
|
|
else if(strcasecmp(key, "--icons-key") == 0)
|
|
optionParseString(key, value, &instance->config.iconsKey);
|
|
else if(strcasecmp(key, "--font-format") == 0)
|
|
optionParseString(key, value, &instance->config.fontFormat);
|
|
else if(strcasecmp(key, "--font-key") == 0)
|
|
optionParseString(key, value, &instance->config.fontKey);
|
|
else if(strcasecmp(key, "--cursor-key") == 0)
|
|
optionParseString(key, value, &instance->config.cursorKey);
|
|
else if(strcasecmp(key, "--cursor-format") == 0)
|
|
optionParseString(key, value, &instance->config.cursorFormat);
|
|
else if(strcasecmp(key, "--terminal-format") == 0)
|
|
optionParseString(key, value, &instance->config.terminalFormat);
|
|
else if(strcasecmp(key, "--terminal-key") == 0)
|
|
optionParseString(key, value, &instance->config.terminalKey);
|
|
else if(strcasecmp(key, "--terminal-font-format") == 0)
|
|
optionParseString(key, value, &instance->config.termFontFormat);
|
|
else if(strcasecmp(key, "--terminal-font-key") == 0)
|
|
optionParseString(key, value, &instance->config.termFontKey);
|
|
else if(strcasecmp(key, "--cpu-format") == 0)
|
|
optionParseString(key, value, &instance->config.cpuFormat);
|
|
else if(strcasecmp(key, "--cpu-usage-format") == 0)
|
|
optionParseString(key, value, &instance->config.cpuUsageFormat);
|
|
else if(strcasecmp(key, "--cpu-key") == 0)
|
|
optionParseString(key, value, &instance->config.cpuKey);
|
|
else if(strcasecmp(key, "--cpu-usage-key") == 0)
|
|
optionParseString(key, value, &instance->config.cpuUsageKey);
|
|
else if(strcasecmp(key, "--gpu-format") == 0)
|
|
optionParseString(key, value, &instance->config.gpuFormat);
|
|
else if(strcasecmp(key, "--gpu-key") == 0)
|
|
optionParseString(key, value, &instance->config.gpuKey);
|
|
else if(strcasecmp(key, "--memory-format") == 0)
|
|
optionParseString(key, value, &instance->config.memoryFormat);
|
|
else if(strcasecmp(key, "--memory-key") == 0)
|
|
optionParseString(key, value, &instance->config.memoryKey);
|
|
else if(strcasecmp(key, "--disk-format") == 0)
|
|
optionParseString(key, value, &instance->config.diskFormat);
|
|
else if(strcasecmp(key, "--disk-key") == 0)
|
|
optionParseString(key, value, &instance->config.diskKey);
|
|
else if(strcasecmp(key, "--battery-format") == 0)
|
|
optionParseString(key, value, &instance->config.batteryFormat);
|
|
else if(strcasecmp(key, "--battery-key") == 0)
|
|
optionParseString(key, value, &instance->config.batteryKey);
|
|
else if(strcasecmp(key, "--locale-format") == 0)
|
|
optionParseString(key, value, &instance->config.localeFormat);
|
|
else if(strcasecmp(key, "--locale-key") == 0)
|
|
optionParseString(key, value, &instance->config.localeKey);
|
|
else if(strcasecmp(key, "--local-ip-key") == 0)
|
|
optionParseString(key, value, &instance->config.localIpKey);
|
|
else if(strcasecmp(key, "--local-ip-format") == 0)
|
|
optionParseString(key, value, &instance->config.localIpFormat);
|
|
else if(strcasecmp(key, "--public-ip-key") == 0)
|
|
optionParseString(key, value, &instance->config.publicIpKey);
|
|
else if(strcasecmp(key, "--public-ip-format") == 0)
|
|
optionParseString(key, value, &instance->config.publicIpFormat);
|
|
else if(strcasecmp(key, "--player-key") == 0)
|
|
optionParseString(key, value, &instance->config.playerKey);
|
|
else if(strcasecmp(key, "--player-format") == 0)
|
|
optionParseString(key, value, &instance->config.playerFormat);
|
|
else if(strcasecmp(key, "--song-key") == 0)
|
|
optionParseString(key, value, &instance->config.songKey);
|
|
else if(strcasecmp(key, "--song-format") == 0)
|
|
optionParseString(key, value, &instance->config.songFormat);
|
|
else if(strcasecmp(key, "--datetime-key") == 0)
|
|
optionParseString(key, value, &instance->config.dateTimeKey);
|
|
else if(strcasecmp(key, "--datetime-format") == 0)
|
|
optionParseString(key, value, &instance->config.dateTimeFormat);
|
|
else if(strcasecmp(key, "--date-key") == 0)
|
|
optionParseString(key, value, &instance->config.dateKey);
|
|
else if(strcasecmp(key, "--date-format") == 0)
|
|
optionParseString(key, value, &instance->config.dateFormat);
|
|
else if(strcasecmp(key, "--time-key") == 0)
|
|
optionParseString(key, value, &instance->config.timeKey);
|
|
else if(strcasecmp(key, "--time-format") == 0)
|
|
optionParseString(key, value, &instance->config.timeFormat);
|
|
|
|
///////////////////
|
|
//Library options//
|
|
///////////////////
|
|
|
|
else if(strcasecmp(key, "--lib-PCI") == 0)
|
|
optionParseString(key, value, &instance->config.libPCI);
|
|
else if(strcasecmp(key, "--lib-vulkan") == 0)
|
|
optionParseString(key, value, &instance->config.libVulkan);
|
|
else if(strcasecmp(key, "--lib-wayland") == 0)
|
|
optionParseString(key, value, &instance->config.libWayland);
|
|
else if(strcasecmp(key, "--lib-xcb-randr") == 0)
|
|
optionParseString(key, value, &instance->config.libXcbRandr);
|
|
else if(strcasecmp(key, "--lib-xcb") == 0)
|
|
optionParseString(key, value, &instance->config.libXcb);
|
|
else if(strcasecmp(key, "--lib-Xrandr") == 0)
|
|
optionParseString(key, value, &instance->config.libXrandr);
|
|
else if(strcasecmp(key, "--lib-X11") == 0)
|
|
optionParseString(key, value, &instance->config.libX11);
|
|
else if(strcasecmp(key, "--lib-gio") == 0)
|
|
optionParseString(key, value, &instance->config.libGIO);
|
|
else if(strcasecmp(key, "--lib-DConf") == 0)
|
|
optionParseString(key, value, &instance->config.libDConf);
|
|
else if(strcasecmp(key, "--lib-dbus") == 0)
|
|
optionParseString(key, value, &instance->config.libDBus);
|
|
else if(strcasecmp(key, "--lib-XFConf") == 0)
|
|
optionParseString(key, value, &instance->config.libXFConf);
|
|
else if(strcasecmp(key, "--lib-rpm") == 0)
|
|
optionParseString(key, value, &instance->config.librpm);
|
|
else if(strcasecmp(key, "--lib-imagemagick") == 0)
|
|
optionParseString(key, value, &instance->config.libImageMagick);
|
|
|
|
//////////////////
|
|
//Module options//
|
|
//////////////////
|
|
|
|
else if(strcasecmp(key, "--disk-folders") == 0)
|
|
optionParseString(key, value, &instance->config.diskFolders);
|
|
else if(strcasecmp(key, "--battery-dir") == 0)
|
|
optionParseString(key, value, &instance->config.batteryDir);
|
|
else if(strcasecmp(key, "--separator-string") == 0)
|
|
optionParseString(key, value, &instance->config.separatorString);
|
|
else if(strcasecmp(key, "--localip-show-ipv4") == 0)
|
|
instance->config.localIpShowIpV4 = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "--localip-show-ipv6") == 0)
|
|
instance->config.localIpShowIpV6 = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "--localip-show-loop") == 0)
|
|
instance->config.localIpShowLoop = optionParseBoolean(value);
|
|
else if(strcasecmp(key, "--os-file") == 0)
|
|
optionParseString(key, value, &instance->config.osFile);
|
|
else if(strcasecmp(key, "--player-name") == 0)
|
|
optionParseString(key, value, &instance->config.playerName);
|
|
else if(strcasecmp(key, "--public-ip-timeout") == 0)
|
|
instance->config.publicIpTimeout = optionParseUInt32(key, value);
|
|
|
|
//////////////////
|
|
//Unknown option//
|
|
//////////////////
|
|
|
|
else
|
|
{
|
|
fprintf(stderr, "Error: unknown option: %s\n", key);
|
|
exit(400);
|
|
}
|
|
}
|
|
|
|
static void parseDefaultConfigFile(FFinstance* instance, FFdata* data)
|
|
{
|
|
FFstrbuf* filename = ffListGet(&instance->state.configDirs, 0);
|
|
uint32_t filenameLength = filename->length;
|
|
|
|
mkdir(filename->chars, S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH); //I hope everybody has a config folder, but who knows
|
|
|
|
ffStrbufAppendS(filename, "/fastfetch/");
|
|
mkdir(filename->chars, S_IRWXU | S_IRGRP | S_IROTH);
|
|
|
|
ffStrbufAppendS(filename, "config.conf");
|
|
|
|
FILE* file = fopen(filename->chars, "r");
|
|
if(file != NULL)
|
|
{
|
|
parseConfigFile(instance, data, file);
|
|
fclose(file);
|
|
ffStrbufSubstrBefore(filename, filenameLength);
|
|
return;
|
|
}
|
|
|
|
file = fopen(filename->chars, "w");
|
|
if(file != NULL)
|
|
{
|
|
fputs(FASTFETCH_DATATEXT_CONFIG, file);
|
|
fclose(file);
|
|
}
|
|
|
|
ffStrbufSubstrBefore(filename, filenameLength);
|
|
}
|
|
|
|
static void parseArguments(FFinstance* instance, FFdata* data, int argc, const char** argv)
|
|
{
|
|
for(int i = 1; i < argc; i++)
|
|
{
|
|
if(i == argc - 1 || (
|
|
*argv[i + 1] == '-' &&
|
|
strcasecmp(argv[i], "--offsetx") != 0 && // --offsetx allows negative values
|
|
strcasecmp(argv[i], "--separator-string") != 0 // Separator string can start with a -
|
|
)) {
|
|
parseOption(instance, data, argv[i], NULL);
|
|
}
|
|
else
|
|
{
|
|
parseOption(instance, data, argv[i], argv[i + 1]);
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void parseStructureCommand(FFinstance* instance, FFdata* data, const char* line)
|
|
{
|
|
const char* setValue = ffValuestoreGet(&data->valuestore, line);
|
|
if(setValue != NULL)
|
|
{
|
|
ffPrintCustom(instance, line, setValue);
|
|
return;
|
|
}
|
|
|
|
if(strcasecmp(line, "break") == 0)
|
|
ffPrintBreak(instance);
|
|
else if(strcasecmp(line, "title") == 0)
|
|
ffPrintTitle(instance);
|
|
else if(strcasecmp(line, "separator") == 0)
|
|
ffPrintSeparator(instance);
|
|
else if(strcasecmp(line, "os") == 0)
|
|
ffPrintOS(instance);
|
|
else if(strcasecmp(line, "host") == 0)
|
|
ffPrintHost(instance);
|
|
else if(strcasecmp(line, "kernel") == 0)
|
|
ffPrintKernel(instance);
|
|
else if(strcasecmp(line, "uptime") == 0)
|
|
ffPrintUptime(instance);
|
|
else if(strcasecmp(line, "processes") == 0)
|
|
ffPrintProcesses(instance);
|
|
else if(strcasecmp(line, "packages") == 0)
|
|
ffPrintPackages(instance);
|
|
else if(strcasecmp(line, "shell") == 0)
|
|
ffPrintShell(instance);
|
|
else if(strcasecmp(line, "resolution") == 0)
|
|
ffPrintResolution(instance);
|
|
else if(strcasecmp(line, "desktopenvironment") == 0 || strcasecmp(line, "de") == 0)
|
|
ffPrintDesktopEnvironment(instance);
|
|
else if(strcasecmp(line, "windowmanager") == 0 || strcasecmp(line, "wm") == 0)
|
|
ffPrintWM(instance);
|
|
else if(strcasecmp(line, "theme") == 0)
|
|
ffPrintTheme(instance);
|
|
else if(strcasecmp(line, "wmtheme") == 0)
|
|
ffPrintWMTheme(instance);
|
|
else if(strcasecmp(line, "icons") == 0)
|
|
ffPrintIcons(instance);
|
|
else if(strcasecmp(line, "font") == 0)
|
|
ffPrintFont(instance);
|
|
else if(strcasecmp(line, "cursor") == 0)
|
|
ffPrintCursor(instance);
|
|
else if(strcasecmp(line, "terminal") == 0)
|
|
ffPrintTerminal(instance);
|
|
else if(strcasecmp(line, "terminalfont") == 0)
|
|
ffPrintTerminalFont(instance);
|
|
else if(strcasecmp(line, "cpu") == 0)
|
|
ffPrintCPU(instance);
|
|
else if(strcasecmp(line, "cpuusage") == 0)
|
|
ffPrintCPUUsage(instance);
|
|
else if(strcasecmp(line, "gpu") == 0)
|
|
ffPrintGPU(instance);
|
|
else if(strcasecmp(line, "memory") == 0)
|
|
ffPrintMemory(instance);
|
|
else if(strcasecmp(line, "disk") == 0)
|
|
ffPrintDisk(instance);
|
|
else if(strcasecmp(line, "battery") == 0)
|
|
ffPrintBattery(instance);
|
|
else if(strcasecmp(line, "locale") == 0)
|
|
ffPrintLocale(instance);
|
|
else if(strcasecmp(line, "localip") == 0)
|
|
ffPrintLocalIp(instance);
|
|
else if(strcasecmp(line, "publicip") == 0)
|
|
ffPrintPublicIp(instance);
|
|
else if(strcasecmp(line, "player") == 0)
|
|
ffPrintPlayer(instance);
|
|
else if(strcasecmp(line, "song") == 0)
|
|
ffPrintSong(instance);
|
|
else if(strcasecmp(line, "datetime") == 0)
|
|
ffPrintDateTime(instance);
|
|
else if(strcasecmp(line, "date") == 0)
|
|
ffPrintDate(instance);
|
|
else if(strcasecmp(line, "time") == 0)
|
|
ffPrintTime(instance);
|
|
else if(strcasecmp(line, "colors") == 0)
|
|
ffPrintColors(instance);
|
|
else
|
|
ffPrintError(instance, line, 0, NULL, NULL, 0, "<no implementation provided>");
|
|
}
|
|
|
|
int main(int argc, const char** argv)
|
|
{
|
|
FFinstance instance;
|
|
ffInitInstance(&instance);
|
|
|
|
//Data stores things only needed for the configuration of fastfetch
|
|
FFdata data;
|
|
ffValuestoreInit(&data.valuestore);
|
|
ffStrbufInitA(&data.structure, 256);
|
|
data.multithreading = true;
|
|
|
|
parseDefaultConfigFile(&instance, &data);
|
|
parseArguments(&instance, &data, argc, argv);
|
|
|
|
//Start detection threads
|
|
if(data.multithreading)
|
|
ffStartDetectionThreads(&instance);
|
|
|
|
//If we don't have a custom structure, use the default one
|
|
if(data.structure.length == 0)
|
|
ffStrbufSetS(&data.structure, FASTFETCH_DATATEXT_STRUCTURE);
|
|
|
|
ffStart(&instance);
|
|
|
|
//Parse the structure and call the modules
|
|
uint32_t startIndex = 0;
|
|
while (startIndex < data.structure.length)
|
|
{
|
|
uint32_t colonIndex = ffStrbufNextIndexC(&data.structure, startIndex, ':');
|
|
data.structure.chars[colonIndex] = '\0';
|
|
|
|
parseStructureCommand(&instance, &data, data.structure.chars + startIndex);
|
|
|
|
startIndex = colonIndex + 1;
|
|
}
|
|
|
|
ffFinish(&instance);
|
|
}
|