#!/usr/bin/perl
# (c) Copyright 2005-2012. CodeWeavers, Inc.
use warnings;
use strict;
# Portable which(1) implementation
sub cxwhich($$;$)
{
my ($dirs, $app, $noexec)=@_;
if ($app =~ /^\//)
{
return $app if ((-x $app or $noexec) and -f $app);
}
elsif ($app =~ /\//)
{
require Cwd;
my $path=Cwd::cwd() . "/$app";
return $path if ((-x $path or $noexec) and -f $path);
}
else
{
foreach my $dir (split /:/, $dirs)
{
return "$dir/$app" if ($dir ne "" and (-x "$dir/$app" or $noexec) and -f "$dir/$app");
}
}
return undef;
}
# Fast dirname() implementation
sub _cxdirname($)
{
my ($path)=@_;
return undef if (!defined $path);
return "." if ($path !~ s!/+[^/]+/*$!!s);
return "/" if ($path eq "");
return $path;
}
# Locate where CrossOver is installed by looking for the directory
# where the cxmenu script is located, unwinding symlinks on the way
sub locate_cx_root(;$)
{
my ($fallback)=@_;
my $argv0=cxwhich($ENV{PATH},$0);
$argv0=$0 if (!defined $argv0);
if ($argv0 !~ m+^/+)
{
require Cwd;
$argv0=Cwd::cwd() . "/$argv0";
}
my $dir=_cxdirname($argv0);
my $bindir=$dir;
$bindir =~ s%/lib$%/bin%;
while (!-x "$bindir/cxmenu" or !-f "$bindir/cxmenu")
{
last if (!-l $argv0);
$argv0=readlink($argv0);
$argv0="$dir/$argv0" if ($argv0 !~ m+^/+);
$dir=_cxdirname($argv0);
$bindir=$dir;
$bindir =~ s%/lib$%/bin%;
}
$bindir =~ s%/(?:\./)+%/%g;
$bindir =~ s%/\.$%%;
$ENV{CX_ROOT}=_cxdirname($bindir);
if ((!-x "$ENV{CX_ROOT}/bin/cxmenu" or !-f "$ENV{CX_ROOT}/bin/cxmenu") and
$fallback)
{
$ENV{CX_ROOT}=$fallback;
}
if (!-x "$ENV{CX_ROOT}/bin/cxmenu" or !-f "$ENV{CX_ROOT}/bin/cxmenu")
{
my $name0=$0;
$name0 =~ s+^.*/++;
print STDERR "$name0:error: could not find CrossOver in '$ENV{CX_ROOT}'\n";
exit 1;
}
return $ENV{CX_ROOT};
}
BEGIN {
unshift @INC, locate_cx_root() . "/lib/perl";
}
use CXLog;
use CXUtils;
my $filters;
sub get_filter_list($$)
{
my ($cxnsplugin, $filter)=@_;
$filter||="";
my $filter_list=$filters->{$filter};
if (!defined $filter_list)
{
my @list;
if ($filter eq "")
{
@list=$cxnsplugin->get_section_names();
}
else
{
@list=split /:+/, $filter;
}
$filters->{$filter}=$filter_list=\@list;
}
return $filter_list;
}
sub get_install_mode($$$)
{
my ($dll, $hash_mode, $default_mode)=@_;
foreach my $mode ("install", "ignore")
{
if (defined $hash_mode->{$mode} and
$dll =~ /(?:$hash_mode->{$mode})/i)
{
return $mode;
}
}
return $default_mode;
}
sub get_dllname($)
{
my ($dllkey)=@_;
my $dllname=cxbasename(demangle_string($dllkey));
my $checksum = unpack("%32C*", $dllkey) % 65535;
$dllname =~ s/\.dll$/.$checksum/i;
return $dllname;
}
sub update_field($$$)
{
my ($section, $name, $value)=@_;
$value||="";
my $oldval=$section->get($name, "");
return 0 if ($oldval eq $value);
if ($value eq "")
{
$section->remove($name);
}
else
{
$section->set($name, $value);
}
return 1;
}
my $field_list;
sub get_field_list($$)
{
if (!defined $field_list)
{
my ($crossover, $scope)=@_;
my @list;
if (defined $crossover)
{
my $prefix=($scope eq "managed" ? "Managed" : "Private");
@list=grep /^$prefix.*NSPluginDirs$/, @{$crossover->get_field_list()};
}
$field_list=\@list;
}
# Return the list, not a reference, so a foreach
# cannot modify the contents of $field_list
return @$field_list;
}
sub field_to_architecture($)
{
my ($arch)=@_;
$arch =~ s/^(?:Managed|Private)(.*)NSPluginDirs$/$1/i;
$arch =~ tr/A-Z/a-z/;
return $arch;
}
sub arch_to_lib_dir($$)
{
my ($desktopdata, $arch)=@_;
return "$desktopdata/cxnsplugin/$arch";
}
# Process command-line options
my $opt_create;
my $opt_create_filter;
my $opt_delete;
my $opt_delete_filter;
my $opt_mode;
my $opt_mode_filter;
my $opt_query;
my $opt_query_filter;
my $opt_list_files;
my $opt_list_files_filter;
my $opt_install;
my $opt_install_filter;
my $opt_uninstall;
my $opt_uninstall_filter;
my $opt_removeall;
my $opt_sync;
my $opt_sync_install_none;
my $opt_sync_uninstall_none;
my $opt_utf8;
my $opt_bottle;
my $opt_conf;
my $opt_tag;
my $opt_pattern;
my $opt_ro_desktopdata;
my $opt_filter;
my $opt_scope;
my $opt_plugin_dirs;
my $opt_verbose;
my $opt_help;
require CXOpts;
my $cxopts=CXOpts->new();
$cxopts->add_options(["create" => \$opt_create,
"create-filter=s" => \$opt_create_filter,
"delete" => \$opt_delete,
"delete-filter=s" => \$opt_delete_filter,
"mode=s" => \$opt_mode,
"mode-filter=s" => \$opt_mode_filter,
"query" => \$opt_query,
"query-filter=s" => \$opt_query_filter,
"list-files" => \$opt_list_files,
"list-files-filter=s" => \$opt_list_files_filter,
"install" => \$opt_install,
"install-filter=s" => \$opt_install_filter,
"uninstall" => \$opt_uninstall,
"uninstall-filter=s" => \$opt_uninstall_filter,
"removeall" => \$opt_removeall,
"sync" => \$opt_sync,
"sync-install-none" => \$opt_sync_install_none,
"sync-uninstall-none" => \$opt_sync_uninstall_none,
"utf8" => \$opt_utf8,
"bottle=s" => \$opt_bottle,
"conf=s" => \$opt_conf,
"tag=s" => \$opt_tag,
"pattern=s" => \$opt_pattern,
"ro-desktopdata"=> \$opt_ro_desktopdata,
"filter=s" => \$opt_filter,
"scope=s" => \$opt_scope,
"plugin-dirs=s" => \$opt_plugin_dirs,
"verbose!" => \$opt_verbose,
"?|h|help" => \$opt_help
]);
my $err=$cxopts->parse();
CXLog::fdopen(2) if ($opt_verbose);
# Validate the command line options
my $usage;
my ($read_only, $only_removeall);
my ($default_mode, $hash_mode);
if ($err)
{
cxerr("$err\n");
$usage=2;
}
elsif ($opt_help)
{
$usage=0;
}
else
{
if (!$opt_utf8)
{
# Re-encode the parameters to UTF-8
require CXRecode;
$opt_filter=CXRecode::from_sys("UTF-8", $opt_filter);
$opt_create_filter=CXRecode::from_sys("UTF-8", $opt_create_filter);
$opt_delete_filter=CXRecode::from_sys("UTF-8", $opt_delete_filter);
$opt_mode_filter=CXRecode::from_sys("UTF-8", $opt_mode_filter);
$opt_query_filter=CXRecode::from_sys("UTF-8", $opt_query_filter);
$opt_list_files_filter=CXRecode::from_sys("UTF-8", $opt_list_files_filter);
$opt_install_filter=CXRecode::from_sys("UTF-8", $opt_install_filter);
$opt_uninstall_filter=CXRecode::from_sys("UTF-8", $opt_uninstall_filter);
}
my $cmd_count=0;
$cmd_count++ if (defined $opt_query);
$cmd_count++ if (defined $opt_list_files);
my $read_only_count=$cmd_count;
$cmd_count++ if (defined $opt_create);
$cmd_count++ if (defined $opt_mode and !$opt_sync);
$cmd_count++ if (defined $opt_delete);
$cmd_count++ if (defined $opt_install);
$cmd_count++ if (defined $opt_uninstall);
$cmd_count++ if (defined $opt_removeall);
$cmd_count++ if (defined $opt_sync);
$read_only=1 if ($read_only_count == $cmd_count);
$only_removeall=1 if ($cmd_count == 1 and defined $opt_removeall);
if ($cmd_count == 0)
{
cxerr("you must specify the operation to perform\n");
$usage=2;
}
elsif ($opt_sync)
{
if ($opt_delete)
{
cxerr("--sync is incompatible with --delete\n");
$usage=2;
}
if ($opt_sync_uninstall_none and ($opt_uninstall or $opt_removeall))
{
cxerr("--sync-uninstall-none is incompatible with --uninstall and --removeall\n");
$usage=2;
}
if ($opt_sync_install_none and $opt_install)
{
cxerr("--sync-install-none is incompatible with --install\n");
$usage=2;
}
if (defined $opt_filter or defined $opt_create_filter or
defined $opt_delete_filter or defined $opt_mode_filter or
defined $opt_query_filter or defined $opt_list_files_filter or
defined $opt_install_filter or defined $opt_uninstall_filter)
{
cxerr("--sync is incompatible with the --filter options\n");
$usage=2;
}
}
elsif ($opt_sync_install_none or $opt_sync_uninstall_none)
{
cxerr("--sync-install-none and --sync-uninstall-none can only be used with --sync\n");
$usage=2;
}
if ($opt_create and defined $opt_mode_filter)
{
cxerr("--create is incompatible with the --mode-filter option\n");
$usage=2;
}
if (defined $opt_mode)
{
# Prepare and check the $opt_mode specification
foreach my $mode_spec (split /;+/, $opt_mode)
{
if ($mode_spec !~ /^(install|ignore)(?:=(.*))?$/i)
{
Loading ...