#!/usr/bin/perl

# Copyright (C) 2010-2014 Trizen <echo dHJpemVueEBnbWFpbC5jb20K | base64 -d>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#-------------------------------------------------------
#  Appname: alsi
#  Created on: 04 October 2010
#  Latest edit on: 28 May 2014
#  Minor patches: 08 August 2020
#  GitHub: https://github.com/trizen/alsi
#-------------------------------------------------------

use strict;

my $appname = 'alsi';
my $version = '0.4.9';

my $home_dir   = $ENV{HOME}            || $ENV{LOGDIR} || (getpwuid($<))[7] || `echo -n ~`;
my $config_dir = $ENV{XDG_CONFIG_HOME} || "$home_dir/.config";

my $alsi_config_dir = "$config_dir/$appname";
my $config_file     = $alsi_config_dir . "/$appname.conf";

my %CONFIG = (
              ALSI_VERSION         => $version,
              USE_VALUES_COLOR     => 0,
              USE_LOGO_FROM_FILE   => 0,
              USAGE_COLORS         => 0,
              USAGE_COLORS_BOLD    => 0,
              USAGE_PRECENT_RED    => 100,
              USAGE_PRECENT_YELLOW => 85,
              USAGE_PRECENT_GREEN  => 50,
              DEFAULT_COLOR_NORMAL => 'blue',
              DEFAULT_COLOR_BOLD   => 'blue',
              PS_COMMAND           => 'ps -A',
              DF_COMMAND           => 'df -Th -x sys -x tmpfs -x devtmpfs &>/dev/stdout',
              SCREENSHOT_COMMAND   => 'scrot -cd 5',
              GTK2_RC_FILE         => "$home_dir/.gtkrc-2.0",
              GTK3_RC_FILE         => "$config_dir/gtk-3.0/settings.ini",
              LOGO_FILE            => "$alsi_config_dir/alsi.logo",
              COLORS_FILE          => "$alsi_config_dir/$appname.colors",
              OUTPUT_FILE          => "$alsi_config_dir/alsi.output",
              WM_FILE              => "$alsi_config_dir/alsi.wm",
              DE_FILE              => "$alsi_config_dir/alsi.de",
              PACKAGES_PATH        => '/var/lib/pacman/local/',
             );

# Creating config unless it exists
if (not -e $config_file or not -e $alsi_config_dir) {
    require File::Path;
    File::Path::make_path($alsi_config_dir);
    write_config_to_file();
}

apply_configuration() unless grep { $_ eq '--noconfig' } @ARGV;

unless (-e $CONFIG{COLORS_FILE}) {
    save_plain($CONFIG{COLORS_FILE}, <<'COLORS');
#!/usr/bin/perl

# Colors for alsi

scalar {
         black   => {normal => "\e[0;30m", bold => "\e[1;30m"},
         red     => {normal => "\e[0;31m", bold => "\e[1;31m"},
         green   => {normal => "\e[0;32m", bold => "\e[1;32m"},
         yellow  => {normal => "\e[0;33m", bold => "\e[1;33m"},
         default => {normal => "\e[0;34m", bold => "\e[1;34m"},
         blue    => {normal => "\e[0;34m", bold => "\e[1;34m"},
         purple  => {normal => "\e[0;35m", bold => "\e[1;35m"},
         cyan    => {normal => "\e[0;36m", bold => "\e[1;36m"},
         white   => {normal => "\e[0;37m", bold => "\e[1;37m"},
         reset   => "\e[0m",
}
COLORS
}

