#!/usr/bin/perl -w
#$Id: vfmg,v 1.61 2004/07/27 13:53:00 gotar Exp $

use strict;
use File::Find;
use Getopt::Long;
use Encode;

my $o_help=0;
my $o_tags=0;
my $o_end=0;
my $o_icons=0;
my $o_exec=0;
my $o_clear=0;
my $o_promote=0;
my $o_verbose=0;
my $o_full=0;
my $o_strip=0;
my $o_output="";
my $o_utf=0;
my $o_enc="";
my $o_xterm="xterm -name xterm-%1 -e %2";
my $o_nomenu=0;

GetOptions('help'=>\$o_help,
	'tags'=>\$o_tags,
	'end|e'=>\$o_end,
	'icons'=>\$o_icons,
	'exec|x'=>\$o_exec,
	'clear'=>\$o_clear,
	'promote'=>\$o_promote,
	'verbose'=>\$o_verbose,
	'full'=>\$o_full,
	'strip'=>\$o_strip,
	'utf8'=>\$o_utf,
	'nomenu|m'=>\$o_nomenu,
	'output=s'=>\$o_enc,
	'xterm|r=s'=>\$o_xterm
	);

if($o_help) {
	print "Usage:	$0 [options] aewm|afterstep|blackbox|enlightenment|fluxbox|fvwm2|icewm|olvwm|qvwm|wmaker|wmaker-old|xfce4|xpde
	-h, --help	- print this help
	-t, --tags	- echo omitted tags to stderr
	-e, --end	- echo omitted XDG file ending to stderr
	-v, --verbose	- verbose stderr output
	-i, --icons	- check for icons existence
	-x, --exec	- check for binaries existence
	-f, --full	- extend icons and binaries to full path (needs -i or -x)
	-c, --clear	- remove empty menus
	-p, --promote	- promote submenus with single entry
	-s, --strip	- strip 1st level menu
	-u, --utf8	- output in utf8 (default is locale setting)
	-m, --nomenu	- don't add additional menu info (valid for fluxbox, blackbox, xfce4)
	-o, --output=	- output in given encoding (e.g. iso-8859-2)
	-r, --xterm=	- set x terminal application (default \"xterm -name xterm-%1 -e %2\")
				example \"gnome-terminal -t Terminal.%1 -x %2\"\n";
	exit;
}

die "Missing argument (aewm|afterstep|blackbox|enlightenment|fluxbox|fvwm2|icewm|olvwm|qvwm|wmaker|wmaker-old|xfce4|xpde)\n"
	unless exists $ARGV[0];
$o_output=$ARGV[0];
die "Unrecognized argument: $o_output\n"
	unless $o_output=~/^(aewm|afterstep|blackbox|enlightenment|fluxbox|fvwm2|icewm|olvwm|qvwm|wmaker|wmaker-old|xfce4|xpde)$/;

my @path;
if($o_exec) {
	@path=split(/:+/,$ENV{'PATH'});
if($o_xterm) {
	my $exists=0;
	my $bin=$o_xterm;
	$bin=~s/(\S+).*/$1/;  #v---------v
	foreach my $dir(@path,"") {	# would be "//dir/.../file" correct?
		if(-x "$dir/$bin") {#----^
			$exists=1;
			$o_xterm="$dir/$o_xterm" if $o_full;
			last;
		}
	}
	$o_xterm="" unless $exists;
}
}

# get locale (for Name[*])

my $lang4="";
$lang4=$ENV{'LANG'} if exists $ENV{'LANG'};
$lang4=$ENV{'LC_MESSAGES'} if exists $ENV{'LC_MESSAGES'};
$lang4=$ENV{'LC_ALL'} if exists $ENV{'LC_ALL'};
my $lang3=$lang4;
$lang3=~s/@.*//;
my $lang2=$lang3;
$lang2=~s/\..*//;
my $lang1=$lang2;
$lang1=~s/_.*//;

# what is $DESKTOP_FILE_PATH?

my %apps;	# $apps{name}{category}=[icon,exec]
find(\&wanted,'/usr/share/applications/');

sub wanted {
	return if (!-f || /^\./ || !/\.desktop$/);
	my $file=$_;
	my $name="";
	my $exec="";
	my $icon="";
	my $cats="";
	my $term=0;
	my $lang=0;
	my $app=0;
	my $enc="iso-8859-1";
	open F_IN, "$file" or warn "$file: $!\n" and return;
	while(<F_IN>) {
		if (/^Name=(.+)/ && $lang<1) {
			$name=$1;
		}
		if (/^Name\[$lang1\]=(.+?)\s*$/ && $lang<2) {
			$name=$1;
			$lang=1;
		}
		if (/^Name\[$lang2\]=(.+?)\s*$/ && $lang<3) {
			$name=$1;
			$lang=2;
		}
		if (/^Name=\[$lang3\](.+?)\s*$/ && $lang<4) {
			$name=$1;
			$lang=3;
		}
		if (/^Name=\[$lang4\](.+?)\s*$/ && $lang<5) {
			$name=$1;
			$lang=4;
		}
		$icon=$1 if /^Icon=(.+?)\s*$/;
		$exec=$1 if /^Exec=(.+?)\s*$/;
		$cats=$1 if /^Categories=(.+?)\s*$/;
		$term=1 if /^Terminal=(?i:1|true)/;
		$app=1 if /^Type=(?i:application)/;
		$enc=$1 if /^Encoding=(.+?)\s*$/;
	}
	close F_IN;
	return unless $app;
	return if $term and not $o_xterm;
	my $bin=$exec;
		$bin=~s/(\S+).*/$1/;  #v---------v
	if($o_exec) {
		my $exists=0;
		foreach my $dir(@path,"") {	# would be "//dir/.../file" correct?
			if(-x "$dir/$bin") {#----^
				$exists=1;
				$exec="$dir/$exec" if $o_full;
				last;
			}
		}
		return unless $exists;
	}
	if($term) {
		$bin=~s|.*/||;
		$_=$o_xterm;
		s/%1/$bin/;
		s/%2/$exec/;
		$exec=$_;
	}
	if($o_icons) {
		my $exists=0;
		foreach my $dir("","$ENV{'HOME'}/.icons","/usr/share/icons","/usr/share/pixmaps") {
			$icon.=".xpm" if -f "$dir/$icon.xpm";
			$icon.=".png" if -f "$dir/$icon.png";
			if(-f "$dir/$icon") {
				$exists=1;
				$icon="$dir/$icon" if $o_full;
				last;
			}
		}
		$icon="" unless $exists;
	}
	my $utfname;
	if($name ne "") {
		if($enc eq "Legacy-Mixed") {
			warn "/usr/share/applications/$file: Legacy-Mixed encoding is depreciated.\n";
			if(!$lang) {
				$enc="iso-8859-1";
			} elsif ($lang==1) {
				warn "/usr/share/applications/$file: cannot get encoding name for `$lang1'. Assuming iso-8859-1\n";
				$enc="iso-8859-1";
			} else {
				use POSIX qw(locale_h);
				my $old_locale=setlocale(LC_ALL);
				setlocale(&POSIX::LC_ALL,$lang);
				eval {
					require I18N::Langinfo;
					I18N::Langinfo->import(qw(langinfo CODESET));
					$enc=langinfo(CODESET());
				};
				setlocale(&POSIX::LC_ALL,$old_locale);
			}
		}
		$utfname=decode($enc,$name);
		unless($utfname) {
			warn "/usr/share/applications/$file: wrong encoding!\n";
			$utfname=$name;
		}
	} else {
		$utfname=$file;
		$utfname=~s/\.desktop$//;
		warn "/usr/share/applications/$file: missing Name tag! using $utfname\n";
	}
	$exec=~s/([^%])%v/$1/g;
	$exec=~s/([^%])%k/$1$file/g;
	$exec=~s/([^%])%c/$1$utfname/g;
	my $iicon="";
	$iicon="--icon $icon" if $icon;
	$exec=~s/([^%])%i/$1$iicon/g;
	$exec=~s/%(?i:[fudn])//g;
	warn "Unknown Exec parameter variable: $1 in file $file, removing\n" if ($exec=~s/(%[^%\s])//);
	$exec=~s/%%/%/g;
	foreach my $cat(split(/;+/,$cats)) {
		$apps{$utfname}{$cat}=[$icon,$exec];	# two apps shouldn't have same names
	}
}

# read XDG menu specification

my $file="";

open F_IN, "/etc/xdg/menus/applications.menu" or die "/etc/xdg/menus/applications.menu: $!\n";
while(<F_IN>) {
	#s/\s*//g;
	chop;
	$file.=$_;
}
close F_IN;

sub gettag {
	$file=~s/.*?<(.*?)>\s*//;
	$1;
}

sub getname {
	$file=~s/\s*(.*?)\s*<//;
	$file="<".$file;
	$1;
}

my @menu;	# $menu[parent]{name}=[x=menu number,icon]
		# $menu[parent]{name}=[-1=entry,icon,exec]
my $level=0;
my $mno=0;	# menu number
my $trigger=0;
my $tag;
my $name;
my $dir;
my @directory;	# $directory[level]=[name,icon]
my $include;
my %tmpapps;
my @menustack;

sub cand {
	my %iapps;	# internal applications list
	my $name;
	foreach $name(keys %apps) {
		$iapps{$name}=$apps{$name};
	}
	while (1) {
		$tag=lc(gettag());
		last if($tag eq '/and');
		if($tag eq 'category') {
			$dir=getname();
			foreach $name(keys %iapps) {
				delete($iapps{$name}) unless exists $iapps{$name}{$dir};
			}
			gettag();	# must be </category> else GIGO and we don't care
			next;
		}
		if($tag=~/^(and|or|not)$/) {
			if ($tag eq 'or') {
				%tmpapps=cor();
			} elsif ($tag eq 'and') {
				%tmpapps=cand();
			} else {
				%tmpapps=cnot();
			}
			foreach $name(keys %iapps) {
				delete($iapps{$name}) unless exists $tmpapps{$name};
			}
			next;
		}
		warn "warning: possible XDG file corruption!: $tag\n" if $o_verbose;
	}
	%iapps;
}

sub cor {
	my %iapps;	# internal applications list
	my $name;
	while (1) {
		$tag=lc(gettag());
		last if($tag eq '/or');
		if($tag eq 'category') {
			$dir=getname();
			foreach $name(keys %apps) {
				$iapps{$name}=$apps{$name} if exists $apps{$name}{$dir};
			}
			gettag();	# must be </category> else GIGO and we don't care
			next;
		}
		if($tag=~/^(and|or|not)$/) {
			if ($tag eq 'or') {
				%tmpapps=cor();
			} elsif ($tag eq 'and') {
				%tmpapps=cand();
			} else {
				%tmpapps=cnot();
			}
			foreach $name(keys %tmpapps) {
				$iapps{$name}=$tmpapps{$name};
			}
			next;
		}
		warn "warning: possible XDG file corruption!: $tag\n" if $o_verbose;
	}
	%iapps;
}

sub cnot {
	my %iapps;	# internal applications list
	my $name;
	foreach $name(keys %apps) {
		$iapps{$name}=$apps{$name};
	}
	while (1) {
		$tag=lc(gettag());
		last if($tag eq '/not');
		if($tag eq 'category') {
			$dir=getname();
			foreach $name(keys %iapps) {
				delete($iapps{$name}) if exists $iapps{$name}{$dir};
			}
			gettag();	# must be </category> else GIGO and we don't care
			next;
		}
		if($tag=~/^(and|or|not)$/) {	# I think it doesn't make any sense
			warn "How did you get here!?\n" if $o_verbose;
			if ($tag eq 'or') {
				%tmpapps=cor();
			} elsif ($tag eq 'and') {
				%tmpapps=cand();
			} else {
				%tmpapps=cnot();
			}
			foreach $name(keys %iapps) {
				delete($iapps{$name}) if exists $tmpapps{$name};
			}
			next;
		}
		warn "warning: possible XDG file corruption!: $tag\n" if $o_verbose;
	}
	%iapps;
}

$#menu++;
while($trigger==0 || $level>0) {
	$tag=lc(gettag());
	if(($tag eq 'category')&& $include) {
		$dir=getname();
		foreach my $name(keys %apps) {
			$menu[$mno]{$name}=[-1,@{$apps{$name}{$dir}}]
				if exists $apps{$name}{$dir};
		}
		gettag();	# must be </category> else GIGO and we don't care
		next;
	}
	if(($tag=~/^(and|or|not)$/)&& $include) {
		if ($tag eq 'or') {
			%tmpapps=cor();
		} elsif ($tag eq 'and') {
			%tmpapps=cand();
		} else {
			%tmpapps=cnot();
		}
		foreach my $name(keys %tmpapps) {
		foreach my $dir (keys %{$tmpapps{$name}}) {
			$menu[$mno]{$name}=[-1,@{$tmpapps{$name}{$dir}}];
		}
		}
		next;
	}
	if($tag eq 'menu') {
		$level++;
		$#menu++;
		$menustack[$#menustack+1]=$mno;
		$mno=$#menu;
		$name="";
		$include=0;
		$trigger=1;
		next;
	}
	if($tag eq '/menu') {
		#for(my $i=0; $i<=$#menu; $i++) {
		my $i=$menustack[$#menustack];
		if(exists $directory[$level]) {
			foreach my $entry(keys %{$menu[$i]}) {
				if($menu[$i]{$entry}[0]==$mno) {
					$directory[$level][0]=$entry unless $directory[$level][0];
					delete($menu[$i]{$entry});
				}
			}
			$menu[$i]{$directory[$level][0]}=[$mno,$directory[$level][1]];
			delete($directory[$level]);
		}
		#}
		$mno=$i;
		$#menustack--;
		$level--;
		next;
	}
	if($tag eq 'include') {
		$include=1;
		next;
	}
	if($tag eq '/include') {
		$include=0;
		next;
	}
	if($tag eq 'name') {
		$name=getname();
		$menu[$menustack[$#menustack]]{" $name"}=[$mno,""];
		gettag();	# must be </name> else GIGO and we don't care
		next;
	}
	if($tag eq 'directory') {
		$dir=getname();
		my $lang=0;
		my $name="";
		my $icon="";
		my $enc="iso-8859-1";
		if(open F_IN, "/usr/share/desktop-directories/$dir") {
	while(<F_IN>) {
		if (/^Name=(.+)/ && $lang<1) {
			$name=$1;
		}
		if (/^Name\[$lang1\]=(.+?)\s*$/ && $lang<2) {
			$name=$1;
			$lang=1;
		}
		if (/^Name\[$lang2\]=(.+?)\s*$/ && $lang<3) {
			$name=$1;
			$lang=2;
		}
		if (/^Name=\[$lang3\](.+?)\s*$/ && $lang<4) {
			$name=$1;
			$lang=3;
		}
		if (/^Name=\[$lang4\](.+?)\s*$/ && $lang<5) {
			$name=$1;
			$lang=4;
		}
		$icon=$1 if /^Icon=(.+?)\s*$/;
		$enc=$1 if /^Encoding=(.+?)\s*$/;
	}
	close F_IN;
	if($o_icons) {
		my $exists=0;
		foreach my $dir("$ENV{'HOME'}/.icons","/usr/share/icons","/usr/share/pixmaps") {
			$icon.=".xpm" if -f "$dir/$icon.xpm";
			$icon.=".png" if -f "$dir/$icon.png";
			if(-f "$dir/$icon") {
				$exists=1;
				$icon="$dir/$icon" if $o_full;
				last;
			}
		}
		$icon="" unless $exists;
	}
		if($name ne "") {
			my $utfname=decode($enc,$name);
			unless($utfname) {
				warn "/usr/share/desktop-directories/$dir: wrong encoding!\n";
				$utfname=$name;
			}
			$directory[$level]=[" $utfname",$icon];
		} else {
			warn "/usr/share/desktop-directories/$dir: missing Name tag!\n";
			$directory[$level]=["",$icon];
		}
		} else {
			warn "/usr/share/desktop-directories/$dir: $!\n";
		}
		gettag();	# must be </directory> else GIGO and we don't care
		next;
	}
	if($tag eq 'mergefile') {
		$name=getname();
		gettag();	# must be </mergefile> else GIGO and we don't care
		my $tmpfile="";
		open F_IN, "/etc/xdg/menus/$name" or (
			warn("/etc/xdg/menus/$name: $!\n"),
			next
		);
		while(<F_IN>) {
			chop;
			$tmpfile.=$_;
		}
		close F_IN;
		$file=$tmpfile.$file;
		next;
	}
	if(($tag=~/^\/(name|directory|and|or|not|category|mergefile)$/)&& $include) {
		warn "warning: XDG file corrupted!\n" if $o_verbose;
	}
	warn "Omitted tag: $tag\n" if $o_tags;
}

warn "Omitted ending: $file\n" if(($file ne "")&& $o_end);

if(($o_clear)&&(!$o_promote)) {
	my @empty;
	for(my $i=$#menu; $i>=0; $i--) {
		$empty[$i]=1;
		foreach my $entry(keys %{$menu[$i]}) {
			$mno=$menu[$i]{$entry}[0];
			if($mno<0) {
				$empty[$i]=0;
			} else {
				if($empty[$mno]) {
					delete($menu[$i]{$entry});
				} else {
					$empty[$i]=0;
				}
			}
		}
	}
}

if($o_promote) {
	my @count;
	for(my $i=$#menu; $i>=0; $i--) {
		$count[$i]=0;
		foreach my $entry(keys %{$menu[$i]}) {
			$mno=$menu[$i]{$entry}[0];
			if($mno<0) {
				$count[$i]++;
			} else {
				if($count[$mno]==0) {
					delete($menu[$i]{$entry});
				} else {
					if($count[$mno]==1) {
						foreach my $name(keys %{$menu[$mno]}) {
							if($menu[$mno]{$name}[0]==-1) {
								$menu[$i]{$name}=[-1,"$menu[$mno]{$name}[1]","$menu[$mno]{$name}[2]"];
							} else {
								my $newname=$name;
								$newname=substr($newname,1);
								$newname="$entry:$newname";
								$menu[$i]{$newname}=[$menu[$mno]{$name}[0],"$menu[$mno]{$name}[1]"];
								delete($menu[$i]{$name});
							}
						}
						delete($menu[$i]{$entry});
					}
					$count[$i]++;
				}
			}
		}
	}
}

$level="";
sub icewm {
	my $no=$_[0];
	foreach my $entry(sort keys %{$menu[$no]}) {
		#next if $menu[$no]{$entry}[0]==0;
		print "$level";
		#print "$no $menu[$no]{$entry}[0] $entry\n";
		$name=$entry;
		$name=~s/\"/\\\"/g;
		if($menu[$no]{$entry}[0]<0) {
			print "prog \"$name\" \"$menu[$no]{$entry}[1]\" $menu[$no]{$entry}[2]\n";
		} else {
			$menu[$no]{$entry}[1]="folder" if $menu[$no]{$entry}[1] eq "";
			$name=substr($name,1);
			print "menu \"$name\" \"$menu[$no]{$entry}[1]\" {\n";
			$level.="	";
			icewm($menu[$no]{$entry}[0]);
			$level=substr($level,1);
			print "$level}\n";
		}
	}
}

sub blackbox {
	my $no=$_[0];
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "$level";
		if($menu[$no]{$entry}[0]<0) {
			print "[exec] ($entry) {$menu[$no]{$entry}[2]}\n";
		} else {
			$name=$entry;
			$name=substr($name,1);
			print "[submenu] ($name)\n";
			$level.="	";
			blackbox($menu[$no]{$entry}[0]);
			$level=substr($level,1);
			print "$level\[end]\n";
		}
	}
}

sub wmakerold {
	my $no=$_[0];
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "$level\"";
		my $name=$entry;
		$name=~s/\"/\\\"/g;
		if($menu[$no]{$entry}[0]<0) {
			print "$name\" EXEC $menu[$no]{$entry}[2]\n";
		} else {
			$name=substr($name,1);
			print "$name\" MENU\n";
			$level.="	";
			wmakerold($menu[$no]{$entry}[0]);
			$level=substr($level,1);
			print "$level\"$name\" END\n";
		}
	}
}

sub wmaker {
	my $no=$_[0];
	my $coma=$_[1];
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "$coma\n$level(\"";
		$name=$entry;
		$name=~s/\"/\\\"/g;
		if($menu[$no]{$entry}[0]<0) {
			$menu[$no]{$entry}[2]=~s/\"/\\\"/g;
			print "$name\", EXEC, \"$menu[$no]{$entry}[2]\")";
		} else {
			$name=substr($name,1);
			print "$name\"";
			$level.="	";
			wmaker($menu[$no]{$entry}[0],",");
			$level=substr($level,1);
			print "\n$level)";
		}
	}
}

sub xfce4 {
	my $no=$_[0];
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "$level<";
		$name=$entry;
		$name=~s/&/&amp;/g;
		$name=~s/\"/&quot;/g;
		$name=~s/</&lt;/g;
		$name=~s/>/&gt;/g;
		if($menu[$no]{$entry}[0]<0) {
			$menu[$no]{$entry}[2]=~s/&/&amp;/g;
			$menu[$no]{$entry}[2]=~s/\"/&quot;/g;
			$menu[$no]{$entry}[2]=~s/</&lt;/g;
			$menu[$no]{$entry}[2]=~s/>/&gt;/g;
			print "app name=\"$name\" cmd=\"$menu[$no]{$entry}[2]\"/>\n";
		} else {
			$name=substr($name,1);
			print "menu name=\"$name\" visible=\"yes\">\n";
			$level.="	";
			xfce4($menu[$no]{$entry}[0]);
			$level=substr($level,1);
			print "$level</menu>\n";
		}
	}
}

sub afterstep {
	my $no=$_[0];
	my $dir=$_[1];
	foreach my $entry(keys %{$menu[$no]}) {
		$name=$entry;
		if($menu[$no]{$entry}[0]<0) {
			$file=$entry;
			$file=~s/\s+/_/g;
			$file=~s|/||g;
			$name=~s/\"/\\\"/g;
			open F_OUT, ">> $dir/$file" or warn "$dir/$file: $!\n";
			print F_OUT "Exec \"$name\" exec $menu[$no]{$entry}[2]\n";
			print F_OUT "MiniPixmap \"$menu[$no]{$entry}[1]\"\n" if $menu[$no]{$entry}[1] ne "";
			#print F_OUT "MiniPixmap \"mini-app.xpm\"\n";
			close F_OUT;
		} else {
			$name=substr($name,1);
			$name=~s|/||g;
			mkpath("$dir/$name",0,0700);
			afterstep($menu[$no]{$entry}[0],"$dir/$name");
		}
	}
}

sub fvwm2 {
	my $no=$_[0];
	my $file;
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "AddToMenu $level	\"";
		$name=$entry;
		$name=~s/\"/\\\"/g;
		if($menu[$no]{$entry}[0]<0) {
			print         "$name\"	Exec $menu[$no]{$entry}[2] &\n";
			print "Style \"$name\"	Icon $menu[$no]{$entry}[1]\n" if $menu[$no]{$entry}[1] ne "";
		} else {
			$name=substr($name,1);
			$file=$name;
			$file=~s/\s+/_/g;
			$level.=".$file";
			print "$name\"	Popup $level\n\n";
			print "AddToMenu $level	\"$name\"	Title\n";
			fvwm2($menu[$no]{$entry}[0]);
			$level=~s/\.$file$//;
		}
	}
	print "\n";
}

sub olvwm {
	my $no=$_[0];
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "$level";
		my $name=$entry;
		$name=~s/\"/\\\"/g;
		if($menu[$no]{$entry}[0]<0) {
			print "\"$name\"	exec $menu[$no]{$entry}[2]\n";
		} else {
			$name=substr($name,1);
			print "\"$name\" MENU\n";
			$level.="	";
			olvwm($menu[$no]{$entry}[0]);
			$level=substr($level,1);
			print "$level\"$name\" END PIN\n";
		}
	}
}

