#!/usr/bin/perl
# Copyright (c) 2002-2005 Mathieu Roy <yeupou@gnu.org>
# This file is part of Package DataBase View
# This file was generated Tue Nov 16 05:34:28 UTC 2010
#
# FULL AUTHORS LIST:
#     Lead:
#     	Mathieu Roy <yeupou--gnu.org>
#     
#     Portuguese (and Brazillian) translation:
#     	Paulo Miguel Peralta Ferreira <pmpf--ist.utl.pt>
#     
#     Spanish translation + a lot of dpkg-related code enhancement:
#     	Federico Montesino Pouzols <fedemp--suidzer0.org>
#     
#     Polish translation:
#     	Arkadiusz Lipiec <A.Lipiec--elka.pw.edu.pl>
#     
#     German translation + Debian packaging + man pages writing:
#     	Florian M. Weps <fmw--at--debian.org>
#     
#     Romanian translation:
#     	Eugen Hoanca <eugenh--urban-grafx.ro>
#     
#     Dutch translation:
#     	Geert Vanderkelen <geert--kemuri.org>
#     
#     Russian translation:
#     	Sergey Baturov <sbaturov--abrazive.spb.ru>
#     
#     Italian translation:
#     	John Flemmings <tungsten180--hotmail.com> Marco Colombo
#     	<m.colombo--ed.ac.uk>
#     
#     Catalan translation:
#     	David Rosal <davidrr--menta.net>
#     
#     Swedish translation:
#     	Daniel Nylander <po--danielnylander.se>
#     
#     Vietnamese translation:
#     	Clytie Siddall <clytie--riverland.net.au>
#     
#     Debian packaging help and fixes:
#     	Jrme Marant <jmarant--nerim.net> Alexis
#     	Sukrieh <sukria--debian.org> Christian Perrier
#     	<bubulle--debian.org>
#     
#     Debian packaging internationalization:
#     	Martin Quinson <Martin.Quinson--tuxfamily.org>
#     	Michel Grentzinger <mic.grentz---online.fr> Miroslav
#     	Kure <kurem--upcase.inf.upol.cz> Christian Perrier
#     	<bubulle--debian.org>
#
# LICENSE:
#     		    GNU GENERAL PUBLIC LICENSE
#     		       Version 2, June 1991
#     
#      Copyright (C) 1989, 1991 Free Software Foundation, Inc.
#     		       59 Temple Place, Suite 330, Boston,
#     		       MA  02111-1307  USA
#      Everyone is permitted to copy and distribute verbatim copies
#      of this license document, but changing it is not allowed.
#     
#     			    Preamble
#     
#       The licenses for most software are designed to take away your
#     freedom to share and change it.  By contrast, the GNU General
#     Public License is intended to guarantee your freedom to share
#     and change free software--to make sure the software is free for
#     all its users.	This General Public License applies to most of
#     the Free Software Foundation's software and to any other program
#     whose authors commit to using it.  (Some other Free Software
#     Foundation software is covered by the GNU Library General Public
#     License instead.)  You can apply it to your programs, too.
#     
#       When we speak of free software, we are referring to freedom,
#       not
#     price.	Our General Public Licenses are designed to make
#     sure that you have the freedom to distribute copies of free
#     software (and charge for this service if you wish), that you
#     receive source code or can get it if you want it, that you can
#     change the software or use pieces of it in new free programs;
#     and that you know you can do these things.
#     
#       To protect your rights, we need to make restrictions that
#       forbid
#     anyone to deny you these rights or to ask you to surrender
#     the rights.  These restrictions translate to certain
#     responsibilities for you if you distribute copies of the
#     software, or if you modify it.
#     
#       For example, if you distribute copies of such a program,
#       whether
#     gratis or for a fee, you must give the recipients all the
#     rights that you have.  You must make sure that they, too,
#     receive or can get the source code.  And you must show them
#     these terms so they know their rights.
#     
#       We protect your rights with two steps: (1) copyright the
#       software, and
#     (2) offer you this license which gives you legal permission
#     to copy, distribute and/or modify the software.
#     
#       Also, for each author's protection and ours, we want to
#       make certain
#     that everyone understands that there is no warranty for this
#     free software.	If the software is modified by someone else
#     and passed on, we want its recipients to know that what they
#     have is not the original, so that any problems introduced by
#     others will not reflect on the original authors' reputations.
#     
#       Finally, any free program is threatened constantly by software
#     patents.  We wish to avoid the danger that redistributors
#     of a free program will individually obtain patent licenses,
#     in effect making the program proprietary.  To prevent this,
#     we have made it clear that any patent must be licensed for
#     everyone's free use or not licensed at all.
#     
#       The precise terms and conditions for copying, distribution and
#     modification follow.  
#     		    GNU GENERAL PUBLIC LICENSE
#        TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
#        MODIFICATION
#     
#       0. This License applies to any program or other work which
#       contains
#     a notice placed by the copyright holder saying it may be
#     distributed under the terms of this General Public License.
#     The "Program", below, refers to any such program or work, and a
#     "work based on the Program" means either the Program or any
#     derivative work under copyright law: that is to say, a work
#     containing the Program or a portion of it, either verbatim or
#     with modifications and/or translated into another language.
#     (Hereinafter, translation is included without limitation in
#     the term "modification".)  Each licensee is addressed as "you".
#     
#     Activities other than copying, distribution and modification
#     are not covered by this License; they are outside its scope.
#     The act of running the Program is not restricted, and the output
#     from the Program is covered only if its contents constitute a
#     work based on the Program (independent of having been made by
#     running the Program).  Whether that is true depends on what
#     the Program does.
#     
#       1. You may copy and distribute verbatim copies of the
#       Program's
#     source code as you receive it, in any medium, provided that
#     you conspicuously and appropriately publish on each copy an
#     appropriate copyright notice and disclaimer of warranty; keep
#     intact all the notices that refer to this License and to the
#     absence of any warranty; and give any other recipients of the
#     Program a copy of this License along with the Program.
#     
#     You may charge a fee for the physical act of transferring a
#     copy, and you may at your option offer warranty protection in
#     exchange for a fee.
#     
#       2. You may modify your copy or copies of the Program or
#       any portion
#     of it, thus forming a work based on the Program, and copy and
#     distribute such modifications or work under the terms of Section
#     1 above, provided that you also meet all of these conditions:
#     
#         a) You must cause the modified files to carry prominent
#         notices stating that you changed the files and the date
#         of any change.
#     
#         b) You must cause any work that you distribute or publish,
#         that in whole or in part contains or is derived from the
#         Program or any part thereof, to be licensed as a whole at no
#         charge to all third parties under the terms of this License.
#     
#         c) If the modified program normally reads commands
#         interactively when run, you must cause it, when started
#         running for such interactive use in the most ordinary way,
#         to print or display an announcement including an appropriate
#         copyright notice and a notice that there is no warranty
#         (or else, saying that you provide a warranty) and that
#         users may redistribute the program under these conditions,
#         and telling the user how to view a copy of this License.
#         (Exception: if the Program itself is interactive but does
#         not normally print such an announcement, your work based
#         on the Program is not required to print an announcement.)
#      These requirements apply to the modified work as a whole.
#     If identifiable sections of that work are not derived from
#     the Program, and can be reasonably considered independent and
#     separate works in themselves, then this License, and its terms,
#     do not apply to those sections when you distribute them as
#     separate works.  But when you distribute the same sections
#     as part of a whole which is a work based on the Program,
#     the distribution of the whole must be on the terms of this
#     License, whose permissions for other licensees extend to the
#     entire whole, and thus to each and every part regardless of
#     who wrote it.
#     
#     Thus, it is not the intent of this section to claim rights or
#     contest your rights to work written entirely by you; rather,
#     the intent is to exercise the right to control the distribution
#     of derivative or collective works based on the Program.
#     
#     In addition, mere aggregation of another work not based on the
#     Program with the Program (or with a work based on the Program)
#     on a volume of a storage or distribution medium does not bring
#     the other work under the scope of this License.
#     
#       3. You may copy and distribute the Program (or a work based
#       on it,
#     under Section 2) in object code or executable form under the
#     terms of Sections 1 and 2 above provided that you also do one
#     of the following:
#     
#         a) Accompany it with the complete corresponding
#         machine-readable source code, which must be distributed
#         under the terms of Sections 1 and 2 above on a medium
#         customarily used for software interchange; or,
#     
#         b) Accompany it with a written offer, valid for at least
#         three years, to give any third party, for a charge no
#         more than your cost of physically performing source
#         distribution, a complete machine-readable copy of the
#         corresponding source code, to be distributed under the
#         terms of Sections 1 and 2 above on a medium customarily
#         used for software interchange; or,
#     
#         c) Accompany it with the information you received as
#         to the offer to distribute corresponding source code.
#         (This alternative is allowed only for noncommercial
#         distribution and only if you received the program in object
#         code or executable form with such an offer, in accord with
#         Subsection b above.)
#     
#     The source code for a work means the preferred form of the
#     work for making modifications to it.  For an executable work,
#     complete source code means all the source code for all modules
#     it contains, plus any associated interface definition files,
#     plus the scripts used to control compilation and installation
#     of the executable.  However, as a special exception, the source
#     code distributed need not include anything that is normally
#     distributed (in either source or binary form) with the major
#     components (compiler, kernel, and so on) of the operating
#     system on which the executable runs, unless that component
#     itself accompanies the executable.
#     
#     If distribution of executable or object code is made by offering
#     access to copy from a designated place, then offering equivalent
#     access to copy the source code from the same place counts as
#     distribution of the source code, even though third parties are
#     not compelled to copy the source along with the object code.  
#       4. You may not copy, modify, sublicense, or distribute
#       the Program
#     except as expressly provided under this License.  Any attempt
#     otherwise to copy, modify, sublicense or distribute the Program
#     is void, and will automatically terminate your rights under
#     this License.  However, parties who have received copies, or
#     rights, from you under this License will not have their licenses
#     terminated so long as such parties remain in full compliance.
#     
#       5. You are not required to accept this License, since you
#       have not
#     signed it.  However, nothing else grants you permission to
#     modify or distribute the Program or its derivative works.
#     These actions are prohibited by law if you do not accept
#     this License.  Therefore, by modifying or distributing the
#     Program (or any work based on the Program), you indicate your
#     acceptance of this License to do so, and all its terms and
#     conditions for copying, distributing or modifying the Program
#     or works based on it.
#     
#       6. Each time you redistribute the Program (or any work based
#       on the
#     Program), the recipient automatically receives a license
#     from the original licensor to copy, distribute or modify the
#     Program subject to these terms and conditions.	You may not
#     impose any further restrictions on the recipients' exercise
#     of the rights granted herein.  You are not responsible for
#     enforcing compliance by third parties to this License.
#     
#       7. If, as a consequence of a court judgment or allegation
#       of patent
#     infringement or for any other reason (not limited to patent
#     issues), conditions are imposed on you (whether by court
#     order, agreement or otherwise) that contradict the conditions
#     of this License, they do not excuse you from the conditions
#     of this License.  If you cannot distribute so as to satisfy
#     simultaneously your obligations under this License and any
#     other pertinent obligations, then as a consequence you may not
#     distribute the Program at all.	For example, if a patent license
#     would not permit royalty-free redistribution of the Program by
#     all those who receive copies directly or indirectly through you,
#     then the only way you could satisfy both it and this License
#     would be to refrain entirely from distribution of the Program.
#     
#     If any portion of this section is held invalid or unenforceable
#     under any particular circumstance, the balance of the section
#     is intended to apply and the section as a whole is intended
#     to apply in other circumstances.
#     
#     It is not the purpose of this section to induce you to
#     infringe any patents or other property right claims or to
#     contest validity of any such claims; this section has the
#     sole purpose of protecting the integrity of the free software
#     distribution system, which is implemented by public license
#     practices.  Many people have made generous contributions to
#     the wide range of software distributed through that system
#     in reliance on consistent application of that system; it is
#     up to the author/donor to decide if he or she is willing to
#     distribute software through any other system and a licensee
#     cannot impose that choice.
#     
#     This section is intended to make thoroughly clear what is
#     believed to be a consequence of the rest of this License.  
#       8. If the distribution and/or use of the Program is
#       restricted in
#     certain countries either by patents or by copyrighted
#     interfaces, the original copyright holder who places the Program
#     under this License may add an explicit geographical distribution
#     limitation excluding those countries, so that distribution
#     is permitted only in or among countries not thus excluded.
#     In such case, this License incorporates the limitation as if
#     written in the body of this License.
#     
#       9. The Free Software Foundation may publish revised and/or
#       new versions
#     of the General Public License from time to time.  Such new
#     versions will be similar in spirit to the present version,
#     but may differ in detail to address new problems or concerns.
#     
#     Each version is given a distinguishing version number.	If the
#     Program specifies a version number of this License which
#     applies to it and "any later version", you have the option of
#     following the terms and conditions either of that version or of
#     any later version published by the Free Software Foundation.
#     If the Program does not specify a version number of this
#     License, you may choose any version ever published by the Free
#     Software Foundation.
#     
#       10. If you wish to incorporate parts of the Program into
#       other free
#     programs whose distribution conditions are different, write
#     to the author to ask for permission.  For software which is
#     copyrighted by the Free Software Foundation, write to the Free
#     Software Foundation; we sometimes make exceptions for this.
#     Our decision will be guided by the two goals of preserving
#     the free status of all derivatives of our free software and
#     of promoting the sharing and reuse of software generally.
#     
#     			    NO WARRANTY
#     
#       11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE
#       IS NO WARRANTY
#     FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
#     EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS
#     AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
#     WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
#     BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
#     AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
#     TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.
#     SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
#     ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
#     
#       12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED
#       TO IN WRITING
#     WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
#     AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE
#     TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL
#     OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY
#     TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
#     OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU
#     OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH
#     ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS
#     BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
#     
#     		     END OF TERMS AND CONDITIONS
#     
#     	    How to Apply These Terms to Your New Programs
#     
#       If you develop a new program, and you want it to be of
#       the greatest
#     possible use to the public, the best way to achieve this is
#     to make it free software which everyone can redistribute and
#     change under these terms.
#     
#       To do so, attach the following notices to the program.
#       It is safest
#     to attach them to the start of each source file to most
#     effectively convey the exclusion of warranty; and each file
#     should have at least the "copyright" line and a pointer to
#     where the full notice is found.
#     
#         <one line to give the program's name and a brief idea of
#         what it does.> Copyright (C) <year>  <name of author>
#     
#         This program is free software; you can redistribute it
#         and/or modify it under the terms of the GNU General Public
#         License as published by the Free Software Foundation;
#         either version 2 of the License, or (at your option)
#         any later version.
#     
#         This program is distributed in the hope that it will
#         be useful, but WITHOUT ANY WARRANTY; without even the
#         implied warranty of MERCHANTABILITY or FITNESS FOR A
#         PARTICULAR PURPOSE.  See the GNU General Public License
#         for more details.
#     
#         You should have received a copy of the GNU General Public
#         License along with this program; if not, write to the Free
#         Software Foundation, Inc., 59 Temple Place, Suite 330,
#         Boston, MA	02111-1307  USA
#     
#     
#     Also add information on how to contact you by electronic and
#     paper mail.
#     
#     If the program is interactive, make it output a short notice
#     like this when it starts in an interactive mode:
#     
#         Gnomovision version 69, Copyright (C) year name of author
#         Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
#         type `show w'.  This is free software, and you are welcome
#         to redistribute it under certain conditions; type `show c'
#         for details.
#     
#     The hypothetical commands `show w' and `show c' should show the
#     appropriate parts of the General Public License.  Of course,
#     the commands you use may be called something other than `show
#     w' and `show c'; they could even be mouse-clicks or menu
#     items--whatever suits your program.
#     
#     You should also get your employer (if you work as a programmer)
#     or your school, if any, to sign a "copyright disclaimer" for
#     the program, if necessary.  Here is a sample; alter the names:
#     
#       Yoyodyne, Inc., hereby disclaims all copyright interest in
#       the program `Gnomovision' (which makes passes at compilers)
#       written by James Hacker.
#     
#       <signature of Ty Coon>, 1 April 1989 Ty Coon, President
#       of Vice
#     
#     This General Public License does not permit incorporating
#     your program into proprietary programs.  If your program is
#     a subroutine library, you may consider it more useful to
#     permit linking proprietary applications with the library.
#     If this is what you want to do, use the GNU Library General
#     Public License instead of this License.
#     
#     
#
#  take a look at http://gna.org/projects/pdbv
#  send comments at <pdbv-dev@gna.org>
#  --"read-only" script, checkout the CVS tree or a tarball--
#  --if you want to modify it with ease--
use strict "vars";
use Locale::gettext;
use POSIX;
use Getopt::Long;
use Term::ANSIColor qw(:constants);
use File::stat;
use Sys::Hostname;
use Tie::IxHash;
setlocale(LC_ALL, "");
textdomain("pdbv");
our $pdbv_type = "rpm";
our $dpkg_dir="/var/lib/dpkg";
our $sname = "pdbv";
our $sver = "2.0.10";
our $sauthor = "Mathieu Roy";
our $smail = "pdbv-dev\@gna.org";
our $surl = "http://gna.org/projects/pdbv";
our $confdir = "/etc/pdbv";
our $sleep = "1";
our $does_new_package_exist = "0";
our $does_orphan_exist = "0";
our $output;
our $output_ext;
our $tag_item_title_open;
our $tag_item_title_close;
our $tag_line_break;
our $cron;
our $cron_lang;
our $debug;
our $force;
our $listing;
our $output_dir;
our $working_dir;
our $light;
our $css;
our $working_dir_css;
our $getopt;
our $arg_help;
our $arg_version;
our $arg_cron;
our $arg_xhtml;
our $epoch_start = time;
our $sbst_unable_to_open = gettext("Unable to open ");
our $popcon_file = "/var/log/popularity-contest";
our $package_info_baseurl;
our $package_installedsize_sum;
our $package_popularity_activated;
our $package_explanationurl_priority;
our %section_packages_sum;
tie %section_packages_sum, "Tie::IxHash";
our %usage_packages_sum;
tie %usage_packages_sum, "Tie::IxHash";
our %package_conffiles;
our %package_configversion;
our %package_conflicts;
our %package_depends;
our %package_description_short;
our %package_description;
our %package_enhances;
our %package_essential;
our %package_installedsize;
our %package_installdate;
our %package_license;
our %package_maintainer;
our %package_origin;
our %package_popularity;
our %package_priority;
our %package_provides;
our %package_recommends;
our %package_replaces;
our %package_section;
our %package_source;
our %package_status;
our %package_suggests;
our %package_version;
our %package_website;
$package_info_baseurl = "http://www.rpmfind.net/linux/rpm2html/search.php?query=";
$package_installedsize_sum;
our @package_list;
sub PdbvPackageInit {
    # First, get one-line information
    my $rpmopt = "-qa --qf \'%{NAME}##%{VERSION}-%{RELEASE}##%{INSTALLTIME:date}##%{SIZE}##%{LICENSE}##%{PACKAGER}##%{GROUP}##%{SOURCERPM}##%{URL}
\'";
    open(STATUS, "rpm $rpmopt |");    
    while (<STATUS>) {
	# Figure out the package name
	my ($pack, $version) = split("##", $_);
	push(@package_list, $pack) if $pack && $version;
	next unless $pack && $version;
	my ($donotcare);
	($donotcare,
	 $package_version{$pack},
	 $package_installdate{$pack},
	 $package_installedsize{$pack},
	 $package_license{$pack},
	 $package_maintainer{$pack},
	 $package_section{$pack},
	 $package_source{$pack},
	 $package_website{$pack}) = split("##", $_); 
        # Misc formating stuff
	$package_installdate{$pack} = PdbvDate($package_installdate{$pack});
        # Whole database installed-size
	$package_installedsize_sum = ($package_installedsize{$pack} + $package_installedsize_sum);
	# Get more-than-one-line data
	$package_description{$pack} = PdbvQuery($pack, "--qf '%{DESCRIPTION}'");
	$package_depends{$pack} = PdbvQuery($pack, "--requires");
	$package_provides{$pack} = PdbvQuery($pack, "--provides");
    }    
    close(STATUS);
    @package_list = sort(@package_list);
}
sub PdbvPackagemanagerVersion {
    my $ret = `rpm --version | head -n 1`;
    chomp($ret);
    $ret =~ s/\.$//;
    return $ret;
}
sub PdbvPackages {
    return @package_list;
}
sub PdbvPackagesSorted {
    return @package_list;
}
sub PdbvBasename {
    my $ret = `rpm -q "$_[0]" --qf '%{NAME}'`;
    return $ret;
}
sub PdbvList {
    # --status give a --list with more informations.
    # will change probably someday
    my $ret = `rpm -q --list "$_[0]"`;
    return $ret;
}
sub PdbvQuery {
    # For data that does not fit one line, that miserably broke things.
    # (You're are welcome to provide patches)
    my $ret = `rpm -q "$_[0]" $_[1]`;
    return $ret;
}
sub PdbvDate { 
    my ($dayname, $day, $month, $year) = split(" ", $_[0]);
    return $year." ".$month;
}
sub PdbvSysinfoGetDistro {
    my $hdist = 0;
    my $ret;
    my $debian_rel = "/etc/debian_version";
    my $redhat_rel = "/etc/redhat-release";
    my $url;
    if (-e $redhat_rel) {
	$hdist = $redhat_rel;
    } elsif (-e $debian_rel) {
	$hdist = $debian_rel;
	$url = "http://www.debian.org";
	$ret = gettext("Debian GNU release ");
    }
    
    if ($hdist) {
	open(FILE, $hdist);
	while (<FILE>) {
	    $ret .= $_; 
	}
	close(FILE);
    } else {
	$ret = gettext("unknown distribution");
    }
    
    if ($url) {
	# This is XHTML specific, should be removed if we add another
	# ouput type.
	return "<a href=\"".$url."\">".$ret."</a>";
    } else {
	return $ret;
    }
}
sub PdbvSysinfoGetUnameKernel {
    my $uname_s = `uname -s 2> /dev/null`;
    my $uname_mr = `uname -mr 2> /dev/null`;
    my $uname_v = `uname -v 2> /dev/null`;
    chomp($uname_s, $uname_mr, $uname_v);
    my $uname_smr = "$uname_s $uname_mr";
    return sprintf(gettext("kernel %s, compiled %s"), $uname_smr, $uname_v);
}
sub PdbvSysinfoGetUnameCpu {
    # We cannot rely on uname, linux does not provide correct informations
    # with something else than /proc/cpuinfo.
    #
    # So we work on /proc/cpuinfo. If it's too much work to maintain it,
    # we'll drop it.
    #
    # If you get "Processor Unknown" or something inappropriate,
    # you can give us the content of/proc/cpuinfo at
    # http://savannah.nongnu.org/bugs/?func=detailbug&bug_id=3751&group_id=2348
    # or at <pdbv-dev@nongnu.org>.
    # If you system does not have /proc/cpuinfo (hurd), you can tell us
    # how to get these informations.
    my $cpuinfo = "/proc/cpuinfo";
    if (-r $cpuinfo) {
	# Look for raw data, ok for:
	# i*86, powerpc, s390, hppa, alpha, ia64, sparc
	my $smp;
	my $bogomips;
	my $vendor;
	my $model;
	my $mhz;
	my $cache;
	my $bogomips;
	# We need to reset the input separator (set by dpkg.pl)
	my $is = $/;
	$/ = "\n";
	open(CPUINFO, "< $cpuinfo");
	while (<CPUINFO>) {
	    # Number of processors
	    if (m/^(processor(.*: \d| \d)|CPU\d)/i) {
		$smp++;
	    }
	    
	    # Details
	    if (m/^vendor/i) {
		# Ex: GenuineIntel
		s/[vendor|machine].*: (.*)/$1/i;
		chomp;
		$vendor = $_;
	    next;
	    }
	    if (m/^(cpu family)/i && !$vendor) {
		# Ex: PA-RISC 2.0 
		s/cpu family.*: (.*)/$1/i;
		chomp;
		$vendor = $_;
		next;	    
	    }
	    if (m/^(model name|cpu model|family|processor.*: Intel|cpu.*:.*Sparc)/i) {
		# Ex: Intel(R) Pentium(R) 4 CPU 1.70GHz
		#     PCA56 
		#     Itanium
		#     Intel StrongARM-110 rev 3 (v4l) 
		#     TI UltraSparc II (BlackBird) 
		s/^[model name|cpu model|family|processor|cpu].*: (.*)/$1/i;
		chomp;
		$model = $_;
		next;
	    }
	    if (m/^(cpu Mhz|clock)/i) {
		# Ex: 1700.121
		s/^[cpu Mhz|clock].*: (.*)/$1/i;
		chomp;
		$mhz = $_;
		next;
	    }
	    if (m/^bogomips/i) {
		# Ex: 3381.65
		s/^bogomips.*: (.*)/$1/i;
		chomp;
		$bogomips = $_;
		next;
	    }
	}
	close(CPUINFO);
	
	# Get back the input separator
	$/ = $is;
	# There must be at least one CPU
	$smp = 1 unless $smp;
	
	# Prepare the final output
	my $cpudetails;
	if ($vendor|$model) {
	    $cpudetails .= "$vendor " if $vendor;
	    $cpudetails .= "$model " if $model;
	} else {
	    $cpudetails .= gettext("unknown");
	}
	if ($mhz|$bogomips) {
	    $cpudetails .= "(";
	    $cpudetails .= "$mhz MHz, " if $mhz;
	    $cpudetails .= "$bogomips bogomips" if $bogomips;
	    $cpudetails .= ")";
	}
	
	# Print
	return $smp." ".sprintf(gettext("processor %s"), $cpudetails);
    }
}
sub PdbvSysinfoGetFree {
    # Free can be available only if there is a /proc/meminfo
    # If so, we try to use free.
    # (There is little chance that procps is not installed)
    if (-e "/proc/meminfo") {
	my $kb = gettext("kB");
	my $memtotal = `free | grep Mem | awk '{print \$2}'`;
	my $swaptotal = `free | grep Swap | awk '{print \$2}'`;
	chomp($memtotal, $swaptotal);
	
	return sprintf(gettext("%s $kb mem, %s $kb swap"), $memtotal, $swaptotal);
    }
}
my $usr_partition;
my $usr_partition_size;
sub PdbvSysinfoDetermineSystemPartitionInfo {
    # We use as possible df
    open(DF, "df /usr |");
    while (<DF>) {
	my $df;
	($df) = /^(\/.*)$/;
	($usr_partition, $usr_partition_size) = split(" ", $df);
    }
    close(DF);
}
sub PdbvSysinfoGetSystemPartition {
    return $usr_partition;
}
sub PdbvSysinfoGetSystemPartitionSize {
    return $usr_partition_size;
}
sub PdbvXhtmlInit {
    $working_dir_css = "$working_dir/style.css" unless $working_dir_css;
    $output = "xhtml" unless $output;
    $output_ext = ".html" unless $output_ext;
    $tag_item_title_open = "<font class=\"itemtitle\">";
    $tag_item_title_close = "</font>";
    $tag_line_break = "<br />";
}
sub PdbvXhtmlPrintHeader {
    # arg1 = $handle
    # arg2 = title
    # arg3 = no <body>
    # arg4 = css relative path
    my $handle = STDOUT;
    my $title = "pdbv";
    my $body = "<body><div class=\"content\">";
    my $csspath;
    $handle = $_[0] if $_[0];
    $title = $_[1] if $_[1];
    $body = "" if $_[2];
    $csspath = $_[3] if $_[3];
    print $handle "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
<html>
<head>
  <title>".$title."</title>
  <meta name=\"Generator\" content=\"".$sname." ".$sver."\" />
  <meta http-equiv=\"Content\" content=\"text/html; charset=UTF-8\" />
  <link rel=\"stylesheet\" type=\"text/css\" href=\"".$csspath."style.css\" />
</head>
".$body."\n";
}
sub PdbvXhtmlPrintFooter {
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    my $date = strftime "%c", localtime;
    print $handle "</div><p class=\"footer\"><a href=\"".$surl."\">".$sname."-".$sver."</a> ".$date."</p>
</body>
</html>\n";
}
sub PdbvXhtmlPrintListingFrame {
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    PdbvXhtmlPrintHeader($handle);
    print $handle "<p>";
    print $handle gettext("Sort by");
    print $handle " <a href=\"list".$output_ext."\" target=\"list\">".gettext("Package")."</a>";
    if ($listing) {
	print $handle " | <a href=\"list_bygroup".$output_ext."\" target=\"list\">".gettext("Section")."</a>";
	print $handle " | <a href=\"list_bydate".$output_ext."\" target=\"list\">".gettext("Date")."</a>";	
	print $handle " | <a href=\"list_byusage".$output_ext."\" target=\"list\">".gettext("Usage")."</a>" if $package_popularity_activated;
	# FIXME: Need to figure out to do that cleanly.
	#print $handle " | <a href=\"list_bysize".$output_ext."\" target=\"list\">".gettext("Size")."</a>";
    }
    print $handle "</p>";
    PdbvXhtmlPrintFooter($handle);
}
sub PdbvXhtmlPrintListFrame {
    my $handle = $_[0] if $_[0];
    my $criterion = $_[1] if $_[1];
    my $pkg_number = 0;
    PdbvXhtmlPrintHeader($handle, gettext("Package List"));
    unless ($criterion) {
	foreach my $pack (PdbvPackagesSorted()) {
	    $pkg_number++;
	    print $handle $pkg_number.". <a href=\"package/".$pack."_".$package_version{$pack}.$output_ext."\" target=\"package\">".$pack." ".$package_version{$pack}."</a>".$tag_line_break."\n";
	} 
    } else {
	my %seen_before;
	my @crit_list;
	my %crit_data;
	while(my ($key, $value) = each(%$criterion)) {
	    unless ($seen_before{$value}) {
		push(@crit_list, $value);
		$seen_before{$value} = 1;
	    }
	}
	@crit_list = sort(@crit_list);
	@crit_list = reverse(@crit_list) if $criterion eq "package_installdate";
	foreach my $crit (@crit_list) {
	    if ($criterion eq "package_installdate") {
		print $handle "<a name=\"".$crit."\" href=\"#".$crit."\" class=\"bold\">".PdbvXhtmlMakeDate($crit)."</a>".$tag_line_break;
	    } else {
		print $handle "<a name=\"".$crit."\" href=\"#".$crit."\" class=\"bold\">".$crit."</a>".$tag_line_break;
	    }
	    my $pkg_number = 0;
	    
	    foreach my $pack (PdbvPackagesSorted()) {
		if ($$criterion{$pack} eq $crit) {
		    $pkg_number++;
		    print $handle $pkg_number.". <a href=\"package/".$pack."_".$package_version{$pack}.$output_ext."\" target=\"package\">".$pack." ".$package_version{$pack}."</a>".$tag_line_break."\n";
		}
	    }
	    print $handle $tag_line_break;
	    # Store the sum of packages for each section
	    $section_packages_sum{$crit} = $pkg_number if $criterion eq "package_section";
	    $usage_packages_sum{$crit} = $pkg_number if $criterion eq "package_popularity";
	}
	
	
	
    }
    PdbvXhtmlPrintFooter($handle);
}
sub PdbvXhtmlPrintItemFrame {
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    my $ret;
    my $pack = $_[1];
    PdbvXhtmlPrintHeader($handle, $pack, 0, "../");
    # Title
    print $handle "<h2 class=\"title\">";
    print $handle gettext("Details for ");
    PdbvXhtmlPrintPackagePointer($handle, $pack);
    print $handle "</h2>";
    print $handle "<h3 class=\"itemtitle\">".$package_description_short{$pack}."</h3>"
	if $package_description_short{$pack};
    
    # General information about the package
    # (the "". is here to avoid a warning "Bareword missing")
    print $handle "".PdbvXhtmlTIT(gettext("Package:"))." ".$pack.$tag_line_break;
    print $handle "".PdbvXhtmlTIT(gettext("Version:"))." ".$package_version{$pack}.$tag_line_break
	if $package_version{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Section:"))." ".$package_section{$pack}.$tag_line_break
	if $package_section{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Priority:"))." ".PdbvXhtmlMakePriority($package_priority{$pack}).$tag_line_break
	if $package_priority{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Essential:"))." ".$package_essential{$pack}.$tag_line_break
	if $package_essential{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Status:"))." ".$package_status{$pack}.$tag_line_break
	if $package_status{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Install-Date:"))." ".PdbvXhtmlMakeDate($package_installdate{$pack}).$tag_line_break
	if $package_installdate{$pack};
    print $handle $tag_line_break;
    # Dependancies information about the package
    print $handle "".PdbvXhtmlTIT(gettext("Depends:"))." ".PdbvXhtmlMakeRelationLinks($package_depends{$pack}).$tag_line_break
	if $package_depends{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Conflicts:"))." ".PdbvXhtmlMakeRelationLinks($package_conflicts{$pack}, "conflicts").$tag_line_break
	if $package_conflicts{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Enhances:"))." ".PdbvXhtmlMakeRelationLinks($package_enhances{$pack}).$tag_line_break
	if $package_enhances{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Provides:"))." ".PdbvXhtmlMakeRelationLinks($package_provides{$pack}).$tag_line_break
	if $package_provides{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Recommends:"))." ".PdbvXhtmlMakeRelationLinks($package_recommends{$pack}).$tag_line_break
	if $package_recommends{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Suggests:"))." ".PdbvXhtmlMakeRelationLinks($package_suggests{$pack}).$tag_line_break
	if $package_suggests{$pack};
    print $handle $tag_line_break;
    # Origin and big description
    print $handle "".PdbvXhtmlTIT(gettext("Maintainer:"))." ".PdbvXhtmlMakeLinks($package_maintainer{$pack}).$tag_line_break
	if $package_maintainer{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Origin:"))." ".$package_origin{$pack}.$tag_line_break
	if $package_origin{$pack};
    if ($package_source{$pack}) {
	print $handle "".PdbvXhtmlTIT(gettext("Source:"))." ";
	PdbvXhtmlPrintPackagePointer($handle, $package_source{$pack});
	print $handle $tag_line_break;
    }
    print $handle "".PdbvXhtmlTIT(gettext("License:"))." ".$package_license{$pack}.$tag_line_break
	if $package_license{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Website:"))." ".PdbvXhtmlMakeLinks($package_website{$pack}).$tag_line_break
	if $package_website{$pack};
    print $handle "".PdbvXhtmlTIT(gettext("Description:"))." ".PdbvXhtmlMakeLinebreak(PdbvXhtmlMakeLinks($package_description{$pack}))
	if $package_description{$pack};
    
    
    # Files on the Harddisk
    if ($package_installedsize{$pack}) {
	print $handle "".PdbvXhtmlTIT(gettext("Installed-Size:"));
	PdbvXhtmlPrintSizeBox($handle, $package_installedsize{$pack});
	print $handle $tag_line_break;
    }
    # Usage of the package, via popcon.
    if ($package_popularity_activated) {
	print $handle "".PdbvXhtmlTIT(gettext("Usage:"));
	PdbvXhtmlPrintPopularityBox($handle, $package_popularity{$pack});
	print $handle $tag_line_break;
    }
    
    print $handle $tag_line_break;
    print $handle "<font class=\"itemtitle\">";
    print $handle gettext("Files:");
    print $handle "</font><br />";
    my @raw = split /^/, PdbvList($pack);
    foreach my $line (@raw) {
	$line =~ s/$/<br \/>/;
	print $handle $line;
    }
    print $handle $ret;
    PdbvXhtmlPrintFooter($handle);
}
sub PdbvXhtmlPrintInfoFrame {    
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    PdbvXhtmlPrintHeader($handle, gettext("Information"));
    
    print $handle "<p>";
    print $handle sprintf(gettext("This is the output of %s version %s, running on %s. "), "<a href=\"$surl\">$sname</a>", $sver, hostname());
    print $handle sprintf(gettext("It was generated in %s."), PdbvExecutionTime());
    print $handle "</p>";
    
    print $handle "<h2>".gettext("Packages Database Information")."</h2>";
    print $handle "<p>";
    print $handle sprintf(gettext("There are %s packages in the database."), scalar(@package_list));
    if ($package_installedsize_sum) {
	print $handle " ".sprintf(gettext("Installed packages take around %s of disk space."), PdbvXhtmlMakeSize($package_installedsize_sum));
    }
    print $handle "</p>";
    # For each section, show the number of packages found (active only if
    # section listing was made or if there's cached information about that
    my $ret;
    while(my($section,$sum) = each(%section_packages_sum)) {
	$ret .= " <a href=\"list_bygroup.html#$section\" target=\"list\">".sprintf(gettext("%s in %s"), $sum, $section)."</a>," if $section;
    }
    if ($ret) {
	chop($ret);
	print $handle "<p>".gettext("Packages were found in the following sections:")." $ret.</p>";
	open(FOUNDINSECTIONCACHE, "> $working_dir/foundinsections");
	print FOUNDINSECTIONCACHE "<p>".gettext("Packages were found in the following sections:")." $ret.</p>";
    } elsif (-e $working_dir."/foundinsections") {
	open(FOUNDINSECTIONCACHE, "< $working_dir/foundinsections");
	while (<FOUNDINSECTIONCACHE>) {
	    print $handle $_;
	}
	close(FOUNDINSECTIONCACHE);
    }
    # For each usage , show the number of packages found (active only if
    # usage listing was made or if there's cached information about that
    $ret = "";
    if ($package_popularity_activated) {
	while(my($usage,$sum) = each(%usage_packages_sum)) {
	    $ret .= " <a href=\"list_byusage.html#$usage\" target=\"list\">$sum $usage</a>," if $usage;
	}
	if ($ret) {
	    chop($ret);
	    print $handle "<p>".gettext("Packages usage appears as following:")." $ret.</p>";
	    open(FOUNDINUSAGECACHE, "> $working_dir/foundinusage");
	    print FOUNDINUSAGECACHE "<p>".gettext("Packages usage appears as following:")." $ret.</p>";
	    
	} elsif (-e $working_dir."/foundinusage") {
	    open(FOUNDINUSAGECACHE, "< $working_dir/foundinusage");
	    while (<FOUNDINUSAGECACHE>) {
		print $handle $_;
	    }
	    close(FOUNDINUSAGECACHE);
	}	
    }
    print $handle "<h2>".gettext("System Information")."</h2>";
    print $handle "<p>";
    print $handle sprintf(gettext("The system appears to be running %s along with the %s."), PdbvSysinfoGetDistro(), PdbvSysinfoGetUnameKernel())."</p><p>";
    print $handle sprintf(gettext("It is %s with %s."), PdbvSysinfoGetUnameCpu(), PdbvSysinfoGetFree());
    print $handle "</p>";
    PdbvXhtmlPrintFooter($handle);
}
sub PdbvXhtmlPrintIndexFrame {    
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    PdbvXhtmlPrintHeader($handle, "$pdbv_type\@".hostname(), 1);
    print $handle "<frameset framespacing=\"0\" border=\"false\" frameborder=\"0\" cols=\"35%,65%\">";
    if ($listing) {
	print $handle "      <frameset framespacing=\"0\" border=\"false\" frameborder=\"0\" rows=\"10%,90%\">"; 
	print $handle "          <frame name=\"listing\" src=\"listing.html\" scrolling=\"auto\" />";
	print $handle "          <frame name=\"list\" src=\"list.html\" scrolling=\"auto\" />";
	print $handle "      </frameset>";
    } else {
	print $handle "   <frame name=\"list\" src=\"list.html\" scrolling=\"auto\" />";
    }
    print $handle "  <frame name=\"package\" src=\"info.html\" scrolling=\"auto\" />";
    print $handle "</frameset>";
    print $handle "<body>";
    PdbvXhtmlPrintFooter($handle);
}
sub PdbvXhtmlPrintPackagePointer {    
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    print $handle "<a href=\"".$package_info_baseurl."".PdbvBasename($_[1])."\">".PdbvBasename($_[1])."</a>";
}
sub PdbvXhtmlTagItemTitle {    
    return $tag_item_title_open.$_[0].$tag_item_title_close;
}
sub PdbvXhtmlTIT {    
    return PdbvXhtmlTagItemTitle($_[0]);
}
sub PdbvXhtmlMakeLinks { 
    my $data = $_[0];
    # htmlize < and >
    $data =~ s/\<(.*)\>/\&lt\;\1\&gt\;/;
    unless ($light) {
	my $ltrs = '\w';
	my $gunk = '/#~:.?+=&%@!\-}';
	my $punc = '.:?\-';
	
	# build hrefs
	$data =~ s{\b( (http|ftp|https) : [${ltrs}${gunk}${punc}] +?)(?= [$punc]* [^${ltrs}${gunk}${punc}] | $ )}{<a href="$1">$1</a>}igox;
	# build mailtos
	$data =~ s{(([a-z0-9_]|\-|\.)+@([^[:space:]&><]*)([[:alnum:]-]))}{<a href=\"mailto:$1\">$1</a>}igox;
    }
    return $data;
}
sub PdbvXhtmlMakeLinebreak {
    my $data = $_[0];
    # build line breaks
    $data =~ s/$/$tag_line_break/gm;
    return $data;
}
sub PdbvXhtmlMakeRelationLinks {
    my $ret;
    if ($light) {
	$ret = $_[0];
    } else {
	# For now, this function only check dependancies over package, without
	# taking care about version.
	my @data = split(", ", $_[0]);
	my $missing_rule = $_[1];
	
	for (@data) {
	    $ret .= $tag_line_break."&nbsp;&nbsp;&nbsp;- ";
	    my @subdata = split(" \\| ", $_);
	    my $first = 0;
	    my $subdata = @subdata;
	    
	    for (@subdata) {
		$ret .= " ".gettext("or")." " if $first;
		my $full_info = $_;
		my ($pack) = /^(.*) \(.*$/;
		$pack = $full_info unless $pack;
		
		# FIXME: This method miss the "Provides:"
		if ($package_version{$pack}) {
		    $ret .= "<a href=\"".$pack."_".$package_version{$pack}.".html\">".$full_info."</a>";
		} elsif ($missing_rule ne 'conflicts' && $subdata < 2) {
		    # Print with missing class only if we are not dealing with 
		    # "Conflicts:" or if we have no "or" case.
		    # (FIXME: this last case remain to be thought about)
		    $ret .= "<font class=\"missing\">".$full_info."</font>";
		} else {
		    $ret .= $full_info;
		} 
		$first = 1;
	    }
	    $ret .= ".";	
	}
    }
    return $ret;
}
sub PdbvXhtmlMakePriority {
    my $ret = $_[0];
    if ($_[0] eq 'required') {
	$ret = gettext("required");
    } elsif ($_[0] eq 'important') {
	$ret = gettext("important");
    } elsif ($_[0] eq 'standard') {
	$ret = gettext("standard");
    } elsif ($_[0] eq 'optional') {
	$ret = gettext("optional");
    } elsif ($_[0] eq 'extra') {
	$ret = gettext("extra");
    }
    
    if ($package_explanationurl_priority) {
	return "<a href=\"".$package_explanationurl_priority."\">".$ret."</a>";
    } else {
	return $ret;
    }
}
sub PdbvXhtmlMakeDate {
    my ($year, $month) = split(" ", $_[0]);
    if ($month eq '01') {
	$month = gettext("January");
    } elsif ($month eq '02') {
	$month = gettext("February");
    } elsif ($month eq '03') {
	$month = gettext("March");
    } elsif ($month eq '04') {
	$month = gettext("April");
    } elsif ($month eq '05') {
	$month = gettext("Mai");
    } elsif ($month eq '06') {
	$month = gettext("June");
    } elsif ($month eq '07') {
	$month = gettext("July");
    } elsif ($month eq '08') {
	$month = gettext("August");
    } elsif ($month eq '09') {
	$month = gettext("September");
    } elsif ($month eq '10') {
	$month = gettext("October");
    } elsif ($month eq '11') {
	$month = gettext("November");
    } elsif ($month eq '12') {
	$month = gettext("December");
    } 
    return $year.", ".$month;
}
sub PdbvXhtmlMakeSize {
    my $size = $_[0];
    
    if ($size >= 1048576) {
	$size = (($size / 1048576 * 100) / 100);
	$size = sprintf("%2.f", $size)." ".gettext("GB");
    } elsif ($size >= 1024) {
	$size = (($size / 1024 * 100) / 100);
	$size = sprintf("%2.f", $size)." ".gettext("MB");
    } else {
	$size = sprintf("%2.f", $size)." ".gettext("kB");
    }
    
    return $size;
}
sub PdbvXhtmlPrintSizeBox { 
    # It was planed to make an exact graphical representation, but
    # $percent almost never reach one.
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    my $size = PdbvXhtmlMakeSize($_[1]);
    my $percent = (($_[1] / $package_installedsize_sum) * 100);
    my $percent_exagerated = sprintf("%2.f\%", ($percent * 100));
    
    print $handle " ".$size." [ ".$percent.gettext("%")." ]".$tag_line_break;
    unless ($percent_exagerated eq " 0%") {
	print $handle "<table nowrap width=\"100%\" class=\"percentbox\"><tr><td width=\"".$percent_exagerated."\" class=\"percentboxused\">&nbsp;</td><td>&nbsp;</td></tr></table>";
    } else {
	print $handle "<table nowrap width=\"100%\" class=\"percentbox\"><tr><td>&nbsp;</td></tr></table>";
    }
}
sub PdbvXhtmlPrintPopularityBox { 
    my $handle = STDOUT;
    $handle = $_[0] if $_[0];
    if ($_[1] eq gettext("recently installed")) {
	print $handle " ".gettext("This package has been installed or updated recently, we do not have meaningful data.");
    } elsif ($_[1] eq gettext("with no executable files")) {
	print $handle " ".gettext("No executable program has been found in this package, we cannot find meaningful data.");
    } elsif ($_[1] eq gettext("unused")) {
	print $handle $tag_line_break."<table nowrap width=\"100%\" class=\"percentboxused\"><tr><td>".gettext("This package has not been used since more than a month.")."</td></tr></table>";
    } else {
	print $handle $tag_line_break."<table nowrap width=\"100%\" class=\"percentbox\"><tr><td>".gettext("This package seems to be frequently used.")."</td></tr></table>";
    } 
}
sub PdbvXhtmlAddRequiredFiles {
    # Htaccess and css files must be there
    # It could be done in core.pl, but it really depends on the xhtml.
    # Set a pointer to .htaccess, normally empty by default
    unless (-e $working_dir."/.htaccess") {
	symlink($confdir."/htaccess", $working_dir."/.htaccess");
	print "$confdir/htaccess -> $working_dir/.htaccess\n" if $debug;
    }
    # Make sure the appropriate css is there
    unless (readlink($working_dir_css) eq $css) {
	symlink($css, $working_dir_css);
	print "$css -> $working_dir_css\n" if $debug;
    }    
}
sub PdbvSHelp {
    print gettext("Usage: pdbv [OPTIONS]")."\n\n";
    print gettext("  -h, --help                 display this help and exit")."\n";
    print gettext("      --version              output version information and exit")."\n\n";
    print gettext("  -d, --dir=/path            output directory")."\n";
    print gettext("  -l, --listing=[all|basic]  listing type generated (default is all)")."\n";
    print 
    print gettext("      --light                run faster but generate less polished output")."\n";
    print gettext("                             (will set listing to basic)")."\n\n";
    print gettext("  -f, --force                refresh the whole output without tests")."\n";
    print gettext("      --xhtml                xhtml output (default)")."\n";
    if ($pdbv_type eq 'pdbv') {
	print gettext("      --dpkg-dir=/path       alternative dpkg top directory")."\n";
	print sprintf(gettext("                             (currently: %s)"), $dpkg_dir)."\n";
	print gettext("      --popcon-file=/path    alternative popularity contest file")."\n";
	print sprintf(gettext("                             (currently: %s)"), $popcon_file)."\n";
    }
    print gettext("Report bugs or suggestions to ")."<$smail>.\n";
}
sub PdbvSVersion {
    print gettext("$sname - $sver")."\n\n";
    print gettext("Copyright (c) $sauthor <$smail>")."\n";
    print gettext("See AUTHORS for more details.")."\n\n";
    print gettext("This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.")."\n";
}
sub PdbvReadConf {
    if (-e $_[0]) {
	defined do $_[0] or warn "Unable to run ".$_[0], RED,"Most commonly, it's a privilege issue.",RESET,"\nAsked";
    }
}
sub PdbvExecutionTime {
    # $epoch_start should have been set since the start.
    # Return diff between $epoch_start and $epoch_now.
    #
    # If arg = raw, we return the epoch diff value.
    # If not, we return something human readable.
    my $diff = time - $epoch_start;
    print "Execution time $diff\n" if $debug;
    
    if ($_[0] eq 'raw') {
	return $diff
    } else {     
	my $sec = $diff % 60;
	$diff = ($diff - $sec) / 60;
	my $min = $diff % 60;
	$diff = ($diff - $min) / 60;
	my $hour = $diff % 24;
	$diff = ($diff - $hour) / 24;
	my $day = $diff % 7;
	
	if ($day > 0) {
	    return sprintf(gettext("%s days, %s hours, %s minutes and %s seconds"), $day, $hour, $min, $sec);
	} elsif ($hour > 0) {
	    return sprintf(gettext("%s hours, %s minutes and %s seconds"), $hour, $min, $sec);
	} else {
	    return sprintf(gettext("%s minutes and %s seconds"), $min, $sec);
	}
    }
}
sub PdbvGenerate {
    # Init 
    mkdir $working_dir."/package";
    
    # Gen each package frame:
    #
    #  * we touch files or create it in case it does not already exists
    #  * we don't create an item if it already exists
    #  * we remove files that havent been touched before the test item:
    #    no longer in the database
    
    PdbvPackageInit();
    PdbvXhtmlInit();
    #  test every package and generate, if needed, 
    #  feed the hash of known files (not orphans)
    my %notorphans;
    foreach my $thispack (PdbvPackages()) {
	my $thispackout = $working_dir."/package/".$thispack."_".$package_version{$thispack}.$output_ext;
	if (! -e $thispackout || $force) {
	    open(ITEM, "> $thispackout");
	    PdbvXhtmlPrintItemFrame(ITEM, $thispack);
	    close(ITEM);
	    $does_new_package_exist = "1";
	    print "$thispackout written\n" if $debug;
	} else {
	    print "$thispackout already existing\n" if $debug;
	}
	$notorphans{$thispackout} = 1;
	
    }
   
    #  seek and destroy orphans
    my @orphans;
    opendir(OUTDIR, $working_dir."/package/");
    while (defined(my $file = readdir(OUTDIR))) {
	# take care only of html files
	next unless $file =~ m/.*\.html$/;
	# add in the orphan list any file that is not in known file hash
	push(@orphans, $working_dir."/package/".$file) unless $notorphans{$working_dir."/package/".$file}
    }
    
    if ($debug) {
	print "orphans:\n";
	foreach my $orphan (@orphans) {
	    print " - ".$orphan."\n";
	}
    }
	
    # Remove each orphans one by one
    my $orphans_removed = unlink @orphans;
    $does_orphan_exist = 1 if $orphans_removed > 1; 
    print "$orphans_removed orphans removed\n" if $debug;
    
    # Gen the lists frames:
    #  basic list is alway generated.
    if ($does_new_package_exist || $does_orphan_exist) {	
	open(LIST, "> ".$working_dir."/list".$output_ext);
	PdbvXhtmlPrintListFrame(LIST);
	close(LIST);
	print "LIST written\n" if $debug;
	if ($listing) {
	    open(LIST, "> ".$working_dir."/list_bygroup".$output_ext);
	    PdbvXhtmlPrintListFrame(LIST, "package_section");
	    close(LIST);
	    print "LIST by group written\n" if $debug;
	    
	    open(LIST, "> ".$working_dir."/list_bydate".$output_ext);
	    PdbvXhtmlPrintListFrame(LIST, "package_installdate");
	    close(LIST);
	    print "LIST by date written\n" if $debug;
	    
	    open(LIST, "> ".$working_dir."/list_byusage".$output_ext);
	    PdbvXhtmlPrintListFrame(LIST, "package_popularity");
	    close(LIST);
	    print "LIST by usage written\n" if $debug;
	    
	    # FIXME: Need to figure out to do that cleanly.
	    #open(LIST, "> ".$working_dir."/list_bysize".$output_ext);
	    #PdbvXhtmlPrintListFrame(LIST, "package_installedsize");
	    #close(LIST);
	    #print "LIST by size written\n" if $debug;
	}
    }
    # Gen the listing frame, which print the listing available:
    open(INDEX, "> ".$working_dir."/listing".$output_ext);
    PdbvXhtmlPrintListingFrame(INDEX);
    close(INDEX);
    print "INDEX written\n" if $debug;
    # Gen an index:
    open(INDEX, "> ".$working_dir."/index".$output_ext);
    PdbvXhtmlPrintIndexFrame(INDEX);
    close(INDEX);
    print "INDEX written\n" if $debug;
    # Gen a general info frame:
    # (lately because it prints execution time)
    open(INFO, "> ".$working_dir."/info".$output_ext);
    PdbvXhtmlPrintInfoFrame(INFO);
    print "INFO written\n" if $debug;
    close(INFO);
    # Add required files (.htaccess, etc...) 
    PdbvXhtmlAddRequiredFiles();
    
    # If we are root and working with the cron working_dir
    # (called output_dir), we chmod files to nobody, to avoid
    # breaking cronjobs.
    if ((getpwuid($<))[0] eq 'root' && $output_dir eq $working_dir) {
	# Until perl chown support -R option, we'll use GNU chown
	# (if there is an easy perl workaround, write to pdbv-dev)
	`chown nobody -R $output_dir > /dev/null`;
	print "$output_dir chowned to nobody\n" if $debug;
    }
}
PdbvReadConf($confdir."/pdbvrc");
PdbvReadConf($ENV{HOME}."/.pdbvrc");
PdbvReadConf($ENV{HOME}."/.pdbvrc2");
our $working_dir = $output_dir if $output_dir;
eval {
    $getopt = GetOptions("help" => \$arg_help,
			 "version" => \$arg_version,
			 "debug" => \$debug,
			 "force" => \$force,
			 "dir=s" => \$working_dir,
			 "listing=s" => \$listing,
			 "cron=s" => \$arg_cron,
			 "xhtml" => \$arg_xhtml,
			 "light" => \$light,
			 "dpkg-dir=s" => \$dpkg_dir,
			 "popcon-file=s" => \$popcon_file)
};
$listing = "0" if $listing eq 'basic' || $light;
$output = "xhtml" if $arg_xhtml;
if ($debug) { use warnings; }
PdbvSHelp() && exit if $arg_help;
PdbvSVersion() && exit if $arg_version;
if ($arg_cron) {
    exit unless $cron eq $arg_cron;
    setlocale(LC_ALL, $cron_lang) if $cron_lang;
}
die gettext("You must choose an output directory.\nCheck your pdbvrc2 or add a command line's option.")."\n" unless $working_dir;
if ((getpwuid($<))[0] eq 'root' && ! $arg_cron) {
    # We use getpwuid() instead of getlogin() because when using `su` 
    # the result is oftenly erroneous with getlogin().
    print gettext("Running pdbv as root jeopardizes your system security, you should not do that.")."\n\n";
    print sprintf(gettext("If you are not running pdbv as root, please fill a bug report on our project page. Do not forget to tell us which perl version and operating system you are using. Give us also the result of %s"), "\`perl -e \"print \$<; print ((getpwuid(\$<))[0]);\"\`")."\n";
}
if ($debug) {
    print "DEBUG = $debug
FORCE = $force
OUTPUT = $output
WORKING_dir = $working_dir
LISTING = $listing\n";
}
mkdir $working_dir unless (-e $working_dir);
unless (-e $working_dir) {
    print gettext("Unable to create ").$working_dir."\n";
    print gettext("Check if the parent directory exists.")."\n";
    print gettext("Check also its mode and ownership.")."\n";
}
PdbvGenerate();
# end
