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-11 17:21:18 +01:00
#define FASTFETCH_DEFAULT_STRUCTURE "Title:Seperator:OS:Host:Kernel:Uptime:Packages:Shell:Resolution:DE:WM:Theme:Icons:Font:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Locale:Break:Colors"
2021-03-03 19:59:39 +01:00
#define FASTFETCH_DEFAULT_CONFIG \
2021-03-19 20:57:07 +01:00
"# Fastfetch configuration\n" \
"# Put arguments here to make them permanently (one per line). \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" \
"# 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 19:59:39 +01:00
//Things only needed by fastfetch
typedef struct FFdata
{
FFvaluestore valuestore ;
2021-03-19 20:57:07 +01:00
FFstrbuf structure ;
FFstrbuf logoName ;
2021-03-03 19:59:39 +01:00
} FFdata ;
2021-03-11 19:40:46 +01:00
static inline void printHelp ()
2021-02-19 16:23:41 +01:00
{
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 "
2021-03-27 19:26:58 +01:00
" -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 "
" --print-default-structure: prints the default stucture and exits \n "
" --print-available-modules: prints a list of available modules and exits \n "
2021-03-03 21:03:12 +01:00
" \n "
"General options: \n "
2021-03-27 19:26:58 +01:00
" --structure <structure>: sets the structure of the fetch. Must be a colon seperated list of keys. Use --print-available-modules to show the default \n "
2021-03-19 21:23:15 +01:00
" --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 "
2021-03-21 17:02:31 +01:00
" --spacing <width>: sets the distance between logo and text \n "
2021-03-19 21:23:15 +01:00
" -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 "
" --print-remaining-logo <?value>: print the remaining logo, if it is higher than the number of lines shown \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-19 20:57:07 +01:00
"Format options: Provide the format string for custom output (+) \n "
" --os-format <format> \n "
" --host-format <format> \n "
" --kernel-format <format> \n "
" --uptime-format <format> \n "
" --packages-format <format> \n "
" --shell-format <format> \n "
" --resolution-format <format> \n "
" --de-format <format> \n "
" --wm-format <format> \n "
" --theme-format <format> \n "
" --icons-format <format> \n "
" --font-format <format> \n "
" --terminal-format <format> \n "
" --terminal-font-format <format> \n "
" --cpu-format <format> \n "
" --gpu-format <format> \n "
" --memory-format <format> \n "
" --disk-format <format> \n "
" --battery-format <format> \n "
" --locale-format <format> \n "
2021-03-06 11:28:38 +01:00
" \n "
2021-03-19 20:57:07 +01:00
"Library optins: Set the path of a library to load \n "
" --lib-PCI <path> \n "
2021-03-21 11:18:06 +01:00
" --lib-X11 <path> \n "
" --lib-Xrandr <path> \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-21 11:18:06 +01:00
static inline void printCommandHelpFormat ()
2021-03-12 10:17:49 +01:00
{
puts (
2021-03-21 11:18:06 +01:00
"A format string is string that contains placeholder for values. \n "
"These placeholders beginn with a '{', contain the index of the value and end with a '}'. \n "
"For example the format string \" Values: {1} ({2}) \" , with the values \" First \" and \" My second val \" , will produce \" Values: First (My second val) \" . \n "
"The format string can contain placeholdes in any oder and multiple occurences. \n "
"To include spaces when setting from command line, surround the whole string with double quotes ( \" ). \n "
" \n "
"If the value index is missing, meaning the placeholder is \" {} \" , an internal counter sets the value index. \n "
"This means, that the format string \" Values: {1} ({2}) \" is equivalent to \" Values: {} ({}) \" . \n "
"Note that this counter only counts empty placeholders, so the format string \" {2} {} {} \" will contain the second value, then the first, and then again the second. \n "
" \n "
"To make formatting easier, a double open curly brace ( \" {{ \" ) will be printed as a single open curly brace and not counted as the beginn of a placeholder. \n "
"If a value index is missformatted or wants a non existing value, it will be printed as is, with the curly braces around it. \n "
"If the last placeholder isn't closed, it will be printed as is, with the open curly braces at the start. \n "
" \n "
2021-03-27 15:39:56 +01:00
"If an format string evaluates to an empty value, the whole line in the output will be discarded. \n "
"You can therefore use --host-format \" \" to disable host output. \n "
"Note that --host-format \"\" would evaluate as not set, and therefore use the built in host format \n "
" \n "
2021-03-21 11:18:06 +01:00
"Format string is also the way to go to set a fixed value, just use one without placeholders. \n "
"For example when running in headless mode you could use \" --resolution-format \" Preferred \" ."
2021-03-19 20:57:07 +01:00
);
}
2021-03-27 19:26:58 +01:00
static inline void printAvailableModules ()
{
puts (
"Battery \n "
"Break \n "
"Colors \n "
"CPU \n "
"DE \n "
"Disk \n "
"Font \n "
"GPU \n "
"Host \n "
"Icons \n "
"Kernel \n "
"Locale \n "
"Memory \n "
"OS \n "
"Packages \n "
"Resolution \n "
"Seperator \n "
"Shell \n "
"Terminal \n "
"TerminalFont \n "
"Theme \n "
"Title \n "
"Uptime \n "
"WM \n "
" \n "
"+ Additional defined by --set"
);
}
2021-03-21 11:18:06 +01:00
static void constructAndPrintCommandHelpFormat ( const char * name , const char * def , uint32_t numArgs , ...)
2021-03-19 20:57:07 +01:00
{
2021-03-21 11:18:06 +01:00
va_list argp ;
va_start ( argp , numArgs );
2021-03-19 20:57:07 +01:00
2021-03-21 11:18:06 +01:00
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 ( "Following values are passed:" );
2021-03-19 20:57:07 +01:00
2021-03-21 11:18:06 +01:00
for ( uint32_t i = 1 ; i <= numArgs ; i ++ )
printf ( " {%u}: %s \n " , i , va_arg ( argp , const char * ));
2021-03-19 20:57:07 +01:00
2021-03-21 11:18:06 +01:00
printf ( "The default is something like \" %s \" . \n " , def );
2021-03-19 20:57:07 +01:00
2021-03-21 11:18:06 +01:00
va_end ( argp );
2021-03-11 22:15:48 +01:00
}
2021-03-11 19:40:46 +01:00
static inline void printCommandHelp ( const char * command )
2021-02-20 19:32:57 +01:00
{
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-21 11:18:06 +01:00
else if ( strcasecmp ( command , "format" ) == 0 )
printCommandHelpFormat ();
2021-03-12 10:17:49 +01:00
else if ( strcasecmp ( command , "os-format" ) == 0 )
2021-03-27 17:48:32 +01:00
{
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"
);
}
2021-03-12 12:16:41 +01:00
else if ( strcasecmp ( command , "host-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "host" , "{} {} {}" , 3 , "Host family" , "Host name" , "Host version" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "kernel-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "kernel" , "{2}" , 3 , "Kernel sysname" , "Kernel release" , "Kernel version" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "uptime-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "uptime" , "{} days {} hours {} mins" , 4 , "Days" , "Hours" , "Minutes" , "Seconds" );
2021-03-11 19:40:46 +01:00
else if ( strcasecmp ( command , "packages-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "packages" , "{2} (pacman), {3} (flatpak)" , 3 , "Number of all packages" , "Number of pacman packages" , "Number of flatpak packages" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "shell-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "shell" , "{2}" , 2 , "Shell path (without name)" , "Shell name" );
2021-03-11 22:15:48 +01:00
else if ( strcasecmp ( command , "resolution-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "resolution" , "{}x{} @ {}Hz" , 3 , "Screen width" , "Screen height" , "Screen refresh rate" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "de-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "de" , "{} {} ({})" , 3 , "DE name" , "DE version" , "Name of display server" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "wm-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "wm" , "{}" , 1 , "WM name" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "theme-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "theme" , "{} [Plasma], {5}" , 5 , "Plasma theme" , "GTK2 theme" , "GTK3 theme" , "GTK4 theme" , "Combined GTK themes" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "icons-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "icons" , "{} [Plasma], {5}" , 5 , "Plasma icons" , "GTK2 icons" , "GTK3 icons" , "GTK4 icons" , "Combined GTK icons" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "font-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "font" , "{} [Plasma], {5}" , 5 , "Plasma font" , "GTK2 font" , "GTK3 font" , "GTK4 font" , "Combined GTK fonts" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "terminal-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "terminal" , "{}" , 1 , "Terminal name" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "terminal-font-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "terminal-font" , "{}" , 1 , "Terminal font name" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "cpu-format" ) == 0 )
2021-03-28 13:02:40 +02:00
constructAndPrintCommandHelpFormat ( "cpu" , "{2} ({4}) @ {7}GHz" , 11 , "CPU name" , "Prettified CPU name" , "CPU Vendor name (Vendor ID)" , "CPU logical core count online" , "CPU logical core count configured" , "CPU physical core count" , "frequency bios limit" , "frequency scaling max" , "frequency scaling min" , "frequency info max" , "frequency info min" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "gpu-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "gpu" , "{} {}" , 2 , "GPU vendor" , "GPU name" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "memory-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "memory" , "{}MiB / {}MiB ({}%)" , 3 , "Used memory" , "Total memory" , "Used memory percentage" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "disk-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "disk" , "{}GB / {}GB ({}%)" , 3 , "Used disk space" , "Total disk space" , "Used disk space percentage" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "battery-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "battery" , "{} {} ({}) [{}%; {}]" , 5 , "Battery manufactor" , "Battery model" , "Battery technology" , "Battery capacity" , "Battery status" );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( command , "locale-format" ) == 0 )
2021-03-21 11:18:06 +01:00
constructAndPrintCommandHelpFormat ( "locale" , "{}" , 1 , "Locale code" );
2021-02-20 19:32:57 +01:00
else
printf ( "No specific help for command %s provided \n " , command );
}
2021-03-11 19:40:46 +01:00
static inline bool optionParseBoolean ( const char * str )
2021-02-27 20:31:54 +01:00
{
2021-03-07 20:35:17 +01:00
if ( str == NULL )
return true ;
return (
2021-03-03 19:59:39 +01:00
strcasecmp ( str , "true" ) == 0 ||
strcasecmp ( str , "yes" ) == 0 ||
strcasecmp ( str , "1" ) == 0
2021-03-07 20:35:17 +01:00
);
2021-02-27 20:31:54 +01:00
}
2021-03-19 20:57:07 +01:00
static inline void optionParseString ( const char * key , const char * value , FFstrbuf * buffer )
2021-03-11 19:40:46 +01:00
{
if ( value == NULL )
{
printf ( "Error: usage: %s <str> \n " , key );
exit ( 477 );
}
2021-03-19 20:57:07 +01:00
ffStrbufSetS ( buffer , value );
2021-02-27 20:31:54 +01:00
}
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 );
}
2021-03-27 19:26:58 +01:00
else if ( strcasecmp ( key , "--print-default-structure" ) == 0 )
{
puts ( FASTFETCH_DEFAULT_STRUCTURE );
exit ( 0 );
}
else if ( strcasecmp ( key , "--print-available-modules" ) == 0 )
{
printAvailableModules ();
exit ( 0 );
}
2021-03-21 17:02:31 +01:00
else if ( strcasecmp ( key , "--spacing" ) == 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-21 17:02:31 +01:00
if ( sscanf ( value , "%hd" , & instance -> config . logo_spacing ) != 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 );
}
}
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 , "--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-27 18:14:19 +01:00
//Set cacheSave as well, beacuse the user expects the values to be cached when expliciting using --recache
2021-03-11 19:40:46 +01:00
instance -> config . recache = optionParseBoolean ( value );
2021-03-07 20:35:17 +01:00
instance -> config . cacheSave = instance -> config . recache ;
2021-03-06 11:28:38 +01:00
}
2021-03-07 20:35:17 +01:00
else if ( strcasecmp ( key , "--show-errors" ) == 0 )
2021-03-11 19:40:46 +01:00
instance -> config . showErrors = optionParseBoolean ( value );
2021-03-07 20:35:17 +01:00
else if ( strcasecmp ( key , "--color-logo" ) == 0 )
2021-03-11 19:40:46 +01:00
instance -> config . colorLogo = optionParseBoolean ( value );
2021-03-19 21:23:15 +01:00
else if ( strcasecmp ( key , "--print-remaining-logo" ) == 0 )
instance -> config . printRemainingLogo = optionParseBoolean ( value );
2021-03-19 20:57:07 +01:00
else if ( strcasecmp ( key , "--structure" ) == 0 )
optionParseString ( key , value , & data -> structure );
else if ( strcasecmp ( key , "-l" ) == 0 || strcasecmp ( key , "--logo" ) == 0 )
optionParseString ( key , value , & data -> logoName );
else if ( strcasecmp ( key , "-s" ) == 0 || strcasecmp ( key , "--seperator" ) == 0 )
optionParseString ( key , value , & instance -> config . seperator );
else if ( strcasecmp ( key , "-c" ) == 0 || strcasecmp ( key , "--color" ) == 0 )
optionParseString ( key , value , & instance -> config . color );
2021-03-12 10:17:49 +01:00
else if ( strcasecmp ( key , "--os-format" ) == 0 )
2021-03-19 20:57:07 +01:00
optionParseString ( key , value , & instance -> config . osFormat );
2021-03-12 12:16:41 +01:00
else if ( strcasecmp ( key , "--host-format" ) == 0 )
2021-03-19 20:57:07 +01:00
optionParseString ( key , value , & instance -> config . hostFormat );
else if ( strcasecmp ( key , "--kernel-format" ) == 0 )
optionParseString ( key , value , & instance -> config . kernelFormat );
else if ( strcasecmp ( key , "--uptime-format" ) == 0 )
optionParseString ( key , value , & instance -> config . uptimeFormat );
2021-03-11 19:40:46 +01:00
else if ( strcasecmp ( key , "--packages-format" ) == 0 )
2021-03-19 20:57:07 +01:00
optionParseString ( key , value , & instance -> config . packagesFormat );
else if ( strcasecmp ( key , "--shell-format" ) == 0 )
optionParseString ( key , value , & instance -> config . shellFormat );
2021-03-11 22:15:48 +01:00
else if ( strcasecmp ( key , "--resolution-format" ) == 0 )
2021-03-19 20:57:07 +01:00
optionParseString ( key , value , & instance -> config . resolutionFormat );
else if ( strcasecmp ( key , "--de-format" ) == 0 )
optionParseString ( key , value , & instance -> config . deFormat );
else if ( strcasecmp ( key , "--wm-format" ) == 0 )
optionParseString ( key , value , & instance -> config . wmFormat );
else if ( strcasecmp ( key , "--theme-format" ) == 0 )
optionParseString ( key , value , & instance -> config . themeFormat );
else if ( strcasecmp ( key , "--icons-format" ) == 0 )
optionParseString ( key , value , & instance -> config . iconsFormat );
else if ( strcasecmp ( key , "--font-format" ) == 0 )
optionParseString ( key , value , & instance -> config . fontFormat );
else if ( strcasecmp ( key , "--terminal-format" ) == 0 )
optionParseString ( key , value , & instance -> config . terminalFormat );
else if ( strcasecmp ( key , "--terminal-font-format" ) == 0 )
optionParseString ( key , value , & instance -> config . termFontFormat );
else if ( strcasecmp ( key , "--cpu-format" ) == 0 )
optionParseString ( key , value , & instance -> config . cpuFormat );
else if ( strcasecmp ( key , "--gpu-format" ) == 0 )
optionParseString ( key , value , & instance -> config . gpuFormat );
else if ( strcasecmp ( key , "--memory-format" ) == 0 )
optionParseString ( key , value , & instance -> config . memoryFormat );
else if ( strcasecmp ( key , "--disk-format" ) == 0 )
optionParseString ( key , value , & instance -> config . diskFormat );
2021-03-04 20:49:12 +01:00
else if ( strcasecmp ( key , "--battery-format" ) == 0 )
2021-03-19 20:57:07 +01:00
optionParseString ( key , value , & instance -> config . batteryFormat );
else if ( strcasecmp ( key , "--locale-format" ) == 0 )
optionParseString ( key , value , & instance -> config . localeFormat );
else if ( strcasecmp ( key , "--lib-PCI" ) == 0 )
optionParseString ( key , value , & instance -> config . libPCI );
else if ( strcasecmp ( key , "--lib-X11" ) == 0 )
optionParseString ( key , value , & instance -> config . libX11 );
else if ( strcasecmp ( key , "--lib-Xrandr" ) == 0 )
optionParseString ( key , value , & instance -> config . libXrandr );
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 )
{
2021-03-27 18:35:30 +01:00
FF_STRBUF_CREATE ( filename );
2021-03-03 19:59:39 +01:00
const char * xdgConfig = getenv ( "XDG_CONFIG_HOME" );
if ( xdgConfig == NULL )
{
2021-03-27 18:35:30 +01:00
ffStrbufAppendS ( & filename , instance -> state . passwd -> pw_dir );
ffStrbufAppendS ( & filename , "/.config" );
2021-03-03 19:59:39 +01:00
}
else
{
2021-03-27 18:35:30 +01:00
ffStrbufAppendS ( & filename , xdgConfig );
2021-03-03 19:59:39 +01:00
}
2021-03-27 18:35:30 +01:00
mkdir ( filename . chars , S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH ); //I hope everybody has a config folder but whow knews
2021-03-27 18:14:19 +01:00
2021-03-27 18:35:30 +01:00
ffStrbufAppendS ( & filename , "/fastfetch/" );
mkdir ( filename . chars , S_IRWXU | S_IRGRP | S_IROTH );
2021-03-03 19:59:39 +01:00
2021-03-27 18:35:30 +01:00
ffStrbufAppendS ( & filename , "config.conf" );
2021-03-03 19:59:39 +01:00
2021-03-27 18:35:30 +01:00
if ( access ( filename . chars , F_OK ) != 0 )
2021-03-03 19:59:39 +01:00
{
2021-03-27 18:35:30 +01:00
FILE * file = fopen ( filename . chars , "w" );
2021-03-03 19:59:39 +01:00
fputs ( FASTFETCH_DEFAULT_CONFIG , file );
fclose ( file );
return ;
}
2021-03-27 18:14:19 +01:00
2021-03-27 18:35:30 +01:00
FILE * file = fopen ( filename . chars , "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-27 14:22:08 +01:00
while (( read = getline ( & lineStart , & len , file )) != - 1 )
{
FFstrbuf line ;
ffStrbufInitS ( & line , lineStart );
ffStrbufTrimRight ( & line , '\n' );
ffStrbufTrim ( & line , ' ' );
2021-03-03 21:42:40 +01:00
2021-03-27 14:22:08 +01:00
if ( line . length == 0 || line . chars [ 0 ] == '#' )
2021-03-03 21:42:40 +01:00
continue ;
2021-03-03 19:59:39 +01:00
2021-03-27 14:22:08 +01:00
char * valueStart = strchr ( line . chars , ' ' );
2021-03-05 23:00:28 +01:00
if ( valueStart == NULL )
2021-03-03 19:59:39 +01:00
{
2021-03-27 14:22:08 +01:00
parseOption ( instance , data , line . chars , NULL );
2021-03-03 19:59:39 +01:00
}
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 == '"' )
{
2021-03-27 14:22:08 +01:00
char * last = line . chars + line . length - 1 ;
2021-03-05 23:00:28 +01:00
if ( * last == '"' )
{
++ valueStart ;
* last = '\0' ;
2021-03-27 14:22:08 +01:00
-- line . length ;
2021-03-05 23:00:28 +01:00
}
}
2021-03-27 14:22:08 +01:00
parseOption ( instance , data , line . chars , valueStart );
2021-03-03 19:59:39 +01:00
}
2021-03-27 14:22:08 +01:00
ffStrbufDestroy ( & line );
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 );
2021-03-27 18:35:30 +01:00
ffStrbufDestroy ( & filename );
2021-03-03 19:59:39 +01:00
}
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
2021-03-23 19:48:52 +01:00
if ( data -> logoName . length == 0 )
2021-03-03 19:59:39 +01:00
ffLoadLogo ( & instance -> config );
else
2021-03-19 20:57:07 +01:00
ffLoadLogoSet ( & instance -> config , data -> logoName . chars );
2021-03-03 19:59:39 +01:00
//This must be done after loading the logo
2021-03-23 19:48:52 +01:00
if ( instance -> config . color . length == 0 )
2021-03-19 20:57:07 +01:00
ffStrbufSetS ( & instance -> config . color , instance -> config . logo . color );
}
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 , "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 );
else if ( strcasecmp ( line , "windowmanager" ) == 0 || strcasecmp ( line , "wm" ) == 0 )
ffPrintWM ( instance );
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 , "terminalfont" ) == 0 )
ffPrintTerminalFont ( 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 run ( FFinstance * instance , FFdata * data )
{
2021-03-23 19:48:52 +01:00
if ( data -> structure . length == 0 )
2021-03-19 20:57:07 +01:00
ffStrbufSetS ( & data -> structure , FASTFETCH_DEFAULT_STRUCTURE );
2021-03-27 18:14:19 +01:00
2021-03-19 20:57:07 +01:00
char * remaining = data -> structure . chars ;
2021-03-03 19:59:39 +01:00
char * colon = NULL ;
while ( true )
{
colon = strchr ( remaining , ':' );
2021-03-27 18:14:19 +01:00
2021-03-03 19:59:39 +01:00
if ( colon != NULL )
* colon = '\0' ;
2021-03-27 18:14:19 +01:00
2021-03-03 19:59:39 +01:00
parseStructureCommand ( instance , data , remaining );
2021-03-27 18:14:19 +01:00
2021-03-03 19:59:39 +01:00
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 );
2021-03-19 20:57:07 +01:00
ffStrbufInit ( & data . structure );
ffStrbufInitA ( & data . logoName , 2048 );
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 );
2021-03-19 21:23:15 +01:00
ffFinish ( & instance );
ffStrbufDestroy ( & data . structure );
ffStrbufDestroy ( & data . logoName );
2021-03-03 19:59:39 +01:00
ffValuestoreDelete ( & data . valuestore );
2021-02-18 22:25:36 +01:00
}