2021-02-18 22:25:36 +01:00
#include "fastfetch.h"
2023-08-17 16:00:24 +08:00
#include "common/commandoption.h"
2022-07-25 13:15:01 +02:00
#include "common/printing.h"
2022-07-25 13:59:19 +02:00
#include "common/parsing.h"
2023-01-28 12:40:12 +01:00
#include "common/io/io.h"
2022-12-14 11:30:50 +08:00
#include "common/time.h"
2023-06-11 00:51:29 +08:00
#include "common/jsonconfig.h"
2023-08-21 09:22:03 +08:00
#include "detection/version/version.h"
2023-02-01 15:56:25 +01:00
#include "util/stringUtils.h"
2023-03-10 17:49:03 +08:00
#include "logo/logo.h"
2023-07-28 14:12:48 +08:00
#include "fastfetch_datatext.h"
2021-02-18 22:25:36 +01:00
2022-06-18 14:25:31 +02:00
#include <stdlib.h>
2022-08-21 21:08:11 +02:00
#include <ctype.h>
2021-04-09 14:07:05 +02:00
#include <string.h>
2022-12-14 11:30:50 +08:00
#include <inttypes.h>
2021-02-22 16:52:51 +01:00
2022-10-13 18:12:54 +08:00
#ifdef WIN32
#include "util/windows/getline.h"
#endif
2023-03-07 16:13:53 +08:00
#include "modules/modules.h"
2023-03-07 14:56:13 +08:00
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 \" ." );
2021-05-15 08:39:20 +02:00
puts ( "The 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
2022-06-14 17:10:46 +02:00
printf ( "The default is something similar to \" %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-10-22 21:53:29 +02:00
if ( command == NULL )
2022-12-12 13:43:10 +01:00
puts ( FASTFETCH_DATATEXT_HELP );
2023-08-24 14:36:32 +08:00
else if ( ffStrEqualsIgnCase ( command , "color" ))
2022-12-12 13:43:10 +01:00
puts ( FASTFETCH_DATATEXT_HELP_COLOR );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "format" ))
2022-12-12 13:43:10 +01:00
puts ( FASTFETCH_DATATEXT_HELP_FORMAT );
2023-08-24 14:36:32 +08:00
else if ( ffStrEqualsIgnCase ( command , "load-config" ) || ffStrEqualsIgnCase ( command , "config" ))
2022-12-12 13:43:10 +01:00
puts ( FASTFETCH_DATATEXT_HELP_CONFIG );
2023-09-22 13:35:02 +08:00
else if ( ffStrEqualsIgnCase ( command , "title-format" ))
{
constructAndPrintCommandHelpFormat ( "title" , "{6}{7}{8}" , 8 ,
"User name" ,
"Host name" ,
"Home directory" ,
"Executable path of current process" ,
"User's default shell" ,
"User name (colored)" ,
"@ symbol (colored)" ,
"Host name (colored)"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "os-format" ))
2021-03-27 17:48:32 +01:00
{
constructAndPrintCommandHelpFormat ( "os" , "{3} {12}" , 12 ,
2021-05-15 08:39:20 +02:00
"System name (typically just Linux)" ,
2021-03-27 17:48:32 +01:00
"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"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "host-format" ))
2021-04-03 11:39:59 +02:00
{
2022-10-05 17:03:30 +08:00
constructAndPrintCommandHelpFormat ( "host" , "{2} {3}" , 8 ,
2022-06-14 17:10:46 +02:00
"product family" ,
"product name" ,
"product version" ,
"product sku" ,
"chassis type" ,
"chassis vendor" ,
"chassis version" ,
"sys vendor"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "bios-format" ))
2022-10-05 00:41:43 +08:00
{
constructAndPrintCommandHelpFormat ( "bios" , "{2} {3}" , 4 ,
"bios date" ,
"bios release" ,
"bios vendor" ,
"bios version"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "board-format" ))
2022-10-05 17:03:30 +08:00
{
constructAndPrintCommandHelpFormat ( "board" , "{2} {3}" , 3 ,
"board name" ,
"board vendor" ,
"board version"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "chassis-format" ))
2022-12-24 22:48:10 +08:00
{
constructAndPrintCommandHelpFormat ( "chassis" , "{2} {3}" , 4 ,
"chassis type" ,
"chassis vendor" ,
"chassis version"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "kernel-format" ))
2021-04-03 11:39:59 +02:00
{
constructAndPrintCommandHelpFormat ( "kernel" , "{2}" , 3 ,
"Kernel sysname" ,
"Kernel release" ,
"Kernel version"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "uptime-format" ))
2021-04-03 11:39:59 +02:00
{
constructAndPrintCommandHelpFormat ( "uptime" , "{} days {} hours {} mins" , 4 ,
"Days" ,
"Hours" ,
"Minutes" ,
"Seconds"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "processes-format" ))
2021-10-18 22:38:00 +08:00
{
constructAndPrintCommandHelpFormat ( "processes" , "{}" , 1 ,
"Count"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "packages-format" ))
2021-04-03 11:39:59 +02:00
{
2023-09-08 15:25:22 +08:00
constructAndPrintCommandHelpFormat ( "packages" , "{2} (pacman){?3}[{3}]{?}, {4} (dpkg), {5} (rpm), {6} (emerge), {7} (eopkg), {8} (xbps), {9} (nix-system), {10} (nix-user), {11} (nix-default), {12} (apk), {13} (pkg), {14} (flatpak-system), {15} (flatpack-user), {16} (snap), {17} (brew), {18} (brew-cask), {19} (port), {20} (scoop), {21} (choco), {22} (pkgtool), {23} (paludis), {24} (winget)" , 24 ,
2021-04-03 11:39:59 +02:00
"Number of all packages" ,
"Number of pacman packages" ,
2021-05-15 18:17:34 +02:00
"Pacman branch on manjaro" ,
2021-05-01 21:22:07 +02:00
"Number of dpkg packages" ,
2021-06-08 20:01:29 +02:00
"Number of rpm packages" ,
2022-02-12 12:13:02 +01:00
"Number of emerge packages" ,
2022-12-27 17:36:58 +08:00
"Number of eopkg packages" ,
2021-06-08 20:01:29 +02:00
"Number of xbps packages" ,
2022-07-26 19:03:15 +02:00
"Number of nix-system packages" ,
2022-07-26 19:15:00 +02:00
"Number of nix-user packages" ,
2022-06-02 22:58:19 +02:00
"Number of nix-default packages" ,
2022-08-18 22:02:21 +02:00
"Number of apk packages" ,
2022-09-20 11:16:08 +02:00
"Number of pkg packages" ,
2023-03-24 17:47:03 +08:00
"Number of flatpak-system packages" ,
"Number of flatpak-user packages" ,
2022-09-05 05:15:19 -07:00
"Number of snap packages" ,
2022-09-16 11:08:10 -06:00
"Number of brew packages" ,
2022-12-27 17:36:58 +08:00
"Number of brew-cask packages" ,
"Number of macports packages" ,
"Number of scoop packages" ,
2023-07-03 23:18:36 +08:00
"Number of choco packages" ,
2023-07-20 16:43:29 +01:00
"Number of pkgtool packages" ,
"Number of paludis packages"
2023-09-08 15:25:22 +08:00
"Number of winget packages"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "shell-format" ))
2021-04-03 11:39:59 +02:00
{
2023-09-13 14:47:13 +08:00
constructAndPrintCommandHelpFormat ( "shell" , "{3} {4}" , 6 ,
2021-06-14 23:22:14 +02:00
"Shell process name" ,
"Shell path with exe name" ,
"Shell exe name" ,
"Shell version" ,
2023-09-13 14:47:13 +08:00
"Shell pid" ,
"Shell pretty name"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "display-format" ))
2021-04-03 11:39:59 +02:00
{
2023-06-12 10:35:28 +08:00
constructAndPrintCommandHelpFormat ( "display" , "{}x{} @ {}Hz" , 7 ,
2021-04-03 11:39:59 +02:00
"Screen width" ,
"Screen height" ,
2023-01-07 22:37:01 +01:00
"Screen refresh rate" ,
2023-02-02 18:16:56 +01:00
"Screen scaled width" ,
2023-06-12 10:35:28 +08:00
"Screen scaled height" ,
"Screen name" ,
"Screen type" ,
"Screen rotation"
2021-04-03 11:39:59 +02:00
);
}
2023-08-09 16:29:04 +08:00
else if ( ffStrEqualsIgnCase ( command , "brightness-format" ))
{
constructAndPrintCommandHelpFormat ( "brightness" , "{}" , 2 ,
"Screen brightness" ,
"Screen name"
);
}
2023-08-09 16:31:24 +08:00
else if ( ffStrEqualsIgnCase ( command , "monitor-format" ))
{
constructAndPrintCommandHelpFormat ( "monitor" , "{}" , 6 ,
"Display name" ,
"Display native resolution width in pixels" ,
"Display native resolution height in pixels" ,
"Display physical width in millimeters" ,
"Display physical height in millimeters" ,
"Display physical diagonal length in inches" ,
"Display physical pixels per inch (PPI)"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "de-format" ))
2021-04-03 11:39:59 +02:00
{
2022-01-02 16:55:26 +01:00
constructAndPrintCommandHelpFormat ( "de" , "{2} {3}" , 3 ,
2021-05-01 13:03:30 +02:00
"DE process name" ,
"DE pretty name" ,
"DE version"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "wm-format" ))
2021-04-03 11:39:59 +02:00
{
2022-01-02 16:55:26 +01:00
constructAndPrintCommandHelpFormat ( "wm" , "{2} ({3})" , 3 ,
2021-04-03 11:39:59 +02:00
"WM process name" ,
2021-04-25 21:32:35 +02:00
"WM pretty name" ,
"WM protocol name"
2021-04-03 11:39:59 +02:00
);
}
2023-06-24 07:20:27 +00:00
else if ( ffStrEqualsIgnCase ( command , "wmtheme-format" ))
2021-04-03 23:10:14 +02:00
{
2023-06-24 07:20:27 +00:00
constructAndPrintCommandHelpFormat ( "wmtheme" , "{}" , 1 ,
2021-04-03 23:10:14 +02:00
"WM theme name"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "theme-format" ))
2021-04-03 11:39:59 +02:00
{
2023-06-08 14:32:15 +08:00
constructAndPrintCommandHelpFormat ( "theme" , "{}" , 1 ,
"Combined themes"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "icons-format" ))
2021-04-03 11:39:59 +02:00
{
2023-06-06 11:26:29 +08:00
constructAndPrintCommandHelpFormat ( "icons" , "{}" , 1 ,
"Combined icons"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "wallpaper-format" ))
2023-06-06 15:48:24 +08:00
{
constructAndPrintCommandHelpFormat ( "wallpaper" , "{}" , 1 ,
"Wallpaper image file"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "font-format" ))
2021-04-03 11:39:59 +02:00
{
2022-09-29 14:15:11 +02:00
constructAndPrintCommandHelpFormat ( "font" , "{} [QT], {} [GTK2], {} [GTK3], {} [GTK4]" , 4 ,
"Font 1" ,
"Font 2" ,
"Font 3" ,
"Font 4"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "cursor-format" ))
2021-06-20 21:04:55 +02:00
{
constructAndPrintCommandHelpFormat ( "cursor" , "{} ({}pt)" , 2 ,
"Cursor theme" ,
"Cursor size"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "terminal-format" ))
2021-04-03 11:39:59 +02:00
{
2022-09-12 15:57:05 +10:00
constructAndPrintCommandHelpFormat ( "terminal" , "{3}" , 10 ,
2021-04-03 11:39:59 +02:00
"Terminal process name" ,
2021-06-14 23:22:14 +02:00
"Terminal path with exe name" ,
2022-09-12 15:57:05 +10:00
"Terminal exe name" ,
2023-09-13 14:34:39 +08:00
"Terminal pid" ,
"Terminal pretty name" ,
"Terminal version"
2021-04-03 11:39:59 +02:00
);
}
2023-06-24 07:20:27 +00:00
else if ( ffStrEqualsIgnCase ( command , "terminalfont-format" ))
2021-04-03 11:39:59 +02:00
{
2023-06-24 07:20:27 +00:00
constructAndPrintCommandHelpFormat ( "terminalfont" , "{}" , 4 ,
2022-09-18 15:53:51 +02:00
"Terminal font" ,
2021-04-05 19:25:34 +02:00
"Terminal font name" ,
"Termianl font size" ,
2021-05-23 19:40:34 +02:00
"Terminal font styles"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "cpu-format" ))
2021-04-03 11:39:59 +02:00
{
2022-09-04 14:12:04 -07:00
constructAndPrintCommandHelpFormat ( "cpu" , "{1} ({5}) @ {7}GHz" , 8 ,
"Name" ,
"Vendor" ,
"Physical core count" ,
"Logical core count" ,
"Online core count" ,
"Min frequency" ,
"Max frequency" ,
"Temperature"
2021-04-03 11:39:59 +02:00
);
}
2023-08-29 17:43:39 +08:00
else if ( ffStrEqualsIgnCase ( command , "cpuusage-format" ))
2021-11-24 16:16:25 +08:00
{
2023-08-29 17:43:39 +08:00
constructAndPrintCommandHelpFormat ( "cpuusage" , "{0}%" , 1 ,
2021-11-24 16:16:25 +08:00
"CPU usage without percent mark"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "gpu-format" ))
2021-04-03 11:39:59 +02:00
{
2023-01-12 11:41:07 +01:00
constructAndPrintCommandHelpFormat ( "gpu" , "{} {}" , 6 ,
2021-04-03 11:39:59 +02:00
"GPU vendor" ,
2021-05-07 17:10:22 +02:00
"GPU name" ,
2022-06-17 23:38:33 +02:00
"GPU driver" ,
2022-09-16 18:11:39 +08:00
"GPU temperature" ,
2023-01-12 11:41:07 +01:00
"GPU core count" ,
"GPU type"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "memory-format" ))
2021-04-03 11:39:59 +02:00
{
2022-08-26 16:02:04 +02:00
constructAndPrintCommandHelpFormat ( "memory" , "{} / {} ({}%)" , 3 ,
"Used size" ,
"Total size" ,
"Percentage used"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "swap-format" ))
2022-09-08 14:51:31 +02:00
{
constructAndPrintCommandHelpFormat ( "swap" , "{} / {} ({}%)" , 3 ,
"Used size" ,
"Total size" ,
"Percentage used"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "disk-format" ))
2021-04-03 11:39:59 +02:00
{
2022-10-17 17:35:06 +02:00
constructAndPrintCommandHelpFormat ( "disk" , "{1} / {2} ({3}%)" , 9 ,
"Size used" ,
"Size total" ,
"Size percentage" ,
"Files used" ,
"Files total" ,
"Files percentage" ,
2023-06-15 00:30:27 +08:00
"True if external volume" ,
2022-10-17 17:35:06 +02:00
"True if hidden volume" ,
"Filesystem"
2021-04-03 11:39:59 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "battery-format" ))
2021-04-03 11:39:59 +02:00
{
2021-05-30 21:35:04 +02:00
constructAndPrintCommandHelpFormat ( "battery" , "{}%, {}" , 5 ,
2021-04-03 11:39:59 +02:00
"Battery manufactor" ,
"Battery model" ,
"Battery technology" ,
"Battery capacity" ,
"Battery status"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "poweradapter-format" ))
2022-09-23 14:59:28 +08:00
{
constructAndPrintCommandHelpFormat ( "poweradapter" , "{}%, {}" , 5 ,
"PowerAdapter watts" ,
"PowerAdapter name" ,
"PowerAdapter manufacturer" ,
"PowerAdapter model" ,
"PowerAdapter description"
);
}
2023-06-20 23:01:18 +08:00
else if ( ffStrEqualsIgnCase ( command , "lm-format" ))
{
constructAndPrintCommandHelpFormat ( "lm" , "{} ({})" , 2 ,
"LM service" ,
"LM type"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "locale-format" ))
2021-04-03 11:39:59 +02:00
{
constructAndPrintCommandHelpFormat ( "locale" , "{}" , 1 ,
"Locale code"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "local-ip-format" ))
2022-01-11 12:36:32 +01:00
{
constructAndPrintCommandHelpFormat ( "local-ip" , "{}" , 1 ,
"Local IP address"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "public-ip-format" ))
2022-01-11 12:36:32 +01:00
{
constructAndPrintCommandHelpFormat ( "public-ip" , "{}" , 1 ,
"Public IP address"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "wifi-format" ))
2022-11-26 18:23:08 +08:00
{
constructAndPrintCommandHelpFormat ( "wifi" , "{4} - {6}" , 3 ,
"Interface description" ,
"Interface status" ,
"Connection status" ,
"Connection SSID" ,
"Connection mac address" ,
2023-01-17 12:45:26 +08:00
"Connection protocol" ,
2022-11-26 18:23:08 +08:00
"Connection signal quality (percentage)" ,
"Connection RX rate" ,
"Connection TX rate" ,
2023-01-17 12:45:26 +08:00
"Connection Security algorithm"
2022-11-26 18:23:08 +08:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "player-format" ))
2022-02-13 23:51:13 +01:00
{
2022-09-11 13:09:33 +02:00
constructAndPrintCommandHelpFormat ( "player" , "{}" , 4 ,
2022-03-22 18:59:04 +01:00
"Pretty player name" ,
"Player name" ,
2023-06-08 16:05:01 +08:00
"Player Identifier" ,
2022-09-11 13:09:33 +02:00
"URL name"
2022-02-13 23:51:13 +01:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "media-format" ))
2022-02-13 23:51:13 +01:00
{
2022-12-30 10:47:57 +08:00
constructAndPrintCommandHelpFormat ( "media" , "{3} - {1}" , 4 ,
2022-09-11 13:09:33 +02:00
"Pretty media name" ,
"Media name" ,
2022-02-13 23:51:13 +01:00
"Artist name" ,
2022-09-11 13:09:33 +02:00
"Album name"
2022-02-13 23:51:13 +01:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "datetime-format" ) == 0 || ffStrEqualsIgnCase ( command , "date-format" ) || ffStrEqualsIgnCase ( command , "time-format" ))
2022-02-25 13:30:37 +01:00
{
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" ,
2022-06-10 15:12:39 -05:00
"hour with leading zero" ,
2022-02-25 13:30:37 +01:00
"hour 12h format" ,
"hour 12h format with leading zero" ,
"minute" ,
"minute with leading zero" ,
"second" ,
"second with leading zero"
);
}
2023-08-21 09:19:16 +08:00
else if ( ffStrEqualsIgnCase ( command , "version-format" ))
{
constructAndPrintCommandHelpFormat ( "version" , "{1} {2}{3} (5)" , 6 ,
"Project name" ,
"Version" ,
"Version tweak" ,
"Build type (debug or release)" ,
"Architecture" ,
"CMake build type (Debug, Release, RelWithDebInfo, MinSizeRel)"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "vulkan-format" ))
2022-06-01 00:04:58 +02:00
{
constructAndPrintCommandHelpFormat ( "vulkan" , "{} (driver), {} (api version)" , 3 ,
"Driver name" ,
"API version" ,
"Conformance version"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "opengl-format" ))
2022-06-04 15:21:34 +02:00
{
constructAndPrintCommandHelpFormat ( "opengl" , "{}" , 3 ,
"version" ,
"renderer" ,
2022-06-04 19:30:26 +02:00
"vendor" ,
"shading language version"
2022-06-04 15:21:34 +02:00
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "opencl-format" ))
2022-06-05 00:18:40 +02:00
{
constructAndPrintCommandHelpFormat ( "opencl" , "{}" , 3 ,
"version" ,
"device" ,
"vendor"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "bluetooth-format" ))
2023-01-24 10:39:33 +01:00
{
constructAndPrintCommandHelpFormat ( "bluetooth" , "{1} (4%)" , 4 ,
"Name" ,
"Address" ,
"Type" ,
"Battery percentage"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "sound-format" ))
2023-01-28 13:45:40 +08:00
{
constructAndPrintCommandHelpFormat ( "sound" , "{2} (3%)" , 4 ,
"Main" ,
"Name" ,
"Volume" ,
"Identifier"
);
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( command , "gamepad-format" ))
2023-02-01 14:01:39 +08:00
{
constructAndPrintCommandHelpFormat ( "gamepad" , "{1}" , 1 ,
"Name" ,
"Identifier"
);
}
2021-02-20 19:32:57 +01:00
else
2021-04-03 11:39:59 +02:00
fprintf ( stderr , "No specific help for command %s provided \n " , command );
2021-02-20 19:32:57 +01:00
}
2023-06-24 10:59:53 +08:00
static void listAvailablePresets ( void )
2021-04-25 11:48:25 +02:00
{
2023-06-24 10:59:53 +08:00
FF_LIST_FOR_EACH ( FFstrbuf , path , instance . state . platform . dataDirs )
2021-04-25 11:48:25 +02:00
{
2023-01-28 17:19:45 +01:00
ffStrbufAppendS ( path , "fastfetch/presets/" );
ffListFilesRecursively ( path -> chars );
2021-04-25 11:48:25 +02:00
}
}
2023-06-24 10:59:53 +08:00
static void listAvailableLogos ( void )
2021-04-25 11:48:25 +02:00
{
2023-06-24 10:59:53 +08:00
FF_LIST_FOR_EACH ( FFstrbuf , path , instance . state . platform . dataDirs )
2023-01-08 01:41:09 +01:00
{
2023-01-28 17:19:45 +01:00
ffStrbufAppendS ( path , "fastfetch/logos/" );
ffListFilesRecursively ( path -> chars );
2023-01-08 01:41:09 +01:00
}
2021-04-25 11:48:25 +02:00
}
2023-06-24 10:59:53 +08:00
static void listConfigPaths ( void )
2023-01-02 16:51:11 +08:00
{
2023-06-24 10:59:53 +08:00
FF_LIST_FOR_EACH ( FFstrbuf , folder , instance . state . platform . configDirs )
2023-01-02 16:51:11 +08:00
{
2023-06-10 21:34:41 +08:00
bool exists = false ;
ffStrbufAppendS ( folder , "fastfetch/config.jsonc" );
exists = ffPathExists ( folder -> chars , FF_PATHTYPE_FILE );
if ( ! exists )
{
ffStrbufSubstrBefore ( folder , folder -> length - ( uint32_t ) strlen ( "jsonc" ));
ffStrbufAppendS ( folder , "conf" );
exists = ffPathExists ( folder -> chars , FF_PATHTYPE_FILE );
}
printf ( "%s%s \n " , folder -> chars , exists ? " (*)" : "" );
2023-01-02 16:51:11 +08:00
}
}
2023-06-24 10:59:53 +08:00
static void listDataPaths ( void )
2023-01-08 01:41:09 +01:00
{
2023-06-24 10:59:53 +08:00
FF_LIST_FOR_EACH ( FFstrbuf , folder , instance . state . platform . dataDirs )
2023-01-08 01:41:09 +01:00
{
ffStrbufAppendS ( folder , "fastfetch/" );
puts ( folder -> chars );
}
}
2023-08-20 20:51:55 +08:00
static void listModules ()
{
unsigned count = 0 ;
for ( int i = 0 ; i <= 'Z' - 'A' ; ++ i )
{
for ( FFModuleBaseInfo ** modules = ffModuleInfos [ i ]; * modules ; ++ modules )
{
++ count ;
printf ( "%d)%s%s \n " , count , count > 9 ? " " : " " , ( * modules ) -> name );
}
}
}
2023-06-24 10:59:53 +08:00
static void parseOption ( FFdata * data , const char * key , const char * value );
2021-04-25 11:48:25 +02:00
2023-06-24 10:59:53 +08:00
static bool parseJsoncFile ( const char * path )
2023-06-10 21:34:41 +08:00
{
2023-06-17 20:39:08 +08:00
yyjson_read_err error ;
yyjson_doc * doc = yyjson_read_file ( path , YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INF_AND_NAN , NULL , & error );
2023-07-05 14:21:35 +08:00
if ( ! doc )
2023-06-10 21:34:41 +08:00
{
2023-07-05 14:21:35 +08:00
if ( error . code != YYJSON_READ_ERROR_FILE_OPEN )
{
2023-08-18 13:28:07 +08:00
fprintf ( stderr , "Error: failed to parse JSON config file `%s` at pos %zu: %s \n " , path , error . pos , error . msg );
2023-06-10 21:34:41 +08:00
exit ( 477 );
}
2023-07-05 14:21:35 +08:00
return false ;
2023-06-17 20:39:08 +08:00
}
2023-07-05 14:21:35 +08:00
if ( instance . state . configDoc )
yyjson_doc_free ( instance . state . configDoc ); // for `--load-config`
instance . state . configDoc = doc ;
return true ;
2023-06-10 21:34:41 +08:00
}
2023-06-24 10:59:53 +08:00
static bool parseConfigFile ( FFdata * data , const char * path )
2021-04-25 11:48:25 +02:00
{
2022-08-22 12:45:20 +02:00
FILE * file = fopen ( path , "r" );
if ( file == NULL )
return false ;
2022-08-21 21:08:11 +02:00
char * line = NULL ;
2021-04-25 11:48:25 +02:00
size_t len = 0 ;
ssize_t read ;
2023-08-15 16:39:20 +08:00
FF_STRBUF_AUTO_DESTROY unescaped = ffStrbufCreate ();
2021-04-25 11:48:25 +02:00
2022-08-21 21:08:11 +02:00
while (( read = getline ( & line , & len , file )) != - 1 )
2021-04-25 11:48:25 +02:00
{
2022-08-21 21:08:11 +02:00
char * lineStart = line ;
char * lineEnd = line + read - 1 ;
//Trim line left
while ( isspace ( * lineStart ))
++ lineStart ;
2021-04-25 11:48:25 +02:00
2022-08-21 21:08:11 +02:00
//Continue if line is empty or a comment
if ( * lineStart == '\0' || * lineStart == '#' )
2021-04-25 11:48:25 +02:00
continue ;
2022-08-21 21:08:11 +02:00
//Trim line right
while ( lineEnd > lineStart && isspace ( * lineEnd ))
-- lineEnd ;
* ( lineEnd + 1 ) = '\0' ;
char * valueStart = strchr ( lineStart , ' ' );
2021-04-25 11:48:25 +02:00
2022-08-21 21:08:11 +02:00
//If the line has no white space, it is only a key
if ( valueStart == NULL )
2021-04-25 11:48:25 +02:00
{
2023-06-24 10:59:53 +08:00
parseOption ( data , lineStart , NULL );
2021-04-25 11:48:25 +02:00
continue ;
}
2022-08-21 21:08:11 +02:00
//separate the key from the value
2021-04-25 11:48:25 +02:00
* valueStart = '\0' ;
++ valueStart ;
2022-08-21 21:08:11 +02:00
//Trim space of value left
while ( isspace ( * valueStart ))
2021-04-25 11:48:25 +02:00
++ valueStart ;
//If we want whitespace in values, we need to quote it. This is done to keep consistency with shell.
2022-08-21 21:08:11 +02:00
if (( * valueStart == '"' || * valueStart == '\'' ) && * valueStart == * lineEnd && lineEnd > valueStart )
2021-04-25 11:48:25 +02:00
{
2022-08-21 21:08:11 +02:00
++ valueStart ;
2022-08-22 12:14:08 +02:00
* lineEnd = '\0' ;
2022-08-21 21:08:11 +02:00
-- lineEnd ;
2021-04-25 11:48:25 +02:00
}
2023-08-15 16:39:20 +08:00
if ( strchr ( valueStart , '\\' ))
{
// Unescape all `\x`s
const char * value = valueStart ;
while ( * value != '\0' )
{
if ( * value != '\\' )
{
ffStrbufAppendC ( & unescaped , * value );
++ value ;
continue ;
}
++ value ;
switch ( * value )
{
case 'n' : ffStrbufAppendC ( & unescaped , '\n' ); break ;
case 't' : ffStrbufAppendC ( & unescaped , '\t' ); break ;
case 'e' : ffStrbufAppendC ( & unescaped , '\e' ); break ;
case '\\' : ffStrbufAppendC ( & unescaped , '\\' ); break ;
default :
ffStrbufAppendC ( & unescaped , '\\' );
ffStrbufAppendC ( & unescaped , * value );
break ;
}
++ value ;
}
parseOption ( data , lineStart , unescaped . chars );
ffStrbufClear ( & unescaped );
}
else
{
parseOption ( data , lineStart , valueStart );
}
2021-04-25 11:48:25 +02:00
}
2022-08-21 21:08:11 +02:00
if ( line != NULL )
free ( line );
2022-08-22 12:45:20 +02:00
fclose ( file );
return true ;
2021-04-25 11:48:25 +02:00
}
2023-08-07 14:15:11 +08:00
static void generateConfigFile ( bool force , const char * type )
2023-01-02 12:43:11 +08:00
{
2023-06-24 10:59:53 +08:00
FFstrbuf * filename = ( FFstrbuf * ) ffListGet ( & instance . state . platform . configDirs , 0 );
2023-01-02 12:43:11 +08:00
// Paths generated in `init.c/initConfigDirs` end with `/`
2023-08-07 14:15:11 +08:00
bool isJsonc = false ;
if ( type )
{
if ( ffStrEqualsIgnCase ( type , "jsonc" ))
isJsonc = true ;
else if ( ! ffStrEqualsIgnCase ( type , "conf" ))
{
fputs ( "config type can only be `jsonc` or `conf` \n " , stderr );
exit ( 1 );
}
}
ffStrbufAppendS ( filename , isJsonc ? "fastfetch/config.jsonc" : "fastfetch/config.conf" );
2023-01-02 12:43:11 +08:00
2023-01-28 11:52:23 +01:00
if ( ! force && ffPathExists ( filename -> chars , FF_PATHTYPE_FILE ))
2023-01-02 12:43:11 +08:00
{
fprintf ( stderr , "Config file exists in `%s`, use `--gen-config-force` to overwrite \n " , filename -> chars );
exit ( 1 );
}
else
{
2023-08-07 14:15:11 +08:00
ffWriteFileData (
filename -> chars ,
isJsonc ? strlen ( FASTFETCH_DATATEXT_CONFIG_USER_JSONC ) : strlen ( FASTFETCH_DATATEXT_CONFIG_USER ),
isJsonc ? FASTFETCH_DATATEXT_CONFIG_USER_JSONC : FASTFETCH_DATATEXT_CONFIG_USER );
2023-01-21 06:27:39 +08:00
printf ( "A sample config file has been written in `%s` \n " , filename -> chars );
2023-01-02 12:43:11 +08:00
exit ( 0 );
}
}
2023-06-24 10:59:53 +08:00
static void optionParseConfigFile ( FFdata * data , const char * key , const char * value )
2021-04-25 11:48:25 +02:00
{
if ( value == NULL )
{
fprintf ( stderr , "Error: usage: %s <file> \n " , key );
exit ( 413 );
}
2023-07-05 14:21:35 +08:00
uint32_t fileNameLen = ( uint32_t ) strlen ( value );
if ( fileNameLen == 0 )
{
fprintf ( stderr , "Error: usage: %s <file> \n " , key );
exit ( 413 );
}
bool isJsonConfig = fileNameLen > strlen ( ".jsonc" ) && strcasecmp ( value + fileNameLen - strlen ( ".jsonc" ), ".jsonc" ) == 0 ;
2021-04-25 11:48:25 +02:00
2022-08-22 12:45:20 +02:00
//Try to load as an absolute path
2023-07-05 14:21:35 +08:00
if ( isJsonConfig ? parseJsoncFile ( value ) : parseConfigFile ( data , value ))
2021-04-25 11:48:25 +02:00
return ;
2022-08-22 12:45:20 +02:00
2023-04-15 15:29:54 +08:00
FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA ( 128 );
2023-08-13 10:18:16 +08:00
if ( ffPathExpandEnv ( value , & absolutePath ))
{
2023-08-21 22:13:54 +08:00
bool success = isJsonConfig ? parseJsoncFile ( absolutePath . chars ) : parseConfigFile ( data , absolutePath . chars );
2023-08-13 10:18:16 +08:00
if ( success )
return ;
}
//Try to load as a relative path
2023-01-15 20:03:28 +01:00
2023-06-24 10:59:53 +08:00
FF_LIST_FOR_EACH ( FFstrbuf , path , instance . state . platform . dataDirs )
2021-04-25 11:48:25 +02:00
{
2023-01-15 20:03:28 +01:00
//We need to copy it, because if a config file loads a config file, the value of path must be unchanged
ffStrbufSet ( & absolutePath , path );
ffStrbufAppendS ( & absolutePath , "fastfetch/presets/" );
ffStrbufAppendS ( & absolutePath , value );
2022-08-22 12:45:20 +02:00
2023-08-21 22:13:54 +08:00
bool success = isJsonConfig ? parseJsoncFile ( absolutePath . chars ) : parseConfigFile ( data , absolutePath . chars );
2021-04-25 11:48:25 +02:00
2023-01-08 01:41:09 +01:00
if ( success )
return ;
2021-04-25 11:48:25 +02:00
}
2023-08-24 14:29:35 +08:00
{
//Try exe path
ffStrbufSet ( & absolutePath , & instance . state . platform . exePath );
ffStrbufSubstrBeforeLastC ( & absolutePath , '/' );
ffStrbufAppendS ( & absolutePath , "/presets/" );
ffStrbufAppendS ( & absolutePath , value );
bool success = isJsonConfig ? parseJsoncFile ( absolutePath . chars ) : parseConfigFile ( data , absolutePath . chars );
if ( success )
return ;
}
2022-08-22 12:45:20 +02:00
//File not found
2021-04-25 11:48:25 +02:00
fprintf ( stderr , "Error: couldn't find config: %s \n " , value );
exit ( 414 );
}
2021-12-20 12:12:55 +01:00
static inline void optionCheckString ( const char * key , const char * value , FFstrbuf * buffer )
2021-03-11 19:40:46 +01:00
{
if ( value == NULL )
{
2021-04-03 11:39:59 +02:00
fprintf ( stderr , "Error: usage: %s <str> \n " , key );
2021-03-11 19:40:46 +01:00
exit ( 477 );
}
2021-11-17 10:59:31 +01:00
ffStrbufEnsureFree ( buffer , 63 ); //This is not needed, as ffStrbufSetS will resize capacity if needed, but giving a higher start should improve performance
2021-12-20 12:12:55 +01:00
}
2023-08-17 16:00:24 +08:00
static void printVersion ()
2023-08-21 09:22:03 +08:00
{
FFVersionResult result = {};
ffDetectVersion ( & result );
printf ( "%s %s%s%s (%s) \n " , result . projectName , result . version , result . versionTweak , result . debugMode ? "-debug" : "" , result . architecture );
2023-08-17 16:00:24 +08:00
}
2023-01-19 14:57:54 +08:00
2023-08-17 16:00:24 +08:00
static void parseOption ( FFdata * data , const char * key , const char * value )
{
///////////////////////
//Informative options//
///////////////////////
if ( ffStrEqualsIgnCase ( key , "-h" ) || ffStrEqualsIgnCase ( key , "--help" ))
{
printCommandHelp ( value );
exit ( 0 );
}
else if ( ffStrEqualsIgnCase ( key , "-v" ) || ffStrEqualsIgnCase ( key , "--version" ))
{
printVersion ();
2022-03-20 17:12:52 +01:00
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--version-raw" ))
2021-03-03 19:59:39 +01:00
{
2022-03-20 13:16:04 +01:00
puts ( FASTFETCH_PROJECT_VERSION );
2021-03-03 19:59:39 +01:00
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--print" ))
2021-03-27 19:26:58 +01:00
{
2022-10-22 13:02:04 +08:00
const char * subkey = key + strlen ( "--print" );
2023-06-19 15:21:49 +08:00
if ( ffStrEqualsIgnCase ( subkey , "-config-system" ))
2022-10-22 13:02:04 +08:00
{
puts ( FASTFETCH_DATATEXT_CONFIG_SYSTEM );
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-config-user" ))
2022-10-22 13:02:04 +08:00
{
puts ( FASTFETCH_DATATEXT_CONFIG_USER );
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-structure" ))
2022-10-22 13:02:04 +08:00
{
puts ( FASTFETCH_DATATEXT_STRUCTURE );
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-logos" ))
2022-10-22 13:02:04 +08:00
{
2023-06-24 10:59:53 +08:00
ffLogoBuiltinPrint ();
2022-10-22 13:02:04 +08:00
exit ( 0 );
}
else
goto error ;
2021-03-03 19:59:39 +01:00
}
2023-06-19 15:21:49 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--list" ))
2021-03-03 19:59:39 +01:00
{
2022-10-22 13:02:04 +08:00
const char * subkey = key + strlen ( "--list" );
2023-06-19 15:21:49 +08:00
if ( ffStrEqualsIgnCase ( subkey , "-modules" ))
2022-10-22 13:02:04 +08:00
{
2023-08-20 20:51:55 +08:00
listModules ();
2022-10-22 13:02:04 +08:00
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-presets" ))
2022-10-22 13:02:04 +08:00
{
2023-06-24 10:59:53 +08:00
listAvailablePresets ();
2022-10-22 13:02:04 +08:00
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-config-paths" ))
2023-01-02 16:51:11 +08:00
{
2023-06-24 10:59:53 +08:00
listConfigPaths ();
2023-01-02 16:51:11 +08:00
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-data-paths" ))
2023-01-08 01:41:09 +01:00
{
2023-06-24 10:59:53 +08:00
listDataPaths ();
2023-01-08 01:41:09 +01:00
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-features" ))
2022-10-22 13:02:04 +08:00
{
ffListFeatures ();
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-logos" ))
2022-10-22 13:02:04 +08:00
{
2023-01-28 17:19:45 +01:00
puts ( "Builtin logos:" );
2022-10-22 13:02:04 +08:00
ffLogoBuiltinList ();
2023-01-28 17:19:45 +01:00
puts ( " \n Custom logos:" );
2023-06-24 10:59:53 +08:00
listAvailableLogos ();
2022-10-22 13:02:04 +08:00
exit ( 0 );
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-logos-autocompletion" ))
2022-10-22 13:02:04 +08:00
{
ffLogoBuiltinListAutocompletion ();
exit ( 0 );
}
else
goto error ;
2022-04-02 14:35:43 +02:00
}
2023-07-03 16:22:16 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--set" ))
{
const char * subkey = key + strlen ( "--set" );
if ( * subkey != '\0' && ! ffStrEqualsIgnCase ( subkey , "-keyless" ))
goto error ;
FF_STRBUF_AUTO_DESTROY customValueStr = ffStrbufCreate ();
ffOptionParseString ( key , value , & customValueStr );
uint32_t index = ffStrbufFirstIndexC ( & customValueStr , '=' );
if ( index == 0 || index == customValueStr . length )
{
fprintf ( stderr , "Error: usage: %s <key>=<str> \n " , key );
exit ( 477 );
}
2023-08-12 09:40:37 +08:00
FF_STRBUF_AUTO_DESTROY customKey = ffStrbufCreateNS ( index , customValueStr . chars );
FFCustomValue * customValue = NULL ;
FF_LIST_FOR_EACH ( FFCustomValue , x , data -> customValues )
{
if ( ffStrbufEqual ( & x -> key , & customKey ))
{
ffStrbufDestroy ( & x -> key );
ffStrbufDestroy ( & x -> value );
customValue = x ;
break ;
}
}
if ( ! customValue ) customValue = ( FFCustomValue * ) ffListAdd ( & data -> customValues );
ffStrbufInitMove ( & customValue -> key , & customKey );
ffStrbufSubstrAfter ( & customValueStr , index );
ffStrbufInitMove ( & customValue -> value , & customValueStr );
2023-07-03 16:22:16 +08:00
customValue -> printKey = * subkey == '\0' ;
}
2021-03-05 23:00:28 +01:00
2022-04-02 14:35:43 +02:00
///////////////////
//General options//
///////////////////
2021-03-03 19:59:39 +01:00
2023-08-24 14:36:32 +08:00
else if ( ffStrEqualsIgnCase ( key , "--load-config" ) || ffStrEqualsIgnCase ( key , "--config" ))
2023-06-24 10:59:53 +08:00
optionParseConfigFile ( data , key , value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--gen-config" ))
2023-08-07 14:15:11 +08:00
generateConfigFile ( false , value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--gen-config-force" ))
2023-08-07 14:15:11 +08:00
generateConfigFile ( true , value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--thread" ) || ffStrEqualsIgnCase ( key , "--multithreading" ))
2023-06-24 10:59:53 +08:00
instance . config . multithreading = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--stat" ))
2022-12-14 13:52:16 +08:00
{
2023-06-24 10:59:53 +08:00
if (( instance . config . stat = ffOptionParseBoolean ( value )))
instance . config . showErrors = true ;
2022-12-14 13:52:16 +08:00
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--allow-slow-operations" ))
2023-06-24 10:59:53 +08:00
instance . config . allowSlowOperations = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--escape-bedrock" ))
2023-06-24 10:59:53 +08:00
instance . config . escapeBedrock = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--pipe" ))
2023-06-24 10:59:53 +08:00
instance . config . pipe = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--load-user-config" ))
2023-06-12 15:48:26 +08:00
data -> loadUserConfig = ffOptionParseBoolean ( value );
2023-07-10 22:12:07 +08:00
else if ( ffStrEqualsIgnCase ( key , "--processing-timeout" ))
instance . config . processingTimeout = ffOptionParseInt32 ( key , value );
2023-08-29 11:13:55 +08:00
else if ( ffStrEqualsIgnCase ( key , "--format" ))
{
switch ( ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "default" , 0 },
{ "json" , 1 },
{},
}))
{
case 0 :
if ( instance . state . resultDoc )
{
yyjson_mut_doc_free ( instance . state . resultDoc );
instance . state . resultDoc = NULL ;
}
break ;
case 1 :
if ( ! instance . state . resultDoc )
{
instance . state . resultDoc = yyjson_mut_doc_new ( NULL );
yyjson_mut_doc_set_root ( instance . state . resultDoc , yyjson_mut_arr ( instance . state . resultDoc ));
}
break ;
}
}
2022-04-02 14:35:43 +02:00
2023-06-12 15:22:46 +08:00
#if defined(__linux__) || defined(__FreeBSD__)
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--player-name" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . playerName );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--os-file" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . osFile );
2023-07-31 23:11:39 +08:00
else if ( ffStrEqualsIgnCase ( key , "--ds-force-drm" ))
instance . config . dsForceDrm = ffOptionParseBoolean ( value );
2023-06-25 14:33:13 +08:00
#elif defined(_WIN32)
else if ( ffStrEqualsIgnCase ( key , "--wmi-timeout" ))
instance . config . wmiTimeout = ffOptionParseInt32 ( key , value );
2023-06-12 15:22:46 +08:00
#endif
2022-04-02 14:35:43 +02:00
////////////////
//Logo options//
////////////////
2023-06-24 10:59:53 +08:00
else if ( ffParseLogoCommandOptions ( & instance . config . logo , key , value )) {}
2022-04-02 14:35:43 +02:00
///////////////////
//Display options//
///////////////////
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--show-errors" ))
2023-06-24 10:59:53 +08:00
instance . config . showErrors = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--disable-linewrap" ))
2023-06-24 10:59:53 +08:00
instance . config . disableLinewrap = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--hide-cursor" ))
2023-06-24 10:59:53 +08:00
instance . config . hideCursor = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "-s" ) || ffStrEqualsIgnCase ( key , "--structure" ))
2023-06-12 15:48:26 +08:00
ffOptionParseString ( key , value , & data -> structure );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--separator" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . keyValueSeparator );
2023-08-17 16:00:24 +08:00
else if ( ffStrStartsWith ( key , "--color" ))
2023-06-10 21:34:41 +08:00
{
2023-08-17 16:00:24 +08:00
const char * subkey = key + strlen ( "--color" );
if ( * subkey == '\0' )
{
optionCheckString ( key , value , & instance . config . colorKeys );
ffOptionParseColor ( value , & instance . config . colorKeys );
ffStrbufSet ( & instance . config . colorTitle , & instance . config . colorKeys );
}
else if ( ffStrEqualsIgnCase ( subkey , "-keys" ))
{
optionCheckString ( key , value , & instance . config . colorKeys );
ffOptionParseColor ( value , & instance . config . colorKeys );
}
2023-08-23 17:07:36 -04:00
else if ( ffStrEqualsIgnCase ( subkey , "-title" ))
2023-08-17 16:00:24 +08:00
{
optionCheckString ( key , value , & instance . config . colorTitle );
ffOptionParseColor ( value , & instance . config . colorTitle );
}
else
goto error ;
2023-06-10 21:34:41 +08:00
}
2023-08-15 17:10:09 +08:00
else if ( ffStrEqualsIgnCase ( key , "--key-width" ))
instance . config . keyWidth = ffOptionParseUInt32 ( key , value );
2023-08-04 16:05:25 +08:00
else if ( ffStrEqualsIgnCase ( key , "--bright-color" ))
instance . config . brightColor = ffOptionParseBoolean ( value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--binary-prefix" ))
2022-08-26 16:02:04 +02:00
{
2023-06-24 10:59:53 +08:00
instance . config . binaryPrefixType = ( FFBinaryPrefixType ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
2023-06-12 15:48:26 +08:00
{ "iec" , FF_BINARY_PREFIX_TYPE_IEC },
{ "si" , FF_BINARY_PREFIX_TYPE_SI },
{ "jedec" , FF_BINARY_PREFIX_TYPE_JEDEC },
{}
});
2022-08-26 16:02:04 +02:00
}
2023-07-10 15:25:45 +08:00
else if ( ffStrEqualsIgnCase ( key , "--size-ndigits" ))
instance . config . sizeNdigits = ( uint8_t ) ffOptionParseUInt32 ( key , value );
else if ( ffStrEqualsIgnCase ( key , "--size-max-prefix" ))
2023-07-10 17:30:08 +08:00
{
instance . config . sizeMaxPrefix = ( uint8_t ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "B" , 0 },
{ "kB" , 1 },
{ "MB" , 2 },
{ "GB" , 3 },
{ "TB" , 4 },
{ "PB" , 5 },
{ "EB" , 6 },
{ "ZB" , 7 },
{ "YB" , 8 },
{}
});
}
2023-07-27 15:58:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--temperature-unit" ))
{
instance . config . temperatureUnit = ( FFTemperatureUnit ) ffOptionParseEnum ( key , value , ( FFKeyValuePair []) {
{ "CELSIUS" , FF_TEMPERATURE_UNIT_CELSIUS },
{ "C" , FF_TEMPERATURE_UNIT_CELSIUS },
{ "FAHRENHEIT" , FF_TEMPERATURE_UNIT_FAHRENHEIT },
{ "F" , FF_TEMPERATURE_UNIT_FAHRENHEIT },
{ "KELVIN" , FF_TEMPERATURE_UNIT_KELVIN },
{ "K" , FF_TEMPERATURE_UNIT_KELVIN },
{},
});
}
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--percent-type" ))
2023-08-24 09:35:17 +08:00
instance . config . percentType = ( uint8_t ) ffOptionParseUInt32 ( key , value );
else if ( ffStrEqualsIgnCase ( key , "--percent-ndigits" ))
instance . config . percentNdigits = ( uint8_t ) ffOptionParseUInt32 ( key , value );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( key , "--no-buffer" ))
2023-06-24 10:59:53 +08:00
instance . config . noBuffer = ffOptionParseBoolean ( value );
2023-08-17 16:00:24 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--bar" ))
{
const char * subkey = key + strlen ( "--bar" );
if ( ffStrEqualsIgnCase ( subkey , "-char-elapsed" ))
ffOptionParseString ( key , value , & instance . config . barCharElapsed );
else if ( ffStrEqualsIgnCase ( subkey , "-char-total" ))
ffOptionParseString ( key , value , & instance . config . barCharTotal );
else if ( ffStrEqualsIgnCase ( subkey , "-width" ))
instance . config . barWidth = ( uint8_t ) ffOptionParseUInt32 ( key , value );
else if ( ffStrEqualsIgnCase ( subkey , "-border" ))
instance . config . barBorder = ffOptionParseBoolean ( value );
else
goto error ;
}
2022-04-02 14:35:43 +02:00
///////////////////
//Library options//
///////////////////
2023-06-19 15:21:49 +08:00
else if ( ffStrStartsWithIgnCase ( key , "--lib" ))
2022-10-22 13:02:04 +08:00
{
const char * subkey = key + strlen ( "--lib" );
2023-06-19 15:21:49 +08:00
if ( ffStrEqualsIgnCase ( subkey , "-PCI" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libPCI );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-vulkan" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libVulkan );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-freetype" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libfreetype );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-wayland" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libWayland );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-xcb-randr" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libXcbRandr );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-xcb" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libXcb );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-Xrandr" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libXrandr );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-X11" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libX11 );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-gio" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libGIO );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-DConf" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libDConf );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-dbus" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libDBus );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-XFConf" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libXFConf );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-sqlite" ) || ffStrEqualsIgnCase ( subkey , "-sqlite3" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libSQLite3 );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-rpm" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . librpm );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-imagemagick" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libImageMagick );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-z" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libZ );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-chafa" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libChafa );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-egl" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libEGL );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-glx" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libGLX );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-osmesa" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libOSMesa );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-opencl" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libOpenCL );
2023-09-17 08:09:31 +03:00
else if ( ffStrEqualsIgnCase ( subkey , "-pulse" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libPulse );
2023-06-19 15:21:49 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-nm" ))
2023-06-24 10:59:53 +08:00
ffOptionParseString ( key , value , & instance . config . libnm );
2023-07-09 17:22:04 +08:00
else if ( ffStrEqualsIgnCase ( subkey , "-ddcutil" ))
ffOptionParseString ( key , value , & instance . config . libDdcutil );
2022-10-22 13:02:04 +08:00
else
goto error ;
}
2022-04-02 14:35:43 +02:00
2023-08-17 16:00:24 +08:00
///////////////////////
//Module args options//
///////////////////////
else if ( ffParseModuleOptions ( key , value )) {}
2022-04-02 14:35:43 +02:00
//////////////////
//Unknown option//
//////////////////
2021-12-19 22:39:22 +01:00
2021-03-03 19:59:39 +01:00
else
{
2022-10-22 13:02:04 +08:00
error :
2021-04-03 11:39:59 +02:00
fprintf ( stderr , "Error: unknown option: %s \n " , key );
2021-03-05 23:00:28 +01:00
exit ( 400 );
2021-03-03 19:59:39 +01:00
}
}
2023-06-24 10:59:53 +08:00
static void parseConfigFiles ( FFdata * data )
2022-07-21 14:37:13 +02:00
{
2023-06-24 10:59:53 +08:00
for ( uint32_t i = instance . state . platform . configDirs . length ; i > 0 ; -- i )
2023-06-10 21:34:41 +08:00
{
2023-06-24 10:59:53 +08:00
FFstrbuf * dir = ffListGet ( & instance . state . platform . configDirs , i - 1 );
2023-06-10 21:34:41 +08:00
uint32_t dirLength = dir -> length ;
ffStrbufAppendS ( dir , "fastfetch/config.jsonc" );
2023-06-24 10:59:53 +08:00
bool success = parseJsoncFile ( dir -> chars );
2023-06-10 21:34:41 +08:00
ffStrbufSubstrBefore ( dir , dirLength );
if ( success ) return ;
}
2023-06-24 10:59:53 +08:00
for ( uint32_t i = instance . state . platform . configDirs . length ; i > 0 ; -- i )
2023-01-02 17:27:06 +08:00
{
2023-01-07 22:51:47 +01:00
if ( ! data -> loadUserConfig )
return ;
2021-02-27 20:31:54 +01:00
2023-06-24 10:59:53 +08:00
FFstrbuf * dir = ffListGet ( & instance . state . platform . configDirs , i - 1 );
2023-01-07 22:51:47 +01:00
uint32_t dirLength = dir -> length ;
2023-01-02 17:27:06 +08:00
2023-01-07 22:51:47 +01:00
ffStrbufAppendS ( dir , "fastfetch/config.conf" );
2023-06-24 10:59:53 +08:00
parseConfigFile ( data , dir -> chars );
2023-01-07 22:51:47 +01:00
ffStrbufSubstrBefore ( dir , dirLength );
2023-01-02 17:27:06 +08:00
}
2021-03-03 19:59:39 +01:00
}
2023-06-24 10:59:53 +08:00
static void parseArguments ( FFdata * data , int argc , const char ** argv )
2021-03-03 19:59:39 +01:00
{
2022-07-21 14:37:13 +02:00
if ( ! data -> loadUserConfig )
return ;
2021-03-03 19:59:39 +01:00
for ( int i = 1 ; i < argc ; i ++ )
{
2023-08-17 16:00:24 +08:00
const char * key = argv [ i ];
if ( * key != '-' )
{
fprintf ( stderr , "Error: invalid option: %s. An option must start with `-` \n " , key );
exit ( 400 );
}
2021-11-18 18:25:24 +01:00
if ( i == argc - 1 || (
2023-08-25 10:32:03 +08:00
argv [ i + 1 ][ 0 ] == '-' &&
argv [ i + 1 ][ 1 ] != '\0' && // `-` is used as an alias for `/dev/stdin`
2021-11-18 18:25:24 +01:00
strcasecmp ( argv [ i ], "--separator-string" ) != 0 // Separator string can start with a -
)) {
2023-06-24 10:59:53 +08:00
parseOption ( data , argv [ i ], NULL );
2021-03-03 19:59:39 +01:00
}
else
{
2023-06-24 10:59:53 +08:00
parseOption ( data , argv [ i ], argv [ i + 1 ]);
2021-03-03 19:59:39 +01:00
++ i ;
}
}
2021-02-27 20:31:54 +01:00
}
2021-12-07 17:20:11 +01:00
int main ( int argc , const char ** argv )
2021-03-03 19:59:39 +01:00
{
2023-06-24 10:59:53 +08:00
ffInitInstance ();
2021-04-07 17:36:03 +02:00
2021-12-07 17:20:11 +01:00
//Data stores things only needed for the configuration of fastfetch
FFdata data ;
2023-06-24 10:59:53 +08:00
ffStrbufInit ( & data . structure );
2023-07-03 16:22:16 +08:00
ffListInit ( & data . customValues , sizeof ( FFCustomValue ));
2022-07-21 14:37:13 +02:00
data . loadUserConfig = true ;
2021-03-27 18:14:19 +01:00
2023-01-20 16:05:03 +08:00
if ( ! getenv ( "NO_CONFIG" ))
2023-06-24 10:59:53 +08:00
parseConfigFiles ( & data );
parseArguments ( & data , argc , argv );
2021-06-17 13:49:25 +02:00
2023-07-05 14:21:35 +08:00
if ( instance . state . configDoc )
{
const char * error = NULL ;
if (
( error = ffParseLogoJsonConfig ()) ||
( error = ffParseGeneralJsonConfig ()) ||
( error = ffParseDisplayJsonConfig ()) ||
( error = ffParseLibraryJsonConfig ()) ||
false
) {
fputs ( error , stderr );
exit ( 477 );
}
}
2023-08-18 13:28:07 +08:00
const bool useJsonConfig = data . structure . length == 0 && instance . state . configDoc ;
if ( useJsonConfig )
2023-08-29 11:13:55 +08:00
ffPrintJsonConfig ( true /* prepare */ );
2023-08-18 13:28:07 +08:00
else
2023-08-29 11:13:55 +08:00
ffPrepareCommandOption ( & data );
2022-09-29 17:14:50 +08:00
2023-06-24 10:59:53 +08:00
ffStart ();
2021-03-03 19:59:39 +01:00
2023-06-13 11:08:49 +08:00
#if defined(_WIN32)
if ( ! instance . config . noBuffer ) fflush ( stdout );
2023-01-12 00:11:25 +08:00
#endif
2023-08-18 13:28:07 +08:00
if ( useJsonConfig )
ffPrintJsonConfig ( false );
2023-06-11 00:51:29 +08:00
else
2023-08-29 11:13:55 +08:00
ffPrintCommandOption ( & data );
2023-06-11 00:51:29 +08:00
2023-08-29 11:13:55 +08:00
if ( instance . state . resultDoc )
{
2023-09-18 20:12:33 +08:00
yyjson_mut_write_fp ( stdout , instance . state . resultDoc , YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES , NULL , NULL );
2021-12-07 17:20:11 +01:00
}
2022-09-22 22:02:58 +02:00
2023-06-24 10:59:53 +08:00
ffFinish ();
2022-09-22 22:02:58 +02:00
2022-09-22 21:28:20 +08:00
ffStrbufDestroy ( & data . structure );
2023-07-03 16:22:16 +08:00
FF_LIST_FOR_EACH ( FFCustomValue , customValue , data . customValues )
{
ffStrbufDestroy ( & customValue -> key );
ffStrbufDestroy ( & customValue -> value );
}
ffListDestroy ( & data . customValues );
2021-03-03 19:59:39 +01:00
2023-06-24 10:59:53 +08:00
ffDestroyInstance ();
2021-02-18 22:25:36 +01:00
}