#!/usr/bin/perl  -w

#TODO: better message to ask people to add to registry
#TODO: increment interface number and regen install and split on new interface

#Depends: perl, wget, imageMagick (needed for the convert program), bzip2, fakeroot, less, gzip
#Optional: to build, need package specific development tools
#In addition:
#debian build needs debhelper, cdbs
#rpm building needs rpm >= 4.1 (rpmbuild-not just rpm)

#(c) Copyright 2005 Daniel Milstein
#
#Licensed under the Apache License, Version 2.0 (the "License");
#you may not use this file except in compliance with the License.
#You may obtain a copy of the License at
#
#http://www.apache.org/licenses/LICENSE-2.0
#
#Unless required by applicable law or agreed to in writing, software
#distributed under the License is distributed on an "AS IS" BASIS,
#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#See the License for the specific language governing permissions and
#limitations under the License.

#Implement patches in all backends

#NOTE: feature requests and bug reports are vastly preferred to patches
#That being said, feature requests, bug reports, and patches would all be greatly appreciated. You may email them to djmilstein@gmail.com.

#Configuration variables
$rpmSys = 0; #If true, use build depends in RPM spec files by default; otherwise, must be overriden with -q

#TODO: remind user to not make absolute symlinks

#dataDir - but be binary relocutable
our $dataDir = `dirname \$(which packer)`;
chomp $dataDir;
$dataDir .= "/../share/packer/"; #must end in /

our $pversion = "0.1.5"; 
our $pinterface = 1;
our $packerUrl = "http://packer.sourceforge.net";
our $home = `cut -d: -f 1,6 /etc/passwd|grep ^\$(whoami)|cut -d: -f2`; #user's home directory
chomp $home;

use constant {
#options for reformatChangelog
   RPM_CHANGELOG => 0,
   GENTOO_CHANGELOG => 1,
#Cache locations
   DEB_CACHE => "packer/cache.d",
   RPM_CACHE => "packer/cache.r",
   GENTOO_CACHE => "packer/cache.g", #really used for debian source packages
   AP_CACHE => "packer/cache.a"
};

our $steps = ["Package name, version, revision", "Program information", "Doc and Config files", "Build deps", "Build commands", "Clean commands", "Install commands", "Packages", "Package splitting", "Changelog", "Patching"];
our $totalSteps = @{$steps};
our $depsMessage = "Dependencies are the most nontrivial part of packer. The format for dependencies is one file that your package depends on per line. This can optionally be followed by 1 or more spaces a qualifier (>=, <, =, etc), and a version number. Packer will automatically convert the file to the name of the package that contains that file. You only need to include 1 file per package that your package will depend on. In addition, you do not need to list files that will be present if the other files are present. For example, if your package needed the lua and lualib include files, it would be enough to put \"/usr/include/lua50/lualib.h >= 5.0\", since the lua include file will be present if the lualib include file is present because in all packaging systems with dependencies, lualib depends on lua.\nDependencies can also be manually specified. See the \"depends\" files in \/usr\/share\/doc\/packer for more information on this.\n";
our $editor;
if ($ENV{'EDITOR'}) {
   $editor = $ENV{'EDITOR'};
}
elsif (-e "/usr/bin/editor") { #symlinked to default editor on some distros
   $editor = "/usr/bin/editor";
}
elsif (-e "/usr/bin/vi") { 
   $editor = "/usr/bin/vi";
}
elsif (-e "/usr/bin/vim") { 
   $editor = "/usr/bin/vim";
}
elsif (-e "/usr/local/bin/vi") {
   $editor = "/usr/local/bin/vi";
}
elsif (-e "/usr/bin/emacs") {
   $editor = "/usr/bin/emacs";
}
elsif (-e "/usr/bin/nano") {
   $editor = "/usr/bin/nano";
}
elsif (-e "/usr/bin/gedit") {
   $editor = "/usr/bin/gedit";
}
else {
   die "Cannot find a text editor. Please set the EDITOR environment variable\n";
}

#RPM needs to be at least version 4.1
#there isn't much error checking in the package building functions since it is assumed that the files are well formatted since they are generated by the wizard

if (!@ARGV) {
   &wizard;
}
else {
   my $d = 0;
   my $b = 0;
   my $r = 0;
   my $s = 0;
   my $a = 0;
   my $g = 0;
   my $force = 0;
   for (@ARGV) {
      for (split //) {
	 if ($_ eq "-") {
	    next;
	 }
	 if ($_ eq "d") {
	    $d = 1;
	 }
	 elsif ($_ eq "s") {
	    $s = 1;
	 }
	 elsif ($_ eq "b") {
	    $b = 1;
	 }
	 elsif ($_ eq "r") {
	    $r = 1;
	 }
	 elsif ($_ eq "f") {
	    $force = 1;
	 }
	 elsif ($_ eq "a") {
	    $a = 1; }
	 elsif ($_ eq "g") {
	    $g = 1;
	 }
	 elsif ($_ eq "q") {
	    $rpmSys = 1;
	 }
	 elsif ($_ eq "e") {
	    $d = 1;
	    $s = 1;
	    $r = 1;
	    $a = 1;
#	    $g = 1; #TODO: put back on
	 }
	 elsif ($_ eq "h") {
	    &help;
	    exit 0;
	 }
	 else {
	    print "Invalid option: $_\n";
	    &help;
	    exit 1;
	 }
      }
   }
   if (&getFullVersion ne &parseSingleLine("packer/changelog")) {
      die "Error: there is no changelog entry for the latest version of the package (" . &getFullVersion  . ")\n";
   }
   if ($r) {
      &rpm($b, $force);
   }
   if ($d) {
      &deb($b, $force);
   }
   if ($s) {
      &slack($b, $force);
   }
   if ($a) {
      &ap($b, $force);
   }
   if ($g) {
      &gentoo($b, $force);
   }
}

sub help {
   print "Packer version $pversion\n\n";
   print "Will launch the wizard if called with no options\n";
   print "-d\tGenerate files neccessary for building a debian package\n";
   print "-r\tGenerage RPM spec files\n";
   print "-s\tGenerage a script to build a Slackware package\n";
   print "-a\tGenerage an Autopackage spec file\n";
#   print "-g\tGenerate a Gentoo ebuild\n"; #TODO: not yet supported
   print "-e\tGenerate everything\n";
   print "-f\tDelete already existing directories that are in the way of generated files\n";
   print "-b\tBuild packages from generated files.\n";
   print "-q\tInclude build depends in RPM spec files\n";
}

sub updateDD {
   return 'if [[ -x "`which update-desktop-database 2>/dev/null`" ]]; then update-desktop-database; fi' . "\n"; #based partially off of dh_installmenu output; part at end makes it easy to detect so it can be stripped and used only once in non-splitting backends
}

sub updateM {
   return 'if [[ -x "`which update-menus 2>/dev/null`" ]]; then update-menus; fi' . "\n"; #based partially off of dh_installmenu output; part at end makes it easy to detect so it can be stripped and used only once in non-splitting backends
}

sub bye {
   die "Error opening file. Do you have the proper permissions?\n"; 
}

sub allIndep {
   $allIndep = 1;
   for (&parseESV("packer/packages")) {
      if (&parseSingleLine("packer/$_.type") ne "i") { 
	 $allIndep = 0;
	 last;
      }
   }
   return $allIndep;
}

sub hasDesktop { #returns true if at least one desktop file exists
   for (&parseESV("packer/packages")) {
      if (&packageHasDesktop($_)) {
	 return 1;
      }
   }
   return 0;
}

sub packageHasDesktop {
   $pack = shift;
   for (&parseESV("packer/" . $pack . ".ds")) {
      return 1;
   }
   return 0;
}

sub sedDirFilter { #needed in ap and rpm
   return "sed '\\&^/usr\$&d;\\&^/usr/share/man&d;\\&^/usr/games\$&d;\\&^/lib\$&d;\\&^/etc\$&d;\\&^/boot\$&d;\\&^/usr/bin\$&d;\\&^/usr/lib\$&d;\\&^/usr/share\$&d;\\&^/var\$&d;\\&^/var/lib\$&d;\\&^/var/spool\$&d;\\&^/var/cache\$&d;\\&^/var/lock\$&d;\\&^/tmp/apkg&d'";
}

sub applyPatches {
   return &patchesStuff(0);
}

sub deapplyPatches {
   return &patchesStuff(1);
}

