replace perl euse with bash euse
authorgenone <genone@gentoo.org>
Sun, 17 Oct 2004 17:50:47 +0000 (17:50 -0000)
committergenone <genone@gentoo.org>
Sun, 17 Oct 2004 17:50:47 +0000 (17:50 -0000)
svn path=/; revision=156

trunk/ChangeLog
trunk/src/euse/AUTHORS
trunk/src/euse/README [deleted file]
trunk/src/euse/TODO [deleted file]
trunk/src/euse/euse
trunk/src/euse/euse.1

index 08a574ec28523c7f627c3199192c0ef9a96104aa..29a65ffba715a5198d78084031495fa1449106cb 100644 (file)
@@ -5,6 +5,7 @@
        * equery: changed defaults for `equery depends` as making a depgraph
                                for the full portage tree isn't a good idea and find_all_packages()
                                uses way to much memory currently
+       * euse: replaced the old perl version with a newly written bash version.
 
 2004-10-12 Marius Mauch <genone@gentoo.org>
        * equery: fix for bug #67210
index 8e777bca594bc6f6deeb54184c384d5186b9ff94..12e6db7a733fd4cb7e3252a67bed809a8b34e668 100644 (file)
@@ -1 +1,2 @@
-* Arun Bhanu <codebear@gentoo.org>
+* original perl version: Arun Bhanu <codebear@gentoo.org>
+* new bash version: Marius Mauch <genone@gentoo.org>
diff --git a/trunk/src/euse/README b/trunk/src/euse/README
deleted file mode 100644 (file)
index 9d9e3de..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-Euse is a command line USE flag editor for Gentoo Linux.
-
-What does it do? 
-================
-USE flags are central to Gentoo Linux. When you want to compile (in Gentoo
-terminology emerge) a new package you can set a few USE flags to customize the
-behavior of the build. At present you do this by editing the /etc/make.conf and
-change the USE variable there. 
-
-With euse you don't have to open the file to edit anymore. You can directly
-add/delete/view USE flags from make.conf. When you want to enable a particular
-USE flag you might want to find out what this flag does. At present, you can
-grep on use.desc and use.local.desc to find the details of an USE flag. With
-euse -i flag you can directly find out the details about an USE flag without
-grepping many files. Read ahead to view the usage.
-
-Usage
-=====
-# euse -c -d -e
-Prints out the current setting of USE variable in make.conf, make.defaults,
-environment variable USE respectively. You can use them individually. E.g.
-# euse -c
-
-# euse -i
-Prints all the use flags with descriptions and their current status.
-1st Column - Use flag
-2nd Column - Shows if the USE flag is enabled or disabled.
-3rd Column - If USE flag is enabled this columns show where it has been
-             enabled. C means make.conf, D means make.defaults, E means
-             enviroment variable USE.
-4th Column - Shows if the use flag is a global or local use flags.
-             For local use flags the desc field(next column) begins with
-             showing which package it belongs to in square brackets.
-5th Column - Use flag description.
-Use Flag | Enabled/Disabled | Conf/Env/Defaults | Global/Local | Desc
-alpha            [-] [ ] [G] indicates that architecture is 64-bit Alpha
-alsa             [+] [C] [G] Adds support for media-libs/alsa-lib (Advanced
-                             Linux Sound Architecture)
-moznocompose     [+] [C] [L] [net-www/mozilla] : If you do NOT want the web page
-                             composer built with mozilla
-
-# euse -i mozilla
-Prints details of just mozilla.
-mozilla          [-] [ ] [G] Adds mozilla support
-
-# euse -E mozilla alsa
-Enables mozilla alsa in make.conf. Accepts one or more arguments to enable.
-
-Case 1:
-If before executing this command the USE in make.conf looks like this:
-USE="tiff doc"
-After executing it becomes:
-USE="tiff doc mozilla alsa"
-
-Case 2:
-If before executing this command the USE in make.conf looks like this:
-USE="tiff doc -mozilla -alsa"
-After executing it becomes:
-USE="tiff doc mozilla alsa"
-
-There are lot of other cases, but you get the idea.
-
-# euse -D mozilla alsa
-Disables mozilla alsa in make.conf. Accepts one or more arguments to enable.
-
-Case 1:
-If before executing this command the USE in make.conf looks like this:
-USE="tiff doc"
-After executing it becomes:
-USE="tiff doc -mozilla -alsa"
-
-Case 2:
-If before executing this command the USE in make.conf looks like this:
-USE="tiff mozilla doc  alsa"
-After executing it becomes:
-USE="tiff -mozilla doc -alsa"
-
-There are lot of other cases, but you get the idea.
-
-Special Case:
-all is special flag. It is equivalent to * in USE setting. You can use "*"
-instead. But is NOT recommended. There are high chances you'll just type *
-instead of "*" and Euse will spit out some warnings. Note that * has be quoted
-to prevent bash expanding the wildchar. You can use all with -E and -D. With -E
-it will remove the last occurrence of -* from the make.conf. With -D it will
-will include -* to the end of the USE setting in make.conf if a -* is already
-present. If not it'll put a -* at the beginning of USE. If it is confusing, try
-it to find out.
-So this is how you use it:
-# euse -E mozilla alsa all
-Case 1:
-If before executing this command the USE in make.conf looks like this:
-USE="-* tiff -mozilla doc -alsa"
-After executing it becomes:
-USE="tiff mozilla doc alsa"
-
-# euse -D mozilla alsa all
-If before executing this command the USE in make.conf looks like this:
-USE="tiff mozilla doc alsa"
-After executing it becomes:
-USE="-* tiff -mozilla doc -alsa"
-
-Note: 
-1. -E and -D flags can be used together like:
-# euse -D mozilla -E alsa
-To enable alsa and disable mozilla in the same command.
-
-
-Author's Note
-=============
-If you have any comments(both good and bad) about the code or any features in
-this program feel free to mail me codebear@gentoo.org.
-
-
-Enjoy!!
-                                                                        --Arun
diff --git a/trunk/src/euse/TODO b/trunk/src/euse/TODO
deleted file mode 100644 (file)
index e69de29..0000000
index c604605f93cd888afea0cd4a7bc54fb50925864a..f2972ad09565ff6b1e183cd221ad6f798b2868f3 100755 (executable)
-#!/usr/bin/perl
-# Name             : euse
-# Purpose          : Command line USE flag editor
-# Author           : Arun Bhanu
-# Version          : 0.1.0
-# Copyright        : GNU GPL v2
-
-use warnings;
-use strict;
-
-use Getopt::Long;
-use File::Copy;
-use Env qw(USE);
-
-# Define constants
-use constant FLAG_TYPE=>['G', 'L'];
-use constant FLAG_MASK=>['+', '-', 'M'];
-use constant FLAG_SITE=>['E', 'C', 'A', 'D', ' '];
-use constant SITE_DESC=>['environment', 'make.conf', 'auto', 'make.defaults'];
-
-# parse_wo_args & parse_with_args populate command line arguments into
-# these. The argument and variable names has to match because we make use
-# of symbolic references. Yeah, I know these are not good names.
-our $h = 0;     # -h|help, boolean 
-our $v = 0;     # -v|version, boolean
-our $c = 0;     # -c|conf, boolean
-our $d = 0;     # -d|defaults, boolean
-our $e = 0;     # -e|env, boolean
-our @i = ();    # -i|info, info accepts many optional values.
-our @p = ();    # -p|package argument, package accepts many values.
-our @E = ();    # -E|enable, enable use flags in make.conf
-our @D = ();    # -D|disable, disable use flags in make.conf. Not a physical 
-                #  delete, but just minus sign in front of the given use flag.
-
-# arguments that does not take values.
-our $Args_Wo_Param = "hvcde"; 
-our $Non_Arg = " ";
-our $Curr_Arg; # Argument being parsed. 
-our %Unknown_Args;  # All unknown arguments are populate here.
-
-our %Uf_warnings;
-
-our $Version = "0.1.0";
-
-# Paths to all the reqd files
-our $FMake_conf     = "/etc/make.conf";
-our $FMake_defaults = "/etc/make.profile/make.defaults";
-our $FUse_desc      = "/etc/make.profile/../use.desc"; 
-our $FUse_local     = "/etc/make.profile/../use.local.desc";
-our $FUse_mask      = "/etc/make.profile/use.mask";
-
-# For my local testing
-#our $FMake_conf = "make.conf"; #/etc/make.conf
-#our $FMake_defaults = "make.defaults"; #/etc/make.profile/make.defaults
-#our $FUse_desc = "use.desc"; #$PORTDIR/profiles/use.desc
-#our $FUse_local = "use.local.desc";#$PORTDIR/profiles/use.local.desc
-#our $FUse_mask = "use.mask";#/etc/make.profile/use.mask
-
-if (-f "/etc/make.profile/parent") { 
-       print "euse doesn't support cascading profiles yet\n";
-       exit(0);
-}
-
-#BEGIN Main
-MAIN: {
-    Getopt::Long::Configure("no_ignore_case");
-    # help, version does not accept arguments
-    # info accepts optional agruments.
-    # package requires arguments.
-    GetOptions(
-        "h|help" => \&parse_wo_args,        # Show usage info.
-        
-        "v|version" => \&parse_wo_args,     # Show version info.
-        
-        "i|info:s" => \&parse_with_args,    # Show use flags info. 
-                                            # Show all use flags if none 
-                                            # specified. (Optional values)
-                                            
-       #"p|package:s" => \&parse_with_args, # Show use flag info for all 
-                                            # given packages (Mandatory values)
-                                            
-        "E|enable:s" => \&parse_with_args,  # enable use flag from make.conf 
-                                            # e.g. mozilla
-                                            
-        "D|disable:s" => \&parse_with_args, # disable use flag from make.conf 
-                                            # e.g. -mozilla.
-
-        "c|conf" => \&parse_wo_args,        # print the contents of make.conf
-                                            # use flag setting
-
-        "d|defaults" => \&parse_wo_args,    # print the contents of 
-                                            # make.defaults use flag setting
-
-        "e|env" => \&parse_wo_args,         # print the contents of 
-                                            # environment use flag setting
-
-        "<>" => \&handle_unknown            # all unknown arguments.
-    ) or usage();
-
-
-    # If no options are entered show usage.
-    if ((my $opts = $h + 
-                    $v + 
-                    ($c or $d or $e) + 
-                    defined(@i) + 
-                    defined(@p) +
-                    (defined(@E) or defined(@D))) < 1) {
-        usage();
-    }
-
-    # If any arguments are provided for options which are boolean show usage.
-    if (%Unknown_Args) {
-        print ("Unknown arguments: \n");
-        foreach (sort keys %Unknown_Args) {
-            print "\t$_ => " . join (" ", @{$Unknown_Args{$_}}) . "\n";
-        }
-        usage();
-    }
-
-    # Only one of -h, -v, -i, -p, -c/-d/-e or -E/-D allowed
-    if ((my $opts = $h + 
-                    $v + 
-                    ($c or $d or $e) + 
-                    defined(@i) + 
-                    defined(@p) +
-                    (defined(@E) or defined(@D))) > 1) {
-        usage("Only one of -h, -v, -i, -p or -E/-D allowed");
-    }
-
-    # Mandatory argument field check if arguments have been entered
-    my @reqd_args = ();
-    if (defined(@E)) {
-        if ($E[0] eq '') {
-            push @reqd_args, "-E"; 
-        }
-    }
-    if (defined(@D)) {
-        if ($D[0] eq '') {
-            push @reqd_args, "-D"; 
-        }
-    }
-    if ($#reqd_args >= 0) {
-        print join(", ", @reqd_args), " require argument(s). \n"; 
-        usage();
-    } 
-
-    # If -h,--help is entered show usage.
-    if ($h) {
-        #check_permissions("rw"); #just for testing purposes
-        usage();
-    }
-
-    # If -v,--version is entered show version.
-    if ($v) {
-        version();
-    }
-
-    if ($c || $d || $e) {
-        #Check the permissions for all the reqd files and sets their path
-        #If not enough permission don't proceed.
-        check_permissions("r");
-        if ($d) {
-            my $defaults_uf_list_ref = parse_make($FMake_defaults);
-            print "USE setting in make.defaults: \n";
-            print (join (" ", @$defaults_uf_list_ref) . "\n\n");
-        }
-
-        if ($c) {
-            my $conf_uf_list_ref = parse_make($FMake_conf);
-            print "USE setting in make.conf: \n";
-            print (join (" ", @$conf_uf_list_ref) . "\n\n");
-        }
-
-        if ($e) {
-            my $env_uf_list_ref = parse_env($USE);
-            print "USE setting in environment: \n";
-            print (join (" ", @$env_uf_list_ref) . "\n\n");
-        }
-        exit(0);
-    }
-    
-    check_permissions("r");
-
-    # Read /usr/portage/profiles/use.desc
-    my %use_flags;
-    parse_use($FUse_desc, \%use_flags);
-
-    # Read /usr/portage/profiles/use.local.desc
-    parse_use_local($FUse_local, \%use_flags);
-
-    # Read /etc/make.profile/use.mask, if exists.
-    parse_use_mask($FUse_mask, \%use_flags) if (-e $FUse_mask);
-
-    # If a -* is found in env, make.conf & make.defaults is skipped.
-    # If a -* is found in make.conf, make.defaults is skipped.
-    # If a -* is found in all the elements in front of -* is skipped.
-    # In each of the case all the elements in front of -* is also skipped.
-    # Read ENV{USE}
-    my (@env_uf_list, @conf_uf_list, @defaults_uf_list) = ();
-    my $env_uf_list_ref = \@env_uf_list;
-    my $conf_uf_list_ref = \@conf_uf_list;
-    my $defaults_uf_list_ref = \@defaults_uf_list;
-
-    $env_uf_list_ref = parse_env($USE) if (defined($USE));     
-    unless (is_all_disabled($env_uf_list_ref)) {
-        # Read /etc/make.conf
-        $conf_uf_list_ref = parse_make($FMake_conf);
-
-        unless (is_all_disabled($conf_uf_list_ref)) {
-            # Read /etc/make.profile/make.defaults
-            $defaults_uf_list_ref = parse_make($FMake_defaults);
-        }
-    }
-
-    # is this the correct way of check the length of an array reference??
-    parse_use_flag($defaults_uf_list_ref, \%use_flags, 3)
-        unless ($#{@$defaults_uf_list_ref} < 0);
-    parse_use_flag($conf_uf_list_ref, \%use_flags, 1)
-        unless ($#{@$conf_uf_list_ref} < 0);
-    parse_use_flag($env_uf_list_ref, \%use_flags, 0) 
-        unless ($#{@$env_uf_list_ref} < 0);
-
-
-    # If -i, --info is entered print all USE flags if no arguments given or 
-    # print the description for the given USE flags.
-    if (defined(@i)) {
-        
-        #if -i mozilla mozilla is entered the extra mozilla is removed.
-        remove_duplicates(\@i);
-        
-        my @use_flag_list = ();
-        my $max_len = 0;
-        my $curr_key_len = 0;
-
-        # Retrieve the objects to be send to the formatting function as an 
-        # array.
-        if ($i[0] eq '') {
-            #Display all USE flags
-            foreach (sort keys %use_flags) {
-                $curr_key_len = length($_);
-                $max_len = $curr_key_len if $curr_key_len > $max_len;
-                push @use_flag_list, $use_flags{$_};
-            }
-        }
-        else {
-            #Display USE flags for given arguments
-            foreach (sort @i) {
-                if (exists($use_flags{$_})) {
-                    $curr_key_len = length($_);
-                    $max_len = $curr_key_len if $curr_key_len > $max_len;
-                    push @use_flag_list, $use_flags{$_} ;
-                }
-                else {
-                    # Invalid use flag
-                    add_warning($_, "Querying an invalid use flag.");
-                }
-            }
-        }
-
-        format_output(\@use_flag_list, \$max_len);
-        format_warning();
-        exit(0);
-    }
-
-    # Enable USE flags and disable USE flags
-    if (defined(@E) || defined(@D)) {
-
-        check_permissions("rw");
-        
-        # Enable the last occurence of the USE flag.  Check if already exists
-        # in make.conf. If exist and enabled leave it alone. If exists and
-        # disabled enable it. If not found, put an entry at the end. Why end?
-        # -* may be in effect somewhere in the USE flag.  So adding in at the
-        # end will make sure it gets enabled.  euse -E "*" or euse -E all will
-        # look for a -* in make.conf. If found removes it.
-        if (defined(@E)) {
-            remove_duplicates(\@E);
-            rearrange_args(\@E);
-            enable_use_flag($conf_uf_list_ref, \%use_flags);
-        }
-
-        # Disable the last occurence of the USE flag. 
-        # euse -D "*" will put a -* at the end of USE flag setting in make.conf.
-        if (defined(@D)) {
-            remove_duplicates(\@D);
-            rearrange_args(\@D);
-            disable_use_flag($conf_uf_list_ref, \%use_flags);
-        }
-        format_warning();
-        exit(0);
-    }
-    exit(0);
-}
-#END Main
-
-# Show usage. Accepts optional argument. If given prints them as warning msg.
-sub usage {
-    warn "@_\n" if @_;
-    die <<EOF;
-'*' leading an option indicates not-yet-implemented
-Usage:
-    -h, --help     - print this message
-    -v, --version  - print version information
-    -i, --info     - print USE flag information for the the given USE flags.
-                     Optional argument.
-    -c, --conf     - print USE flag setting in make.conf
-    -d, --defaults - print USE flag setting in make.defaults
-    -e, --env      - print USE flag setting in environment variable USE
-   *-p, --package  - requires a package name to be given for which you 
-                     want to see USE flags.
-    -E, --enable   - enable use flag to make.conf e.g. -E mozilla puts mozilla 
-                     in make.conf. Mandatory argument.
-    -D, --disable  - disable use flag from make.conf e.g. -D mozilla 
-                     puts -mozilla in make.conf. Mandatory argument.
-
-Please see the README file for more details.
-
-EOF
-
-}
-
-# Show version
-sub version
-{
-    die <<EOF;
-EUSE version $Version
-Copyright (C) 2003 - Arun Bhanu
-This program may be freely distributed under the terms of the GNU GPL v2.
-
-EOF
-
-}
-
-# check permissions for all reqd files
-sub check_permissions 
-{
-    my ($r, $w) = split(//, shift());
-
-    #make.conf requires rw permissions. all the other files require read
-    #permission
-    my $errors = "";
-
-    # for make.conf
-    if ((defined($r) && $r eq "r") && (defined($w) && $w eq "w")) {
-        #print "rw defined \n";
-        unless (-e $FMake_conf && -r _ && -w _) {
-            $errors .= "requires read,write permissions for $FMake_conf. \n";
-        }
-    }
-    elsif (defined($r) && $r eq "r") {
-        #print "r defined \n";
-        unless (-e $FMake_conf && -r _) {
-            $errors .= "requires read,write permissions for $FMake_conf. \n";
-        }
-    }
-
-    # for all the other files
-    if (defined($r) && $r eq "r") {
-        #print "r defined \n";
-        unless (-e $FMake_defaults && -r _) {
-            $errors .= "requires read permissions for $FMake_defaults. \n";
-        }
-        unless (-e $FUse_desc && -r _) {
-            $errors .= "requires read permissions for $FUse_desc. \n";
-        }
-
-        unless (-e $FUse_local && -r _) {
-            $errors .= "requires read permissions for $FUse_local. \n";
-        }
-
-        if (-e $FUse_mask) {
-            unless (-r $FUse_mask) {
-                $errors .= "requires read permissions for $FUse_mask. \n";
-            }
-        }
-    }
-
-    die "EUSE exiting with following errors: \n$errors" unless ($errors eq "");
+#!/bin/bash
+
+# $Header$
+
+# bash replacement for the original euse by Arun Bhanu
+# Author: Marius Mauch <genone@gentoo.org>
+# Version: 0.2
+# Licensed under the GPL v2
+
+PROGRAM_NAME=euse
+PROGRAM_VERSION=0.1
+
+MAKE_CONF_PATH=/etc/make.conf
+MAKE_GLOBALS_PATH=/etc/make.globals
+MAKE_PROFILE_PATH=/etc/make.profile
+MAKE_CONF_BACKUP_PATH=/etc/make.conf.euse_backup
+
+MODE="showhelp"                # available operation modes: showhelp, showversion, showdesc, showflags, modify
+
+parse_arguments() {
+       if [ -z "${1}" ]; then
+               return
+       fi
+       while [ -n "${1}" ]; do
+               case "${1}" in
+                       -h | --help)    MODE="showhelp";;
+                       -v | --version) MODE="showversion";;
+                       -i | --info)    MODE="showdesc";;
+                       -l | --local)   SCOPE="local";;
+                       -g | --global)  SCOPE="global";;
+                       -a | --active)  MODE="showflags";;
+                       -E | --enable)  MODE="modify"; ACTION="add";;
+                       -D | --disable) MODE="modify"; ACTION="remove";;
+                       -P | --prune)   MODE="modify"; ACTION="prune";;
+                       -*)
+                               echo "ERROR: unknown option ${1} specified."
+                               echo
+                               MODE="showhelp"
+                               ;;
+                       *)
+                               ARGUMENTS="${ARGUMENTS} ${1}"
+                               ;;
+               esac
+               shift
+       done
 }
 