sub qvwm {
	my $no=$_[0];
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "$level";
		$name=$entry;
		$name=~s/\"/\\\"/g;
		if($menu[$no]{$entry}[0]<0) {
			$menu[$no]{$entry}[2]=~s/\"/\\\"/g;
			print "\"$name\" \"$menu[$no]{$entry}[1]\" \"$menu[$no]{$entry}[2]\"\n";
		} else {
			$name=substr($name,1);
			print "\"$name\" \"$menu[$no]{$entry}[1]\"\n$level+\n";
			$level.="	";
			qvwm($menu[$no]{$entry}[0]);
			$level=substr($level,1);
			print "$level-\n";
		}
	}
}

sub aewm {
	my $no=$_[0];
	my $name;
	foreach my $entry(sort keys %{$menu[$no]}) {
		print "$level";
		$name=$entry;
		$name=~s/\"/\\\"/g;
		if($menu[$no]{$entry}[0]<0) {
			$menu[$no]{$entry}[2]=~s/\"/\\\"/g;
			print "cmd \"$name\" \"$menu[$no]{$entry}[2]\"\n";
		} else {
			$name=substr($name,1);
			print "menu \"$name\"\n";
			$level.="	";
			aewm($menu[$no]{$entry}[0]);
			$level=substr($level,1);
			print "${level}end\n";
		}
	}
}