sub patchesStuff {
   $deApply = shift;
   $str = "";
   for (<packer/patches/*.diff>) {
      if ($_ eq "packer/patches/differ.diff") {
	 next; #TODO: document this
      }
      $str .= "patch -p1 ";
      if ($deApply) {
	 $str .= "-R ";
      }
      $str .= "< $_\n";
   }
   return $str;
}

sub disp {
   our $orig = shift;
   our $folded = `echo '$orig'|fold -s`;
   if (!chomp $orig) {
      chomp $folded;
   }
   print $folded;
}

sub lookup {
   $dataFile = shift;
   $key = shift;
   open DATAFILE, $dataDir . $dataFile;
   for (<DATAFILE>) {
      chomp;
      /([^:]+):([^#]+)\s*(#.*)?/; #the nature of the pattern means that there can be colons in the second half of the expression, which is useful
      if ($key eq $1) {
	 return $2;
      }
   }
   die ("Error: could not lookup \"$key\" in $dataFile. Sorry about that. Please send a bug report.\n");
}

sub checkCache {
   our $cacheFile = shift;
   our $search = shift;
   our @cache = &parseESV($cacheFile);
   for (@cache) {
      m#^([^\s]*)\s+([^\s]*)\s*$#;
      if ($1 eq $search) {
	 return $2;
      }
   }
   return "";
}

sub addToCache {
   $cacheFile = shift;
   $key = shift;
   $value = shift;
   system "echo \"$key $value\" >> $cacheFile";
}

sub wizard {
   if (!-e "packer") {
      mkdir "packer" or &bye;
      mkdir "packer/patches" or &bye;
      system "echo $pinterface > packer/pversion";
   }
   if (-e "packer/complete") {
      &menu;
   }
   else {
      $progress = &parseSingleLine("packer/progress");
      if (!-e "packer/progress") {
	 &disp("Welcome to packer. Packer needs to know some information before it can generate packages. At any time, you can leave packer by pressing Ctrl+C and packer will resume from the last step completed.\n");
	 &pause;
      }
      &step($progress);
   }
}

sub menu {
   while(1) {
      system("clear");
      print "What would you like to change?\n";
      $i = 1;
      for (@{$steps}) {
	 print "$i: $_\n";
	 ++$i;
      }
      print "\nType q to quit\n";
      $number = &input;
      if ($number eq "q") {
	 last;
      }
      if ($number >= 1 && $number <=$totalSteps) {
	 &step($number, 1);
      }
   }
}

sub input { #this function is used instead of <STDIN> just in case the input method is later changed to readline
   $input = <STDIN>;
   chomp $input;
   return $input;
}

sub getFullVersion {
   return &parseSingleLine("packer/version") . "-" . &parseSingleLine("packer/revision");
}

sub edit {
   $file = shift;
   while (1) {
      system "$editor $file";
      if (-e $file) {
	 last;
      }
      else {
	 print "You did not save the file. Reopening editor...\n";
	 &pause;
      }
   }
}

sub preserveDir { #also adds stuff to files; saves the modifed files without the .sh extension, which is read by the packer backends
   #this function doesn't really do what its name ("preserveDir") indicates but I'm too lazy to change it
   $rawfile = shift;
   $file = $rawfile;
   $file =~ s#\.sh$##;
   open TFILE, "> $file" or &bye;
   our $oldfh = select TFILE;
#   print "PACKER_CWD=\`pwd\`\n";
   &printFile("$rawfile", "");
#   print "cd \$PACKER_CWD\n";
   if ($rawfile eq "packer/install.sh") { #install menu and desktop files
      print "mkdir -p \$install_dir/usr/share/applications\n";
      print "mkdir -p \$install_dir/usr/share/man\n";
      for (<packer/*.ds>) {
	 $dfile = $_;
	 m#([\w\-\+]+)\.ds$#;
	 $package = $1;
	 for (&parseESV($dfile)) {
	    print "cp $_.desktop \$install_dir/usr/share/applications\n";
	    #menu files installed in backends
	 }
      }
      #make sure all manpages are gzipped
      print "files=\$(find \${install_dir}/usr/share/man -name '*.bz2')\n";
      print "if [[ \"\$files\" ]]; then echo \"\$files\"|xargs bunzip2 -q; fi\n"; #unbzip all manpages
      print "files=\$(find \${install_dir}/usr/share/man -name '*.[0-9]')\n";
      print "if [[ \"\$files\" ]]; then echo \"\$files\"|xargs gzip -9;fi\n"; #gzip all manpages per Debian policy
   }
   elsif ($rawfile eq "packer/split.sh") { #put menu and desktop files into proper packages
      for (&parseESV("packer/packages")) {
	 $package = $_;
	 $package_dir = "\$" . $package . "_dir";
	 $package_dir =~ s#-#_#g;
	 print "mkdir -p $package_dir/usr/share/applications\n";
	 for (&parseESV("packer/$package.ds")) {
	    s#^.*/##;
	    print "cp \$install_dir/usr/share/applications/$_.desktop $package_dir/usr/share/applications\n";
	 }
      }
   }
   close TFILE;
   select $oldfh;
}

sub yn { #yes or no quesetion
   $message = shift;
   while (1) {
      &disp($message);
      $yn = &input;
      if ($yn eq "y" || $yn eq "yes") {
	 return 1;
      }
      elsif ($yn eq "n" || $yn eq "no") {
	 return 0;
      }
      else {
	 print "Please say either yes or no.\n\n";
      }
   }
}

sub singleLineChange {
   our $disp = shift;
   our $defaultFile = shift;
   while (1) {
      &disp($disp);
      our $default = "";
      if (-e "$defaultFile") {
	 $default = &parseSingleLine($defaultFile);
	 if ($default) {
	    print " [$default]";
	 }
      }
      print ": ";
      $input = &input;
      if (!$input) {
	 if (!$default) {
	    print "You must enter something!\n\n";
	    next;
	 }
	 $input = $default;
      }
      system "echo '$input' > $defaultFile";
      print "\n";
      return $input;
   }
}

sub pause {
   print "Press enter to continue...\n";
   <STDIN>;
}

sub validatePackageName {
   $name = shift;
   $match = $name =~ /^[a-z0-9\-\.\+]+$/; #why it will not just let me put this in the if statement, I know not
   if (!$match) {
      print "Invalid package name. Package names may only contain lowercase letters, numbers, periods, pluses (+), and hyphens(-).\n";
      return 0;
   }
   return 1;
}

sub editCategory {
   our $p = shift;
   while (1) {
      &disp("The category list is about to be fed through less. Examine the list and find the number of the category that the software fits best in. Packer will then automatically categorize your software in all software packaging environments that it supports based on your selection upon package generation.\n");
      &pause;
      $list = "Find the number for the correct category. This the SuSE list modified so that it can  accomodate all packaging systems supported by packer.\n\n";
      $i=1;
      @categories = &parseESV($dataDir . "sect_template");
      for (@categories) {
	 chop; #take off :
	 if ($i > 99) { #align it
	    $space = " ";
	 }
	 elsif ($i > 9) {
	    $space = "  ";
	 }
	 else {
	    $space = "   ";
	 }
	 $list .= "$i:$space$_\n";
	 ++$i;
      }
      system("echo '$list'|less -");
      print "Please type the number corresponding to the category that you want: ";
      $number = &input;
      chomp $number;
      if ($number >= 1 && $number-1 <= @categories) {
	 $cat = ${@categories}[$number-1];
	 last;
      }
      else {
	 warn "Invalid category\n";
	 &pause;
      }
   }
   system "clear";
   print "Packer recommends the following categorizations:\n";
   $cat_names = ["Debian", "SuSE", "Mandriva", "Redhat/Fedora", "Gentoo", "Freedesktop.org menu entry", "Debian menu entry", "Mandriva menu entry"];
   $cat_files = ["sect_debian", "sect_suse", "sect_mandriva", "sect_rh", "sect_gentoo", "sect_freedesktop", "sect_dmenu", "sect_mmenu"];
   $i = 0;
   for ($i=0;$i < @{$cat_names};++$i) {
      $thiscat = &lookup(${@{$cat_files}}[$i], $cat);
      if ($i == 0 && $thiscat eq "libs" && $p =~ /-dev(el)?$/) {
	 $thiscat = "libdevel"; #debian wants library development packages in libdevel
      }
      print $i+1 . ". ${@{$cat_names}}[$i]: $thiscat\n";
      &writeSingleLine("packer/$p.${@{$cat_files}}[$i]", $thiscat);
   }
   while (1) {
      &disp( "Enter the number corresponding the the category you want to modify, or press enter to accept the current categorizations. If your program is an educational program, your menu entries will almost certainly need to be manually recategorized. ");
      $number = &input;
      if (!$number ||!$number ||  $number == 0) {
	 last;
      }
      elsif ($number > @{$cat_names} || $number < 0) {
	 print "Invalid selection.\n";
      }
      else {
	 print "Enter the new category: \n";
	 &writeSingleLine("packer/$p." . ${@{$cat_files}}[$number-1], &input);
      }
   }
}

sub checkEdit { #if the file doesn't exist, pause; otherwise, make sure the user really wants to edit the file
   our $file = shift;
   if (! -e $file) {
      &pause;
      &edit($file);
   }
   else {
      if (&yn("Do you want to edit this again? ")) {
	 &edit($file);
      }
   }
}

sub editPackage {
   @packages = &parseESV("packer/packages");
   $onlyPackage = shift; #is this the only package that is being build (no splitting)?
   $existingPackage = shift; #existing package index
   $op = ">>";
   if ($existingPackage) {
      $pname = $existingPackage;
   }
   elsif (!$onlyPackage) {
      print "Enter the package name: ";
      $pname = &input; #TODO: make sure this name is unique
      if (!&validatePackageName($pname)) {
	 return;
      }
   }
   else {
      $pname = &parseSingleLine("packer/spackage");
      $op = ">";
   }
   if (&yn("Is this package platform independent?")) {
      $type = "i";
   }
   else {
      $type = "b";
   }
   system "echo $type >packer/$pname.type";
   print "Launching text editor to edit the package summary (a short phrase well under 80 characters).\n";
   &checkEdit("packer/$pname.desc");
   print "Launching text editor to edit the package description. Each line should be under 80 characters.\n";
   &checkEdit("packer/$pname.ldesc");
   &disp("Launching text editor to edit the package dependencies. $depsMessage\n");
   &checkEdit("packer/$pname.deps");
   &disp("Launching text editor to edit post-installation actions for this package. In almost all cases, you will want to leave this blank\n");
   &checkEdit("packer/$pname.postinst.sh");
   system "cp packer/$pname.postinst.sh packer/$pname.postinst"; #some processing might be done first in the future

   #categorization
   if (-e "packer/$pname.sect_debian") { #if the debian cat is there, they all should be there
      if (&yn("Would you like to redo the categorization? ")) {
	 &editCategory($pname);
      }
   }
   else {
      &editCategory($pname);
   }

   #menu entries
   system "touch packer/$pname.ds";
   if (&yn("Would you like to edit menu items for this package?")) {
      while (1) {
	 print "Type the number of a menu item below to delete it or type 0 to add a new menu item. Simply press enter when you are finished.\n";
	 $i = 1;
	 @ds = &parseESV("packer/$pname.ds");
	 @is = &parseESV("packer/$pname.is"); #icons
	 if (-e "packer/$pname.ds") { #desktop files
	    for (@ds) {
	       s#.desktop$##;
	       print "$i: $_\n";
	       ++$i;
	    }
	    print "\n";
	 }
	 $number = &input;

	 if ($number =~ /^\s*$/) { #end
	    &preserveDir("packer/install.sh"); #regenerate desktop file install stuff
	    &preserveDir("packer/split.sh");
	    last;
	 }
	 elsif ($number =~ /\D/) {
	    print "Invalid selection\n";
	 }
	 elsif ($number == 0) { #new item
	    print "Packer needs a .desktop file, and will automatically generate other menu entry file formats as needed from it.\n";
	    if (&yn("Is there a preexisting .desktop file?")) {
	       print "Where is it in relation to the current directory?: ";
	       push @ds, &input;
	       print "What icon, if any, does this desktop file use? It should use a 32x32 xpm, although the desktop file should refer to a png of the same name.";
	       push @is, &input;
	    }
	    else {
	       print "What would you like to call this menu entry (this should be one word and should be a unique name):";
	       $fname = &input . ".desktop"; #TODO: error checking, here and in other places 
	       print "What should the menu item appear as on the menu? ";
	       $mname = &input;;
	       $terminal = &yn("Is this a console program?");
	       print "What command needs to be executed to launch the file? ";
	       $exec = &input;
	       &disp("What short comment should there be with this menu item? Leave blank for there to be none: ");
	       $comment = &input;
	       &disp("What icon will be used? This should be a 32x32 xpm. Give the location relative to the current directory. Leave blank for no icon. ");
	       $icon = &input;
	       push @is, $icon;
	       $icon =~ s#\.xpm$#.png#;
	       $icon =~ s#^.*/##;
	       $cat = &parseSingleLine("packer/$pname.sect_freedesktop");
	       mkdir "gen_menus";
	       open DESKTOP, "> gen_menus/$fname" or &bye;
	       select DESKTOP;
	       print "[Desktop Entry]\n";
	       print "Encoding=UTF-8\n";
	       print "Name=$mname\n";
	       if ($comment) {
		  print "Comment=$comment\n";
	       }
	       print "Exec=$exec\n";
	       if ($icon) {
		  print "Icon=$icon\n";
	       }
	       if ($terminal) {
		  print "Terminal=true\n";
	       }
	       print "Type=Application\n";
	       print "Categories=$cat\n";
	       close DESKTOP;
	       select STDOUT;
	       push @ds, "gen_menus/$fname";
	    }
	 }
	 else {
	    if ($number > @ds) {
	       print "Invalid selection.\n";
	    }
	    else {
	       $_ = $ds[$number-1];
	       if (m#^gen_menus/#) {
		  system "rm $_.desktop";
	       }
	       splice(@ds, $number-1, 1);
	       splice(@is, $number-1, 1);
	    }
	 }
	 &writeESV("packer/$pname.ds", \@ds);
	 &writeESV("packer/$pname.is", \@is);
      }
   }
   if (!$existingPackage) {
      system "echo $pname $op packer/packages";
   }
}

