2021-06-19 14:57:27 +02:00
/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
Licensed under the Apache License , Version 2.0 ( the " License " ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an " AS IS " BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
indent = tab
tab - size = 4
*/
# include <array>
# include <ranges>
# include <atomic>
# include <fstream>
2021-09-01 21:40:13 +02:00
# include <string_view>
2021-06-19 14:57:27 +02:00
2021-06-19 22:48:31 +02:00
# include <btop_config.hpp>
2021-06-20 00:49:13 +02:00
# include <btop_shared.hpp>
2021-06-19 22:48:31 +02:00
# include <btop_tools.hpp>
2021-06-19 14:57:27 +02:00
2021-10-16 23:52:06 +02:00
using std : : array , std : : atomic , std : : string_view , std : : string_literals : : operator " " s ;
2021-06-19 14:57:27 +02:00
namespace fs = std : : filesystem ;
namespace rng = std : : ranges ;
using namespace Tools ;
//* Functions and variables for reading and writing the btop config file
namespace Config {
2021-07-21 03:17:34 +02:00
atomic < bool > locked ( false ) ;
2021-10-16 23:52:06 +02:00
atomic < bool > writelock ( false ) ;
2021-07-21 03:17:34 +02:00
bool write_new ;
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
const vector < array < string , 2 > > descriptions = {
2021-09-12 15:58:23 +02:00
{ " color_theme " , " #* Name of a btop++/bpytop/bashtop formatted \" .theme \" file, \" Default \" and \" TTY \" for builtin themes. \n "
" #* Themes should be placed in \" ../share/btop/themes \" relative to binary or \" $HOME/.config/btop/themes \" " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " theme_background " , " #* If the theme set background should be shown, set to False if you want terminal background transparency. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " truecolor " , " #* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " force_tty " , " #* Set to true to force tty mode regardless if a real tty has been detected or not. \n "
" #* Will force 16-color mode and TTY theme, set all graph symbols to \" tty \" and swap out other non tty friendly symbols. " } ,
2021-06-20 22:07:04 +02:00
2021-09-18 14:42:53 +02:00
{ " presets " , " #* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets. \n "
" #* Format: \" box_name:P:G,box_name:P:G \" P=(0 or 1) for alternate positons, G=graph symbol to use for box. \n "
" #* Use withespace \" \" as seprator between different presets. \n "
" #* Example: \" cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty \" " } ,
2021-10-12 17:34:52 +02:00
{ " vim_keys " , " #* Set to True to enable \" h,j,k,l \" keys for directional control in lists. \n "
" #* Conflicting keys for h: \" help \" and k: \" kill \" is accessible while holding shift. " } ,
2021-08-22 16:04:01 +02:00
{ " rounded_corners " , " #* Rounded corners on boxes, is ignored if TTY mode is ON. " } ,
2021-07-21 03:17:34 +02:00
{ " graph_symbol " , " #* Default symbols to use for graph creation, \" braille \" , \" block \" or \" tty \" . \n "
" #* \" braille \" offers the highest resolution but might not be included in all fonts. \n "
" #* \" block \" has half the resolution of braille but uses more common characters. \n "
" #* \" tty \" uses only 3 different symbols but will work with most fonts and should work in a real TTY. \n "
" #* Note that \" tty \" only has half the horizontal resolution of the other two, so will show a shorter historical view. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " graph_symbol_cpu " , " # Graph symbol to use for graphs in cpu box, \" default \" , \" braille \" , \" block \" or \" tty \" . " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " graph_symbol_mem " , " # Graph symbol to use for graphs in cpu box, \" default \" , \" braille \" , \" block \" or \" tty \" . " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " graph_symbol_net " , " # Graph symbol to use for graphs in cpu box, \" default \" , \" braille \" , \" block \" or \" tty \" . " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " graph_symbol_proc " , " # Graph symbol to use for graphs in cpu box, \" default \" , \" braille \" , \" block \" or \" tty \" . " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " shown_boxes " , " #* Manually set which boxes to show. Available values are \" cpu mem net proc \" , separate values with whitespace. " } ,
2021-06-20 22:07:04 +02:00
2021-08-03 23:47:46 +02:00
{ " update_ms " , " #* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " proc_sorting " , " #* Processes sorting, \" pid \" \" program \" \" arguments \" \" threads \" \" user \" \" memory \" \" cpu lazy \" \" cpu responsive \" , \n "
2021-08-15 23:20:55 +02:00
" #* \" cpu lazy \" sorts top process over time (easier to follow), \" cpu responsive \" updates top process directly. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " proc_reversed " , " #* Reverse sorting order, True or False. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " proc_tree " , " #* Show processes as a tree. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " proc_colors " , " #* Use the cpu graph colors in the process list. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " proc_gradient " , " #* Use a darkening gradient in the process list. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " proc_per_core " , " #* If process cpu usage should be of the core it's running on or usage of the total available cpu power. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " proc_mem_bytes " , " #* Show process memory as bytes instead of percent. " } ,
2021-06-20 22:07:04 +02:00
2021-08-03 23:47:46 +02:00
{ " proc_info_smaps " , " #* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate) " } ,
2021-07-26 01:06:34 +02:00
2021-07-29 23:40:56 +02:00
{ " proc_left " , " #* Show proc box on left side of screen instead of right. " } ,
2021-07-21 03:17:34 +02:00
{ " cpu_graph_upper " , " #* Sets the CPU stat shown in upper half of the CPU graph, \" total \" is always available. \n "
" #* Select from a list of detected attributes from the options menu. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " cpu_graph_lower " , " #* Sets the CPU stat shown in lower half of the CPU graph, \" total \" is always available. \n "
" #* Select from a list of detected attributes from the options menu. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " cpu_invert_lower " , " #* Toggles if the lower CPU graph should be inverted. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " cpu_single_graph " , " #* Set to True to completely disable the lower CPU graph. " } ,
2021-06-20 22:07:04 +02:00
2021-07-29 23:40:56 +02:00
{ " cpu_bottom " , " #* Show cpu box at bottom of screen instead of top. " } ,
2021-07-21 03:17:34 +02:00
{ " show_uptime " , " #* Shows the system uptime in the CPU box. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " check_temp " , " #* Show cpu temperature. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " cpu_sensor " , " #* Which sensor to use for cpu temperature, use options menu to select from list of available sensors. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " show_coretemp " , " #* Show temperatures for cpu cores also if check_temp is True and sensors has been found. " } ,
2021-06-20 22:07:04 +02:00
2021-08-03 23:47:46 +02:00
{ " cpu_core_map " , " #* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core. \n "
2021-09-17 14:25:54 +02:00
" #* Use lm-sensors or similar to see which cores are reporting temperatures on your machine. \n "
2021-08-03 23:47:46 +02:00
" #* Format \" x:y \" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries. \n "
" #* Example: \" 4:0 5:1 6:3 \" " } ,
2021-07-21 03:17:34 +02:00
{ " temp_scale " , " #* Which temperature scale to use, available values: \" celsius \" , \" fahrenheit \" , \" kelvin \" and \" rankine \" . " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " show_cpu_freq " , " #* Show CPU frequency. " } ,
2021-06-20 22:07:04 +02:00
2021-09-01 21:40:13 +02:00
{ " clock_format " , " #* Draw a clock at top of screen, formatting according to strftime, empty string to disable. \n "
" #* Special formatting: /host = hostname | /user = username | /uptime = system uptime " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " background_update " , " #* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " custom_cpu_name " , " #* Custom cpu model name, empty string to disable. " } ,
2021-06-20 22:07:04 +02:00
2021-08-10 20:20:33 +02:00
{ " disks_filter " , " #* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace \" \" . \n "
" #* Begin line with \" exclude= \" to change to exclude filter, otherwise defaults to \" most include \" filter. Example: disks_filter= \" exclude=/boot /home/user \" . " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " mem_graphs " , " #* Show graphs instead of meters for memory values. " } ,
2021-06-20 22:07:04 +02:00
2021-07-29 23:40:56 +02:00
{ " mem_below_net " , " #* Show mem box below net box instead of above. " } ,
2021-07-21 03:17:34 +02:00
{ " show_swap " , " #* If swap memory should be shown in memory box. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " swap_disk " , " #* Show swap as a disk, ignores show_swap value above, inserts itself after first disk. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " show_disks " , " #* If mem box should be split to also show disks info. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " only_physical " , " #* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " use_fstab " , " #* Read disks list from /etc/fstab. This also disables only_physical. " } ,
2021-06-20 22:07:04 +02:00
2021-09-12 15:58:23 +02:00
{ " show_io_stat " , " #* Toggles if io activity % (disk busy time) should be shown in regular disk usage view. " } ,
2021-06-20 22:07:04 +02:00
2021-09-12 15:58:23 +02:00
{ " io_mode " , " #* Toggles io mode for disks, showing big graphs for disk read/write speeds. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " io_graph_combined " , " #* Set to True to show combined read/write io graphs in io mode. " } ,
2021-06-20 22:07:04 +02:00
2021-09-17 14:25:54 +02:00
{ " io_graph_speeds " , " #* Set the top speed for the io graphs in MiB/s (100 by default), use format \" mountpoint:speed \" separate disks with whitespace \" \" . \n "
2021-08-10 20:20:33 +02:00
" #* Example: \" /mnt/media:100 /:20 /boot:1 \" . " } ,
2021-06-20 22:07:04 +02:00
2021-08-15 23:20:55 +02:00
{ " net_download " , " #* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " net_upload " , " " } ,
2021-06-20 22:07:04 +02:00
2021-08-15 23:20:55 +02:00
{ " net_auto " , " #* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest. " } ,
2021-06-20 22:07:04 +02:00
2021-08-15 23:20:55 +02:00
{ " net_sync " , " #* Sync the auto scaling for download and upload to whichever currently has the highest scale. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " net_iface " , " #* Starts with the Network Interface specified here. " } ,
2021-06-20 22:07:04 +02:00
2021-07-21 03:17:34 +02:00
{ " show_battery " , " #* Show battery stats in top right if battery is present. " } ,
2021-06-19 14:57:27 +02:00
2021-10-17 22:26:43 +02:00
{ " selected_battery " , " #* Which battery to use if multiple are present. \" Auto \" for auto detection. " } ,
2021-09-22 17:38:06 +02:00
{ " log_level " , " #* Set loglevel for \" ~/.config/btop/btop.log \" levels are: \" ERROR \" \" WARNING \" \" INFO \" \" DEBUG \" . \n "
2021-07-21 03:17:34 +02:00
" #* The level set includes all lower levels, i.e. \" DEBUG \" will show all logging info. " }
} ;
2021-06-19 14:57:27 +02:00
2021-07-21 03:17:34 +02:00
unordered_flat_map < string , string > strings = {
{ " color_theme " , " Default " } ,
{ " shown_boxes " , " cpu mem net proc " } ,
{ " graph_symbol " , " braille " } ,
2021-09-18 14:42:53 +02:00
{ " presets " , " cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty " } ,
2021-07-21 03:17:34 +02:00
{ " graph_symbol_cpu " , " default " } ,
{ " graph_symbol_mem " , " default " } ,
{ " graph_symbol_net " , " default " } ,
{ " graph_symbol_proc " , " default " } ,
{ " proc_sorting " , " cpu lazy " } ,
{ " cpu_graph_upper " , " total " } ,
{ " cpu_graph_lower " , " total " } ,
{ " cpu_sensor " , " Auto " } ,
2021-10-17 22:26:43 +02:00
{ " selected_battery " , " Auto " } ,
2021-08-03 23:47:46 +02:00
{ " cpu_core_map " , " " } ,
2021-07-21 03:17:34 +02:00
{ " temp_scale " , " celsius " } ,
2021-08-22 16:04:01 +02:00
{ " clock_format " , " %X " } ,
2021-07-21 03:17:34 +02:00
{ " custom_cpu_name " , " " } ,
{ " disks_filter " , " " } ,
{ " io_graph_speeds " , " " } ,
{ " net_iface " , " " } ,
{ " log_level " , " WARNING " } ,
{ " proc_filter " , " " } ,
{ " proc_command " , " " } ,
2021-09-01 21:40:13 +02:00
{ " selected_name " , " " } ,
2021-07-21 03:17:34 +02:00
} ;
unordered_flat_map < string , string > stringsTmp ;
unordered_flat_map < string , bool > bools = {
{ " theme_background " , true } ,
{ " truecolor " , true } ,
2021-08-22 16:04:01 +02:00
{ " rounded_corners " , true } ,
2021-07-21 03:17:34 +02:00
{ " proc_reversed " , false } ,
{ " proc_tree " , false } ,
{ " proc_colors " , true } ,
{ " proc_gradient " , true } ,
2021-08-12 22:25:18 +02:00
{ " proc_per_core " , true } ,
2021-07-21 03:17:34 +02:00
{ " proc_mem_bytes " , true } ,
2021-07-26 01:06:34 +02:00
{ " proc_info_smaps " , false } ,
2021-07-29 23:40:56 +02:00
{ " proc_left " , false } ,
2021-07-21 03:17:34 +02:00
{ " cpu_invert_lower " , true } ,
{ " cpu_single_graph " , false } ,
2021-07-29 23:40:56 +02:00
{ " cpu_bottom " , false } ,
2021-07-21 03:17:34 +02:00
{ " show_uptime " , true } ,
{ " check_temp " , true } ,
{ " show_coretemp " , true } ,
{ " show_cpu_freq " , true } ,
{ " background_update " , true } ,
{ " mem_graphs " , true } ,
2021-07-29 23:40:56 +02:00
{ " mem_below_net " , false } ,
2021-07-21 03:17:34 +02:00
{ " show_swap " , true } ,
{ " swap_disk " , true } ,
{ " show_disks " , true } ,
{ " only_physical " , true } ,
2021-09-26 19:35:09 +02:00
{ " use_fstab " , true } ,
2021-07-21 03:17:34 +02:00
{ " show_io_stat " , true } ,
{ " io_mode " , false } ,
{ " io_graph_combined " , false } ,
{ " net_auto " , true } ,
{ " net_sync " , false } ,
{ " show_battery " , true } ,
2021-10-12 17:34:52 +02:00
{ " vim_keys " , false } ,
2021-07-21 03:17:34 +02:00
{ " tty_mode " , false } ,
{ " force_tty " , false } ,
{ " lowcolor " , false } ,
{ " show_detailed " , false } ,
{ " proc_filtering " , false } ,
} ;
unordered_flat_map < string , bool > boolsTmp ;
unordered_flat_map < string , int > ints = {
{ " update_ms " , 2000 } ,
2021-08-15 23:20:55 +02:00
{ " net_download " , 100 } ,
{ " net_upload " , 100 } ,
2021-07-21 03:17:34 +02:00
{ " detailed_pid " , 0 } ,
{ " selected_pid " , 0 } ,
{ " proc_start " , 0 } ,
{ " proc_selected " , 0 } ,
2021-07-26 01:06:34 +02:00
{ " proc_last_selected " , 0 } ,
2021-07-21 03:17:34 +02:00
} ;
unordered_flat_map < string , int > intsTmp ;
bool _locked ( const string & name ) {
2021-10-16 23:52:06 +02:00
atomic_wait ( writelock , true ) ;
2021-07-21 03:17:34 +02:00
if ( not write_new and rng : : find_if ( descriptions , [ & name ] ( const auto & a ) { return a . at ( 0 ) = = name ; } ) ! = descriptions . end ( ) )
write_new = true ;
return locked . load ( ) ;
2021-06-19 14:57:27 +02:00
}
fs : : path conf_dir ;
fs : : path conf_file ;
2021-10-17 22:26:43 +02:00
vector < string > available_batteries = { " Auto " } ;
2021-07-18 15:44:32 +02:00
vector < string > current_boxes ;
2021-09-18 14:42:53 +02:00
vector < string > preset_list = { " cpu:0:default,mem:0:default,net:0:default,proc:0:default " } ;
int current_preset = - 1 ;
bool presetsValid ( const string & presets ) {
vector < string > new_presets = { preset_list . at ( 0 ) } ;
for ( int x = 0 ; const auto & preset : ssplit ( presets ) ) {
if ( + + x > 9 ) {
validError = " Too many presets entered! " ;
return false ;
}
for ( int y = 0 ; const auto & box : ssplit ( preset , ' , ' ) ) {
if ( + + y > 4 ) {
validError = " Too many boxes entered for preset! " ;
return false ;
}
const auto & vals = ssplit ( box , ' : ' ) ;
if ( vals . size ( ) ! = 3 ) {
validError = " Malformatted preset in config value presets! " ;
return false ;
}
if ( not is_in ( vals . at ( 0 ) , " cpu " , " mem " , " net " , " proc " ) ) {
validError = " Invalid box name in config value presets! " ;
return false ;
}
if ( not is_in ( vals . at ( 1 ) , " 0 " , " 1 " ) ) {
validError = " Invalid position value in config value presets! " ;
return false ;
}
if ( not v_contains ( valid_graph_symbols_def , vals . at ( 2 ) ) ) {
validError = " Invalid graph name in config value presets! " ;
return false ;
}
}
new_presets . push_back ( preset ) ;
}
preset_list = move ( new_presets ) ;
return true ;
}
//* Apply selected preset
void apply_preset ( const string & preset ) {
string boxes ;
2021-09-20 18:20:30 +02:00
2021-09-18 14:42:53 +02:00
for ( const auto & box : ssplit ( preset , ' , ' ) ) {
const auto & vals = ssplit ( box , ' : ' ) ;
boxes + = vals . at ( 0 ) + ' ' ;
2021-09-20 18:20:30 +02:00
}
if ( not boxes . empty ( ) ) boxes . pop_back ( ) ;
auto min_size = Term : : get_min_size ( boxes ) ;
if ( Term : : width < min_size . at ( 0 ) or Term : : height < min_size . at ( 1 ) ) {
return ;
}
for ( const auto & box : ssplit ( preset , ' , ' ) ) {
const auto & vals = ssplit ( box , ' : ' ) ;
2021-09-18 14:42:53 +02:00
if ( vals . at ( 0 ) = = " cpu " ) set ( " cpu_bottom " , ( vals . at ( 1 ) = = " 0 " ? false : true ) ) ;
else if ( vals . at ( 0 ) = = " mem " ) set ( " mem_below_net " , ( vals . at ( 1 ) = = " 0 " ? false : true ) ) ;
else if ( vals . at ( 0 ) = = " proc " ) set ( " proc_left " , ( vals . at ( 1 ) = = " 0 " ? false : true ) ) ;
set ( " graph_symbol_ " + vals . at ( 0 ) , vals . at ( 2 ) ) ;
}
2021-09-20 18:20:30 +02:00
2021-09-18 14:42:53 +02:00
if ( check_boxes ( boxes ) ) set ( " shown_boxes " , boxes ) ;
}
2021-07-18 15:44:32 +02:00
2021-07-24 02:13:26 +02:00
void lock ( ) {
2021-10-16 23:52:06 +02:00
atomic_wait ( writelock ) ;
2021-07-24 02:13:26 +02:00
locked = true ;
2021-06-19 14:57:27 +02:00
}
2021-09-12 15:58:23 +02:00
string validError ;
bool intValid ( const string & name , const string & value ) {
int i_value ;
try {
i_value = stoi ( value ) ;
}
catch ( const std : : invalid_argument & ) {
validError = " Invalid numerical value! " ;
return false ;
}
catch ( const std : : out_of_range & ) {
validError = " Value out of range! " ;
return false ;
}
2021-09-17 14:25:54 +02:00
catch ( const std : : exception & e ) {
validError = ( string ) e . what ( ) ;
return false ;
}
2021-09-12 15:58:23 +02:00
if ( name = = " update_ms " and i_value < 100 )
validError = " Config value update_ms set too low (<100). " ;
else if ( name = = " update_ms " and i_value > 86400000 )
validError = " Config value update_ms set too high (>86400000). " ;
else
return true ;
return false ;
}
bool stringValid ( const string & name , const string & value ) {
if ( name = = " log_level " and not v_contains ( Logger : : log_levels , value ) )
validError = " Invalid log_level: " + value ;
else if ( name = = " graph_symbol " and not v_contains ( valid_graph_symbols , value ) )
validError = " Invalid graph symbol identifier: " + value ;
else if ( name . starts_with ( " graph_symbol_ " ) and ( value ! = " default " and not v_contains ( valid_graph_symbols , value ) ) )
validError = " Invalid graph symbol identifier for " + name + " : " + value ;
else if ( name = = " shown_boxes " and not value . empty ( ) and not check_boxes ( value ) )
validError = " Invalid box name(s) in shown_boxes! " ;
2021-09-18 14:42:53 +02:00
else if ( name = = " presets " and not presetsValid ( value ) )
return false ;
2021-09-12 15:58:23 +02:00
else if ( name = = " cpu_core_map " ) {
const auto maps = ssplit ( value ) ;
bool all_good = true ;
for ( const auto & map : maps ) {
const auto map_split = ssplit ( map , ' : ' ) ;
if ( map_split . size ( ) ! = 2 )
all_good = false ;
else if ( not isint ( map_split . at ( 0 ) ) or not isint ( map_split . at ( 1 ) ) )
all_good = false ;
if ( not all_good ) {
validError = " Invalid formatting of cpu_core_map! " ;
return false ;
}
}
return true ;
}
else if ( name = = " io_graph_speeds " ) {
const auto maps = ssplit ( value ) ;
bool all_good = true ;
for ( const auto & map : maps ) {
const auto map_split = ssplit ( map , ' : ' ) ;
if ( map_split . size ( ) ! = 2 )
all_good = false ;
else if ( map_split . at ( 0 ) . empty ( ) or not isint ( map_split . at ( 1 ) ) )
all_good = false ;
if ( not all_good ) {
validError = " Invalid formatting of io_graph_speeds! " ;
return false ;
}
}
return true ;
}
else
return true ;
return false ;
}
string getAsString ( const string & name ) {
if ( bools . contains ( name ) )
return ( bools . at ( name ) ? " True " : " False " ) ;
else if ( ints . contains ( name ) )
return to_string ( ints . at ( name ) ) ;
else if ( strings . contains ( name ) )
return strings . at ( name ) ;
return " " ;
}
2021-07-24 02:13:26 +02:00
void flip ( const string & name ) {
2021-06-19 14:57:27 +02:00
if ( _locked ( name ) ) {
2021-06-21 22:52:55 +02:00
if ( boolsTmp . contains ( name ) ) boolsTmp . at ( name ) = not boolsTmp . at ( name ) ;
else boolsTmp . insert_or_assign ( name , ( not bools . at ( name ) ) ) ;
2021-06-19 14:57:27 +02:00
}
2021-06-21 22:52:55 +02:00
else bools . at ( name ) = not bools . at ( name ) ;
2021-06-19 14:57:27 +02:00
}
2021-07-21 03:17:34 +02:00
void unlock ( ) {
2021-06-30 22:28:12 +02:00
if ( not locked ) return ;
2021-08-10 20:20:33 +02:00
atomic_wait ( Runner : : active ) ;
2021-10-16 23:52:06 +02:00
atomic_lock lck ( writelock , true ) ;
2021-07-21 03:17:34 +02:00
try {
if ( Proc : : shown ) {
ints . at ( " selected_pid " ) = Proc : : selected_pid ;
2021-09-01 21:40:13 +02:00
strings . at ( " selected_name " ) = Proc : : selected_name ;
2021-07-21 03:17:34 +02:00
ints . at ( " proc_start " ) = Proc : : start ;
ints . at ( " proc_selected " ) = Proc : : selected ;
}
2021-06-19 14:57:27 +02:00
2021-07-21 03:17:34 +02:00
for ( auto & item : stringsTmp ) {
strings . at ( item . first ) = item . second ;
}
stringsTmp . clear ( ) ;
2021-06-19 14:57:27 +02:00
2021-07-21 03:17:34 +02:00
for ( auto & item : intsTmp ) {
ints . at ( item . first ) = item . second ;
}
intsTmp . clear ( ) ;
2021-06-19 14:57:27 +02:00
2021-07-21 03:17:34 +02:00
for ( auto & item : boolsTmp ) {
bools . at ( item . first ) = item . second ;
}
boolsTmp . clear ( ) ;
}
catch ( const std : : exception & e ) {
Global : : exit_error_msg = " Exception during Config::unlock() : " + ( string ) e . what ( ) ;
2021-08-12 22:25:18 +02:00
exit ( 1 ) ;
2021-06-19 14:57:27 +02:00
}
locked = false ;
}
2021-07-24 02:13:26 +02:00
bool check_boxes ( const string & boxes ) {
2021-07-18 15:44:32 +02:00
auto new_boxes = ssplit ( boxes ) ;
for ( auto & box : new_boxes ) {
2021-07-04 01:18:48 +02:00
if ( not v_contains ( valid_boxes , box ) ) return false ;
}
2021-07-29 23:40:56 +02:00
current_boxes = move ( new_boxes ) ;
2021-07-04 01:18:48 +02:00
return true ;
}
2021-07-29 23:40:56 +02:00
void toggle_box ( const string & box ) {
2021-09-20 18:20:30 +02:00
auto old_boxes = current_boxes ;
2021-08-17 22:33:21 +02:00
auto box_pos = rng : : find ( current_boxes , box ) ;
if ( box_pos = = current_boxes . end ( ) )
2021-07-29 23:40:56 +02:00
current_boxes . push_back ( box ) ;
else
2021-08-17 22:33:21 +02:00
current_boxes . erase ( box_pos ) ;
2021-07-29 23:40:56 +02:00
string new_boxes ;
if ( not current_boxes . empty ( ) ) {
for ( const auto & b : current_boxes ) new_boxes + = b + ' ' ;
new_boxes . pop_back ( ) ;
}
2021-09-20 18:20:30 +02:00
auto min_size = Term : : get_min_size ( new_boxes ) ;
if ( Term : : width < min_size . at ( 0 ) or Term : : height < min_size . at ( 1 ) ) {
current_boxes = old_boxes ;
return ;
}
2021-07-29 23:40:56 +02:00
Config : : set ( " shown_boxes " , new_boxes ) ;
}
void load ( const fs : : path & conf_file , vector < string > & load_warnings ) {
2021-06-19 14:57:27 +02:00
if ( conf_file . empty ( ) )
return ;
2021-06-21 22:52:55 +02:00
else if ( not fs : : exists ( conf_file ) ) {
2021-06-19 14:57:27 +02:00
write_new = true ;
return ;
}
std : : ifstream cread ( conf_file ) ;
if ( cread . good ( ) ) {
vector < string > valid_names ;
for ( auto & n : descriptions )
valid_names . push_back ( n [ 0 ] ) ;
string v_string ;
getline ( cread , v_string , ' \n ' ) ;
2021-09-01 21:40:13 +02:00
if ( not s_contains ( v_string , Global : : Version ) )
2021-06-19 14:57:27 +02:00
write_new = true ;
2021-06-21 22:52:55 +02:00
while ( not cread . eof ( ) ) {
2021-06-19 14:57:27 +02:00
cread > > std : : ws ;
if ( cread . peek ( ) = = ' # ' ) {
cread . ignore ( SSmax , ' \n ' ) ;
continue ;
}
string name , value ;
getline ( cread , name , ' = ' ) ;
2021-07-18 15:44:32 +02:00
if ( name . ends_with ( ' ' ) ) name = trim ( name ) ;
2021-06-21 22:52:55 +02:00
if ( not v_contains ( valid_names , name ) ) {
2021-06-19 14:57:27 +02:00
cread . ignore ( SSmax , ' \n ' ) ;
continue ;
}
2021-07-18 15:44:32 +02:00
cread > > std : : ws ;
2021-06-19 14:57:27 +02:00
if ( bools . contains ( name ) ) {
cread > > value ;
2021-06-21 22:52:55 +02:00
if ( not isbool ( value ) )
2021-07-29 23:40:56 +02:00
load_warnings . push_back ( " Got an invalid bool value for config name: " + name ) ;
2021-06-19 14:57:27 +02:00
else
bools . at ( name ) = stobool ( value ) ;
}
else if ( ints . contains ( name ) ) {
cread > > value ;
2021-06-21 22:52:55 +02:00
if ( not isint ( value ) )
2021-07-29 23:40:56 +02:00
load_warnings . push_back ( " Got an invalid integer value for config name: " + name ) ;
2021-09-12 15:58:23 +02:00
else if ( not intValid ( name , value ) ) {
load_warnings . push_back ( validError ) ;
2021-08-22 16:04:01 +02:00
}
2021-06-19 14:57:27 +02:00
else
ints . at ( name ) = stoi ( value ) ;
}
else if ( strings . contains ( name ) ) {
if ( cread . peek ( ) = = ' " ' ) {
cread . ignore ( 1 ) ;
getline ( cread , value , ' " ' ) ;
}
else cread > > value ;
2021-09-12 15:58:23 +02:00
if ( not stringValid ( name , value ) )
load_warnings . push_back ( validError ) ;
2021-06-19 14:57:27 +02:00
else
strings . at ( name ) = value ;
}
cread . ignore ( SSmax , ' \n ' ) ;
}
2021-07-29 23:40:56 +02:00
if ( not load_warnings . empty ( ) ) write_new = true ;
2021-06-19 14:57:27 +02:00
}
}
2021-07-21 03:17:34 +02:00
void write ( ) {
2021-06-21 22:52:55 +02:00
if ( conf_file . empty ( ) or not write_new ) return ;
2021-06-19 14:57:27 +02:00
Logger : : debug ( " Writing new config file " ) ;
std : : ofstream cwrite ( conf_file , std : : ios : : trunc ) ;
if ( cwrite . good ( ) ) {
cwrite < < " #? Config file for btop v. " < < Global : : Version ;
for ( auto [ name , description ] : descriptions ) {
2021-07-18 15:44:32 +02:00
cwrite < < " \n \n " < < ( description . empty ( ) ? " " : description + " \n " )
< < name < < " = " ;
if ( strings . contains ( name ) )
cwrite < < " \" " < < strings . at ( name ) < < " \" " ;
else if ( ints . contains ( name ) )
cwrite < < ints . at ( name ) ;
else if ( bools . contains ( name ) )
cwrite < < ( bools . at ( name ) ? " True " : " False " ) ;
2021-06-19 14:57:27 +02:00
}
}
}
}