unless (-e $CONFIG{OUTPUT_FILE}) {
    save_plain($CONFIG{OUTPUT_FILE}, <<'OUTPUT_FILE');
#!/usr/bin/perl

# '%sTitle:%s %s'
#  |    \   \  ` Value
#  \     \   `-- End of BC (or start of NC)
#   BC    ` Label

# NC = normal color (color1)
# BC = bold color   (color2)

#-- Other valid options are:
# USERNAME   - ex: {USERNAME => '%sUsername:%s %s'},
# CPU_LOAD   - ex: {CPU_LOAD => '%sCPU load average:%s %s'},
# OTHER      - ex: {OTHER => '%sResolution:%s 1024x768'},
# COMMAND    - ex: {COMMAND => ['%sBinaries:%s %s', 'ls /usr/bin | wc -l']},
# HARDCODED  - ex: {HARDCODED => "\e[1;37m\e[41mTHIS IS ALSI\e[0m"},

# GTK3_THEME      - ex: {GTK3_THEME      => '%sGTK3 theme:%s %s'},
# GTK3_ICON_THEME - ex: {GTK3_ICON_THEME => '%sGTK3 icon theme:%s %s'},
# GTK3_FONT_NAME  - ex: {GTK3_FONT_NAME  => '%sGTK3 font name:%s %s'},

[
    {OS       => '%sOS:%s %s'},          # Operating system
    {HOSTNAME => '%sHostname:%s %s'},    # Hostname
    {UPTIME   => '%sUptime:%s %s'},      # Uptime
    {KERNEL   => '%sKernel:%s %s'},      # Kernel version
    {SHELL    => '%sShell:%s %s'},       # Shell
    {PACKAGES => '%sPackages:%s %s'},    # Number of installed packages
    {WM_DE    => '%s%s:%s %s'},          # Window Manager or Desktop Environment

    {GTK2_THEME      => '%sGTK2 theme:%s %s'},         # Gtk2 theme
    {GTK2_ICON_THEME => '%sGTK2 icon theme:%s %s'},    # Gtk2 icon theme
    {GTK2_FONT_NAME  => '%sGTK2 font name:%s %s'},     # Gtk2 font name

    {RAM        => '%sRAM:%s %s'},                # RAM usage
    {SWAP       => '%sSWAP:%s %s'},               # SWAP usage
    {CPU        => '%sCPU:%s %s'},                # CPU name
    {PARTITIONS => undef},                        # Partitions goes here
]
OUTPUT_FILE
}

unless (-e $CONFIG{WM_FILE}) {
    save_plain($CONFIG{WM_FILE}, <<'WM_FILE');
#!/usr/bin/perl

# PROCESS_NAME  =>  WINDOW_MANAGER_NAME

scalar {
         '2wm'                   => '2wm',
         '9wm'                   => '9wm',
         'afterstep'             => 'AfterStep',
         'antiwm'                => 'AntiWM',
         'awesome'               => 'Awesome',
         'barewm'                => 'Bare WM',
         'beryl'                 => 'Beryl',
         'blackbox'              => 'Blackbox',
         'bspwm'                 => 'bspwm',
         'clfswm'                => 'CLFS WM',
         'compiz'                => 'Compiz',
         'ctwm'                  => 'CTWM',
         'cwm'                   => 'CWM',
         'dswm'                  => 'DSWM',
         'dwm'                   => 'DWM',
         'echinus'               => 'Echinus',
         'enlightenment'         => 'Enlightenment',
         'euclid'                => 'Euclid',
         'evil-wm'               => 'EvilWM',
         'evilpoison'            => 'EviL Poison',
         'fluxbox'               => 'Fluxbox',
         'flwm'                  => 'FLWM',
         'fvwm'                  => 'FVWM',
         'hackedbox'             => 'Hackedbox',
         'hildon-desktop'        => 'Matchbox',
         'i3'                    => 'i3',
         'icewm'                 => 'IceWM',
         'ion-3'                 => 'Ion3',
         'ion3'                  => 'Ion3',
         'jwm'                   => 'JWM',
         'karmen'                => 'Karmen',
         'kwin'                  => 'Kwin',
         'larswm'                => 'Lars WM',
         'lewm'                  => 'LEWM',
         'lwm'                   => 'LWM',
         'matwm2'                => 'matWM2',
         'metacity'              => 'Metacity',
         'musca'                 => 'Musca',
         'notion'                => 'Notion',
         'openbox'               => 'Openbox',
         'openbox-gnome-session' => 'Openbox (GNOME session)',
         'openbox-kde-session'   => 'Openbox (KDE session)',
         'pawm'                  => 'PAWM',
         'pekwm'                 => 'PekWM',
         'qlwm'                  => 'qLWM',
         'qtile'                 => 'Qtile',
         'quarkwm'               => 'QuarkWM',
         'ratpoison'             => 'ratpoison',
         'sawfish'               => 'Sawfish',
         'scrot-wm'              => 'ScrotWM',
         'scrotwm'               => 'ScrotWM',
         'sithwm'                => 'SithWM',
         'stumpwm'               => 'StumpWM',
         'subtle'                => 'Subtle',
         'swm'                   => 'SWM',
         'tinywm'                => 'TinyWM',
         'tritium'               => 'Tritium',
         'twm'                   => 'twm',
         'velox'                 => 'Velox',
         'vtwm'                  => 'VtWM',
         'vwm'                   => 'VWM',
         'w9wm'                  => 'w9wm',
         'weewm'                 => 'WeeWM',
         'windowmaker'           => 'WindowMaker',
         'windwm'                => 'WindWM',
         'wmaker'                => 'WindowMaker',
         'wmfs'                  => 'Wmfs',
         'WMFS'                  => 'WMFS',
         'wmii'                  => 'wmii',
         'wmii36'                => 'wmii36',
         'xmonad'                => 'xmonad',
         'yeahwm'                => 'YeahWM',
}
WM_FILE
}