sub enlightenment {
	my $no=$_[0];
	my $F_OUT;
	open $F_OUT, ">> $dir/$_[1].menu" or warn "$dir/$_[1].menu: $!\n";
	print $F_OUT "\"$_[2]\"\n";
	foreach my $entry(sort keys %{$menu[$no]}) {
		$name=$entry;
		if($menu[$no]{$entry}[0]<0) {
			$name=~s/\"/\\\"/g;
			print $F_OUT "\"$name\" \"$menu[$no]{$entry}[1]\" exec \"$menu[$no]{$entry}[2]\"\n";
		} else {
			$name=substr($name,1);
			$name=~s|/||g;
			my $name2=$name;
			$name2=~s/\"/\\\"/g;
			print $F_OUT "\"$name2\" \"$menu[$no]{$entry}[1]\" menu \"$dir/$name2.menu\"\n";
			enlightenment($menu[$no]{$entry}[0],"$name","$name");
		}
	}
	close $F_OUT;
}

sub xpde {
	my $no=$_[0];
	my $dir=$_[1];
	foreach my $entry(keys %{$menu[$no]}) {
		$name=$entry;
		if($menu[$no]{$entry}[0]<0) {
			$file=$entry;
			$file=~s|/||g;
			$name=~s/\"/\\\"/g;
			open F_OUT, ">> $dir/$file.lnk" or warn "$dir/$file.lnk: $!\n";
			print F_OUT "[Shortcut]\nCaption=$name\nCommand=$menu[$no]{$entry}[2]\n";
			print F_OUT "Icon=$menu[$no]{$entry}[1]\n" if $menu[$no]{$entry}[1] ne "";
			close F_OUT;
		} else {
			$name=substr($name,1);
			$name=~s|/||g;
			mkpath("$dir/$name",0,0700);
			xpde($menu[$no]{$entry}[0],"$dir/$name");
		}
	}
}