sub writeESV {
   our $file = shift;
   our $values = shift;
   open FILE, "> $file" or &bye;
   our $oldfh = select FILE;
   for (@{$values}) {
      print $_ . "\n";
   }
   close FILE;
   select $oldfh;
}

sub writeSingleLine {
   my $file = shift;
   my $line = shift;
   open FILE, ">  $file" or &bye;
   our $oldfh = select FILE;
   print $line . "\n";
   close FILE;
   select $oldfh;
}

sub step { #perform a certain step in the wizard
   $step = shift;
   if (!$step) {
      $step = 1;
   }
   $menu = shift; #true if called by the menu function
   system("clear");
   if (!$menu) {
      print "Step $step of $totalSteps: " . ${@{$steps}}[$step-1] . "\n\n";
   }

   if ($step == 1) { #Package name, version, revision
      while (1) {
	 $spackage = &singleLineChange("Enter package name", "packer/spackage");
	 if (!&validatePackageName($spackage)) {
	    system ("rm packer/spackage");
	 }
	 else {
	    last;
	 }
      }
      &singleLineChange("Enter display name (What the package is called; may be the same as the package name) ", "packer/dpackage");
      $oldversion = &parseSingleLine("packer/version");
      $version = &singleLineChange("Enter package version", "packer/version"); #the packagers themselves ignore packer/version and use the latest version in the changelog
      if ($oldversion ne $version) {
	 system "echo 1 >packer/revision";
      }
      &singleLineChange("Enter package revision", "packer/revision"); #the packagers themselves ignore packer/version and use the latest version in the changelog
   }
   elsif ($step == 2) { #Origin (homepage, source tarball), Maintainer, Packager, license, etc
      &singleLineChange("Enter package homepage", "packer/source");
      &singleLineChange("Enter package tarball location. You really should use [[version]] instead of the version number here, if possible. Be sure to include the protocol (which should be either http:// or ftp:// for this) at the beginning", "packer/tarball");
      &singleLineChange("Enter copyright statement (ex. (c) Copyright 2004-2005 John Smith)", "packer/copyright");
      &singleLineChange("Enter your name , followed by your email in triangular brackets (ex. John Smith <john\@smith.name>", "packer/packager");
      &singleLineChange("Enter the name of the maintainer and his/her email in the same format as before", "packer/maintainer");
      &singleLineChange("What license does this program use (abbreviate if applicable). It is _strongly_ recommended that you enter the name of the license as it appears on the list at http://packer.sf.net/lic. For proprietary licenses not listed, please use one of the general terms \"Proprietary\", \"Freeware\", \"Shareware\", or \"Charityware\".", "packer/license");
      if (&yn("Is this program relocutable? Ie will it function equally well whether it is installed to /usr /usr/local, or any other location?")) {
	 &writeSingleLine("packer/reloc", "y");
      }
      else {
	 &writeSingleLine("packer/reloc", "n");
      }
   }
   elsif ($step == 3) { #docs
      if (-e "README") {
	 push @docs, "README";
      }
      if (-e "AUTHORS") {
	 push @docs, "AUTHORS";
      }
      if (-e "CHANGELOG") {
	 push @docs, "CHANGELOG";
      }
      if (-e "Changelog") {
	 push @docs, "Changelog";
      }
      if (-e "README.txt") { #These shouldn't be in GNU/Linux programs, but they are not uncommon in them
	 push @docs, "README.txt";
      }
      if (-e "Readme.txt") {
	 push @docs, "Readme.txt";
      }
      if (-e "NOTICE") {
	 push @docs, "NOTICE";
      }
      if (-e "NEWS") {
	 push @docs, "NEWS";
      }
      &writeESV("packer/docs", \@docs);
      print "About to edit the docs file. Please list one documentation file per line. These files will be installed for you in /usr/share/doc in EVERY subpackage, so it may not be appropriate to put all documentation here.\n";
      &pause;
      &edit("packer/docs");
      print "About to edit the list of configuration files. Same format as above, but these must be manually installed.\n";
      &pause;
      &edit("packer/config");
   }
   elsif ($step == 4) { #build deps
      if (&yn("Does your package need anything to build besides the standard build tools (gcc, g++, make, etc)? ")) {
	 print "About to edit a file. $depsMessage.";
	 &pause;
	 &edit("packer/bdeps");
      }
      else {
	 system "touch packer/bdeps";
      }
   }
   elsif ($step == 5) {
      $doThisStep = 1;
      if (-e "configure.ac") { #autoconfig detected
	 open BUILD, "> packer/build.sh" or &bye;
	 select BUILD;
	 print "./configure --prefix=/usr\n";
	 print "make\n";
	 close BUILD;
	 &preserveDir("packer/build.sh");
	 open INSTALL, "> packer/install.sh" or &bye;
	 select INSTALL;
	 print "make install DESTDIR=\$install_dir\n";
	 close INSTALL;
	 &preserveDir("packer/install.sh");
	 open CLEAN, "> packer/clean.sh" or &bye;
	 select CLEAN;
	 print "make distclean\n";
	 close CLEAN;
	 &preserveDir("packer/clean.sh");
	 select STDOUT;
	 if (!&yn("It looks like this package uses autotools. Packer automatically generated code to compile and install this package. Would you like to look it over or modify it (in most cases answer no; do not worry about splitting the package yet, if applicable)?")) {
	    $step = 8;
	    $doThisStep = 0;
	 }
      }
      if ($doThisStep) {
	 &disp("About to edit file. Please put in it the commands, enter seperated, to build your package. Only build it, do not install it. Many packages will only need to put \"make\" for this. Do NOT put in a shabang (#!) at the beginning of the file.\n");
	 &pause;
	 &edit("packer/build.sh");
	 &preserveDir("packer/build.sh"); #adds stuff to file to make sure it ends in the correct directory saves the modified version as packer/build
      }
   }
   elsif ($step == 6) {
      &disp("About to edit file. Please enter the commands necessary to delete files created during the build stage. Many packages will only need to put \"make clean\".\n");
      &pause;
      &edit("packer/clean.sh");
      &preserveDir("packer/clean.sh");
   }
   elsif ($step == 7) {
      &disp("About to edit file. Please enter the commands necessary to install the package to \$install_dir (which will be defined before the install code runs) as the root directory. If your package cannot do it, you may want to exit packer now, patch the package, and reenter packer.\n");
      &pause;
      &edit("packer/install.sh");
      &preserveDir("packer/install.sh");
   }
   elsif ($step == 8) { #Packages
      #TODO: make sure that new newPackage clears the packages file before it runs
      while (1) {
	 if (!-e "packer/packages") {
	    if (&yn("Do you want to split this package into two or more packages?:")) {
	       print "Okay; enter info for the first package. This package must be the \"primary\" package and its description should describe the source package as a whole. This description will then be used when exporting to formats where it is illogical to split packages, such as gentoo and autopackage.\n";
	       &editPackage(0, "");
	       print "Enter info for the second package\n";
	       &editPackage(0, "");
	    }
	    else {
	       &editPackage(1, "");
	       last;
	    }
	 }
	 $i=1;
	 @packages = &parseESV("packer/packages");
	 print "\n";
	 for (@packages) {
	    print "$i: Edit $_\n";
	    ++$i;
	 }
	 print "$i: New package\n";
	 print $i+2 . ": Remove package\n";
	 print $i+3 . ": Rename package\n";
	 print $i+4 . ": Done with packages\n";
	 print "\nEnter your selection: ";
	 $number = &input;
	 if (!$number || $number =~ /\D/ || $number < 1 || $number > $i+4) {
	    print "Invalid selection\n";
	    next;
	 }
	 elsif ($number-1 <= @packages) {
	    &editPackage(1, $packages[$number-1]);
	 }
	 elsif ($number == $i) { #new package
	    &editPackage(1, "");
	 }
	 elsif ($number == $i+2) { #remove package
	    print "What is the number of the package that you with to remove? ";
	    system "rm -f packer/" . $packages[$name-1] . ".*";
	    $num = &input;
	    if ($num > @packages) {
	       print "Invalid package\n";
	    }
	    else {
	       splice @packages, $num-1, 1;
	       &writeESV("packer/packages", \@packages);
	    }
	 }
	 elsif ($number == $i+3) { #rename package
	    print "Enter the number of the package you want to rename: ";
	    $number = &input;
	    if ($number < 1 || $number > @packages) {
	       print "Invalid number\n";
	    }
	    else {
	       print "Enter new name: ";
	       $nname = &input;
	       if (&validatePackageName($nname)) {
		  splice @packages, $number-1, 1, $nname;
		  &writeESV("packer/packages", \@packages);
	       }
	    }
	 }
	 else {
	    if (@packages >= 1) {
	       last;
	    }
	    else {
	       print "You must have at least one package!\n";
	    }
	 }
      }
   }
   elsif ($step == 9) { #package splitting
      @packages = &parseESV("packer/packages");
      if (@packages == 1) {
	 open SPLIT, "> packer/split.sh" or &bye;
	 select SPLIT;
	 $nname = $packages[0];
	 $nname =~ s/-/_/;
	 print "cp -ra \$install_dir/* \$${nname}_dir\n";
	 close SPLIT;
	 select STDOUT;
	 &preserveDir("packer/split.sh");
      }
      else {
	 &disp("Launching editor. You will now need to enter the commands to split the package. The files you installed will still be in \$install_dir. You must move them to \$package_dir, where package is the name of a package with all hypens (-) replaced with underscores. \$package_dir will at most only contain things in usr/share/doc \$install_dir will only contain the files that your package installed. Here is an example package splitting, for packages \"foobar\" and \"foobar-data\":\n\n");
	 print "mkdir \$foobar/usr";
	 print "mv \$install_dir/usr/bin \$foobar/usr\n";
	 print "mkdir \$foobar_data/usr\n";
	 print "mv \$install_dir/share \$foobar_data/usr\n\n";
	 &pause;
	 &edit("packer/split");
      }
   }
   elsif ($step == 10) { #changelog
      $mod = 0; #does a changelog entry for this version alrady exist?
      if (-e "packer/changelog" && &getFullVersion eq &parseSingleLine("packer/changelog")) { #if an entry for this version already exists...
	 open CHANGELOG, "< packer/changelog" or &bye;
	 open CLR, "> packer/changelog.latest" or &bye;
	 select CLR;
	 <CHANGELOG>; #skip version
	 <CHANGELOG>; #skip date
	 while (<CHANGELOG>) {
	    if (/^-/) {
	       last;
	    }
	    else {
	       s/^\* //;
	       print;
	    }
	 }
	 close CHANGELOG;
	 close CLR;
	 select STDOUT;
	 $mod = 1;
      }
      &disp("About to launch editor. Please enter a changelog entry for version " . &parseSingleLine("packer/version") . "-" . &parseSingleLine("packer/revision") . ". Just put down one change that you made per line. Do not prefix anything with a * or anything like it - packer will add that for you.\n");
      &pause;
      &edit("packer/changelog.latest");
      system "touch packer/changelog";
      open OLD, "< packer/changelog" or &bye;
      open NEW, "> packer/changelog.new" or &bye;
      select NEW;
      print &getFullVersion . "\n";
      print `date -R`; #date includes a \n for us
      &printFile("packer/changelog.latest", "* ");
      print "-- " . &parseSingleLine("packer/packager") . "\n";
      if ($mod) { #modifying existing entry, so skip the first entry in the current changelog
	 while (<OLD>) {
	    if (/^-/) { #if we are at the end of the first entry
	       last;
	    }
	 }
      }
      while (<OLD>) {
	 print;
      }
      close OLD;
      close NEW;
      select STDOUT;
      system "mv -f  packer/changelog.new packer/changelog";
      system "rm -f packer/changelog.latest";
   }
   elsif ($step == 11) {
      &disp("If you have patches for this packages, simply put them in the packer/patches directory. All patches must end of .diff and must not be compressed. They also must be appliable with -p1. To generate a patch from the original tarball to the current working directory, ignoring packer-generated files, you may use the differ tool, which is distributed with packer. It can be called with \"differ tarball\", where tarball is a tar.gz file with the package sourcecode (if the source code came in a .tar.bz2 file, you will need to repackage it to use it as .tar.gz file to use it with differ). Note that the patch that differ generates (or any patch with the name \"differ.diff\") will only be applied to RPM and Gentoo packages.");
      print "\n\nIt should be noted that generated desktop files reside in the gen_menus directory. Thus, if you utilized this feature, you must have either have the gen_menus directory in the original tarball or include a patch to add the gen_menus directory. Otherwise, building RPMs will fail.\n\n"; #TODO: proofread
      &pause;
   }

   if (!$menu) {
      if ($step == $totalSteps) {
	 system "clear";
	 system "touch packer/complete";
	 system "rm -f packer/progress";
	 print "Packages can now be created.\nUse packer --help to see how.\n\n";
	 print "Once your packer files are included in the package,\n";
	 print "please add " . &parseSingleLine("packer/spackage") . " to the packer registry at\n";
	 print "http://packer.sf.net/reg.html. If I know people are using packer through the registry,\nI will be encouraged to continue work on packer.\n\n";
	 print "Thank you for using packer!\n";
      }
      else {
	 ++$step;
	 system "clear";
	 system "echo $step >packer/progress";
	 &step($step, 0); #next step; recursion may be inefficient, but I would be writing this in assembly if I were concerned about effeciency ;-)
	 		#TODO: convert to while loop`
      }
   }
}