unless (-e $CONFIG{DE_FILE}) {
    save_plain($CONFIG{DE_FILE}, <<'DE_FILE');
#!/usr/bin/perl

# PROCESS_NAME  =>  DESKTOP_ENVIRONMENT_NAME

scalar {
         'gnome-session' => 'GNOME',
         'kdm'           => 'KDE',
         'ksmserver'     => 'KDE',
         'lxsession'     => 'LXDE',
         'xfce4-session' => 'XFCE4',
         'xfwm4'         => 'XFCE4',
}
DE_FILE
}

unless (-e $CONFIG{LOGO_FILE}) {
    save_plain($CONFIG{LOGO_FILE}, <<'LOGO');
    $c1                               Y\     /Y\t\t
    $c1                               | \ _ / |\t\t
    $c1         _____                 | =(_)= |\t\t
    $c1     ,-~"     "~-.           ,-~\/^ ^\/~-.\t\t
    $c1   ,^ ___     ___ ^.       ,^ ___     ___ ^.\t
    $c1  / .^   ^. .^   ^. \     / .^   ^. .^   ^. \\\t
    $c1 Y  l    O! l    O!  Y   Y  lo    ! lo    !  Y\t
    $c1 l_ `.___.' `.___.' _[   l_ `.___.' `.___.' _[\t
    $c1 l^~"-------------"~^I   l^~"-------------"~^I\t
    $c1 !\,               ,/!   !                   !\t
    $c1  \ ~-.,_______,.-~ /     \                 /\t
    $c1   ^.             .^       ^.             .^\t
    $c1     "-.._____.,-"           "-.._____.,-"\t\t
    \t\t\t\t\t\t\t
    $c2        WHY DOES THE LOGO FOR GENTOO LINUX\t\t
    \t\t\t\t\t\t\t
    $c2           LOOK LIKE A RETARDED PAC-MAN?\t\t$z
LOGO
}

sub help {
    print <<"HELP";
Usage:
    $0 [options]\n
Main options:
    -a  --archey         : use archey's logo
    -n  --screenfetch    : use screenfetch's logo
    -f  --file-logo=file : read logo from a specific file
    -t  --text-color     : use color for values as well
    -l  --list           : output the lines bellow the logo
    -u  --usage-colors   : highlight the usage for RAM and HDD
        --usage-bcolors  : same as above, but with bold colors

    --bold=[color]       : change the bold color
    --normal=[color]     : change the normal color
    --[color]            : set color1 and color2 at the same color.

    Available colors are: black, red, green yellow,
                          blue, purple, cyan and white
Other options:
    --update-config     : update the configuration file
    --noconfig          : don't load the configuration file
    -s --screenshot     : take a screenshot
    -h --help           : print help and exit
    -v --version        : print version and exit

Logo file:
    special variables   : \$c1, \$c2, \$z *
    escaped characters  : \\t, \\e, \\x

* Note: the variables are also valid as \${var_name}
        when are followed by a word character.

** Config file   : $config_file
** Colors file   : $CONFIG{COLORS_FILE}
** Output file   : $CONFIG{OUTPUT_FILE}
** Logo   file   : $CONFIG{LOGO_FILE}
** WManagers     : $CONFIG{WM_FILE}
** DEnvironments : $CONFIG{DE_FILE}\n
HELP
    exit 0;
}

sub version {
    print "$appname $version\n";
    exit 0;
}

# Save hash config to file
sub write_config_to_file {
    save_hash($config_file, \%CONFIG);
    return 1;
}

# argv options
my %opt;

# Set config file to %CONFIG
sub apply_configuration {
    my $config_ref = do $config_file;
    if (ref $config_ref eq 'HASH') {
        while (my ($key, $value) = each %$config_ref) {
            $CONFIG{$key} = $value;
        }
    }
    else {
        write_config_to_file();
    }
    if ($CONFIG{ALSI_VERSION} ne $version) {
        $CONFIG{ALSI_VERSION} = $version;
        $opt{update_config}   = 1;
    }
}

sub parse_arguments {
    require Getopt::Long;
    Getopt::Long::GetOptions(

        # Main options
        'help|h|?'  => \&help,
        'version|v' => \&version,

        # Colors
        'normal|color1|c1=s' => \$CONFIG{DEFAULT_COLOR_NORMAL},
        'bold|color2|c2=s'   => \$CONFIG{DEFAULT_COLOR_BOLD},
        'default|d'          => sub { ($opt{default_color}) = @_ },
        'blue|bl'            => sub { ($opt{default_color}) = @_ },
        'red|r'              => sub { ($opt{default_color}) = @_ },
        'green|g'            => sub { ($opt{default_color}) = @_ },
        'yellow|y'           => sub { ($opt{default_color}) = @_ },
        'black|b'            => sub { ($opt{default_color}) = @_ },
        'purple|p'           => sub { ($opt{default_color}) = @_ },
        'cyan|c'             => sub { ($opt{default_color}) = @_ },
        'white|w'            => sub { ($opt{default_color}) = @_ },

        # Others
        'usage-colors|u!'              => \$CONFIG{USAGE_COLORS},
        'usage-bold-colors|ub!'        => \$CONFIG{USAGE_COLORS_BOLD},
        'text-color|t!'                => \$CONFIG{USE_VALUES_COLOR},
        'list|l'                       => \$opt{bellow_logo},
        'file-logo|logo-from-file|f:s' => \$opt{logo_from_file},
        'noconfig!'                    => \$opt{noconfig},
        'screenfetch|n'                => \$opt{screenfetch_logo},
        'archey|a'                     => \$opt{archey_logo},
        'screenshot|s'                 => \$opt{take_screenshot},
        'update-config|reconfigure!'   => \$opt{update_config},
    );
}

# Parsing arguments
@ARGV && parse_arguments();

my $colors = do $CONFIG{COLORS_FILE};
unless (ref $colors eq 'HASH') {
    die "[!] There is a problem with the COLORS_FILE '$CONFIG{COLORS_FILE}': " . ($! || q{doesn't return a HASH ref}) . "\n";
}

$colors->{default}{normal} = $colors->{$CONFIG{DEFAULT_COLOR_NORMAL}}{normal};
$colors->{default}{bold}   = $colors->{$CONFIG{DEFAULT_COLOR_BOLD}}{bold};

if (defined $opt{default_color}) {
    $colors->{default} = $colors->{$opt{default_color}};
}

if ($CONFIG{USE_VALUES_COLOR}) {
    $colors->{reset} = $colors->{default}{normal};
}

my ($c1, $c2, $z) = ($colors->{default}{normal}, $colors->{default}{bold}, $colors->{reset});

my $wm = do $CONFIG{WM_FILE};
my $de = do $CONFIG{DE_FILE};

#------ SUBROUTINES -------#

sub get_usage_color {
    my ($percent) = @_;
    foreach my $color (qw(green yellow red)) {
        return $colors->{$color}{$CONFIG{USAGE_COLORS_BOLD} ? 'bold' : 'normal'}
          if $percent <= $CONFIG{"USAGE_PRECENT_\U$color\E"};
    }
}

sub get_total_size_color {
    $CONFIG{USE_VALUES_COLOR}
      ? $CONFIG{USAGE_COLORS_BOLD}
          ? $c1 =~ s/0/1/r
          : $c1
      : q{};
}

# Format a partition
{
    my $tmp_clr = '';
    my $tmp_gcl = '';

    sub format_partition {
        my ($name, $used, $total, $used_percent, $type) = @_;

        $total ||= 1;
        $used_percent //= int($used / $total * 100);

        if ($CONFIG{USAGE_COLORS} or $CONFIG{USAGE_COLORS_BOLD}) {
            $tmp_clr = get_usage_color($used_percent);
            $tmp_gcl //= get_total_size_color();
        }

        @_ == 5 || do {
            $total .= 'M';
            $used  .= 'M';
        };

        (defined($name) ? "$c2${name}:$z " : "")
          . "$tmp_clr$used$z / $tmp_gcl$total$z ($tmp_clr$used_percent%$z)"
          . (defined($type) ? " ($type)" : "");
    }
}

# Getting GTK informations
{
    my %GTKRC;

    sub get_gtkrc_info {
        my ($name, $version) = @_;

        exists($GTKRC{$name})
          && return $GTKRC{$name};

        my $gtkrc_content;
        my $file = $version == 3 ? $CONFIG{GTK3_RC_FILE} : $CONFIG{GTK2_RC_FILE};

        sysopen(my $fh, $file, 0) or return;
        sysread $fh, $gtkrc_content, -s $file;

        foreach my $pair (["THEME", 'gtk-theme-name'], ["ICON_THEME", 'gtk-icon-theme-name'], ['FONT_NAME', 'gtk-font-name'],)
        {
            ($GTKRC{"GTK${version}_$pair->[0]"}) = $gtkrc_content =~ m{^\s*$pair->[1]\s*=\s*['"]?([^"'\n]+)}m;
        }

        $GTKRC{$name};
    }
}

# Logos
if (defined $opt{logo_from_file} or $CONFIG{USE_LOGO_FROM_FILE}) {
    unless (-r $CONFIG{LOGO_FILE}) {
        warn "[!] Unable to read '$CONFIG{LOGO_FILE}': $!\n";
        undef $opt{logo_from_file};
    }
}

my $arch_logo;
if (defined $opt{logo_from_file} or $CONFIG{USE_LOGO_FROM_FILE}) {
    open my $logo_fh, '<', (-f $opt{logo_from_file} ? $opt{logo_from_file} : $CONFIG{LOGO_FILE});
    while (defined(my $line = <$logo_fh>)) {
        $line =~ s/(?<!\\)(?:\\\\)*\K\\(?![\$\\tex])/\\\\/g;
        $line =~ s/"/\\"/g;
        $line =~ s/(?<!\\)(?:\\\\)*\K((?:\$(?!(\{)?(?:c[12]|z)(??{$2 ? '\}' : ''})(?(?<!\})\b)))|[%\@])/\\$1/g;
        $arch_logo .= eval qq["$line"];
    }
    close $logo_fh;
}
elsif ($opt{archey_logo}) {
    $arch_logo = <<"LOGO";
$c1                  +\t\t\t
$c1                  #\t\t\t
$c1                 ###\t\t\t
$c1                #####\t\t\t
$c1                ######\t\t\t
$c1               ; #####;\t\t\t
$c1              +##.#####\t\t\t
$c1             +##########\t\t
$c1            ######$c2#####$c1##;\t\t
$c1           ###$c2############$c1+\t\t
$c1          #$c2######   #######\t\t
$c2        .######;     ;###;`".\t\t
$c2       .#######;     ;#####.\t\t
$c2       #########.   .########`\t\t
$c2      ######'           '######\t\t
$c2     ;####                 ####;\t
$c2     ##'                     '##\t
$c2    #'                         `#$z\t
LOGO
}
elsif ($opt{screenfetch_logo}) {
    $arch_logo = <<"LOGO";
$c1                   -`\t\t\t
$c1                  .o+`\t\t\t
$c1                 `ooo/\t\t\t
$c1                `+oooo:\t\t\t
$c1               `+oooooo:\t\t
$c1               -+oooooo+:\t\t
$c1             `/:-:++oooo+:\t\t
$c1            `/++++/+++++++:\t\t
$c1           `/++++++++++++++:\t\t
$c1          `/+++o${c2}oooooooo${c1}oooo/`\t\t
$c2         $c1./${c2}ooosssso++osssssso$c1+`\t\t
$c2        .oossssso-````/ossssss+`\t
$c2       -osssssso.      :ssssssso.\t
$c2      :osssssss/        osssso+++.\t
$c2     /ossssssss/        +ssssooo/-`\t
$c2   `/ossssso+/:-        -:/+osssso+-\t
$c2  `+sso+:-`                 `.-/+oso:\t
$c2 `++:.                           `-/+/\t
$c2 .`                                 `+/$z\t
LOGO
}
elsif ($opt{bellow_logo}) {
    $arch_logo = <<"LOGO";
        $c2,$c1                       _     _ _
       $c2/$c1#$c2\\$c1        __ _ _ __ ___| |__ | (_)_ __  _   ___  __
      $c2/$c1###$c2\\$c1      / _` | '__/ __| '_ \\| | | '_ \\| | | \\ \\/ /
     $c2/$c1#####$c2\\$c1    | (_| | | | (__| | | | | | | | | |_| |>  <
    $c2/$c1##,-,##$c2\\$c1    \\__,_|_|  \\___|_| |_|_|_|_| |_|\\__,_/_/\\_\\
   $c2/$c1##(   )##$c2\\$c1
  $c2/$c1#.--   --.#$c2\\\e[1;37m   A simple, elegant GNU/Linux distribution.
 $c2/$c1`           `$c2\\$z
LOGO
}
else {
    $arch_logo = <<"LOGO";
                  $c1##$z\t\t\t
                 $c1#$c2##$c1#$z\t\t\t
                $c1#$c2####$c1#$z\t\t\t
               $c1#$c2######$c1#$z\t\t\t
              $c1#$c2########$c1#$z\t\t
             $c1#$c2##########$c1#$z\t\t
            $c1#$c2############$c1#$z\t\t
           $c1#$c2##############$c1#$z\t\t
          $c1#$c2################$c1#$z\t\t
         $c1#$c2##################$c1#$z\t\t
        $c1#$c2#######$c1######$c2#######$c1#$z\t\t
       $c1#$c2#######$c1#$z      $c1#$z$c2#######$c1#$z\t\t
      $c1#$c2########$c1#$z      $c1#$z$c2########$c1#$z\t
     $c1#$c2#########$c1#$z      $c1#$z$c2#########$c1#$z\t
    $c1#$c2######$c1###$z          $c1###$c2######$c1#$z\t
   $c1#$c2####$c1##$z                  $c1##$c2####$c1#$z\t
  $c1#$c2##$c1#$z                          $c1#$c2##$c1#$z\t
 $c1#$c2#$c1#$z                              $c1#$c2#$c1#$z\t
LOGO
}

