2021-02-18 22:25:36 +01:00
|
|
|
#include "fastfetch.h"
|
2021-02-22 20:36:25 +01:00
|
|
|
#include "fastfetch_config.h"
|
2021-03-03 19:59:39 +01:00
|
|
|
#include "util/FFvaluestore.h"
|
2021-02-18 22:25:36 +01:00
|
|
|
|
2021-02-27 20:31:54 +01:00
|
|
|
#include <malloc.h>
|
2021-02-27 20:50:13 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <unistd.h>
|
2021-02-27 20:31:54 +01:00
|
|
|
#include <sys/stat.h>
|
2021-02-27 20:50:13 +01:00
|
|
|
#include <fcntl.h>
|
2021-02-22 16:52:51 +01:00
|
|
|
|
2021-03-05 21:38:35 +01:00
|
|
|
#define FASTFETCH_DEFAULT_STRUCTURE "Title:Seperator:OS:Host:Kernel:Uptime:Packages:Shell:Resolution:DE:WM:Theme:Icons:Font:Terminal:CPU:GPU:Memory:Disk:Battery:Locale:Break:Colors"
|
2021-03-03 19:59:39 +01:00
|
|
|
|
|
|
|
|
#define FASTFETCH_DEFAULT_CONFIG \
|
2021-03-03 21:42:40 +01:00
|
|
|
"## Fastfetch configuration\n" \
|
|
|
|
|
"## Put arguments here to make them permanently.\n" \
|
|
|
|
|
"## Direct arguments will overwrite the corresponding ones in this files\n" \
|
|
|
|
|
"## Each line is whitespace trimmed on beginn and end.\n" \
|
|
|
|
|
"## Empty lines or lines starting with # are ignored.\n" \
|
|
|
|
|
"## There are more arguments possible than listed here, take a look at fastfetch --help!\n" \
|
2021-03-05 21:49:13 +01:00
|
|
|
"## This version of the file was shipped with "FASTFETCH_PROJECT_VERSION".\n" \
|
|
|
|
|
"## Use fastfetch --print-default-config > ~/.config/fastfetch/config.conf to generate a new one with current defaults.\n" \
|
2021-03-03 21:42:40 +01:00
|
|
|
"\n" \
|
|
|
|
|
"## General options:\n" \
|
|
|
|
|
"# --structure "FASTFETCH_DEFAULT_STRUCTURE"\n" \
|
2021-03-05 23:00:28 +01:00
|
|
|
"# --spacer 4\n" \
|
|
|
|
|
"# --seperator \": \"\n" \
|
2021-03-03 21:42:40 +01:00
|
|
|
"# --offsetx 0\n" \
|
|
|
|
|
"# --recache false\n" \
|
|
|
|
|
"# --show-errors false\n" \
|
|
|
|
|
"\n" \
|
|
|
|
|
"## Logo options:\n" \
|
|
|
|
|
"# --color-logo true\n" \
|
|
|
|
|
"\n" \
|
2021-03-06 11:28:38 +01:00
|
|
|
"## OS options:\n" \
|
|
|
|
|
"# --os-architecture true\n" \
|
|
|
|
|
"\n" \
|
2021-03-07 11:58:24 +01:00
|
|
|
"## Host options:\n" \
|
|
|
|
|
"# --host-version true\n" \
|
|
|
|
|
"\n" \
|
2021-03-05 23:26:05 +01:00
|
|
|
"## Shell options:\n" \
|
|
|
|
|
"# --shell-path false\n" \
|
|
|
|
|
"\n" \
|
2021-03-03 21:42:40 +01:00
|
|
|
"## Battery options:\n" \
|
|
|
|
|
"# --battery-manufacturer true\n" \
|
|
|
|
|
"# --battery-model true\n" \
|
|
|
|
|
"# --battery-technology true\n" \
|
|
|
|
|
"# --battery-capacity true\n" \
|
|
|
|
|
"# --battery-status true\n"
|
2021-03-03 19:59:39 +01:00
|
|
|
|
|
|
|
|
//Things only needed by fastfetch
|
|
|
|
|
typedef struct FFdata
|
|
|
|
|
{
|
|
|
|
|
FFvaluestore valuestore;
|
|
|
|
|
char structure[2048];
|
|
|
|
|
char logoName[32];
|
|
|
|
|
} FFdata;
|
|
|
|
|
|
2021-02-19 16:23:41 +01:00
|
|
|
static void printHelp()
|
|
|
|
|
{
|
|
|
|
|
puts(
|
2021-03-03 21:03:12 +01:00
|
|
|
"Usage: fastfetch <options>\n"
|
2021-02-20 19:32:57 +01:00
|
|
|
"\n"
|
2021-03-03 21:03:12 +01:00
|
|
|
"Informative options:\n"
|
|
|
|
|
" -h, --help: shows this message and exits\n"
|
|
|
|
|
" -h <command>, --help <command>: shows help for a specific command and exits\n"
|
|
|
|
|
" -v --version: prints the version of fastfetch and exits\n"
|
|
|
|
|
" --list-logos: list available logos and exits\n"
|
|
|
|
|
" --print-logos: shows available logos and exits\n"
|
|
|
|
|
" --print-default-config: prints the default config and exits\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"General options:\n"
|
2021-03-05 23:00:28 +01:00
|
|
|
" --structure <structure>: sets the structure of the fetch. Must be a colon seperated list of keys\n"
|
|
|
|
|
" --set <key=value>: hard set the value of an key\n"
|
|
|
|
|
" -c <color>, --color <color>: sets the color of the keys. Must be a linux console color code (+)\n"
|
|
|
|
|
" --spacer <width>: sets the distance between logo and text\n"
|
|
|
|
|
" -s <str>, --seperator <str>: sets the seperator between key and value. Default is a colon with a space\n"
|
|
|
|
|
" -x <offset>, --offsetx <offset>: sets the x offset. Can be negative to cut the logo, but no more than logo width.\n"
|
|
|
|
|
" --show-errors <?value>: print occuring errors\n"
|
|
|
|
|
" -r <?value> --recache <?value>: if set to true, no cached values will be used\n"
|
2021-03-03 19:59:39 +01:00
|
|
|
"\n"
|
2021-03-03 21:03:12 +01:00
|
|
|
"Logo options:\n"
|
2021-03-05 23:00:28 +01:00
|
|
|
" -l <name>, --logo <name>: sets the shown logo. Also changes the main color accordingly\n"
|
|
|
|
|
" --color-logo <?value>: if set to false, the logo will be black / white\n"
|
2021-03-03 21:03:12 +01:00
|
|
|
"\n"
|
2021-03-06 11:28:38 +01:00
|
|
|
"OS options:\n"
|
|
|
|
|
" --os-architecture <?value>: Show the architecture of the os\n"
|
|
|
|
|
"\n"
|
2021-03-07 11:58:24 +01:00
|
|
|
"Host options:\n"
|
|
|
|
|
" --host-version <?value>: Show the version of the host platform, if possible. Most likely, this will be the BIOS version\n"
|
|
|
|
|
"\n"
|
2021-03-05 23:26:05 +01:00
|
|
|
"Shell options:\n"
|
|
|
|
|
" --shell-path <?value>: Show the full path of the shell\n"
|
|
|
|
|
"\n"
|
2021-03-03 21:03:12 +01:00
|
|
|
"Battery options:\n"
|
|
|
|
|
" --battery-manufacturer <?value>: Show the manufacturer of the battery, if possible\n"
|
|
|
|
|
" --battery-model <?value>: Show the model of the battery, if possible\n"
|
|
|
|
|
" --battery-technology <?value>: Show the technology of the battery, if possible\n"
|
|
|
|
|
" --battery-capacity <?value>: Show the capacity of the battery, if possible\n"
|
|
|
|
|
" --battery-status <?value>: Show the status of the battery, if possible\n"
|
2021-03-05 21:38:35 +01:00
|
|
|
" --battery-format <format>: Provide the printf format string for battery output (+)\n"
|
2021-03-03 21:03:12 +01:00
|
|
|
"\n"
|
2021-03-03 19:59:39 +01:00
|
|
|
"If an value starts with an ?, it is optional. \"true\" will be used if not set.\n"
|
2021-03-03 21:03:12 +01:00
|
|
|
"An (+) at the end indicates that more help can be printed with --help <option>\n"
|
2021-03-03 19:59:39 +01:00
|
|
|
"All options can be make permanent in $XDG_CONFIG_HOME/fastfetch/config.conf"
|
2021-02-19 16:23:41 +01:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-04 20:49:12 +01:00
|
|
|
static inline void printCommandHelpColor()
|
2021-02-20 19:32:57 +01:00
|
|
|
{
|
|
|
|
|
puts(
|
|
|
|
|
"usage: fastfetch --color <color>\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"<color> must be a color encoding for linux terminals. It is inserted between \"ESC[\" and \"m\".\n"
|
|
|
|
|
"Infos about them can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors.\n"
|
|
|
|
|
"Examples:\n"
|
|
|
|
|
" \"--color 35\": sets the color to pink\n"
|
|
|
|
|
" \"--color 4;92\": sets the color to bright Green with underline\n"
|
|
|
|
|
" \"--color 5;104\": blinking text on a blue background\n"
|
2021-02-20 20:00:06 +01:00
|
|
|
"If no color is set, the main color of the logo will be used.\n"
|
2021-02-20 19:32:57 +01:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-04 20:49:12 +01:00
|
|
|
static inline void printCommandHelpBatteryFormat()
|
|
|
|
|
{
|
|
|
|
|
puts(
|
|
|
|
|
"usage fastfetch --battery-format <format>\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"<format> is a string of maximum length 32, which is passed to printf as the format string.\n"
|
|
|
|
|
"The arguments passed to printf are 5 strings in following order:\n"
|
|
|
|
|
"manufacturer, model, technology, capacity, status\n"
|
|
|
|
|
"If an value was disabled via battery-* argument, or could not be determined, it will be an zero length string.\n"
|
|
|
|
|
"The default value is something like \"%s %s (%s) [%s; %s]\"."
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-20 19:32:57 +01:00
|
|
|
static void printCommandHelp(const char* command)
|
|
|
|
|
{
|
2021-03-04 20:49:12 +01:00
|
|
|
if(strcasecmp(command, "c") == 0 || strcasecmp(command, "color") == 0)
|
2021-02-20 19:32:57 +01:00
|
|
|
printCommandHelpColor();
|
2021-03-04 20:49:12 +01:00
|
|
|
else if(strcasecmp(command, "battery-format") == 0)
|
|
|
|
|
printCommandHelpBatteryFormat();
|
2021-02-20 19:32:57 +01:00
|
|
|
else
|
|
|
|
|
printf("No specific help for command %s provided\n", command);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
static bool parseBoolean(const char* str)
|
2021-02-27 20:31:54 +01:00
|
|
|
{
|
2021-03-03 19:59:39 +01:00
|
|
|
return
|
|
|
|
|
strcasecmp(str, "true") == 0 ||
|
|
|
|
|
strcasecmp(str, "yes") == 0 ||
|
|
|
|
|
strcasecmp(str, "1") == 0
|
|
|
|
|
;
|
2021-02-27 20:31:54 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
static void parseStructureCommand(FFinstance* instance, FFdata* data, const char* line)
|
2021-02-27 20:31:54 +01:00
|
|
|
{
|
2021-03-03 19:59:39 +01:00
|
|
|
const char* setValue = ffValuestoreGet(&data->valuestore, line);
|
|
|
|
|
if(setValue != NULL)
|
|
|
|
|
{
|
|
|
|
|
ffPrintCustom(instance, line, setValue);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-27 20:31:54 +01:00
|
|
|
if(strcasecmp(line, "break") == 0)
|
|
|
|
|
ffPrintBreak(instance);
|
|
|
|
|
else if(strcasecmp(line, "title") == 0)
|
|
|
|
|
ffPrintTitle(instance);
|
|
|
|
|
else if(strcasecmp(line, "seperator") == 0)
|
|
|
|
|
ffPrintSeperator(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, "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);
|
2021-03-05 21:38:35 +01:00
|
|
|
else if(strcasecmp(line, "windowmanager") == 0 || strcasecmp(line, "wm") == 0)
|
|
|
|
|
ffPrintWM(instance);
|
2021-02-27 20:31:54 +01:00
|
|
|
else if(strcasecmp(line, "theme") == 0)
|
|
|
|
|
ffPrintTheme(instance);
|
|
|
|
|
else if(strcasecmp(line, "icons") == 0)
|
|
|
|
|
ffPrintIcons(instance);
|
|
|
|
|
else if(strcasecmp(line, "font") == 0)
|
|
|
|
|
ffPrintFont(instance);
|
|
|
|
|
else if(strcasecmp(line, "terminal") == 0)
|
|
|
|
|
ffPrintTerminal(instance);
|
|
|
|
|
else if(strcasecmp(line, "cpu") == 0)
|
|
|
|
|
ffPrintCPU(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, "colors") == 0)
|
|
|
|
|
ffPrintColors(instance);
|
|
|
|
|
else
|
|
|
|
|
ffPrintError(instance, line, "<no implementaion provided>");
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
static void parseOption(FFinstance* instance, FFdata* data, const char* key, const char* value)
|
2021-02-27 20:31:54 +01:00
|
|
|
{
|
2021-03-03 19:59:39 +01:00
|
|
|
if(strcasecmp(key, "-h") == 0 || strcasecmp(key, "--help") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
printHelp();
|
|
|
|
|
else
|
|
|
|
|
printCommandHelp(value);
|
|
|
|
|
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "-v") == 0 || strcasecmp(key, "--version") == 0)
|
|
|
|
|
{
|
2021-03-05 21:49:13 +01:00
|
|
|
puts(FASTFETCH_PROJECT_NAME" "FASTFETCH_PROJECT_VERSION);
|
2021-03-03 19:59:39 +01:00
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--list-logos") == 0)
|
|
|
|
|
{
|
|
|
|
|
ffListLogos();
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--print-logos") == 0)
|
|
|
|
|
{
|
|
|
|
|
ffPrintLogos(instance->config.colorLogo);
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--print-default-config") == 0)
|
|
|
|
|
{
|
|
|
|
|
puts(FASTFETCH_DEFAULT_CONFIG);
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--show-errors") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.showErrors = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.showErrors = parseBoolean(value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <logo>\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(401);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
2021-02-27 20:31:54 +01:00
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
strcpy(data->logoName, value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--color-logo") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.colorLogo = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.colorLogo = parseBoolean(value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "-c") == 0 || strcasecmp(key, "--color") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <color>\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(402);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
size_t len = strlen(value);
|
|
|
|
|
if(len > 28)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: max color string length is 28, %zu given\n", len);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(403);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
sprintf(instance->config.color, "\033[%sm", value);
|
|
|
|
|
}
|
2021-03-05 23:00:28 +01:00
|
|
|
else if(strcasecmp(key, "--spacer") == 0)
|
2021-03-03 19:59:39 +01:00
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <width>\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(404);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
2021-03-05 23:00:28 +01:00
|
|
|
if(sscanf(value, "%hd", &instance->config.logo_spacer) != 1)
|
2021-03-03 19:59:39 +01:00
|
|
|
{
|
|
|
|
|
printf("Error: couldn't parse %s to uint16_t\n", value);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(405);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "-s") == 0 || strcasecmp(key, "--seperator") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <seperator>\n", key);
|
|
|
|
|
exit(406);
|
|
|
|
|
}
|
|
|
|
|
size_t len = strlen(value);
|
|
|
|
|
if(len > 15)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: max seperator length is 15, %zu given\n", len);
|
|
|
|
|
exit(407);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
2021-03-05 23:00:28 +01:00
|
|
|
strcpy(instance->config.seperator, value);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "-x") == 0 || strcasecmp(key, "--offsetx") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <offset>\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(408);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
if(sscanf(value, "%hi", &instance->config.offsetx) != 1)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: couldn't parse %s to int16_t\n", value);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(409);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--structure") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <structure>\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(410);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
strcpy(data->structure, value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--set") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <key=value>\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(411);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* seperator = strchr(value, '=');
|
2021-03-05 23:00:28 +01:00
|
|
|
|
|
|
|
|
if(seperator == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <key=value>, '=' missing\n", key);
|
|
|
|
|
exit(412);
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
*seperator = '\0';
|
|
|
|
|
|
|
|
|
|
ffValuestoreSet(&data->valuestore, value, seperator + 1);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "-r") == 0 || strcasecmp(key, "--recache") == 0)
|
|
|
|
|
{
|
2021-03-06 11:28:38 +01:00
|
|
|
//Set cacheSave as well, beacuse the user expects the values to be cached when expliciting using --recache
|
2021-03-03 19:59:39 +01:00
|
|
|
if(value == NULL)
|
2021-03-06 11:28:38 +01:00
|
|
|
{
|
2021-03-03 19:59:39 +01:00
|
|
|
instance->config.recache = true;
|
2021-03-06 11:28:38 +01:00
|
|
|
instance->config.cacheSave = true;
|
|
|
|
|
}
|
2021-03-03 19:59:39 +01:00
|
|
|
else
|
2021-03-06 11:28:38 +01:00
|
|
|
{
|
2021-03-03 19:59:39 +01:00
|
|
|
instance->config.recache = parseBoolean(value);
|
2021-03-06 11:28:38 +01:00
|
|
|
instance->config.cacheSave = instance->config.recache;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--os-architecture") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.osShowArchitecture = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.osShowArchitecture = parseBoolean(value);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
2021-03-07 11:58:24 +01:00
|
|
|
else if(strcasecmp(key, "--host-version") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.hostShowVersion = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.hostShowVersion = parseBoolean(value);
|
|
|
|
|
}
|
2021-03-05 23:26:05 +01:00
|
|
|
else if(strcasecmp(key, "--shell-path") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.shellShowPath = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.shellShowPath = parseBoolean(value);
|
|
|
|
|
}
|
2021-03-03 21:03:12 +01:00
|
|
|
else if(strcasecmp(key, "--battery-manufacturer") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.batteryShowManufacturer = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.batteryShowManufacturer = parseBoolean(value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--battery-model") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.batteryShowModel = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.batteryShowModel = parseBoolean(value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--battery-technology") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.batteryShowTechnology = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.batteryShowTechnology = parseBoolean(value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--battery-capacity") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.batteryShowCapacity = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.batteryShowCapacity = parseBoolean(value);
|
|
|
|
|
}
|
|
|
|
|
else if(strcasecmp(key, "--battery-status") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
instance->config.batteryShowStatus = true;
|
|
|
|
|
else
|
|
|
|
|
instance->config.batteryShowStatus = parseBoolean(value);
|
|
|
|
|
}
|
2021-03-04 20:49:12 +01:00
|
|
|
else if(strcasecmp(key, "--battery-format") == 0)
|
|
|
|
|
{
|
|
|
|
|
if(value == NULL)
|
|
|
|
|
{
|
|
|
|
|
printf("Error: usage: %s <format>\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(413);
|
2021-03-04 20:49:12 +01:00
|
|
|
}
|
|
|
|
|
size_t len = strlen(value);
|
|
|
|
|
if(len > 32)
|
|
|
|
|
{
|
|
|
|
|
printf("max battery format string length is 32, %zu given\n", len);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(414);
|
2021-03-04 20:49:12 +01:00
|
|
|
}
|
|
|
|
|
strcpy(instance->config.batteryFormat, value);
|
|
|
|
|
}
|
2021-03-03 19:59:39 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
printf("Error: unknown option: %s\n", key);
|
2021-03-05 23:00:28 +01:00
|
|
|
exit(400);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void parseConfigFile(FFinstance* instance, FFdata* data)
|
|
|
|
|
{
|
|
|
|
|
char fileName[256];
|
|
|
|
|
|
|
|
|
|
const char* xdgConfig = getenv("XDG_CONFIG_HOME");
|
|
|
|
|
if(xdgConfig == NULL)
|
|
|
|
|
{
|
|
|
|
|
strcpy(fileName, instance->state.passwd->pw_dir);
|
|
|
|
|
strcat(fileName, "/.config");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
strcpy(fileName, xdgConfig);
|
|
|
|
|
}
|
|
|
|
|
mkdir(fileName, S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH); //I hope everybody has a config folder but whow knews
|
2021-02-27 20:31:54 +01:00
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
strcat(fileName, "/fastfetch/");
|
|
|
|
|
mkdir(fileName, S_IRWXU | S_IRGRP | S_IROTH);
|
|
|
|
|
|
|
|
|
|
strcat(fileName, "config.conf");
|
|
|
|
|
|
|
|
|
|
if(access(fileName, F_OK) != 0)
|
|
|
|
|
{
|
|
|
|
|
FILE* file = fopen(fileName, "w");
|
|
|
|
|
fputs(FASTFETCH_DEFAULT_CONFIG, file);
|
|
|
|
|
fclose(file);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-02-27 20:31:54 +01:00
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
FILE* file = fopen(fileName, "r");
|
2021-02-27 20:31:54 +01:00
|
|
|
|
2021-03-05 23:00:28 +01:00
|
|
|
char* lineStart = NULL;
|
2021-03-03 19:59:39 +01:00
|
|
|
size_t len = 0;
|
2021-02-27 20:31:54 +01:00
|
|
|
ssize_t read;
|
|
|
|
|
|
2021-03-05 23:00:28 +01:00
|
|
|
while ((read = getline(&lineStart, &len, file)) != -1) {
|
|
|
|
|
|
|
|
|
|
//We need to copy lineStart because we modify this value, but need the original for free
|
|
|
|
|
char* line = lineStart;
|
2021-03-03 19:59:39 +01:00
|
|
|
|
2021-02-27 20:31:54 +01:00
|
|
|
if(line[read - 1] == '\n')
|
|
|
|
|
line[read - 1] = '\0';
|
2021-03-03 19:59:39 +01:00
|
|
|
else
|
|
|
|
|
line[read] = '\0';
|
2021-02-27 21:04:50 +01:00
|
|
|
|
2021-02-28 17:10:12 +01:00
|
|
|
ffTrimTrailingWhitespace(line);
|
2021-03-03 21:42:40 +01:00
|
|
|
|
|
|
|
|
//This trims leading whitespace
|
2021-03-05 23:00:28 +01:00
|
|
|
while(*line == ' ')
|
2021-03-03 21:42:40 +01:00
|
|
|
++line;
|
|
|
|
|
|
|
|
|
|
if(line[0] == '\0' || line[0] == '#')
|
|
|
|
|
continue;
|
2021-03-03 19:59:39 +01:00
|
|
|
|
2021-03-05 23:00:28 +01:00
|
|
|
char* valueStart = strchr(line, ' ');
|
|
|
|
|
if(valueStart == NULL)
|
2021-03-03 19:59:39 +01:00
|
|
|
{
|
|
|
|
|
parseOption(instance, data, line, NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-03-05 23:00:28 +01:00
|
|
|
//Seperate key and value by simply replacing the first space with a \0
|
|
|
|
|
*valueStart = '\0';
|
|
|
|
|
++valueStart;
|
|
|
|
|
|
|
|
|
|
//Trim whitespace at beginn of value
|
|
|
|
|
while(*valueStart == ' ')
|
|
|
|
|
++valueStart;
|
|
|
|
|
|
2021-03-05 23:26:05 +01:00
|
|
|
//If we want whitespace in values, we need to quote it. This is done to keep consistency with shell.
|
2021-03-05 23:00:28 +01:00
|
|
|
if(*valueStart == '"')
|
|
|
|
|
{
|
|
|
|
|
char* last = valueStart + strlen(valueStart) - 1;
|
|
|
|
|
if(*last == '"')
|
|
|
|
|
{
|
|
|
|
|
++valueStart;
|
|
|
|
|
*last = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parseOption(instance, data, line, valueStart);
|
2021-03-03 19:59:39 +01:00
|
|
|
}
|
2021-02-27 20:31:54 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-05 23:00:28 +01:00
|
|
|
if(lineStart != NULL)
|
|
|
|
|
free(lineStart);
|
2021-03-03 19:59:39 +01:00
|
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void parseArguments(FFinstance* instance, FFdata* data, int argc, const char** argv)
|
|
|
|
|
{
|
2021-03-06 11:28:38 +01:00
|
|
|
//This is generally a good idea, because cached values most likely contain values generated with other arguments
|
|
|
|
|
//Hovwever we dont do this with arguments in the config file, because they are more likely to stay the same
|
|
|
|
|
//If caching is _really_ wanted (e.g. a call in .bashrc with arguments), one can still set --recache false
|
|
|
|
|
if(argc > 1)
|
|
|
|
|
{
|
|
|
|
|
instance->config.recache = true;
|
|
|
|
|
instance->config.cacheSave = false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
for(int i = 1; i < argc; i++)
|
|
|
|
|
{
|
|
|
|
|
if(i == argc - 1 || argv[i + 1][0] == '-')
|
|
|
|
|
{
|
|
|
|
|
parseOption(instance, data, argv[i], NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parseOption(instance, data, argv[i], argv[i + 1]);
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-27 20:31:54 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-03 19:59:39 +01:00
|
|
|
static void applyData(FFinstance* instance, FFdata* data)
|
|
|
|
|
{
|
|
|
|
|
//We must do this after parsing all options because of color options
|
|
|
|
|
if(data->logoName[0] == '\0')
|
|
|
|
|
ffLoadLogo(&instance->config);
|
|
|
|
|
else
|
|
|
|
|
ffLoadLogoSet(&instance->config, data->logoName);
|
|
|
|
|
|
|
|
|
|
//This must be done after loading the logo
|
|
|
|
|
if(instance->config.color[0] == '\0')
|
|
|
|
|
strcpy(instance->config.color, instance->config.logo.color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void run(FFinstance* instance, FFdata* data)
|
|
|
|
|
{
|
|
|
|
|
if(data->structure[0] == '\0')
|
|
|
|
|
strcpy(data->structure, FASTFETCH_DEFAULT_STRUCTURE);
|
|
|
|
|
|
|
|
|
|
char* remaining = data->structure;
|
|
|
|
|
char* colon = NULL;
|
|
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
|
{
|
|
|
|
|
colon = strchr(remaining, ':');
|
|
|
|
|
|
|
|
|
|
if(colon != NULL)
|
|
|
|
|
*colon = '\0';
|
|
|
|
|
|
|
|
|
|
parseStructureCommand(instance, data, remaining);
|
|
|
|
|
|
|
|
|
|
if(colon != NULL)
|
|
|
|
|
remaining = colon + 1;
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, const char** argv)
|
2021-02-22 13:45:14 +01:00
|
|
|
{
|
2021-02-27 18:30:05 +01:00
|
|
|
FFinstance instance;
|
|
|
|
|
ffInitState(&instance.state);
|
2021-03-03 21:03:12 +01:00
|
|
|
ffDefaultConfig(&instance.config);
|
2021-03-03 19:59:39 +01:00
|
|
|
|
|
|
|
|
FFdata data;
|
|
|
|
|
ffValuestoreInit(&data.valuestore);
|
|
|
|
|
data.structure[0] = '\0'; //We use this in run to detect if a structure was set
|
2021-03-05 23:00:28 +01:00
|
|
|
data.logoName[0] = '\0'; //We use this in applyData to detect if a logo was set
|
2021-03-03 19:59:39 +01:00
|
|
|
|
|
|
|
|
parseConfigFile(&instance, &data);
|
|
|
|
|
parseArguments(&instance, &data, argc, argv);
|
2021-03-05 23:26:05 +01:00
|
|
|
applyData(&instance, &data); //Here we do things that need to be done after parsing all options
|
2021-03-03 19:59:39 +01:00
|
|
|
|
|
|
|
|
run(&instance, &data);
|
|
|
|
|
|
|
|
|
|
ffValuestoreDelete(&data.valuestore);
|
2021-02-18 22:25:36 +01:00
|
|
|
}
|