sub checkfiles {
   my @files = ("docs", "bdeps", "packager", "changelog", "copyright",  "packages", "build", "install", "source", "tarball", "spackage", "license", "clean", "maintainer");
   for (@files) {
      if (!-e "packer/$_") {
	 die "Error: cannot find required file packer/$_.\n";
      }
   }
}

sub checkdir {
   my $dir = shift;
   my $force = shift;
   if (-e $dir) {
      if ($force) {
	 system "rm -rf $dir";
      }
      else {
	 die "Directory \"$dir\" already exists. Delete it or call packer with the -f option\n";
      }
   }
   mkdir($dir);
}

sub regen { #regenerate build, install, clean, and split and write new interface version
   &preserveDir("packer/build.sh");
   &preserveDir("packer/install.sh");
   &preserveDir("packer/clean.sh");
   &preserveDir("packer/split.sh");
   &writeSingleLine("packer/pversion", $pinterface);
}

sub checkpversion { #is the current version of packer high enough?
   open PVERSION, "< packer/pversion" or &bye;
   our $ppversion = <PVERSION>;
   close PVERSION;
   chomp $ppversion;
   if ($pinterface < $ppversion) {
      die "Your version of packer is not high enough to pack this package\n";
   }
   elsif ($pinterface > $ppversion) {
      if ($ppversion == 0) {
	 &regen;
      }
   }
}

sub parseESV { #parse enter seperated values
   $efile = shift;
   my @values;
   if (!open PEFILE, "< $efile") {
      return @values; #empty array
   }
   while (<PEFILE>) {
      chomp $_;
      push @values, $_;
   }
   close PEFILE;
   return @values;
}

sub parseSingleLine {
   $file = shift;
   if (!-e $file) {
      return "";
   }
   open FILE, "< $file" or &bye;
   $file = <FILE>;
   close FILE;
   chomp $file;
   return $file;
}

sub rpmSearchFiles {
   $filesRef = shift;
   undef @d;
   for (@{$filesRef}) {
      our $f = $_;
      if ($f =~ /^[a-z]+:/) {
	 if (/^r/) {
	    s/^r://;
	    push @d, $f;
	 }
      }
      elsif ($f =~ m#^/#) {
	 push @d, &rpmSearchFile($f);
      }
      elsif (!$f =~ m#:#) {
	 push @d, $f;
      }
   }
   return @d;
}

sub rpmSearchFile {
   my $dep_raw = shift;
   my $dep = &breakDep($dep_raw);
   $file = ${@{$dep}}[0];
   $version = ${@{$dep}}[1];
   $cached = &checkCache(RPM_CACHE, $file);
   if ($cached) {
      return $cached . $version;
   }
   print STDOUT "Querying SuSE package db via yahoo.com...\n";
   $filer = $file;
   $filer =~ s#/#%2F#g;
   system "wget -q -O packer/tmp \"http://search.yahoo.com/search?p=site%3Anovell.com+$filer&prssweb=Search&ei=UTF-8&fr=FP-pull-web-t&n=10&fl=0&vc=&x=wrt\" &> /dev/null";
   open TMP, "< packer/tmp" or &bye;
   while (<TMP>) {
      if (m#www.novell.com/products/linuxpackages/[a-z]+/([A-Za-z0-9_\-\.\+]+).html#) {
	 $dep = $1;
	 close TMP;
	 system "rm -f packer/tmp";
	 &addToCache(RPM_CACHE, $file, $dep);
	 return $dep . $version;
      }
   }
   close TMP;
#   system "rm -f packer/tmp";
   die "Cannot find RPM package for file $file\n";
}

sub breakDep { #break the dependency into the file and the version indicator
   my $dep = shift;
   $dep =~ /(\S+)(.*)/;
   my $file = $1;
   my $version;
   if ($2) {
      $version = $2;
   }
   else {
      $version = "";
   }
   my $split = [$1, $2];
   return $split;
}

sub deb_source_pkg {
   our $deb = shift;
   our $cached = &checkCache(GENTOO_CACHE, $deb);
   if ($cached) {
      return $cached;
   }
   print STDOUT "Looking for source package on packages.debian.org...\n";
   system "wget -q -O packer/tmp http://packages.debian.org/unstable/" . &deb_search_file(${@{$dep}}[0], 1) . " &> /dev/null";
   open QUERY, "< packer/tmp" or &bye;
   while (<QUERY>) {
      if (m#<a href="http://packages.qa.debian.org/([A-Za-z0-9\-\+\.]+)">developer information for#) {
	 close QUERY;
	 system "rm -f packer/tmp";
	 my $src_dep = $1;
	 $src_dep =~ s#-defaults$##; #needed for python to work (otherwise it would be python-defaults)
	 &addToCache(GENTOO_CACHE, $deb, $src_dep);
	 return $src_dep;
      }
   }
}

sub gentoo_search_file { #returns the debian search package for a file
                         #not always completely accurate :-(
   our $param = shift;
   if ($param =~ m#^/#) {
      our $dep = &breakDep($param);
      our $version = ${@{$dep}}[1];
      $version =~ s#\s##g; #don't confuse gentoo with non-seperator whitespace
      our $pkg =  &deb_source_pkg(&deb_search_file(${@{$dep}}[0]));

   }
   elsif ($param =~ m#^g:\s*(.*)#) {
      return $1;
   }
   else {
      return ""; #shouldn't be included
   }
}

sub deb_search_file {
   #make sure contents file is present
   if (! -e "$home/.packer/Contents-i386.gz") {
      system("mkdir -p $home/.packer");
      if (!system("wget -O $home/.packer/Contents-i386.gz ftp://ftp.us.debian.org/debian/dists/unstable/Contents-i386.gz")) {
	 print "Error: could not fetch debian contents file from internet.\n";
	 exit 1;
      }
   }
   
   $dep = &breakDep(shift);
   $file = @{$dep}[0];
   $version = @{$dep}[1];
   $cached =  &checkCache(DEB_CACHE, $file);
   $gentoo = shift; #true if gentoo_search_file called it; return the URL for the package DB entry instead of the package name
   if ($cached) {
      if ($gentoo) {
	 return $cached;
      }
      else {
	 $cached =~ m#/(.*)#;
	 return $1 . $version;
      }
   }
   $file =~ s#^/##;
   print STDOUT "$file searching\n"; #TODO: remove
   print STDOUT "Searching for debian package name (this will take a while, but will only be done once per dep)\n";
   my $rawDeb = `zgrep '^$file\t' $home/.packer/Contents-i386.gz`;
   #$rawDeb =~ m#\s([^/]+)/([^/]+)$#;
    $rawDeb =~ m#\s(.*,)?([^/]+)/([^/]+)$#;
    if (!$3) {
      warn "Could not file dependency for file /$file\n";
      exit 1;
   }
   our $deb = $3;
   chomp $deb;
   print STDOUT "deb: $deb\n"; #TODO: remove
   our $fulldeb = "$2/$3";
   chomp $fulldeb;
   if ($gentoo) {
      return $fulldeb;
   }
   &addToCache(DEB_CACHE, "/$file", $fulldeb);
   return $deb . $version;
}