$o_enc="utf-8" if ($o_utf and not $o_enc);
#use open OUT => ':utf8';
eval "use open OUT => ':locale'" unless $o_enc;
binmode(STDOUT, ":encoding($o_enc)") if $o_enc;

if($o_output eq "icewm") {
	icewm($o_strip);
	exit;
}
if($o_output eq "blackbox") {
	print "[begin] (Blackbox)\n" unless $o_nomenu;
	blackbox($o_strip);
	print "[end]\n" unless $o_nomenu;
	exit;
}
if($o_output eq "wmaker-old") {
	wmakerold($o_strip);
	exit;
}
if($o_output eq "wmaker") {
	if($o_strip) {
		wmaker(1,",");
	} else {
		wmaker(0,"");
	}
	exit;
}
if($o_output eq "xfce4") {
	print "<xfdesktop-menu>
	<title name=\"Desktop Menu\" visible=\"yes\"/>\n" unless $o_nomenu;
	$level.="	";
	xfce4($o_strip);
	print "</xfdesktop-menu>\n" unless $o_nomenu;
	exit;
}
if($o_output eq "afterstep") {
	use File::Path;
	my $dir="$ENV{'HOME'}/GNUstep/Library/AfterStep/start";
	if((-d "$dir")||(-f "$dir")) {
		rmtree("$dir.old",0,0);
		rename("$dir","$dir.old");
		mkpath("$dir",0,0700);
		#open F_OUT, ">> $dir/\.include" or warn "$dir/.include: $!\n";
		#print F_OUT "keepname\ninclude \"../start.old\"\n";
		#close F_OUT;
	} else {
		mkpath("$dir",0,0700);
	}
	afterstep($o_strip,$dir);
	exit;
}
if($o_output eq "fluxbox") {	# This is the same as blackbox (I hope so)
	print "[begin] (Fluxbox)\n" unless $o_nomenu;
	blackbox($o_strip);
	print "[end]\n" unless $o_nomenu;
	exit;
}
if($o_output eq "fvwm2") {
	$level="fvwm2";
	fvwm2($o_strip);
	exit;
}
if($o_output eq "olvwm") {
	olvwm($o_strip);
	exit;
}
if($o_output eq "qvwm") {
	print "[StartMenu]\n";
	qvwm($o_strip);
	exit;
}
if($o_output eq "aewm") {
	aewm($o_strip);
	exit;
}
if($o_output eq "enlightenment") {
	use File::Path;
	$dir="$ENV{'HOME'}/.enlightenment/menus";
	if((-d "$dir")||(-f "$dir")) {
		rmtree("$dir.old",0,0);
		rename("$dir","$dir.old");
	}
	mkpath("$dir",0,0700);	# or die
	enlightenment($o_strip,"index","Enlightenment");
	exit;
}
if($o_output eq "xpde") {
	use File::Path;
	my $dir="$ENV{'HOME'}/.xpde/Start Menu/Programs";
	if((-d "$dir")||(-f "$dir")) {
		rmtree("$dir.old",0,0);
		rename("$dir","$dir.old");
	}
	mkpath("$dir",0,0700);
	xpde($o_strip,$dir);
	exit;
}
