#!/usr/bin/perl

use strict;
use Libconf qw(:helpers);
use Libconf::Glueconf::Generic::KeyValue;
use Libconf::Glueconf::Generic::Shell;

my $portage = 0;
my $paludis = 1;

our $VERSION='0.0.7';
my $paludis_uf_file = '/etc/paludis/use.conf';
my $paludis_kw_file = '/etc/paludis/keywords.conf';
my $paludis_brc = '/etc/paludis/bashrc';
my $paludis_dir = '/etc/paludis';
my $uf_file = '/etc/portage/package.use';
my $kw_file = '/etc/portage/package.keywords';
my $mc_file = '/etc/make.conf';
my $portage_dir = '/usr/portage';
my $alpha_order = 0;
my $strict = 0;
our $nowarn = 0;
my (@actions, @keywords, $show, $list, $desc, $do_keyword);
foreach my $i (0..@ARGV-1) {
    member($ARGV[$i], '--help', '-h') and usage();
    member($ARGV[$i], '--version', '-v') and version();
    $ARGV[$i] eq '--package-file' and $uf_file = $ARGV[++$i], next;
    $ARGV[$i] eq '--keywords-file' and $kw_file = $ARGV[++$i], next;
    $ARGV[$i] eq '--make-conf-file' and $mc_file = $ARGV[++$i], next;
    $ARGV[$i] eq '--portage-dir' and $portage_dir = $ARGV[++$i], next;
    $ARGV[$i] eq '--alpha-order' and $alpha_order = 1, next;
    $ARGV[$i] eq '--show' and $show = 1, next;
    $ARGV[$i] eq '--list' and $list = 1, next;
    $ARGV[$i] eq '--desc' and $desc = 1, next;
    $ARGV[$i] eq '--strict' and $strict = 1, next;
    $ARGV[$i] eq '--nowarn' and $nowarn = 1, next;
    $ARGV[$i] eq '--keywords' || $ARGV[$i] eq '--' and $do_keyword = 1, next;
    if ($do_keyword) {
        push @keywords, $ARGV[$i];
    } else {
        push @actions, $ARGV[$i];
    }
}

my $use_global_uf = !@actions || $actions[0] =~ /^(\+|\-|\%)/;
!@actions and !$show and $show = 1;

my $uf = { _plus => [], _minus => [], _order => [] };
my $kw = { _plus => [], _minus => [], _order => [] };
my $uf_desc_kw;
my $uf_desc_uf;
if ($paludis) {
	$uf_desc_kw = { map { $_ => "stable keyword for $_", "~$_" => "unstable keyword for $_" } get_paludis_archlist() };
} elsif ($portage) {
	$uf_desc_kw = { map { $_ => "stable keyword for $_", "~$_" => "unstable keyword for $_" } get_archlist() };
} else {
	die "You have not selected either portage or paludis!"
}
if ($paludis) {
	$uf_desc_uf = paludis_get_uf_desc();
} elsif ($portage) {
	$uf_desc_uf = get_uf_desc();
} else {
	die "You have not selected either portage or paludis!"
}
$uf_desc_uf->{'*'} = 'all the flags';
$uf_desc_kw->{'*'} = 'all the keywords';

my $uf_desc = $do_keyword ? $uf_desc_kw : $uf_desc_uf;
if ($list) {
    while(my ($key, $value) = each(%$uf_desc)) {
        print "$key" . ($desc ? ": $value" : '') ."\n";
    }
    exit(0);
}
my ($flags, $package, $kwords);
my $file;
if ($paludis) {
	if ($do_keyword) {
	    $file = $use_global_uf ? $paludis_kw_file : $paludis_kw_file;
	} else {
	    $file = $use_global_uf ? $paludis_uf_file : $paludis_uf_file;
	}
} elsif ($portage) {
	if ($do_keyword) {
	    $file = $use_global_uf ? $mc_file : $kw_file;
	} else {
	    $file = $use_global_uf ? $mc_file : $uf_file;
	}
} else {
	die "You have not selected either portage or paludis!"
}
-e $file or open FILE,">$file" or die "couldn't create empty '$file'"; close FILE;
(-w $file || $show) && -r $file or die "'$file' is not a readable and writable file";