my $config_array = do $CONFIG{OUTPUT_FILE};

{    # GENERATE OUTPUT
    my @output;
    if (ref $config_array eq 'ARRAY') {
        foreach my $item (@$config_array) {

            # OS
            if (exists $item->{OS}) {
                my $arch = `uname -m`;
                push @output,
                  sprintf($item->{OS},
                          $c2, $z, -e '/etc/arch-release'
                          ? "Arch Linux $arch"
                          : substr(`uname -o`, 0, -1) . " $arch");
            }

            # CPU
            elsif (exists $item->{CPU}) {
                my $cpu;
                if (sysopen(my $cpu_fh, '/proc/cpuinfo', 0)) {
                    while (defined(my $cpu_line = <$cpu_fh>)) {
                        if (!index($cpu_line, 'model name')) {
                            $cpu = substr($cpu_line, 13);
                            last;
                        }
                    }
                }
                $cpu //= `uname -p`;
                $cpu = join(' ', split(' ', $cpu));

                push @output, sprintf($item->{CPU}, $c2, $z, $cpu);
            }

            # RAM
            elsif (exists $item->{RAM}) {
                my $freeram  = 0;
                my $totalram = 1;

                if (sysopen(my $ram_fh, '/proc/meminfo', 0)) {
                    while (defined(my $ram_line = <$ram_fh>)) {
                        my (undef, $ammount) = split(' ', $ram_line);
                        $. == 1 ? ($totalram = $ammount / 1024) : ($. > 1 && $. != 3) ? ($freeram += $ammount / 1024) : ();
                        $. == 5 && last;
                    }
                }
                else {
                    next;
                }

                push @output,
                  sprintf($item->{RAM}, $c2, $z, format_partition(undef, int($totalram - $freeram), int($totalram)));
            }

            # SWAP
            elsif (exists $item->{SWAP}) {
                sysopen(my $fh, '/proc/swaps', 0) or next;
                scalar <$fh>;    # ignore the column names
                next if eof($fh);
                my (undef, undef, $totalswap, $usedswap) = split(' ', scalar <$fh>);
                push @output,
                  sprintf($item->{SWAP}, $c2, $z, format_partition(undef, int($usedswap / 1024), int($totalswap / 1024)));
            }

            # WM or DE
            elsif (exists $item->{WM_DE}) {
                my $wm_de = ['Window Manager', "Unknown"];
                open my $ps_pipe, '-|', $CONFIG{PS_COMMAND};
                while (defined(my $process = <$ps_pipe>)) {
                    $process = (split(' ', $process))[-1];
                    if (exists $de->{$process}) {
                        $wm_de = ['DE', $de->{$process}];
                        last;
                    }
                    elsif (
                        exists $wm->{$process} or (
                            substr($process, -8) eq '-session' and exists $wm->{
                                do { $process =~ s/-session$//; $process }
                            }
                        )
                      ) {
                        $wm_de = ['WM', $wm->{$process}];
                        last;
                    }
                }

                push @output, sprintf($item->{WM_DE}, $c2, $wm_de->[0], $z, $wm_de->[1]);
            }

            # UPTIME
            elsif (exists $item->{UPTIME}) {

                my $uptime;
                if (sysopen(my $uptime_fh, '/proc/uptime', 0)) {
                    local $/ = ' ';
                    $uptime = <$uptime_fh>;
                }
                else {
                    next;
                }

                my $day = int($uptime / 86400);
                $uptime %= 86400;
                my $hours = int($uptime / 3600);
                $uptime %= 3600;
                my $min = sprintf('%02d', int($uptime / 60));
                my $sec = $uptime % 60;

                $uptime = '';
                $uptime = "$day day, " if $day == 1;
                $uptime = "$day days, " if $day > 1;
                $uptime .= $hours ? "${hours}:$min" : "$min min";
                $uptime .= ", $sec sec" unless $day;

                push @output, sprintf($item->{UPTIME}, $c2, $z, $uptime);
            }

            # KERNEL
            elsif (exists $item->{KERNEL}) {
                my $kernel;
                if (sysopen(my $osrelease_fh, '/proc/sys/kernel/osrelease', 0)) {
                    sysread($osrelease_fh, $kernel, 64);
                }
                else {
                    $kernel = `uname -r`;
                }

                push @output, sprintf($item->{KERNEL}, $c2, $z, $kernel);
            }

            # HOSTNAME
            elsif (exists $item->{HOSTNAME}) {
                my $hostname;
                if (sysopen(my $hostname_fh, '/proc/sys/kernel/hostname', 0)) {
                    sysread($hostname_fh, $hostname, 64);
                }
                else {
                    $hostname = `uname -n`;
                }
                push @output, sprintf($item->{HOSTNAME}, $c2, $z, $hostname);
            }

            # PACKAGES
            elsif (exists $item->{PACKAGES}) {
                my $packages;
                if (opendir(my $dir_h, $CONFIG{PACKAGES_PATH})) {
                    $packages = () = readdir $dir_h;
                    $packages -= 2;
                    if (-e $CONFIG{PACKAGES_PATH} . '/ALPM_DB_VERSION') {
                        $packages -= 1;
                    }
                }
                else {
                    next;
                }

                push @output, sprintf($item->{PACKAGES}, $c2, $z, $packages);
            }

            # SHELL
            elsif (exists $item->{SHELL}) {
                push @output, sprintf($item->{SHELL}, $c2, $z, ($ENV{SHELL} || (getpwuid($<))[-1] || 'Unknown'));
            }

            # GTK2 THEME
            elsif (exists $item->{GTK2_THEME}) {
                my $gtk2_theme = get_gtkrc_info('GTK2_THEME', 2) // next;
                push @output, sprintf($item->{GTK2_THEME}, $c2, $z, $gtk2_theme);
            }

            # GTK2 ICON THEME
            elsif (exists $item->{GTK2_ICON_THEME}) {
                my $gtk2_icon_theme = get_gtkrc_info('GTK2_ICON_THEME', 2) // next;
                push @output, sprintf($item->{GTK2_ICON_THEME}, $c2, $z, $gtk2_icon_theme);
            }

            # GTK2 FONT NAME
            elsif (exists $item->{GTK2_FONT_NAME}) {
                my $gtk2_font_name = get_gtkrc_info('GTK2_FONT_NAME', 2) // next;
                push @output, sprintf($item->{GTK2_FONT_NAME}, $c2, $z, $gtk2_font_name);
            }

            # GTK3 THEME
            elsif (exists $item->{GTK3_THEME}) {
                my $gtk3_theme = get_gtkrc_info('GTK3_THEME', 3) // next;
                push @output, sprintf($item->{GTK3_THEME}, $c2, $z, $gtk3_theme);
            }

            # GTK3 ICON THEME
            elsif (exists $item->{GTK3_ICON_THEME}) {
                my $gtk3_icon_theme = get_gtkrc_info('GTK3_ICON_THEME', 3) // next;
                push @output, sprintf($item->{GTK3_ICON_THEME}, $c2, $z, $gtk3_icon_theme);
            }

            # GTK3 FONT NAME
            elsif (exists $item->{GTK3_FONT_NAME}) {
                my $gtk3_font_name = get_gtkrc_info('GTK3_FONT_NAME', 3) // next;
                push @output, sprintf($item->{GTK3_FONT_NAME}, $c2, $z, $gtk3_font_name);
            }

            # PARTITIONS
            elsif (exists $item->{PARTITIONS}) {

                my %partitions;
                open my $df_pipe, '-|', $CONFIG{DF_COMMAND};
                scalar <$df_pipe>;    # skip first line
                while (defined($df_pipe) and defined(my $line = <$df_pipe>)) {
                    my (undef, $type, $totalsize, $used, undef, $used_percent, $mountpoint) = split(' ', $line);
                    chop $used_percent;

                    my $orig_mnt = $mountpoint;
                    $mountpoint =
                        $mountpoint eq '/'      ? 'Root'
                      : $mountpoint =~ m{^.*/}s ? ucfirst substr($mountpoint, $+[0])
                      :                           ucfirst $mountpoint;

                    $partitions{$orig_mnt} = format_partition($mountpoint, $used, $totalsize, $used_percent, $type);
                }

                my %seen;
                push @output, sort grep { !$seen{$_}++ } values %partitions;
            }

            # OTHER
            elsif (exists $item->{OTHER}) {
                push @output, sprintf($item->{OTHER}, $c2, $z);
            }

            # HARDCODED
            elsif (exists $item->{HARDCODED}) {
                push @output, $item->{HARDCODED};
            }

            # CPU LOAD
            elsif (exists $item->{CPU_LOAD}) {
                sysopen(my $fh, '/proc/loadavg', 0) or next;
                sysread($fh, (my $cpu_load_average), 14);
                push @output, sprintf($item->{CPU_LOAD}, $c2, $z, $cpu_load_average);
            }

            # USERNAME
            elsif (exists $item->{USERNAME}) {
                push @output,
                  sprintf($item->{USERNAME},
                          $c2, $z, ($ENV{USERNAME} // $ENV{LOGNAME} // getlogin() // (getpwuid($<))[0] // 'Unknown'));
            }

            # COMMAND
            elsif (exists $item->{COMMAND} and ref $item->{COMMAND} eq 'ARRAY') {
                push @output, sprintf($item->{COMMAND}[0], $c2, $z, `$item->{COMMAND}[1]`);
            }
        }
    }
    else {
        die "[!] There is a problem with the OUTPUT_FILE '$CONFIG{OUTPUT_FILE}': "
          . ($! || q{doesn't return an ARRAY ref}) . "\n";
    }

    my $output = "\n";
    if ($opt{bellow_logo}) {
        $output .= $arch_logo . "\n";
        foreach my $line (@output) {
            chomp($line);
            $output .= "${c1}> " . $line . "\n";
        }
    }
    else {
        my @arch_logo = split(/\n/, $arch_logo);
        while (my ($index, $line) = each @arch_logo) {
            chomp($output[$index]);
            $output .= $line . $output[$index] . "\n";
        }
    }

    $output .= "\e[0m" if $CONFIG{USE_VALUES_COLOR};
    $output .= "\n";

    print $output;
}

save_hash($config_file, \%CONFIG) if $opt{update_config};
exec $CONFIG{SCREENSHOT_COMMAND}  if $opt{take_screenshot};

sub save_hash {
    my ($file, $config) = @_;

    my $header = <<'HEAD';
#!/usr/bin/perl

HEAD
    require Data::Dump;
    my $txt = Data::Dump::dump($config);

    # Replace the home directory with $ENV{HOME}
    if (defined($ENV{HOME}) and $home_dir eq $ENV{HOME}) {
        $txt =~ s/\Q$home_dir\E/\$ENV{HOME}/g;
    }

    return save_plain($file, $header . 'scalar ' . $txt . "\n");
}

sub save_plain {
    my ($file, $plain_config) = @_;
    open(my $fh, '>', $file) or return;
    print {$fh} $plain_config;
    return close $fh;
}