sub printFile {
   $file = shift;
   $linePrefix = shift;
   open FILE, "< $file" or &bye;
   while (<FILE>) {
      s#\$([a-zA-Z_]+)#\${$1}#g; #in debian, the Makefile like it like this. In other places, it does not do any harm
      print $linePrefix . $_;
   }
   close FILE;
}

sub getAllDeps { #get all deps in all subpackages
   @packages = &parseESV("packer/packages");
   for (@packages) {
      for (&parseESV("packer/$_.deps")) {
	 $dep = $_;
	 $already = 0;
	 for (@deps) {
	    if ($_ eq $dep) {
	       $already = 1; #do not list dependencies twice
	       last;
	    }
	 }
	 if (!$already) {
	    push @deps, $dep;
	 }
      }
   }
   return @deps;
}

sub fileToAp { #find autopackage dependency names
   our $dep = shift;
   our $deps = &breakDep($dep);
   our $s1 = &deb_source_pkg(&deb_search_file(${@{$deps}}[0]));
   our $version = ${@{$deps}}[1];
   our $skelDir = shift;
   our $cache = &checkCache(AP_CACHE, $s1);
   if ($cache) {
      if ($cache eq "NULL") {
	 return "";
      }
      else {
	 return $cache . $version;
      }
   }
   
   our $s2 = $s1;
   $s2 =~ s#^lib##; #s2: without any initial "lib"
   our @skels = `/bin/ls -d $skelDir/*/*`;
   for (@skels) {
      m#.*(@.*/(.*))#;
      if ($s1 eq $2 || $s2 eq $2) {
	 &addToCache(AP_CACHE, $s1, $1);
	 return $1 . $version;
      }
   }
   &addToCache(AP_CACHE, $s1, "NULL");
   return "";
}

sub ap {
   if (&parseSingleLine("packer/reloc") ne "y") {
      print STDERR "Error: to make an autopackage, your program must be relocutable and you specified that it was not.\n";
      exit 1;
   }
   our $skelDir = `which makeinstaller`;
   if (!$skelDir) {
      print STDERR "Error: to build an autopackage specfile, you must have the autopackage developer tools installed from autopackage.org.\n";
      exit 1;
   }
   chomp $skelDir;
   $skelDir = `dirname $skelDir`;
   chomp $skelDir;
   $skelDir .= "/../share/autopackage/skeletons/";
   
   $build = shift;
   $force = shift;
   &checkfiles();
   &checkpversion();
   &checkdir("autopackage", $force);
   open AP, "> autopackage/default.apspec" or &bye;
   select AP;
   print "#Generated by packer version $pversion ($packerUrl)\n";
   print "#Thus, you may not want to modify this file directly.\n\n";
   print "[Meta]\n";
   $source = &parseSingleLine("packer/source");
   $source =~ s#http://##;
   $source =~ s#ftp://##;
   $source =~ s#[a-z\.A-Z0-9]\.html$##;
   $source =~ s#/$##;
   $spackage = &parseSingleLine("packer/spackage");
   $rootname = "\@$source";
   if ($rootname =~ /sourceforge.net/ || $rootname =~ /sf.net/ || !$rootname =~ /^\@.+$spackage/) {
      $rootname .= "/$spackage";
   }
   $rootname =~ s#^\@www.#\@#;
   print "RootName: $rootname:\$SOFTWAREVERSION\n";
   print "DisplayName: $spackage\nShortName: $spackage\n";
   print "Maintainer: " . &parseSingleLine("packer/maintainer") . "\n";
   print "Packager: " . &parseSingleLine("packer/packager") . "\n";
   print "URL: " . &parseSingleLine("packer/source") . "\n";
   print "License: " . &parseSingleLine("packer/license") . "\n";
   print "SoftwareVersion: " . &parseSingleLine("packer/version") . "\n";
   print "PackageVersion: " . &parseSingleLine("packer/revision") . "\n";
   @packages = &parseESV("packer/packages");
   $package = $packages[0]; #it is illogical to split an autopackage. we shall assume that the first package is the primary package, as we told the user to do
   print "Summary: " . &parseSingleLine("packer/$package.desc") . "\n"; #TODO: support for non-English languages
   print "AutopackageTarget: 1.0\n"; #TODO: 1.0 or 1.2?

   print "[Description]\n";
   &printFile("packer/$package.ldesc", "");

   print "\n\n[BuildPrepare]\n";
   print &applyPatches;
   print "export install_dir=\$build_root\n";
   &printFile("packer/build", "");
   &printFile("packer/install", "");

   #icons
   print "mkdir -p \$build_root/usr/share/icons\n";
   for (<packer/*is>) {
      for (&parseESV($_)) {
	 $xpm = $_;
	 $png = $xpm;
	 $png =~ s#^.*/##;
	 $png =~ s#\.xpm$#.png#;
	 print "convert $xpm \$build_root/usr/share/icons/$png\n";
      }
   }
   print "mkdir -p \$build_root/usr/share/doc/$spackage\n";
   print "cp -ra " . join(" ", &parseESV("packer/docs")) . " \$build_root/usr/share/doc/$spackage\n";

   my $sedDirFilter=&sedDirFilter;
   #write installation script
   print <<INSTALLSCRIPT;
escapedPrefix=\\\\\\\$PREFIX
escapedBr=\$(echo \$build_root|sed "s/\\//\\\\\\\\\\//g")
inst=\$build_root/packer_inst
echo outputStatus "Creating directories..." >> \$inst
find \$build_root -type d|sed "s/^\$escapedBr//"|sed "/^\\s*\$/d"|$sedDirFilter|sed "s/^\\/usr/\$escapedPrefix/"|while read dir; do #install directories
   echo mkdir -p \$dir >> \$inst
   echo logDir \$dir >> \$inst
done

echo outputStatus "Preparing to install files..." >> \$inst
files=`find \$build_root ! -wholename \$inst  ! -type d|sed "s/\$escapedBr\\///"`
numfiles=\$(echo "\$files"|wc -l|grep -oE '^[0-9]+')
compressProgress=0
if [[ numfiles -gt 100 ]]; then
   compressProgress=1