-# clean up reqd
-sub handle_unknown
-{
-    no strict 'refs';
-    if (defined $Curr_Arg) {
-        my $option = $Curr_Arg;
-        if ($option =~ /[$Args_Wo_Param]/) {
-            #print "param not required \n";
-            #print "Option: $option " . join (",", @_) . "\n";
-            push @{$Unknown_Args{$option}}, @_;
-        }
-        else {
-            #print "param is okay \n";
-            push @$option, @_;
-        }
-    }
-    else {
-        #print "curr flag not defined \n";
-        push @{$Unknown_Args{$Non_Arg}}, @_;
-    }
+error() {
+       echo "ERROR: ${1}"
+       exit 1
 }
 
-sub parse_with_args
-{
-    no strict 'refs';
-    my ($option, $value) = @_;
-    #print "parse with handle: " . $option . " " . $value . "\n";
-
-    push @$option, $value; #do not allow comma separated.
-    $Curr_Arg = $option;
-
+check_sanity() {
+       # file permission tests
+       local descdir
+       
+       descdir="$(get_portdir)/profiles"
+       
+       [ ! -r "${MAKE_CONF_PATH}" ] && error "${MAKE_CONF_PATH} is not readable"
+       [ ! -r "${MAKE_GLOBALS_PATH}" ] && error "${MAKE_GLOBALS_PATH} is not readable"
+       [ ! -s "${MAKE_PROFILE_PATH}" ] && error "${MAKE_PROFILE_PATH} is not a symlink"
+       [ -z "$(get_portdir)" ] && error "\$PORTDIR couldn't be determined"
+       [ ! -d "${descdir}" ] && error "${descdir} does not exist or is not a directory"
+       [ ! -r "${descdir}/use.desc" ] && error "${descdir}/use.desc is not readable"
+       [ ! -r "${descdir}/use.local.desc" ] && error "${descdir}/use.local.desc is not readable"
+       [ ! -r "$(get_make_defaults)" ] && error "$(get_make_defaults) is not readable"
+       [ "${MODE}" == "modify" -a ! -w "${MAKE_CONF_PATH}" ] && error ""${MAKE_CONF_PATH}" is not writable"
 }
 
-sub parse_wo_args
-{
-    no strict 'refs';
-    my ($option, $value) = @_;
-    #print "parse wo handle: " . $option . " " . $value . "\n";
-    $$option = $value;
-    $Curr_Arg = $option;
+showhelp() {
+       echo "${PROGRAM_NAME} v${PROGRAM_VERSION}"
+       echo
+       echo "Syntax: ${PROGRAM_NAME} <option> [suboptions] [useflaglist]"
+       echo
+       echo "Options: -h, --help      - show this message"
+       echo "         -v, --version   - show version information"
+       echo "         -i, --info      - show descriptions for the given useflags"
+       echo "         -g, --global    - show only global use flags (suboption)"
+       echo "         -l, --local     - show only local use flags (suboption)"
+       echo "         -a, --active    - show currently active useflags and their origin"
+       echo "         -E, --enable    - enable the given useflags"
+       echo "         -D, --disable   - disable the given useflags"
+       echo "         -P, --prune     - remove all references to the given flags from"
+       echo "                           make.conf to revert to default settings"
+       echo
+       echo "Notes: ${PROGRAM_NAME} currently only works for global flags defined"
+       echo "       in make.globals, make.defaults or make.conf, it doesn't handle"
+       echo "       use.defaults, use.mask or package.use yet (see portage(5) for details on"
+       echo "       these files)."
+       echo "       If multiple options are specified only the last one will be used."
 }
 
-# Generic subroutine to read a file. 
-# Returns an array of lines in array context or returns the whole file in a 
-# single scalar in scalar context.
-sub read_file {
-    my $file_name = shift();
-    if (open FILE, $file_name) {
-        local $/ = undef unless wantarray;
-        return <FILE>;
-    }
-    else {
-        die "Couldn't read file $file_name. $! \n";
-    }
-    #return; # returns undef in scalar context, () in list context
+showversion() {
+       echo "${PROGRAM_NAME} v${PROGRAM_VERSION}"
+       echo "Written by Marius Mauch"
+       echo
+       echo "Copyright (C) 2004 Gentoo Foundation, Inc."
+       echo "This is free software; see the source for copying conditions."
 }
 
-sub parse_use
-{
-    my $file_name = shift();
-    my $use_flags_ref = shift();
-    my @lines = read_file($file_name);
-    chomp @lines;
-    foreach (@lines) {
-        if (/^\s*([-a-z0-9_+]+)\s+-\s*(.*)$/i) {
-            $use_flags_ref->{$1} = create_use_flag($1, $2, FLAG_TYPE->[0]);
-        }
-    }
+# the following function creates a bash array ACTIVE_FLAGS that contains the
+# global use flags, indexed by origin: 0: environment, 1: make.conf, 
+# 2: make.defaults, 3: make.globals
+get_useflags() {
+       # only calculate once as calling emerge is painfully slow
+       [ -n "${USE_FLAGS_CALCULATED}" ] && return
+       
+       # backup portdir so get_portdir() doesn't give false results later
+       portdir_backup="${PORTDIR}"
+
+       ACTIVE_FLAGS[0]="${USE}"
+       USE=""
+       source "${MAKE_CONF_PATH}"
+       ACTIVE_FLAGS[1]="${USE}"
+       USE=""
+       source $(get_make_defaults)
+       ACTIVE_FLAGS[2]="${USE}"
+       USE=""
+       source "${MAKE_GLOBALS_PATH}"
+       ACTIVE_FLAGS[3]="${USE}"
+
+       # restore saved env variables
+       USE="${ACTIVE_FLAGS[0]}"
+       PORTDIR="${portdir_backup}"
+
+       # get the currently active USE flags as seen by portage, this has to be after
+       # restoring USE or portage won't see the original environment
+       ACTIVE_FLAGS[9]="$(emerge --info | grep 'USE=' | cut -b 5- | sed -e 's:"::g')" #'
+       USE_FLAGS_CALCULATED=1
 }
 
-sub parse_use_local
-{
-    my $file_name = shift();
-    my $use_flags_ref = shift();
-    my @lines = read_file($file_name);
-    chomp @lines;
-    foreach (@lines) {
-        if (m{^\s*([-a-z0-9_/+]*):([-a-z0-9_/+]*)\s*-\s*(.*)$}i)
-        {
-            my $pkg_name = $1;
-            my $use_flag = $2;
-            my $use_desc = $3;
-            $use_flags_ref->{$use_flag} = 
-                create_use_flag($use_flag, $use_desc, FLAG_TYPE->[1], 
-                    FLAG_MASK->[1], $pkg_name);
-        }
-    }
+# get the list of all known USE flags by reading use.desc and/or use.local.desc
+# (depending on the value of $SCOPE)
+get_useflaglist() {
+       local descdir
+
+       descdir="$(get_portdir)/profiles"
+       
+       if [ -z "${SCOPE}" -o "${SCOPE}" == "global" ]; then
+               egrep "^[^# ]+ +-" "${descdir}/use.desc" | cut -d\  -f 1
+       fi
+       if [ -z "${SCOPE}" -o "${SCOPE}" == "local" ]; then
+               egrep "^[^# :]+:[^ ]+ +-" "${descdir}/use.local.desc" | cut -d: -f 2 | cut -d\  -f 1
+       fi
 }
 
-sub parse_use_mask
-{
-
-    my $file_name = shift();
-    my $use_flags_ref = shift();
-    my @lines = read_file($file_name);
-    chomp @lines;
-    my @use_mask;
-    foreach (@lines) {
-        if (m/^\s*([-a-z0-9_+]+)\s*$/i)
-        {
-            my $use_flag = $1;
-            if (exists $use_flags_ref->{$use_flag}) {
-                $use_flags_ref->{$use_flag}->[3] = FLAG_MASK->[2];
-            }
-            else {
-                add_warning($use_flag, "Found in use.mask, but is not a valid use flag.");
-            }
-        }
-    }
-
-
-    #return \@use_mask;
+# get the path to make.defaults by traversing the cascaded profile directories
+get_make_defaults() {
+       local curdir
+       local notfound
+       local parent
+       
+       notfound=1
+       curdir="$(readlink -f ${MAKE_PROFILE_PATH})"
+       
+       while [ ! -f "${curdir}/make.defaults" -a -f "${curdir}/parent" ]; do
+               parent="$(grep -v '(^#|^ *$)' ${curdir}/parent)"
+               curdir="$(readlink -f ${curdir}/${parent})"
+       done
+
+       echo "${curdir}/make.defaults"
 }
 
-sub add_warning
-{
-    my $use_flag = shift();
-    my $msg = shift();
-    if (exists $Uf_warnings{$use_flag}) {
-        push @{$Uf_warnings{$use_flag}}, $msg;
-        
-    }
-    else {
-        my @warn_list = ($msg);
-        $Uf_warnings{$use_flag} = \@warn_list;
-    }
+# little helper function to get the status of a given flag in one of the 
+# ACTIVE_FLAGS elements. Arguments are 1: flag to test, 2: index of ACTIVE_FLAGS,
+# 3: echo value for positive (and as lowercase for negative) test result, 
+# 4 (optional): echo value for "missing" test result, defaults to blank
+get_flagstatus_helper() {
+       if echo " ${ACTIVE_FLAGS[${2}]} " | grep " ${1} " > /dev/null; then
+               echo -n "${3}"
+       elif echo " ${ACTIVE_FLAGS[${2}]} " | grep " -${1} " > /dev/null; then
+               echo -n "$(echo ${3} | tr [[:upper:]] [[:lower:]])"
+       else
+               echo -n "${4:- }"
+       fi
 }
 
-sub parse_make
-{
-    my $file_name = shift();
-    my $lines = read_file($file_name);
-    my @site_uf_list;
-    if ($lines =~ m/^\s*USE[\s\n]*=[\s\n]*"([^"]*)"/ms) 
-    {
-        my $use_var = $1;
-        $use_var =~ s/[\r\n\\]/ /g;
-        @site_uf_list = split(' ', $use_var);
-    }
-    #print ("Make: \n" . join (" ", @site_uf_list) . "\n");
-    return \@site_uf_list;
-}
-
-sub parse_env
-{
-    my $env = shift();
-    $env = "" unless (defined($env));
-    #print "USE: $env \n";
-    my @site_uf_list = split(' ', $env);
-    #print ("Env: " . join (" ", @site_uf_list) . "\n");
-    return \@site_uf_list;
-}
-
-sub parse_use_flag
-{
-    my $site_uf_list_ref = shift();
-    my $use_flags_ref = shift();
-    my $site_index = shift();
-
-    #print "Flag site: $site_index -> " . FLAG_SITE->[$site_index] . "\n";
-    #print "Flag desc: $site_index -> " . SITE_DESC->[$site_index] . "\n";
-    my ($isenabled, $use_wo_sign, $use_with_sign);
-    # recurse from back to front. if -* is found the rest of the elements in
-    # front is ignored.
-    for (my $i = $#{@$site_uf_list_ref}; $i >= 0; $i--) {
-        my $curr_flag = $site_uf_list_ref->[$i];
-        #print "curr flag: $curr_flag \n";
-        last if ($curr_flag =~ m/^-\*$/);
-        $isenabled = 1; # sign = 1 is enabled, sign = 0 is disabled.
-        $use_wo_sign = $use_with_sign = $curr_flag;
-        if ($use_with_sign =~ /^-(.*)/) {
-            $use_wo_sign = $1;
-            $isenabled = 0;
-        } 
-
-        if (exists $use_flags_ref->{$use_wo_sign}) {
-            $use_flags_ref->{$use_wo_sign}->[5] = FLAG_SITE->[$site_index];
-            if ($use_flags_ref->{$use_wo_sign}->[3] eq FLAG_MASK->[2]) {
-                add_warning($use_wo_sign, "$use_with_sign found in " . 
-                    SITE_DESC->[$site_index] . " is masked. You shouldn't be " .
-                    "setting this use flag.");
-            }
-            #if ($use_flags_ref->{$use_wo_sign}->[3] eq FLAG_MASK->[3] ) {
-            #    add_warning($use_wo_sign, "$use_with_sign found in " . 
-            #        SITE_DESC->[$site_index] . " is an internal flag. You " .
-            #        "shouldn't be setting this use flag.");
-            #}
-            if ($isenabled) {
-                $use_flags_ref->{$use_wo_sign}->[3] = FLAG_MASK->[0];
-            }
-            else {
-                $use_flags_ref->{$use_wo_sign}->[3] = FLAG_MASK->[1];
-            }
-            
-        }
-        else {
-            add_warning($use_wo_sign, "$use_with_sign found in " . 
-                SITE_DESC->[$site_index] . " not a valid use flag.");
-        }
-    }
-}
-
-# checks if -* is found in any given site - environment, make.conf, 
-# make.defaults
-# Return 1 if -* is found, return 0 otherwise.
-sub is_all_disabled
-{
-    my $site_uf_list_ref = shift();
-    #print (join (" ", @$site_uf_list_ref) . "\n");
-    foreach (@$site_uf_list_ref) {
-        return 1 if (m/^-\*$/);
-    }
-    return 0;
-}
-
-sub enable_use_flag
-{
-    my $conf_uf_list_ref = shift();
-    my $use_flags_ref = shift();
-    # if -* is found in env, should we enable the flag in environment instead
-    # of make.conf
-    #print "Enabling in make.conf... \n";
-    my @add_flags;
-    my @del_flags;
-    my $enable_all = 0;
-    #my $disable_start = 0;
-    my $disable_found = 0;
-    EFLAG: foreach my $eflag (@E) {
-        if ($eflag eq "*" or $eflag eq "all") {
-            #print "$eflag need to del -* use flag.. \n"; 
-            $enable_all = 1;
-            $eflag = "*";
-            push @del_flags, $eflag;
-            foreach my $cflag (@$conf_uf_list_ref) {
-                if ($cflag eq "-*") {
-                    $disable_found = 1;
-                    last;
-                }
-            }
-            next EFLAG;
-        }
-        if (exists $use_flags_ref->{$eflag}) {
-            if ($use_flags_ref->{$eflag}->[3] eq FLAG_MASK->[2]) {
-                add_warning($eflag, "$eflag is masked. Enabling a masked " . 
-                    "flag.");
-                next EFLAG;
-            }
-            my $count = 0;
-            for (my $i = $#{@$conf_uf_list_ref}; $i >= 0; $i--) {
-                my $curr_flag = $conf_uf_list_ref->[$i];
-                #print "curr flag: $curr_flag eflag: $eflag \n";
-                
-                if ($curr_flag eq $eflag) {
-                    #print "flag exists.. \n"; 
-                    next EFLAG;
-                }
-
-                my $eflag_sign = "-".$eflag;
-                if ($curr_flag eq $eflag_sign) {
-                    #print "need to del use flag.. \n"; 
-                    push @del_flags, $eflag;
-                    next EFLAG;
-                }
-
-                if ($curr_flag eq "-*") {
-                    $count++;
-                    if ($enable_all) {
-                        if ($disable_found && ($count == 1)) {
-                            next;
-                        }
-                        else {
-                            push @add_flags, $eflag;
-                            next EFLAG;
-                        }
-                    }
-                    else {
-                        push @add_flags, $eflag;
-                        next EFLAG;
-                    }
-                    
-                }
-            }
-            #print "$eflag - need to enable this flag...\n";
-            push @add_flags, $eflag;
-        } 
-        else {
-            add_warning($eflag, "Enabling invalid use flag.");
-        }
-    }
-    
-    # should I use timestamp instead of .old suffix?
-    if (@add_flags || @del_flags) {
-    
-        my $make_conf = read_file($FMake_conf);
-        #my $timestamp = get_timestamp();
-        #copy ($FMake_conf, "$FMake_conf.$timestamp");
-        copy ($FMake_conf, "$FMake_conf.bkeuse");
-        if (@add_flags) {
-            #print "these are flags to add...\n";
-            my $eflags = join (" ", @add_flags);
-            #print ($eflags . "\n");
-            $make_conf =~ 
-                s/(^\s*USE[\s\n]*=[\s\n]*")([^"]*)(")/$1$2 $eflags$3/ms;
-
-            # If there is no USE flag setting in make.conf include it and
-            # add the flags.
-            unless (defined($1)) {
-                #print "There are flags to add but no USE setting \n";
-                $make_conf =~ s/(^\s*#\s*Host)/USE="$eflags"\n$1/ms;
-            }
-        }
-        
-        my $use_setting = "";
-        if (@del_flags) {
-            #print "these are flags to del...\n";
-            my $dflags = join (" ", @del_flags);
-            #print ($dflags . "\n");
-
-            if ($make_conf =~ /^\s*USE[\s\n]*=[\s\n]*"([^"]*)"/ms) {
-                $use_setting = $1;
-            }
-            foreach my $dflag (@del_flags) {
-                if ($dflag eq "*") {
-                    $use_setting =~ s/^(.*)-\*(.*)$/$1$2/ms;
-                }
-                else {
-                    # \Q, \E prevents flags like libg++ to bonk
-                    $use_setting =~ s/^(.*)(-\Q$dflag\E)(.*)$/$1$dflag$3/ms;
-                }
-            }
-            $make_conf =~ 
-                s/(^\s*USE[\s\n]*=[\s\n]*")([^"]*)(")/$1$use_setting$3/ms;
-        }
-        open(OUTFILE, ">$FMake_conf") or 
-            die("couldn't open make.conf");
-        print OUTFILE $make_conf;
-        close OUTFILE;
-    }
-    print "USE setting in make.conf after enabling: \n";
-    my $make_conf = read_file($FMake_conf);
-    my $use_setting = "";
-    $make_conf =~ /^\s*USE[\s\n]*=[\s\n]*"([^"]*)"/ms; 
-    if (defined($1)) {
-        $use_setting = $1;
-    }
-    #print "$use_setting \n";
-    print (join(" ", split(' ', $use_setting)));
-    print "\n";
+# prints a status string for the given flag, each column indicating the presence
+# for portage, in the environment, in make.conf, in make.defaults and in make.globals.
+# full positive value would be "[+ECDG]", full negative value would be [-ecdg],
+# full missing value would be "[-    ]" (portage only sees present or not present)
+get_flagstatus() {
+       get_useflags
+
+       echo -n '['
+       get_flagstatus_helper "${1}" 9 "+" "-"
+       get_flagstatus_helper "${1}" 0 "E"
+       get_flagstatus_helper "${1}" 1 "C"
+       get_flagstatus_helper "${1}" 2 "D"
+       get_flagstatus_helper "${1}" 3 "G"
+       echo -n '] '
 }
 
-sub disable_use_flag
-{
-    my $conf_uf_list_ref = shift();
-    my $use_flags_ref = shift();
-    my @add_flags;
-    my @del_flags;
-    my $disable_all = 0;
-    #my $disable_start = 0;
-    my $disable_found = 0;
-
-    foreach my $cflag (@$conf_uf_list_ref) {
-        if ($cflag eq "-*") {
-            $disable_found = 1;
-            last;
-        }
-    }
-
-    DFLAG: foreach my $dflag (@D) {
-        
-        if ($dflag eq "*" or $dflag eq "all") {
-            #print "$dflag need $disable_found to add -* use flag.. \n"; 
-            $disable_all = 1;
-            $dflag = "-*";
-            push @del_flags, $dflag if ($disable_found);
-            next DFLAG;
-        }
-
-        if (exists $use_flags_ref->{$dflag}) {
-            if ($use_flags_ref->{$dflag}->[3] eq FLAG_MASK->[2]) {
-                add_warning($dflag, "$dflag is masked. Disabling a masked " . 
-                    "flag.");
-                next DFLAG;
-            }
-
-            for (my $i = $#{@$conf_uf_list_ref}; $i >= 0; $i--) {
-                my $curr_flag = $conf_uf_list_ref->[$i];
-                #print "curr flag: $curr_flag dflag: $dflag \n";
-
-                if ($disable_all) {
-                    if ($disable_found) {
-                        push @del_flags, "-".$dflag;
-                        next DFLAG;
-                    }
-                    else {
-                        my $dflag_sign = "-".$dflag;
-                        if ($curr_flag eq $dflag_sign) {
-                            #print "flag exists.. \n"; 
-                            next DFLAG;
-                        }
-                        if ($curr_flag eq $dflag) {
-                            push @add_flags, $dflag;
-                            next DFLAG;
-                        }
-                    }
-                }
-                else {
-                    my $dflag_sign = "-".$dflag;
-                    if ($curr_flag eq $dflag_sign) {
-                        #print "flag exists.. \n"; 
-                        next DFLAG;
-                    }
-                    if ($curr_flag eq $dflag) {
-                        push @add_flags, $dflag;
-                        next DFLAG;
-                    }
-
-                    if ($disable_found) {
-                        if ($curr_flag eq "-*") {
-                            push @del_flags, "-".$dflag;
-                            next DFLAG;
-                        }
-                    }
-                }
-            }
-            unless ($disable_found) {
-                #print "$dflag - need to disable this flag...\n";
-                push @del_flags, "-".$dflag;
-            }
-        } 
-        else {
-            add_warning($dflag, "Disabling invalid use flag.");
-        }
-    }
-
-    my $make_conf = read_file($FMake_conf);
-    copy ($FMake_conf, "$FMake_conf.bkeuse");
-    if ($disable_all && !$disable_found) {
-        $make_conf =~ 
-            s/(^\s*USE[\s\n]*=[\s\n]*")([^"]*)(")/$1-* $2$3/ms;
-    }
-
-    if (@add_flags || @del_flags) {
-        #my $timestamp = get_timestamp();
-        #copy ($FMake_conf, "$FMake_conf.$timestamp");
-        
-        if (@del_flags) {
-            print "these are flags to disable...\n";
-            my $dflags = join (" ", @del_flags);
-            #print ($dflags . "\n");
-            $make_conf =~ 
-                s/(^\s*USE[\s\n]*=[\s\n]*")([^"]*)(")/$1$2 $dflags$3/ms;
-
-            # If there is no USE flag setting in make.conf include it and
-            # disable the flags.
-            unless (defined($1)) {
-                print "There are flags to del but no USE setting \n";
-                $make_conf =~ s/(^\s*#\s*Host)/USE="$dflags"\n$1/ms;
-            }
-        }
-
-        my $use_setting = "";
-        if (@add_flags) {
-            #print "these are flags to enable...\n";
-            my $eflags = join (" ", @add_flags);
-            #print ($eflags . "\n");
-            if ($make_conf =~ /^\s*USE[\s\n]*=[\s\n]*"([^"]*)"/ms) {
-                $use_setting = $1;
-            }
-            foreach my $eflag (@add_flags) {
-                # should only enable the last one occurence 
-                # Is there are better regex for this to avoid backtracking?
-                # \Q, \E prevents flags like libg++ to bonk
-                $use_setting =~ s/(.*)\Q$eflag\E(.*)/$1-$eflag$2/s;
-            }
-            $make_conf =~ 
-                s/(^\s*USE[\s\n]*=[\s\n]*")([^"]*)(")/$1$use_setting$3/ms;
-
-        }
-
-    }
-
-    open(OUTFILE, ">$FMake_conf") or 
-        die("couldn't open make.conf");
-    print OUTFILE $make_conf;
-    close OUTFILE;
-
-    print "USE setting in make.conf after disabling: \n";
-    $make_conf = read_file($FMake_conf);
-    my $use_setting = "";
-    $make_conf =~ /^\s*USE[\s\n]*=[\s\n]*"([^"]*)"/ms; 
-    if (defined($1)) {
-        $use_setting = $1;
-    }
-    #print "$use_setting \n";
-    print (join(" ", split(' ', $use_setting)));
-    print "\n";
+# faster replacement to `portageq portdir`
+get_portdir() {
+       if [ -z "${PORTDIR}" ]; then
+               use_backup="${USE}"
+               source "${MAKE_GLOBALS_PATH}"
+               source "$(get_make_defaults)"
+               source "${MAKE_CONF_PATH}"
+               USE="${use_backup}"
+       fi
+       echo "${PORTDIR}"
 }
 
-# is there a better way of rearranging? This works, but any better solutions?
-sub rearrange_args
-{
-    my $arg_array_ref = shift();
-    my @new_arg_array = ();
-    foreach my $arg (@$arg_array_ref) {
-        if ($arg eq "*" or $arg eq "all") {
-            unshift @new_arg_array, $arg; 
-        }
-        else {
-            push @new_arg_array, $arg;
-        }
-    }
-    @$arg_array_ref = @new_arg_array;
+# This function takes a list of use flags and shows the status and 
+# the description for each one, honoring $SCOPE
+showdesc() {
+       local descdir
+       local current_desc
+       local found_one
+       local args
+       
+       args="${*:-*}"
+       
+       if [ -z "${SCOPE}" ]; then
+               SCOPE="global" showdesc ${args}
+               echo
+               SCOPE="local" showdesc ${args}
+               return
+       fi
+       
+       descdir="$(get_portdir)/profiles"
+       
+       [ "${SCOPE}" == "global" ] && echo "global use flags (searching: ${args})"
+       [ "${SCOPE}" == "local" ] && echo "local use flags (searching: ${args})"
+       echo "************************************************************"
+       
+       if [ "${args}" == "*" ]; then
+               args="$(get_useflaglist | sort -u)"
+       fi
+       
+       set ${args}
+       
+       foundone=0
+       while [ -n "${1}" ]; do
+               if [ "${SCOPE}" == "global" ]; then
+                       if grep "^${1}  *-" "${descdir}/use.desc" > /dev/null; then
+                               get_flagstatus "${1}"
+                               foundone=1
+                       fi
+                       grep "^${1}  *-" "${descdir}/use.desc"
+               fi
+               # local flags are a bit more complicated as there can be multiple 
+               # entries per flag and we can't pipe into printf
+               if [ "${SCOPE}" == "local" ]; then
+                       if grep ":${1}  *-" "${descdir}/use.local.desc" > /dev/null; then
+                               foundone=1
+                       fi
+                       grep ":${1}  *-" "${descdir}/use.local.desc" \
+                               | sed -e "s/^\([^:]\+\):\(${1}\) *- *\(.\+\)/\1|\2|\3/g" \
+                               | while read line; do
+                                       pkg="$(echo $line | cut -d\| -f 1)"
+                                       flag="$(echo $line | cut -d\| -f 2)"
+                                       desc="$(echo $line | cut -d\| -f 3)"
+                                       get_flagstatus "${flag}"
+                                       printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc}"
+                               done
+               fi
+               shift
+       done
+       
+       if [ ${foundone} == 0 ]; then
+               echo "no matching entries found"
+       fi
 }
 
-# removes duplicate elements of an array
-sub remove_duplicates
-{
-    my $arg_array_ref = shift();
-    my %arg_hash;
-    my @unique_args = grep { !$arg_hash{$_} ++ } @$arg_array_ref;
-    @$arg_array_ref = @unique_args;
+# show a list of all currently active flags and where they are activated
+showflags() {
+       local args
+
+       get_useflags
+       
+       args="${*:-*}"
+       
+       if [ "${args}" == "*" ]; then
+               args="$(get_useflaglist | sort -u)"
+       fi
+       
+       set ${args}
+       
+       while [ -n "${1}" ]; do
+               if echo " ${ACTIVE_FLAGS[9]} " | grep " ${1} " > /dev/null; then
+                       printf "%-20s" ${1}
+                       get_flagstatus ${1}
+                       echo
+               fi
+               shift
+       done
 }
 
-sub get_timestamp
-{
-    my ($sec, $min, $hour, $day, $mon, $year) = (localtime)[0..5];
-    $mon += 1;
-    $year  += 1900;
-    # need to format hour, min, second, day, mon to 2 digits.
-    my $timestamp = sprintf ('%4u%02u%02u%02u%02u%02u', 
-        $year, $mon, $day, $hour, $min, $sec);
-    print "$timestamp\n";
-    return $timestamp;
+# two small helpers to add or remove a flag from a USE string
+add_flag() {
+       NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE} ${1}"
 }
 
-
-
-
-#array[name, desc, type, mask, pkg, site]
-# name - name of the use flag (Required)
-# desc - description for the use flag (Required)
-# type - where the use flag is found. Acceptable values (global,local). Global
-#        means use.desc and local means use.local.desc (Required)
-# mask - whether the use flag is enabled, disabled or masked. Acceptable values
-#        (enabled,disabled,masked,internal) (Optional)
-# pkg  - for local use flags, package which it belongs to. For global use flags
-#      - it is empty.
-# site - if the use flag is enabled where is it enabled. Acceptable values 
-#        (E,C,A,D,-) (Optional)
-#        E - environment
-#        C - make.conf
-#        A - auto
-#        D - make.defaults
-#        - - not enabled
-sub create_use_flag(\$\$\$;\$\$\$)
-{
-    my ($name, $desc, $type) = ($_[0], $_[1], $_[2]);
-    my $mask = (defined($_[3]) ? $_[3] : FLAG_MASK->[1]);
-    my $pkg  = (defined($_[4]) ? $_[4] : "");
-    my $site = (defined($_[5]) ? $_[5] : FLAG_SITE->[4]);
-    my @use_flag = ($name, $desc, $type, $mask, $pkg, $site);
-    #print (join (" ", @use_flag) . "\n");
-    return \@use_flag;
+remove_flag() {
+       NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE// ${1} / }"
 }
 
-# to format all the warning messages
-sub format_warning
-{
-    if (%Uf_warnings) {
-        print "EUSE WARNINGS!! \n";
-        my $max_len = 0;
-        my $curr_key_len = 0;
-        foreach (sort keys %Uf_warnings) {
-            $curr_key_len = length($_);
-            $max_len = $curr_key_len if $curr_key_len > $max_len;
-        }
-        
-        my ($use_flag_name, $warning_msg);
-        
-        my $warn_format = "format WARNINGS_FORMAT= \n" .
-'@' . ('<'x($max_len-1)) . ' => ' . '^' . ('<'x(80-$max_len-4-1)) . "\n" .
-'$use_flag_name, $warning_msg' ."\n" .
-(' 'x($max_len+4)) . '^' . ('<'x(80-$max_len-4-1-2)) . '~~' . "\n" . 
-'$warning_msg' . "\n" .
-".\n";
-        eval $warn_format;
-        #print $warn_format;
-
-        my $warn_bot_format = "format WARNINGS_BOT_FORMAT= \n" .
-(' 'x($max_len)) . ' => ' . '^' . ('<'x(80-$max_len-4-1)) . "\n" . 
-'$warning_msg' . "\n" .
-(' 'x($max_len+4)) . '^' . ('<'x(80-$max_len-4-1-2)) . '~~' . "\n" . 
-'$warning_msg' . "\n" .
-".\n";
-
-        eval $warn_bot_format;
-        #print $warn_bot_format;
-
-        foreach (sort keys %Uf_warnings) {
-            $use_flag_name = $_;
-            my $count = 0;
-            foreach (@{$Uf_warnings{$_}}) {
-                $~ = ($count++ == 0) ? 
-                        'WARNINGS_FORMAT' : 'WARNINGS_BOT_FORMAT';
-                $warning_msg = $_;
-                write;
-            }
-        }
-    }
+# USE flag modification function. Mainly a loop with calls to add_flag and 
+# remove_flag to create a new USE string which is then inserted into make.conf.
+modify() {
+       if [ -z "${*}" ]; then
+               if [ "${ACTION}" != "prune" ]; then
+                       echo "WARNING: no USE flags listed for modification, do you really"
+                       echo "         want to ${ACTION} *all* known USE flags?"
+                       echo "         If you don't please press Ctrl-C NOW!!!"
+                       sleep 5
+                       set $(get_useflaglist | sort -u)
+               fi
+       fi
+       
+       get_useflags
+       
+       NEW_MAKE_CONF_USE=" ${ACTIVE_FLAGS[1]} "
+       
+       while [ -n "${1}" ]; do
+               if [ "${ACTION}" == "add" ]; then
+                       if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+                               shift
+                       elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+                               remove_flag "-${1}"
+                       else
+                               add_flag "${1}"
+                               shift
+                       fi
+               elif [ "${ACTION}" == "remove" ]; then
+                       if echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+                               shift
+                       elif echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+                               remove_flag "${1}"
+                       else
+                               add_flag "-${1}"
+                               shift
+                       fi
+               elif [ "${ACTION}" == "prune" ]; then
+                       if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+                               remove_flag "${1}"
+                       elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+                               remove_flag "-${1}"
+                       fi
+                       shift
+               fi
+       done
+       
+       #echo "old flags:"
+       #echo ${ACTIVE_FLAGS[1]}
+       #echo
+       #echo "new flags:"
+       #echo ${NEW_MAKE_CONF_USE}
+       
+       # a little loop to add linebreaks so we don't end with one ultra-long line
+       NEW_MAKE_CONF_USE_2=""
+       for x in ${NEW_MAKE_CONF_USE}; do
+               if [ $(((${#NEW_MAKE_CONF_USE_2}%70)+${#x}+2)) -gt 70 ]; then
+                       NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}\\ \\n     $x "
+               else
+                       NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}${x} "
+               fi
+       done
+
+       # make a backup just in case the user doesn't like the new make.conf
+       cp -p "${MAKE_CONF_PATH}" "${MAKE_CONF_BACKUP_PATH}"
+       
+       # as sed doesn't really work with multi-line patterns we have to replace USE
+       # on our own here. Basically just skip everything between USE=" and the 
+       # closing ", printing our new USE line there instead.
+       inuse=0
+       (while read -r line; do
+               [ "${line:0:4}" == "USE=" ] && inuse=1
+               [ "${inuse}" == "0" ] && echo -E "${line}"
+               if [ "${inuse}" == "1" ] && echo "${line}" | egrep '" *(#.*)?$' > /dev/null; then
+                       echo -n 'USE="'
+                       echo -ne "${NEW_MAKE_CONF_USE_2%% }"
+                       echo '"'
+                       inuse=0
+               fi
+       done ) < "${MAKE_CONF_BACKUP_PATH}" | sed -e 's:\\ $:\\:' > "${MAKE_CONF_PATH}"
+       
+       echo "${MAKE_CONF_PATH} was modified, a backup copy has been placed at ${MAKE_CONF_BACKUP_PATH}"
 }
 
-# formatted output for euse -i
-sub format_output
-{
-    my @use_flag_list = @{shift()};
-    my $max_len = ${shift()};
-    #print "Use flag list: $#use_flag_list \n";
-    #print "Key Length: $max_len \n";
-    if ($#use_flag_list < 0) {
-        print ("No matching use flags to display!! \n");
-        return;
-    }
-    my @use_flag;
-    my ($use_flag_name, $use_flag_desc, $use_flag_type, $use_flag_mask, 
-        $use_flag_site);
-    
-    # No of columns = 80
-    # -1 to compensate for < or @ char in format
-    # -2 to compensate for ~~ in format
-    # No of other chars excluding use flag name = 14
-    my $use_flag_format = "format USE_FLAG_FORMAT= \n" .
-'@' . ('<'x($max_len-1)) . ' [@]' . ' [@] [@] ' . '^' . ('<'x(80-$max_len-13-1)) . "\n" .
-'$use_flag_name, $use_flag_mask, $use_flag_site, $use_flag_type, $use_flag_desc' ."\n" .
-(' 'x($max_len+13)) . '^' . ('<'x(80-$max_len-13-1-2)) . '~~' . "\n" . 
-'$use_flag_desc' . "\n" .
-".\n";
-
-    eval $use_flag_format;
-    #print $use_flag_format;
+##### main program comes now #####
 
+parse_arguments "$@"
+check_sanity
 
-    $~ = 'USE_FLAG_FORMAT';
-    foreach (@use_flag_list) {
-        @use_flag = @{$_};
-        $use_flag_name = $use_flag[0];
-        $use_flag_desc = ($use_flag[4] eq "" ? 
-            $use_flag[1] : "[" . $use_flag[4] . "] : " . $use_flag[1]);
-        $use_flag_type = $use_flag[2];
-        $use_flag_mask = $use_flag[3];
-        $use_flag_site = $use_flag[5];
-        write;
-    }
-
-}
-
-# TODO:
-# 1. -p feature
-# 2. pipe the output to less to implement paging.
-# 3. flag to disable all warnings.
-# 4. filters - all global, local, enabled through make.conf,
-#    make.defaults, env. All enabled flags, all disabled flags.
-# 5. combine -d, -c, -e with -i to give detailed output.
-# 
+eval ${MODE} ${ARGUMENTS}
index f5c57e0d9703eed9bea1046c6ac1d4123814ba2f..07bec3fe51c06af7601802935a7502455a7c4170 100644 (file)
@@ -1,89 +1,98 @@
-.TH EUSE 1 2003-05-01 "Gentoo Linux" "Gentoo Toolkit"
-.SH NAME
+.TH "EUSE" "1" "2004-10-17" "Gentoo Linux" "Gentoo Toolkit"
+.SH "NAME"
 euse \- Gentoo: command line USE flag editor
-.SH SYNOPSIS
+.SH "SYNOPSIS"
 .B euse
-\fI[options]\fB
-.SH DESCRIPTION
-.PP
+\fI<option> [suboption] [useflaglist]\fB
+.SH "DESCRIPTION"
+.PP 
 .I euse
-is used to set(disable/enable) USE flags /etc/make.conf without having to edit
+is used to set(disable/enable) USE flags in /etc/make.conf without having to edit
 the file directly. It is also used to get detail information about use flags
 like description, status of flags(enabled/disabled), type of flag(global/local)
-etc. It can also be queried for viewing the current use flag settings in
-/etc/make.conf, /etc/make.defaults and environment.
-.SH OPTIONS 
-.TP
-\fB-c, --conf\fI
-Print the USE flag setting in /etc/make.conf
-.TP
-\fB-d, --defaults\fI
-Print the USE flag setting in /etc/make.profile/make.defaults
-.TP
-\fB-e, --env\fI
-Print the USE flag setting in environment
-.TP
-\fB-E, --enable\fI
-Enables USE flag(s) in make.conf. It accepts one or more USE flags space
-separted as parameters. Please read README for all the different cases it
-handles.
-.TP
-\fB-D, --disable\fI
-Disables USE flag(s) in make.conf. Puts a '-' sign infront of the use flag and
-appends to USE setting of make.conf. It accepts one or more USE flags space
-separted as parameters. Please read README for all the different cases it
-handles.
-.TP
-\fB-i, --info\fI
+etc.
+.SH "OPTIONS "
+.TP 
+\fB\-E, \-\-enable\fI
+Enables USE flag(s) in make.conf. It accepts one or more space seperated 
+USE flags as parameters.
+.TP 
+\fB\-D, \-\-disable\fI
+Disables USE flag(s) in make.conf. Puts a '\-' sign in front of the USE flag
+and appends it to the USE setting in make.conf. It accepts one or more 
+space seperated USE flags as parameters.
+.TP 
+\fB\-P, \-\-prune\fI
+Removes USE flag(s) in make.conf. Removes all positive and negative references to
+the given USE flags from make.conf.
+.TP 
+\fB\-i, \-\-info\fI
 Prints detail information about the USE flag(s). If no arguments are given then
-all the USE flag(global & local) information is printed. If one or more
-arguments are given(space separated) then information of only those flags are
+it assumes you want information for all USE flags. If one or more
+arguments are given (space separated) then only information for those flags is
 printed. 
 .sp
 .RS
 The output is in the following format:
-.br
-alpha         [-] [ ] [G] indicates that architecture ...
-.br
-moznocompose  [+] [C] [L] [net-www/mozilla] : If you  ... 
-.br
-The column descriptions are:
-.IP flag_name
-name of the use flag
-.IP flag_status
-indicates whether the USE flag is enabled or disabled. - indicates disabled, +
-indicates enabled.
-.IP flag_location
-indicates where the USE flag is enabled or disabled.
-C indicates make.conf, D indicates make.defaults, E indicates environment.
-.IP flag_type
-indicates if the flag is global USE flag or a local USE flag.If it is local USE
-flag, then the description column begins with the package which it belongs to
-in square brackets. See moznocompose example above.
-.IP description
-gives a short description of the USE flag
-.TP
-\fB-h, --help\fI
+.br 
+\fB[\- cD ]\fI alpha \- indicates that architecture ...
+.br 
+\fB[\-   ]\fI moznocompose (net\-www/mozilla):.br 
+Disable building of mozilla's web page composer 
+.br 
+The the indicators in the first column are:
+.IP is_active
++ if the flag is seen as active by portage, \- if not
+.IP is_in_env
+E if the flag is enabled in the environment, e if it is
+disabled in the environment, nothing if it's not affected
+by the environment
+.IP is_in_make_conf
+C if the flag is enabled in make.conf, c if it is
+disabled in make.conf, nothing if it's not affected
+by make.conf
+.IP is_in_make_defaults
+D if the flag is enabled in make.defaults, d if it is
+disabled in make.defaults, nothing if it's not affected
+by make.defaults
+.IP is_in_make_globals
+G if the flag is enabled in make.globals, g if it is
+disabled in make.globals, nothing if it's not affected
+by make.globals
+.br 
+Then follows the name of the flag, for local flags the
+package name and then the description (on a new line for
+local flags).
+.TP 
+\fB\-a, \-\-active\fI
+Shows all currently active USE flags and where they are activated (see 
+description for \fB\-\-info\fI).
+.TP 
+\fB\-h, \-\-help\fI
 Show the help message listing all the available flags and a short description
-.TP
-\fB-v, --version\fI
+.TP 
+\fB\-v, \-\-version\fI
 Show the version information
-.SH FILES
+.SH "FILES"
 /etc/make.conf
-.br
+.br 
 /etc/make.profile/make.defaults
-.br
+.br 
+/etc/make.globals
+.br 
 $PORTDIR/profiles/use.desc
-.br
+.br 
 $PORTDIR/profiles/use.local.desc
-.br
-/etc/make.profile/use.mask
-.SH AUTHOR
-Arun Bhanu <codebear@gentoo.org>
-.SH BUGS
-No reported bugs yet.
+.br 
+
+.SH "AUTHOR"
+Original version by Arun Bhanu <codebear@gentoo.org>
+.br 
+Updated for rewritten euse by Marius Mauch <genone@gentoo.org>
+.SH "BUGS"
+euse doesn't handle USE flags enabled or disabled by use.defaults, use.mask
+or package.use yet. It also doesn't completely understand the \-* flag.
 .SH "SEE ALSO"
 .BR ufed(8), 
-.BR README
-.TP
+.TP 
 The \fI/usr/bin/euse\fR script.