if ($paludis) {
	if ($use_global_uf) { 
		my $bashrc = Libconf::Glueconf::Generic::Shell->new({ filename => $paludis_brc,
									shell_style => 'true_bash',
									shell_command => '/bin/bash',
									});
		string_2_uf($uf, $uf_desc_uf, $paludis_uf_file->{'* USE: '});
		string_2_uf($kw, $uf_desc_kw, $paludis_kw_file->{'* '});
		if ($show) {
			if ($do_keyword) {
			my $ak = $paludis_kw_file->{'* '};
			$ak ||= 'unset';
			print "global accepted keywords : $ak\n";
			} else {
			print uf_2_string($uf, $alpha_order) . "\n";
			}
		} else {
			if (@actions > 0) {
			string_2_uf($uf, $uf_desc_uf, @actions);
			paludis_save_uf_flags(uf_2_string($uf, $alpha_order), $paludis_uf_file);
			}
			if ($do_keyword) {
			foreach my $keyword (@keywords) {
				if ($keyword eq '%') {
				my @a = @{$kw->{_order}};
				remove($kw, $_) foreach(@a);
				} else {
				string_2_uf($kw, $uf_desc_kw, $keyword);
				}
			}
			paludis_save_kw(uf_2_string($kw, $alpha_order), $paludis_kw_file);
			}
		}
	
	} else {
		$flags = Libconf::Glueconf::Generic::KeyValue->new({ filename => $paludis_uf_file,
									separator_char => '(?:\s|$)',
									output_separator_char => ' ',
									allow_space => 1,
									handle_quote => 0,
									accept_empty_value => 1,
								});
		if ($do_keyword) {
			$kwords = Libconf::Glueconf::Generic::KeyValue->new({ filename => $paludis_kw_file,
									separator_char => '(?:\s|$)',
									output_separator_char => ' ',
									allow_space => 1,
									handle_quote => 0,
									accept_empty_value => 1,
									});
		}
		$package = shift @actions;
		if (!$show) {
			if (@actions > 0) {
			-e "$paludis_uf_file.old" and unlink("$paludis_uf_file.old") || die "couldn't remove $uf_file.old\n";
			open(FILE, $paludis_uf_file) or die "couldn't open $paludis_uf_file\n";
			open(OUTFILE, ">$paludis_uf_file.old") or die "couldn't write to $paludis_uf_file.old\n";
			{ local $/; my $c = <FILE>; print OUTFILE $c; }
			}
			if ($do_keyword) {
			-e "$paludis_kw_file.old" and unlink("$paludis_kw_file.old") || die "couldn't remove $paludis_kw_file.old\n";
			open(FILE, $paludis_kw_file) or die "couldn't open $paludis_kw_file\n";
			open(OUTFILE, ">$paludis_kw_file.old") or die "couldn't write to $paludis_kw_file.old\n";
			{ local $/; my $c = <FILE>; print OUTFILE $c; }
			}
		}
		
		if ($package !~ m|/| ) {
			my @ext_package;
			foreach (keys %$flags, keys %$kwords) {
			m|/$package$| and push @ext_package, $_;
			}
			@ext_package > 1 and die "multiple package match : " . join (', ', @ext_package) . ". Specify more \n";
			@ext_package == 0 and die "no package matching $package were found. To add a new package, you have to fully specify it (for instance 'net-im/amsn').\n";
			$package = $ext_package[0];
		}
		
		if (exists $flags->{$package}) {
			string_2_uf($uf, $uf_desc_uf, $flags->{$package});
		}
		if (exists $kwords->{$package}) {
			string_2_uf($kw, $uf_desc_kw, $kwords->{$package});
		}
		if ($show) {
			if ($do_keyword) {
			print uf_2_string($kw, $alpha_order) . "\n";
			} else {
			print uf_2_string($uf, $alpha_order) . "\n";
			}
		} else {
			if (@actions > 0) {
			foreach my $action (@actions) {
				if ($action eq '%') {
				my @a = @{$uf->{_order}};
				remove($uf, $_) foreach(@a);
				} else {
				string_2_uf($uf, $uf_desc_uf, $action);
				}
			}
			my $s = uf_2_string($uf, $alpha_order);
			if (length($s)) {
				$flags->{$package} = $s;
			} else {
				delete $flags->{$package};
			}
			$flags->write_conf();
			}
			if (@keywords > 0) {
			foreach my $keyword (@keywords) {
				if ($keyword eq '%') {
				my @a = @{$kw->{_order}};
				remove($kw, $_) foreach(@a);
				} else {
				string_2_uf($kw, $uf_desc_kw, $keyword);
				}
			}
			my $s = uf_2_string($kw, $alpha_order);
			if (length($s)) {
				$kwords->{$package} = $s;
			} else {
				delete $kwords->{$package};
			}
			$kwords->write_conf();
			}
		}
	}
} elsif ($portage) {
	if ($use_global_uf) { 
	my $make_conf = Libconf::Glueconf::Generic::Shell->new({ filename => $mc_file,
								shell_style => 'true_bash',
								shell_command => '/bin/bash',
								});
	string_2_uf($uf, $uf_desc_uf, $make_conf->{USE});
	string_2_uf($kw, $uf_desc_kw, $make_conf->{ACCEPT_KEYWORDS});
	if ($show) {
		if ($do_keyword) {
		my $ak = $make_conf->{ACCEPT_KEYWORDS};
		$ak ||= 'unset';
		print "global accepted keywords : $ak\n";
		} else {
		print uf_2_string($uf, $alpha_order) . "\n";
		}
	} else {
		if (@actions > 0) {
		string_2_uf($uf, $uf_desc_uf, @actions);
		save_mc_flags(uf_2_string($uf, $alpha_order), $mc_file);
		}
		if ($do_keyword) {
		foreach my $keyword (@keywords) {
			if ($keyword eq '%') {
			my @a = @{$kw->{_order}};
			remove($kw, $_) foreach(@a);
			} else {
			string_2_uf($kw, $uf_desc_kw, $keyword);
			}
		}
		save_mc_kw(uf_2_string($kw, $alpha_order), $mc_file);
		}
	}
	
	} else {
	$flags = Libconf::Glueconf::Generic::KeyValue->new({ filename => $uf_file,
								separator_char => '(?:\s|$)',
								output_separator_char => ' ',
								allow_space => 1,
								handle_quote => 0,
								accept_empty_value => 1,
							});
	if ($do_keyword) {
		$kwords = Libconf::Glueconf::Generic::KeyValue->new({ filename => $kw_file,
								separator_char => '(?:\s|$)',
								output_separator_char => ' ',
								allow_space => 1,
								handle_quote => 0,
								accept_empty_value => 1,
								});
	}
	$package = shift @actions;
	if (!$show) {
		if (@actions > 0) {
		-e "$uf_file.old" and unlink("$uf_file.old") || die "couldn't remove $uf_file.old\n";
		open(FILE, $uf_file) or die "couldn't open $uf_file\n";
		open(OUTFILE, ">$uf_file.old") or die "couldn't write to $uf_file.old\n";
		{ local $/; my $c = <FILE>; print OUTFILE $c; }
		}
		if ($do_keyword) {
		-e "$kw_file.old" and unlink("$kw_file.old") || die "couldn't remove $kw_file.old\n";
		open(FILE, $kw_file) or die "couldn't open $kw_file\n";
		open(OUTFILE, ">$kw_file.old") or die "couldn't write to $kw_file.old\n";
		{ local $/; my $c = <FILE>; print OUTFILE $c; }
		}
	}
	
	if ($package !~ m|/| ) {
		my @ext_package;
		foreach (keys %$flags, keys %$kwords) {
		m|/$package$| and push @ext_package, $_;
		}
		@ext_package > 1 and die "multiple package match : " . join (', ', @ext_package) . ". Specify more \n";
		@ext_package == 0 and die "no package matching $package were found. To add a new package, you have to fully specify it (for instance 'net-im/amsn').\n";
		$package = $ext_package[0];
	}
	
	if (exists $flags->{$package}) {
		string_2_uf($uf, $uf_desc_uf, $flags->{$package});
	}
	if (exists $kwords->{$package}) {
		string_2_uf($kw, $uf_desc_kw, $kwords->{$package});
	}
	if ($show) {
		if ($do_keyword) {
		print uf_2_string($kw, $alpha_order) . "\n";
		} else {
		print uf_2_string($uf, $alpha_order) . "\n";
		}
	} else {
		if (@actions > 0) {
		foreach my $action (@actions) {
			if ($action eq '%') {
			my @a = @{$uf->{_order}};
			remove($uf, $_) foreach(@a);
			} else {
			string_2_uf($uf, $uf_desc_uf, $action);
			}
		}
		my $s = uf_2_string($uf, $alpha_order);
		if (length($s)) {
			$flags->{$package} = $s;
		} else {
			delete $flags->{$package};
		}
		$flags->write_conf();
		}
		if (@keywords > 0) {
		foreach my $keyword (@keywords) {
			if ($keyword eq '%') {
			my @a = @{$kw->{_order}};
			remove($kw, $_) foreach(@a);
			} else {
			string_2_uf($kw, $uf_desc_kw, $keyword);
			}
		}
		my $s = uf_2_string($kw, $alpha_order);
		if (length($s)) {
			$kwords->{$package} = $s;
		} else {
			delete $kwords->{$package};
		}
		$kwords->write_conf();
		}
	}
	}
} else {
	die "You have not selected either portage or paludis!"
}