fi
filenum=0
echo "\$files"|while read file; do
   echo progressBar \$filenum \$numfiles "Installing files" \$compressProgress >> \$inst
   filedest=\$(echo \"\$file\"|sed s/^usr/\$escapedPrefix/) #change prefix from default prefix to \$PREFIX 
   if [[ -n \$(find \$build_root/\$file -type l) ]]; then #file is a symbolic link
      echo cp -a \$file \$filedest >> \$inst;echo logFile \$filedest >> \$inst
   else
      case \$file in
	 etc/*)
	    destfile=\$file
	    if [[ \${file::3} != "etc" ]]; then
	       \$destfile = \$(echo "\$file\"|sed "s/^etc/\$HOME\\/.config/")
	    fi
	    echo copyFile --silent \$file /\$destfile >> \$inst
	    ;;
	*.applications)
	   echo installGnome2AppEntry \$file >> \$inst
	   ;;
	 *.mime|*.keys)
	    echo installGnome2Mime \$file >> \$inst
	    ;;
	 *.schemas)
	    echo installGConfSchema \$file >> \$inst
	    ;;
	 *.desktop)
	    if grep NoDisplay=true \$build_root/\$file; then
	       echo installMimeDesktop \$file >> \$inst
	    else
	       echo installDesktop Applications \$file >> \$inst #TODO: 1st arg: more descriptive
	    fi
	    ;;
	 usr/share/icons/*|usr/share/pixmaps/*)
	    echo installIcon \$file >> \$inst
	    ;;
	 *.info)
	    echo installInfo \$file >> \$inst
	    ;;
	 *.so*)
	    echo installLib \$file >> \$inst
	    ;;
	 usr/share/locale/*|share/locale/*)
	    if [[ -z "\$localeInstalled" ]]; then
	       echo installLocale \$(dirname \$file) >> \$inst
	       \$localeInstalled=1
	    fi
	    ;;
	 *.[0-9]|*.[0-9].gz|*.[0-9].bz2|*.[0-9][0-9]|*.[0-9][0-9].gz|*.[0-9][0-9].bz2)
	    echo installMan \$(echo \$(dirname \$file)|grep -oE '[0-9]+') \$file >> \$inst
	    ;;
	 *)
	    somethingInstalled=0
	    if [[ -n \$(find \$build_root/\$file -perm -0100) ]]; then #is executable
	       echo installExe \$file >> \$inst
	       somethingInstalled=1
	    elif [[ -n \$(echo "\$file"|grep -E "\.xml\$") ]]; then #xml file
	       if [[ -n \$(grep http://www.freedesktop.org/standards/shared-mime-info \$build_root=\$file) ]]; then
		  echo installMime \$file >> \$inst
		  somethingInstalled=1
	       fi
	    fi
	    if [[ "\$somethingInstalled" = 0 ]]; then
	       echo copyFile --silent \$file \$filedest >> \$inst
	    fi
	    ;;
      esac
   fi
   (( ++filenum ))
done
echo progressBar \$numfiles \$numfiles "Files installed" >> \$inst
INSTALLSCRIPT
  

   print "\n[BuildUnprepare]\n";
   print &deapplyPatches;
   &printFile("packer/clean", "");
   print "\n[Imports]\necho '*'|import\n\n";

   print "[Prepare]\n";
   @deps = &getAllDeps;
   for (@deps) {
      if (m#^/#) { #no package system specific deps
	 $depSplit = &breakDep($_);
	 our $rdep = @{$depSplit}[0];
	 if (our $apdep = &fileToAp($rdep, $skelDir)) { #can find corresponding rootname
	    our $vdep = @{$depSplit}[1];
	    if ($vdep =~ /^\s*>=\s*(.*)/) {
	       print "requireAtLeast \"$apdep\":$1\n";
	    }
	    elsif ($vdep =~ /^\s*=\s*(.*)/) {
	       print "requireExact \"$apdep\":$1\n";
	    }
	    else {
	       print "requireAtLeast \"$apdep\":0\n";
	    }
	 }
	 else {
	    if ($rdep =~ m#^/usr/# && ! $rdep =~ m#^/usr/local/#) {
	       $ldep = $rdep;
	       $ldep =~ s#^/usr/#/usr/local/#;
	    }
	    else {
	       $ldep = "";
	    }
	    $pname = &deb_search_file($rdep);
	    print "outputTest \"" . $pname . "\"\n";
	    print "if [[ -f $rdep ]]";
	    if ($ldep) {
	       print " || [[ -f $ldep ]]";
	    }
	    print "; then\n\toutputTestPass\nelse\n\toutputTestFail\n\toutputFail \"$pname not installed. Please install that package and try again\"\n";
	    print "\tfalse\nfi\n";
	 }
      }
      elsif (m#^ap:(.*)#) { #autopackage specific deps
	 print $1 . "\n"; #this will need to be a full autopackage statement detecting deps
      }
   }

   #TODO: find install script in advance in [PrepareBuild]
   print "\n\n[Install]\n"; #TODO: make it so script works better
   print "source packer_inst\n";

   for (<packer/*.postinst>) {
      &printFile($_, "");
   }
   print"\n[Uninstall]\nuninstallFromLog\n";
   close AP;
   select STDOUT;
   print "Autopackage apspec generated. WARNING: C++ programs that are not statically linked with all C++ libraries will crash on systems running g++ 3.4 or higher if compiled on g++ 3.3, or will crash on systems running g++ 3.3 or lower if compiled on g++ 3.4 or higher because of the c++ ABI problem. This will likely be fixed in future versions of autopackage..\n";

   if ($build) {
      system "makeinstaller";
   }
}

sub gentoo { #TODO: config files
   $build = shift;
   $force = shift;
   &checkfiles;
   &checkpversion;
   &checkdir("gentoo", $force);

   #find the correct category
   our @packages = &parseESV("packer/packages");
   our $firstPackage = $packages[0];
   our $dir = &parseSingleLine("packer/$firstPackage.sect_gentoo");
   our $spackage = &parseSingleLine("packer/spackage");
   our $version = &parseSingleLine("packer/version");
   our $revision = &parseSingleLine("packer/revision");
   mkdir "gentoo/$dir";
   mkdir "gentoo/$dir/$spackage";
   
   $efile = "$spackage-$version";
   if ($revision >= 2) {
      $efile .= "-r" . $revision-1;
   }
   $efile .= ".ebuild";
   open EBUILD, "> gentoo/$dir/$spackage/$efile" or &bye;
   select EBUILD;
   print "# Copyright 1999-2005 Gentoo Foundation\n# Distributed under the terms of the GNU General Public License v2\n# \$Header: /cvsroot/packer/packer/src/packer,v 1.15 2006/01/02 01:37:55 dmilstein Exp $\n\n";
   print "#Generated by packer $pversion ($packerUrl).\n#As such, you may not want to modify this file directly, if one can make changes using packer instead.\n\n";
   print "SLOT=0\n";
   print "LICENSE=" . &parseSingleLine("packer/license") . "\n";
   print "KEYWORDS=\"~x86\" #this line will probably have to be modified\n"; #TODO:make a mechanism for editing gentoo-specific stuff with packer
   @packages = &parseESV("packer/packages");
   $package = $packages[0]; #splitting makes no sense here
   print "DESCRIPTION=\"" . &parseSingleLine("packer/$package.desc") . "\"\n";
   $tarball = &parseSingleLine("packer/tarball");
   $tarball =~ s/\[\[version\]\]/\${PV}/g;
   print "SRC_URL=\"$tarball\"\n";
   print "HOMEPAGE=\"" . &parseSingleLine("packer/source") . "\"\n";
   print "IUSE=\"\"\n";
   @raw_bdeps = &parseESV("packer/bdeps");
   undef @bdeps;
   print "DEPEND=\""; #DEPEND - build depends 
   for (@raw_bdeps) {
      our $f = &gentoo_search_file($_);
      if ($f) {
	 push @bdeps, $f;
      }
   }
   $depSep = " \\\n" . " " x 9; #dependency seperator; this will make the deps line up also
   &printCommaList(\@bdeps, $depSep); #space seperated list
   print "\"\nRDEPEND=\""; #RDEPEND - runtime depends
   @rdeps = &getAllDeps; #raw dependencies
   undef @deps; #just in case another packaging function already defined it
   my @deps;
   for (@rdeps) {
      #TODO: process deps properly with debian source packages
      our $d = &gentoo_search_file($_);
      if ($d) {
	 push @deps, $d;
      }
   }
   &printCommaList(\@deps, $depSep);
   print "\"\n";
   print "\nfunction src_compile {\n";
   &printFile("packer/build", "\t");
   print "}\n\nfunction src_install {\n";
   print "\texport install_dir=\${D}\n";
   &printFile("packer/install", "\t");
   print "}\n";
   close EBUILD;
   #TODO: changelog
}

sub slack { 
   $build = shift;
   $force = shift;
   &checkfiles();
   &checkpversion();
   &checkdir("slack", $force);
   open SLACK, "> slack/slack.sh" or &bye;
   select SLACK;
   print "#!/bin/sh\n\n";
   print "#Generated by packer $pversion ($packerUrl).\n#Thus, it may not be advistable to modify this script, as your changes may be overridden.\n";
   print "if [[ `id -u` != \"0\" ]]; then echo \"Error: you must either execute this script as roof or use fakeroot\"; exit 1; fi\n";
   print &applyPatches;
   @package_names = &parseESV("packer/packages");
   for (@package_names) { #exports
      $nname = $_;
      $nname =~ s/-/_/g;
      print "export ${nname}_dir=slack/$_\n";
      print "mkdir slack/$_\n";
   }
   print "export install_dir=`pwd`/slack/tmp\n";
   print "mkdir slack/tmp\n";
   print "\n";
   #install and configure
   &printFile("packer/clean", "");
   &printFile("packer/build", "");
   &printFile("packer/install", "");
   &printFile("packer/split", "");
   #build packages
   for (@package_names) {
      $p = $_;
      
      #doc files (config files ignored)
      print "mkdir -p slack/$p/usr/share/doc/$p\n";
      print "cp -ra " . join(" ", &parseESV("packer/docs")) . " slack/$p/usr/share/doc/$p\n";

      #icons
      print "mkdir -p slack/$p/usr/share/icons\n";
      for (<packer/$p.is>) {
	 for (&parseESV($_)) {
	    $xpm = $_;
	    $png = $xpm;
	    $png =~ s#^.*/##;
	    $png =~ s#\.xpm$#.png#;
	    print "convert $xpm slack/$p/usr/share/icons/$png\n";
	 }
      }
      print "mkdir slack/$p/install\n";
      print "cat > slack/$p/install/doinst.sh << PACKER_HERE_BLAHBLAH\n";
      print "#!/bin/sh\n\n";
      open PI, "< packer/$p.postinst";
      while (<PI>) {
	 s#`#\\`#g;
	 s#\\#\\\\#g;
	 if (m#PACKER_HERE_BLAHBLAH#) {
	    die "Cannot have \"PACKER_HERE_BLAHBLAH\" in postinstallation script\n";
	 }
	 #print;
      }
      close PI;
      if (&packageHasDesktop($p)) {
	 $updateDD = &updateDD;
	 $updateDD =~ s#`#\\`#g;
	 print $updateDD;
      }
      print "PACKER_HERE_BLAHBLAH\n";
      print "cd slack/$p\n";
      print "tar -czvpf ../../../${p}_" . &getFullVersion . ".tgz *\n";
      print "cd ../..\n";
      #TODO: add install/doinst.sh for update-desktop-database
      print "rm -rf slack/$p\n";
   }
   print "rm -rf slack/tmp\n";
   print &deapplyPatches;
   print "echo Packages generated in parent directory\n";
   close SLACK;
   select STDOUT;
   print "Slackware package generation script created\n";
   if ($build) {
      system "fakeroot sh slack/*.sh || sudo sh slack/*.sh || su -c 'sh slack/*.sh'";
   }
}

sub getRPMDir {
   my $grep = `grep \%_topdir ~/.rpmmacros`;
   if ($grep =~ m#\%_topdir\s*(.*)#) {
      return $1;
   }
   elsif (-e "/usr/src/rpm") { #for non-Fedora/Red hat distros
      return "/usr/src/rpm";
   }
   elsif (-e "/usr/src/redhat") {
      return "/usr/src/redhat";
   }
   else {
      return "";
   }
}

sub populateRPMDir { #find the rpm root
   my $dir = &getRPMDir;
   if (!$dir) {
      warn "Cannot find the RPM directory. You will have to copy the tarball and patches there manually or the RPM build process will fail.\n";
      &pause;
   }
   my $tarball_url = &parseSingleLine("packer/tarball");
   my $version = &parseSingleLine("packer/version");
   $tarball_url =~ s/\[\[version\]\]/$version/g;
   $tarball = $tarball_url;
   $tarball =~ s#^.*/##; #basename
   if (!-e "$dir/SOURCES/$tarball") {
      print "Fetching tarball...\n";
      system "wget -O $dir/SOURCES/$tarball $tarball_url";
   }
   if (<rpm/*.diff.bz2>) {
      print "Copying patches...\n";
      system "cp -f rpm/*.diff.bz2 $dir/SOURCES"; #let's hope the user has permissions...
   }
}

sub rpm {
   $build = shift;
   $force = shift;
   &checkfiles();
   &checkpversion();
   &checkdir("rpm", $force);
   @patches = <packer/patches/*.diff>;

   #find program information
   $fl_changelog = &parseSingleLine("packer/changelog");
   $fl_changelog =~ /(.*)-(.*)/;
   my $version = $1;
   $revision = $2;
   $spackage = &parseSingleLine("packer/spackage");

   @packages = &parseESV("packer/packages");
   @package_names = @packages;

   open SPECFILE, "> rpm/$spackage-$version-${revision}.spec.template" or &bye;
   select SPECFILE;
   print "#Generated by packer $pversion ($packerUrl)\n";
   print "#Thus, it may not be advisable to modify this file directly, as your changes may get overridden.\n";

   print "License: " . &parseSingleLine("packer/license") . "\n";;
   print "Version: " . $version . "\n";
   print "Release: " . $revision . "mdk #PACKER_MANDRIVA_BLAHBLAH\n";
   print "Release: " . $revision . "suse #PACKER_SUSE_BLAHBLAH\n";
   print "Release: " . $revision . " #PACKER_RH_BLAHBLAH\n";
   $tarball = &parseSingleLine("packer/tarball");
   $tarball =~ s#\[\[version\]\]#\%{version}#g;
   @ds = &parseESV("packer/bdeps");
   if ($rpmSys) {
      @bdeps = &rpmSearchFiles(\@ds);
      if (@bdeps > 0) {
	 print "\nBuildRequires: ";
	 &printCommaList(\@bdeps);
      }
   }
   print "\nSource: " . $tarball . "\n";
   print "Packager: " . &parseSingleLine("packer/packager") . " #PACKER_MANDRIVA_BLAHBLAH\n";
   $i = 1;
   if (<packer/patches/*.diff>) {
      system("cp packer/patches/*.diff rpm");
      system("bzip2 rpm/*.diff");
   }
   for (@patches) {
      s&^.*/&&;
      s/$/.bz2/;
      push @patches_f, $_;
      print "Patch$i: $_\n";
      ++$i;
   }
   $first = 1;

   #RPM does not allow nonarch subpackages when there are arch parts of it
   if (&allIndep) {
      print "BuildArch: noarch\n";
   }

   for (@packages) {
      $name = $_;
      if (!$first) {
	 print "\%package -n $name\n";
      }
      else {
	 print "\nName: " . $name . "\n";
      }
      @ds = &parseESV("packer/$name.deps");
      @deps = &rpmSearchFiles(\@ds);
      if (@deps > 0) {
	 print "Requires: ";
	 &printCommaList(\@deps);
	 print "\n";
      }

      print "Group: " . &parseSingleLine("packer/$name.sect_mandriva")  . " #PACKER_MANDRIVA_BLAHBLAH\n";
      print "Group: " . &parseSingleLine("packer/$name.sect_rh") . " #PACKER_RH_BLAHBLAH\n";
      print "Group: ". &parseSingleLine("packer/$name.sect_suse") . " #PACKER_SUSE_BLAHBLAH\n";

      #TODO: SuSE group
      print "Summary: " . &parseSingleLine("packer/$name.desc") . "\n";
      print "BuildRoot: \%{_tmppath}/\%{name}-\%{version}-root\n\n";
      print "\%description -n $name\n";
      &printFile("packer/$name.ldesc", "");
      print "\n\%files";
      if (!$first) {
	 print " -n $name";
      }
      print " -f \%{_tmppath}/$name.flist\n";
      print "\%defattr(-,root,root)\n";
      print "\%doc " . join(" ", &parseESV("packer/docs"))  ."\n";
      print "\%config " . join(" ", &parseESV("packer/config")) . "\n";
      print "\n\n";
      $first = 0;
      print "\n\%post -n $name\n";
      &printFile("packer/$name.postinst", "");
      our $updateDD = &updateDD;
      chomp $updateDD;
      if (&packageHasDesktop($name)) {
	 print "\%{update_menus} #PACKER_MANDRIVA_BLAHBLAH\n";
	 print $updateDD . " #PACKER_NOMANDRIVA_BLAHBLAH\n";
      }
      print "\n\%postun\n";
      if (&packageHasDesktop($name)) {
	 print "\%{clean_menus} #PACKER_MANDRIVA_BLAHBLAH\n";
	 print $updateDD . " #PACKER_NOMANDRIVA_BLAHBLAH\n";
      }
   }
   print "\n\%prep\n\%setup -n $spackage-$version\n";
   $i = 1;
   for (@patches_f) {
     print "\%patch$i -p1\n"; 
     ++$i;
   }
   print "\n\%build\n";
   print "rm -rf \$RPM_BUILD_ROOT\n";
   &printFile("packer/build", "");
   print "\n\%install\n";
   print "rm -rf \$RPM_BUILD_ROOT\n";
   print "mkdir -p \$RPM_BUILD_ROOT/install\n";
   print "export install_dir=\$RPM_BUILD_ROOT/install\n";
   $nname = &parseSingleLine("packer/spackage");
   $nname =~ s/-/_/g; #bash doesn't like - in variables
   for (@package_names) {
      if ($_ =~ /^\s*$/) { #skip blank lines
	 next;
      }
      $name = $_;
      $nname = $_;
      $nname =~ s/-/_/g; #bash doesn't like - in variables
      print "export ${nname}_dir=\$RPM_BUILD_ROOT/${name}_dir\n";
      print "mkdir -p \$RPM_BUILD_ROOT/${name}_dir\n";
   }
   &printFile("packer/install", "");
   print "rm -rf \$install_dir/usr/share/applications #PACKER_MANDRIVA_BLAHBLAH\n";
   &printFile("packer/split", "");
   for (@package_names) {
      $p = $_;
      #Mandriva menu
      for (&parseESV(<packer/$_.ds>)) {
	 our $cat = &parseSingleLine("packer/$p.sect_mmenu");
	 our $menu = `desktop2menu -ms $p '$cat' $_.desktop`;
	 chomp $menu;
	 s#^.*/##;
	 s#.desktop$##;
	 print "echo '$menu' > \$RPM_BUILD_ROOT/\%{_menudir}/$_ #PACKER_MANDRIVA_BLAHBLAH\n";
      }

      print "find \$RPM_BUILD_ROOT/${p}_dir ! -type d|sed s^\$RPM_BUILD_ROOT/${p}_dir^^|sed /^\\s*\$/d > \%{_tmppath}/$p.flist\n"; #files
      print "find \$RPM_BUILD_ROOT/${p}_dir -type d|sed s^\$RPM_BUILD_ROOT/${p}_dir^^|" . &sedDirFilter  . "|sed /^\\s*\$/d|sed 's&^&\%dir &' >> \%{_tmppath}/$p.flist\n";
   }
   print "cp -ra \$RPM_BUILD_ROOT/*_dir/* \$RPM_BUILD_ROOT\n";
   print "rm -rf \$RPM_BUILD_ROOT/*_dir\n";
   print "rm -rf \$RPM_BUILD_ROOT/install\n";
   print "\n\%clean\n";
   &printFile("packer/clean", "");

   #changelog
   print "\n\%changelog\n";
   &reformatChangelog(RPM_CHANGELOG);
   
   close SPECFILE;

   #Convert the template to actual rpm specs
   #The following comments at the end of the filename are acted upon (the PACKER at the beginning and the BLAHBLAH at the end is there to make the keywords (hopefully) unique):
   #PACKER_MANDRIVA_BLAHBLAH: only use this line in the Mandriva spec file
   #PACKER_NOMANDRIVA_BLAHBLAH: use this line is every spec file but the Mandriva spec file
   #PACKER_RH_BLAHBLAH: only use this line in the Fedora/Red Hat spec file
   #PACKER_SUSE_BLAHBLAH: only use this line in the SuSE spec file
   #
   #This system is needed because Mandriva, Fedora/Redhat, and SuSE all have different categories. In edition, Mandriva uses the menu system for menu entries, while the other distributions mentioned above use the freedesktop.org menu standard
   $basename = "${spackage}-${version}-${revision}";
   &rpmSpecFilter(["RH", "SUSE", "NOMANDRIVA"], "${basename}mdk.spec");  #Mandriva
   &rpmSpecFilter(["MANDRIVA", "SUSE"], "${basename}.spec"); #Fedora/Red Hat
   &rpmSpecFilter(["MANDRIVA", "RH"], "${basename}suse.spec"); #SuSE (TODO: right name?)
   system "rm rpm/*.spec.template"; #We don't want the template file to stay around
   select STDOUT;
   print "RPM spec files generated\n";
   if ($build) {
      &populateRPMDir; #copy patches, download tarball, to SOURCES dir
      system "rpmbuild -ba rpm/*.spec";
   }
}

#TODO: sort the functions in a more logical manner (use vim folding to help do this)

sub rpmSpecFilter { #make a spec file from a spec file template
   our $comments = shift;
   our $newfile = shift;
   our $mandriva = 0;
   if ($newfile =~ /mdk/) {
      $mandriva = 1;
   }
   $ret = "cat rpm/*.spec.template";
   for (@{$comments}) {
      $ret .= "|sed /#PACKER_${_}_BLAHBLAH\$/d";
   }
   $ret .= "|sed 's/ #PACKER_[A-Z]\\+_BLAHBLAH\$//'"; #It is unprofessional to have these comments in the final spec file, especially with the BLAHBLAH
   if (!$mandriva) {
      $ret .= "|sed 's/mdk\$//'";
   }
   $ret .= " > rpm/$newfile";
   system $ret;
}

sub printCommaList { #print a list seperated by commas, or, optionally, be another seperator
   $listref = shift;
   $sep = shift;
   if (!$sep) {
      $sep = ", "; #commas by default
   }
   $first = 1;
   for (@{$listref}) {
      if (!$first) {
	 print $sep;
      }
      else {
	 $first = 0;
      }
      print $_;
   }
}

sub reformatChangelog { #the changelog format is so similar to the debian format that deb doesn't need this function
   undef @items;
   undef $date;
   undef $version;
   undef $sig;

   $type = shift;
   for (&parseESV("packer/changelog")) {
      if (/^(...,.*)$/) {
	 $date = $_;
      }
      elsif (/^\*(.*)$/) {
	 push @items, $1;
      }
      elsif  (/^-- (.*)$/) { #sig line; end of this entry
	 $sig = $1;
	 if ($type == RPM_CHANGELOG) {
	    print "* ";
	    $date =~ /^([A-Z][a-z]{2}), (\d\d) ([A-Z][a-z]{2}) (\d{4})/;
	    print "$1 $3 $2 $4 $sig ${version}mdk\n";
	    for (@items) {
	       print "- $_\n";
	    }
	 }
	 undef @items;
	 undef $date;
	 undef $version;
	 undef $sig;
      }
      else {
	 $version = $_;
      }
   }
}