sub version {
    print qq(
Flagedit version $VERSION
);
    exit(0);
}

sub usage {
    print qq(

flagedit allows you to edit the use flags or the keywords for a particular
ebuild, or for the whole system. a backup is done for each modified file, named
file.old.

Usage: flagedit [PACKAGE] [ACTIONS | -- KEYWORD_ACTIONS] [ OPTIONS ]

Examples:
 flagedit net-im/amsn --show     # shows the use flag set for net-im/amsn
 flagedit net-im/amsn +gnome     # adds the gnome use flag to net-im/amsn
 flagedit net-im/amsn -kde +xmms # adds the xmms use flag and set the -kde one
 flagedit net-im/amsn %kde       # resets the kde use flag (it's removed from
                                 #   the line)

 flagedit %kde                   # resets the global use flag (it's removed in
                                 #   make.conf)
 flagedit +gnome -qt             # add gnome and -qt in make.conf

 flagedit net-im/amsn -- %x86    # reset the x86 keyword for net-im/amsn
 flagedit net-im/amsn -- +~ppc +~x86   # adds the ~ppc and ~x86 keywords for
                                       #   net-im/amsn
 flagedit net-im/amsn -- %       # resets the keywords for this package
 flagedit -- +~x86               # sets ACCEPT_KEYWORDS to "~x86"
                                 # in /etc/make.conf

You can mix the flags and keywords :
 flagedit net-im/amsn +gnome -- +~x86

PACKAGE is a package name (like dev-ruby/ruby-atk). If no package is given,
flagedit will edit the maine USE flags (in make.conf), or the main
ACCEPT_KEYWORDS (in make.conf)

ACTIONS are :
+FLAG \t enable the FLAG. Example : +sse
-FLAG \t disable the FLAG. Example : -sse
%FLAG \t reset the FLAG to default. Example : %sse
% \t reset the whole flags of PACKAGE to default.
  \t In this case, PACKAGE is not optional

KEYWORD_ACTIONS are :
+KEYWORD \t enable the keyword. Example : +x86
-KEYWORD \t disable the KEYWORD. Example : -~x86
%KEYWORD \t reset the KEYWORD to default. Example : %x86
% \t\t reset the whole keywords of PACKAGE to default.
  \t\t In this case, PACKAGE is not optional


OPTIONS are :
  --package-file=<path>   specify an alternate package.use file (default is
                            /etc/portage/package.use)
  --make-conf-file=<path> specify an alternate make.conf file (default is
                            /etc/make.conf)
  --portage-dir=<path>    specify an alternate portage directory path (default
                            is /usr/portage)
  --alpha-order           sort the flags alphabetically instead of keeping the
                            original order
  --show                  don't edit, display the flags of the PACKAGE. If no
                            package is given, display the system USE flags.
  --list                  don't edit, display the entire list of possible flags.
  --desc                  if specified with --list, display the flags
                            description also.
  --strict                if a specified flag name is invalid, dies, instead of
                            just warning.
  --nowarn                if a specified flag name is invalid, don't warn.
  --help                  this help
  
see http://damz.net/flagedit/

);
    exit(0);    
}

sub paludisdirs {
	my @paludisdirs;
	while (<${paludis_dir}/repositories/*>) {
		if (/location = (.+)/) {
			$1 =~ s/\${ROOT}/\//;
			push (@paludisdirs, $1);
		}
	}
	@paludisdirs;
}

sub get_paludis_archlist {
    my @arch_list;
    foreach my $paludisdir (paludisdirs()) {
        -e "$paludisdir/profiles/arch.list" or next;
        my @l = map { chomp; $_ } cat_("$paludisdir/profiles/arch.list");
        push @arch_list, @l;
    }
    @arch_list;
}

sub paludis_get_uf_desc {

    ####
    # list of USE flags

    my $use_desc = {};

    foreach my $paludisdir (paludisdirs()) {
        -e "$paludisdir/profiles/use.desc" or warn "fatal error : couldn't find the flag descriptions `$paludisdir/profiles/use.desc').\n", next;
        my $use_desc_struct = Libconf::Glueconf::Generic::KeyValue->new({ filename => "$paludisdir/profiles/use.desc",
                                                                          separator_char => '\s-\s',
                                                                          allow_space => 1,
                                                                          handle_quote => 0,
                                                                          accept_empty_value => 1,
                                                                        });

        while (my ($key, $value) = each %$use_desc_struct) {
            $use_desc->{$key} = $value;
        }
        # get the use.local.desc description
        -e "$paludisdir/profiles/use.local.desc" or
          warn "warning : couldn't find the local descriptions `$paludisdir/profiles/use.local.desc'.\n", next;
        my $use_local_desc = Libconf::Glueconf::Generic::KeyValue->new({ filename => "$paludisdir/profiles/use.local.desc",
                                                                         separator_char => '\s-',
                                                                         allow_space => 1,
                                                                         handle_quote => 0,
                                                                         accept_empty_value => 1,
                                                                       });
        # match the "package:flag - description" syntax and merge with use.desc
        while (my ($key, $value) = each %$use_local_desc) {
            my ($package, $flag) = split /:/, $key;
            # the decription is added, not replaced, so that a flag can have multiple description
            $use_desc->{$flag} .= (length($use_desc->{$flag}) ? ' --- ' : '') . "Local Flag: $value ($package)";
        }
    }

    # we remove the internal flags not to be set by users, but not the masked flags.

    foreach (keys %$use_desc) {
        if ($use_desc->{$_} =~ /(\!\!internal use only\!\!)|(indicates.*(architecture|platform))/i) {
            delete $use_desc->{$_};
        }
    }
    $use_desc;
}

sub portdirs {
    # default portage directory
    my $make_conf = Libconf::Glueconf::Generic::Shell->new({ filename => $mc_file,
                                                             shell_style => 'true_bash',
                                                             shell_command => '/bin/bash',
                                                           });

    ($portage_dir, $make_conf->{PORTDIR_OVERLAY});
}

sub get_archlist {
    my @arch_list;
    foreach my $portdir (portdirs()) {
        -e "$portdir/profiles/arch.list" or next;
        my @l = map { chomp; $_ } cat_("$portdir/profiles/arch.list");
        push @arch_list, @l;
    }
    @arch_list;
}

sub cat_ { my ($f, $e) = @_;
           local *F;
           open F, defined $e ? ("<:encoding($e)", $f) : $f or die "reading file $f failed: $!\n";
           my @l = <F>;
           wantarray() ? @l : join '', @l
       }

sub get_uf_desc {

    ####
    # list of USE flags

    my $use_desc = {};

    foreach my $portdir (portdirs()) {
        -e "$portdir/profiles/use.desc" or warn "fatal error : couldn't find the flag descriptions `$portdir/profiles/use.desc').\n", next;
        my $use_desc_struct = Libconf::Glueconf::Generic::KeyValue->new({ filename => "$portdir/profiles/use.desc",
                                                                          separator_char => '\s-\s',
                                                                          allow_space => 1,
                                                                          handle_quote => 0,
                                                                          accept_empty_value => 1,
                                                                        });

        while (my ($key, $value) = each %$use_desc_struct) {
            $use_desc->{$key} = $value;
        }
        # get the use.local.desc description
        -e "$portdir/profiles/use.local.desc" or
          warn "warning : couldn't find the local descriptions `$portdir/profiles/use.local.desc'.\n", next;
        my $use_local_desc = Libconf::Glueconf::Generic::KeyValue->new({ filename => "$portdir/profiles/use.local.desc",
                                                                         separator_char => '\s-',
                                                                         allow_space => 1,
                                                                         handle_quote => 0,
                                                                         accept_empty_value => 1,
                                                                       });
        # match the "package:flag - description" syntax and merge with use.desc
        while (my ($key, $value) = each %$use_local_desc) {
            my ($package, $flag) = split /:/, $key;
            # the decription is added, not replaced, so that a flag can have multiple description
            $use_desc->{$flag} .= (length($use_desc->{$flag}) ? ' --- ' : '') . "Local Flag: $value ($package)";
        }
    }

    # we remove the internal flags not to be set by users, but not the masked flags.

    foreach (keys %$use_desc) {
        if ($use_desc->{$_} =~ /(\!\!internal use only\!\!)|(indicates.*(architecture|platform))/i) {
            delete $use_desc->{$_};
        }
    }
    $use_desc;
}

#while (my ($key, $value) = each %{$profile->{use_mask_hash}}) {
#    $value or next;
#    delete $use_desc->{$key};
#}

# add the flag from use.default if the corresponding package is installed
#my %use_default_flags;
#while (my ($flag, $package) = each %{$profile->{use_defaults}}) {
#    if (defined($package)) {
#        my @glob = glob("/var/db/pkg/$package-[0-9]*");
#        @glob > 0 and $use_default_flags{$flag} = '+';
#    }
#}


########





sub string_2_uf {
    my ($uf, $uf_desc, @strings) = @_;
    foreach (split(/\s/, join(' ', @strings))) {
        /^\+(.+)/ and add($uf, $uf_desc, $1, '+', '-', '_minus', '_plus', '+'), next;
        /^\-(.+)/ and add($uf, $uf_desc, $1, '-', '+', '_plus', '_minus', '-'), next;
        /^\%(.+)/ and remove($uf, $1), next;
        add($uf, $uf_desc, $_, '+', '-', '_minus', '_plus', '+');
    }
}

sub remove_from_list {
    my ($elmt, $list) = @_;
    my @tmp;
    $_ eq $elmt or push(@tmp, $_) foreach (@{$list});
    @{$list} = @tmp;
}

sub add {
    my ($uf, $uf_desc, $flag, $a1, $a2, $a3, $a4, $a5) = @_;
    $uf->{$flag} eq $a1 and return;
    $uf->{$flag} eq $a2 and remove_from_list($flag, $uf->{$a3});
    my $warn = "'$flag' seems to be a wrong flag";
    (!$nowarn && !exists $uf_desc->{$flag}) and $strict ? die "fatal error : $warn\n" : warn "warning : $warn, I hope you know what you're doing\n";
    push @{$uf->{$a4}}, $flag;
    remove_from_list($flag, $uf->{_order});
    push @{$uf->{_order}}, $flag;
    $uf->{$flag} = $a5;
}

sub remove {
    my ($uf, $flag) = @_;
    remove_from_list($flag, $uf->{$_}) foreach (qw(_plus _minus _order));
    delete $uf->{$flag};
}

sub uf_2_string {
    my ($uf, $alpha_order) = @_;
    join (' ', map { ($uf->{$_} eq '+' ? '' : '-') . $_ } ($alpha_order ? sort { uc($a) cmp uc($b) } @{$uf->{_order}} : @{$uf->{_order}}) );
}

# stolen from ufed
sub save_mc_flags {
    my ($flags, $make_conf_file) = @_;
    my $contents;

    -e "$make_conf_file.old" and unlink("$make_conf_file.old") || die "couldn't unlink $make_conf_file.old \n";
    rename($make_conf_file, "$make_conf_file.old") or die "couldn't rename $make_conf_file\n";

    open(FILE, "$make_conf_file.old") or die "couldn't open $make_conf_file.old", return;
    open(OUTFILE, ">$make_conf_file") or die "couldn't open $make_conf_file", return;

    { local $/; $contents = <FILE> }

    if($contents =~ s/^([^\S\n]*)USE="[^"]*"/
       my $i = $1;
       $_ = qq(USE="$flags");
       s!^!$i!mg; # preserve indentation
       $_
       /me) {
        # nothing here, s/// did all the work
    } elsif($contents =~ s/^\#USE=(.*)/\#USE=$1\nUSE="$flags"\n/m) {
        # nothing here, s/// did all the work
    } else {
        $contents .= qq(\nUSE="$flags"\n);
    }

    print OUTFILE $contents;

    close(OUTFILE);
    close(FILE);

    chmod(0644, $make_conf_file);
}


sub paludis_save_kw {
    my ($flags, $paludis_kw_file) = @_;
    my $contents;

    -e "$paludis_kw_file.old" and unlink("$paludis_kw_file.old") || die "couldn't unlink $paludis_kw_file.old \n";
    rename($paludis_kw_file, "$paludis_kw_file.old") or die "couldn't rename $paludis_kw_file\n";

    open(FILE, "$paludis_kw_file.old") or die "couldn't open $paludis_kw_file.old", return;
    open(OUTFILE, ">$paludis_kw_file") or die "couldn't open $paludis_kw_file", return;

    { local $/; $contents = <FILE> }

    if($contents =~ s/^([^\S\n]*)\* "[^"]*"/
       my $i = $1;
       $_ = qq(* "$flags");
       s!^!$i!mg; # preserve indentation
       $_
       /me) {
        # nothing here, s/// did all the work
    } elsif($contents =~ s/^\#\* (.*)/\#\* $1\n\* "$flags"\n/m) {
        # nothing here, s/// did all the work
    } else {
        $contents .= qq(\n* "$flags"\n);
    }

    print OUTFILE $contents;

    close(OUTFILE);
    close(FILE);

    chmod(0644, $paludis_kw_file);
}

# stolen from ufed
sub paludis_save_uf_flags {
    my ($flags, $paludis_uf_file) = @_;
    my $contents;

    -e "$paludis_uf_file.old" and unlink("$paludis_uf_file.old") || die "couldn't unlink $paludis_uf_file.old \n";
    rename($paludis_uf_file, "$paludis_uf_file.old") or die "couldn't rename $paludis_uf_file\n";

    open(FILE, "$paludis_uf_file.old") or die "couldn't open $paludis_uf_file.old", return;
    open(OUTFILE, ">$paludis_uf_file") or die "couldn't open $paludis_uf_file", return;

    { local $/; $contents = <FILE> }

    if($contents =~ s/^([^\S\n]*)\* "[^"]*"/
       my $i = $1;
       $_ = qq(USE="$flags");
       s!^!$i!mg; # preserve indentation
       $_
       /me) {
        # nothing here, s/// did all the work
    } elsif($contents =~ s/^\#\* (.*)/\#\* $1\n\* "$flags"\n/m) {
        # nothing here, s/// did all the work
    } else {
        $contents .= qq(\n* "$flags"\n);
    }

    print OUTFILE $contents;

    close(OUTFILE);
    close(FILE);

    chmod(0644, $paludis_uf_file);
}


sub save_mc_kw {
    my ($flags, $make_conf_file) = @_;
    my $contents;

    -e "$make_conf_file.old" and unlink("$make_conf_file.old") || die "couldn't unlink $make_conf_file.old \n";
    rename($make_conf_file, "$make_conf_file.old") or die "couldn't rename $make_conf_file\n";

    open(FILE, "$make_conf_file.old") or die "couldn't open $make_conf_file.old", return;
    open(OUTFILE, ">$make_conf_file") or die "couldn't open $make_conf_file", return;

    { local $/; $contents = <FILE> }

    if($contents =~ s/^([^\S\n]*)ACCEPT_KEYWORDS="[^"]*"/
       my $i = $1;
       $_ = qq(ACCEPT_KEYWORDS="$flags");
       s!^!$i!mg; # preserve indentation
       $_
       /me) {
        # nothing here, s/// did all the work
    } elsif($contents =~ s/^\#ACCEPT_KEYWORDS=(.*)/\#ACCEPT_KEYWORDS=$1\nACCEPT_KEYWORDS="$flags"\n/m) {
        # nothing here, s/// did all the work
    } else {
        $contents .= qq(\nACCEPT_KEYWORDS="$flags"\n);
    }

    print OUTFILE $contents;

    close(OUTFILE);
    close(FILE);

    chmod(0644, $make_conf_file);
}