sub deb { #TODO: configuration files
   $build = shift;
   $force = shift;

   &checkfiles;
   &checkpversion;
   &checkdir("debian", $force);

   #source package name
   $spackage = &parseSingleLine("packer/spackage");

   #changelog
   #changelog format example (note the lack of whitespace):
   #0.1-2
   #DATE
   #*added better description
   #-- John Smith <jsmith@smith.name>
   #0.1-1
   #*initial packaging
   #-John Smith <jsmith@smith.name>
   open PCHANGELOG, "< packer/changelog" or die "cannot open packer/changelog\n";
   open DCHANGELOG, "> debian/changelog" or die "cannot open debian/changelog\n";
   select DCHANGELOG;

   $first = 1;
   while (<PCHANGELOG>) {
      $line = $_;
      chomp $line;
      if (substr($line, 0, 1) eq "*") {
	 print "  " . $line . "\n";
      }
      elsif (substr($line, 0, 1) eq "-") {
	 print " " . $line . "  " . $date . "\n";
	 undef $date;
      }
      else {
	 if ($line =~ /^([^A-Za-z].*)-(.*)$/) {
	    $cversion = $1;
	    $crevision = $2;
	    if ($first) { #the first entry is the newest and current entry
	       $version = $cversion;
	       # $revision = $crevision;
	       $first = 0;
	    }
	    else {
	       print "\n";
	    }
	    print "$spackage ($cversion-$crevision) unstable; urgency=low\n";
	 }
	 else { #The date
	    $date = $line; #will insert when we do the sig
	 }
      }
   }
   print "\n";
   close PCHANGELOG;
   close DCHANGELOG;

   $license = &parseSingleLine("packer/license");

   #control
   open CONTROL, "> debian/control" or die "cannot write to debian/control";
   select CONTROL;
   print "Source: $spackage\n";
   print "Priority: optional\n";
   print "Maintainer: " . &parseSingleLine("packer/packager")  . "\n";
   print "Section: " . &parseSingleLine("packer/" . &parseSingleLine("packer/packages") . ".sect_debian") . "\n";
   print "Build-Depends: cdbs, debhelper (>= 4.1.0)";
   @bdeps = &parseESV("packer/bdeps");
   if (&allIndep) {
      push @bdepsi, @bdeps;
      undef @bdeps;
   }
   else {
      for (@bdeps) {
	 if (/^\s*$/) {next;} #ignore if it is just a blank line
	 elsif (/^di:(.*)$/) {push @bdepsi, $1;}
	 elsif (m#^/#) {
	    $dep = &deb_search_file($_);
	    print ", " . $dep;
	 }
	 elsif (m#^d:(.*)#) {
	    print ", " . $1;
	 }
      }
   }
   print "\n";
   if (@bdepsi) {
      $first = 1;
      print "Build-Depends-Indep: ";
      for (@bdepsi) {
	 if (!$first) {
	    print ", ";
	 }
	 else {
	    $first = 0;
	 }
	 if (m#^/#) {
	    print &deb_search_file($_);
	 }
	 elsif (m#^di?:(.*)#) {
	    print $1;
	 }
      }
      print "\n";
   }
   print "Standards-Version: 3.6.2.1\n\n";

   @package_names = &parseESV("packer/packages");
   for (@package_names) {
      $pname = $_;
      print "Package: " . $_ . "\n";

      print "Section: ";
      if ($license eq "Nonfree") {
	 print "nonfree/";
      }
      print &parseSingleLine("packer/$pname.sect_debian");
      
      print "\nArchitecture: ";
      if (&parseSingleLine("packer/$_.type") eq "i") {print "all\n";}
      else {print "any\n";}
      print 'Depends: ${shlib:Depends}, ${misc:Depends}';
      for (&parseESV("packer/$_.deps")) {
	 if (/^\//) { #if it starts with a /, and is therefore assumed to be an absolute file name
	    $dep = &deb_search_file($_);
	    $dep =~ s#python\d\.\d-(.*)#python-$1#;
	    push @deps, $dep;
	 }
	 elsif (/^d:/) { #it is a debian package; TODO: document this
	    push @deps, $_;
	 }
	 elsif (/^r:/) { #it is an RPM file
	 }
	 elsif (/^g:/) { #it is a gentoo package
	 }
	 elsif (/^dr:(.*)/) { #debian:recommends
	    push @rec, $1;
	 }
	 elsif (/^ds:(.*)/) { #debian:suggetsion
	    push @sug, $1;
	 }
	 else { #it is another package included in this file
	    push @deps, $_;
	 }
      }
      if (@deps) {
	 print ", ";
	 &printCommaList(\@deps);
	 print "\n";
	 undef @deps;
      }
      if (@rec) {
	 print "Recommends: ";
	 &printCommaList(\@rec);
	 print "\n";
      }
      if (@sug) {
	 print "Suggests: ";
	 &printCommaList(\@sug);
	 print "\n";
      }
      print "Description: " . &parseSingleLine("packer/$pname.desc") . "\n";
      open LDESC, "< packer/$pname.ldesc" or &bye;
      while (<LDESC>) {
	 chomp;
	 if (/^\s*$/) {
	    print " .\n";
	 }
	 else {
	    print " $_\n";
	 }
      }
      close LDESC;
      print "\n";
   }
   close CONTROL;

   #Copyright file
   open COPYRIGHT, "> debian/copyright" or &bye;
   select COPYRIGHT;
   print "This package was debianized using packer version $pversion ($packerUrl) by " . &parseSingleLine("packer/packager") . " on " . `date -R` . "\n"; #again, date provides 1 \n
   print "The software was downloaded from " . &parseSingleLine("packer/source") . "\n\n";
   print &parseSingleLine("packer/copyright") . "\n\n";
   if ($license eq "GPL" || $license eq "GPL-2" || $license eq "BSD" || $license eq "Artistic" || $license eq "LGPL-2" || $license eq "LGPL" || $license eq "LGPL-2.1") {
      print "Licensed under the $license, which can be found in /usr/share/common-licenses/$license.\n";
   }
   else {
      print "The license is as follows:\n";
      $lfile = "";
      if (-e "COPYING") {
	 $lfile = "COPYING";
      }
      elsif (-e "LICENSE") {
	 $lfile = "LICENSE";
      }
      else {
	 die "Error: you must have the license in either COPYING or LICENSE.";
      }
      open LICENSE, "< $lfile" or &bye;
      while (<LICENSE>) {print;}
      close LICENSE;
   }
   close COPYRIGHT;
   
   system "cp packer/docs debian/docs";
   system "cp packer/config debian/conffiles";
   #TODO doc-base

   #postinstallation things
   for (&parseESV("packer/packages")) {
      $p = $_;
      $pfile = "packer/" . $p . ".postinst";
      $new = "debian/$p.postinst";
      open POSTINST, "> $new" or &bye;
      select POSTINST;
      print "#!/bin/sh\n\n";
      print "if [[ \"\$1\" != \"configure\" ]]; then exit 0; fi\n";
      if (&packageHasDesktop($p)) {
	 print &updateDD . &updateM;
      }
      &printFile($pfile, "");
      close POSTINST;
      system "chmod 755 $new";

      #postrm
      if (&packageHasDesktop($p)) {
	 $new =~ s#.postinst$#.postrm#;
	 open POSTRM, "> $new";
	 select POSTRM;
	 print "#!/bin/sh\n\n";
	 print &updateDD . &updateM;
	 close POSTRM;
	 system "chmod 755 $new";
      }
   }
   
   #rules
   @packages = &parseESV("packer/packages");
   open RULES, "> debian/rules" or &bye;
   select RULES;
   print "#!/usr/bin/make -f\n\n";
   print "#Automatically generated by packer $pversion ($packerUrl).\n";
   print "#Thus, it may be a bad idea to modify this file, as changes will be overridden if the file is regenerated.\n";
   print "#If there are changes that need to be made to this file, please file a bug report with packer so that the changes can be made without directly modifying this file.\n\n";
   print "include /usr/share/cdbs/1/rules/debhelper.mk\n\n";
   print "include /usr/share/cdbs/1/rules/simple-patchsys.mk\n\n";
   for (@packages) {
      $nname = $_;
      $nname =~ s/-/_/g;
      print "$nname" . "_dir=\`pwd\`/debian/$_" . "\n";
   }
   print "install_dir=\`pwd\`/debian/tmp\n";
   print "\n";
   $first = 1;
   @package_names = @packages;
   for (@packages) {
      $p = $_;
      print "binary-install/$p";
      print "::";
      if (!$first) {
	 print "binary-install/$package_names[0]";
      }
      print "\n";
      if ($first) {
	 &printFile("packer/build", "\t");
	 &printFile("packer/install", "\t");
	 &printFile("packer/split", "\t");
	 for (@package_names) { #desktop files and menu files
	    $package = $_;
	    print "\tmkdir -p debian/$package/usr/share/menu\n";
	    for (<packer/$package.ds>) {
	       @desktops = &parseESV($_);
	       if (@desktops > 0) {
		  for (@desktops) {
		     $desktop = $_;
		     $desktop =~ s#^.*/##;
		     $desktop = "debian/$package/usr/share/applications/" . $desktop;
		     print "\tsed s/\\\\.png\$\\/.xpm/ $desktop> $desktop\n";
		     our $cat = &parseSingleLine("packer/$package.sect_dmenu");
		     system "desktop2menu -d $package '$cat' $_.desktop";
		     s#\.desktop$#.menu#;
		     $menu = "$_.menu";
		     s#^.*/##;
		     s#\.menu$##;
		     print "\tcp $menu debian/$package/usr/share/menu/$_\n";
		  }
		  print "\n";
	       }
	    }
	    for (<packer/$package.is>) {
	       for (&parseESV($_)) {
		  print "\tdh_install -p$package $_ usr/share/pixmaps\n";
	       }
	    }
	 }
	 $first = 0;
      }
   }
   print "clean::\n";
   &printFile("packer/clean", "\t");
   close RULES;
   system "chmod u+x debian/rules";
   select STDOUT;
   print "Debian package source files generated\n";

   #watch file
   $tb = &parseSingleLine("packer/tarball");
   $tb =~ s/\[\[version\]\]/\(\.\*\)/g;
   $tb =~ s/\./\\./g;
   open WATCH, "> debian/watch" or &bye;
   select WATCH;
   print "version=3\n";
   print "$tb\n";
   close WATCH;

   #patches
   if (-e "packer/patches") {
      system("cp -r packer/patches debian"); #easy as that
      system("rm -f debian/patches/differ.diff");
   }
   system "rm -f debian/patches/differ.dif"; #not wanted for this build method; will appear in .diff.gz

   if ($build) {
      #Make sure that the orig.tar.gz is there
      $tarball_url = &parseSingleLine("packer/tarball");
      $version = &parseSingleLine("packer/version");
      $tarball_url =~ s#\[\[version\]\]#$version#g;
      $tarball_real = $tarball_url;
      $tarball_real =~ s#^.*/##;
      $tarball = $tarball_real;
      $bzip = 0;
      if ($tarball =~ s#.bz2$#.gz#) {
	 $bzip = 1;
      }
      $tarball_orig = $tarball;
      $tarball_orig =~ s#.tar.gz$#.orig.tar.gz#;
      $tarball_orig =~ s#-(\d)#_$1#;
      if (! -e "../$tarball_orig") {
	 system "wget $tarball_url -O ../$tarball_real\n";
	 if ($bzip) {
	    system "bunzip2 ../$tarball_real";
	    $tarball_real =~ s#.bz2$##;
	    system "gzip -9 ../$tarball_real";
	 }
	 system "mv ../$tarball ../$tarball_orig";
      }
      
      #Cannot let rpm, other dirs, get in the way in the .diff.gz process
      system "dpkg-buildpackage -rfakeroot -tc -i'((rpm)|(slack)|(autopackage)|(gentoo)|(packer))/.*'";
   }
}

