wpkg test coverage results

Coverage test results of the Windows Packager by Made to Order Software Corporation.

LCOV - code coverage report
Current view: top level - tools - wpkg.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 687 2688 25.6 %
Date: 2013-08-09 Functions: 48 126 38.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*    wpkg.cpp -- manage debian archives
       2             :  *    Copyright (C) 2012-2013  Made to Order Software Corporation
       3             :  *
       4             :  *    This program is free software; you can redistribute it and/or modify
       5             :  *    it under the terms of the GNU General Public License as published by
       6             :  *    the Free Software Foundation; either version 2 of the License, or
       7             :  *    (at your option) any later version.
       8             :  *
       9             :  *    This program is distributed in the hope that it will be useful,
      10             :  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  *    GNU General Public License for more details.
      13             :  *
      14             :  *    You should have received a copy of the GNU General Public License along
      15             :  *    with this program; if not, write to the Free Software Foundation, Inc.,
      16             :  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  *
      18             :  *    Authors
      19             :  *    Alexis Wilke   alexis@m2osw.com
      20             :  */
      21             : 
      22             : /** \file
      23             :  * \brief The implementation of the wpkg tool.
      24             :  *
      25             :  * This file is the implementation of the wpkg tool with already over 7,000
      26             :  * lines of code and comments. The file includes all the commands that are
      27             :  * supported by wpkg. However, most of the implementation is found in the
      28             :  * libdebpackages library.
      29             :  */
      30             : #include    "libdebpackages/wpkgar_build.h"
      31             : #include    "libdebpackages/wpkgar_install.h"
      32             : #include    "libdebpackages/wpkgar_remove.h"
      33             : #include    "libdebpackages/wpkgar_repository.h"
      34             : #include    "libdebpackages/wpkgar_tracker.h"
      35             : #include    "libdebpackages/wpkg_util.h"
      36             : #include    "libdebpackages/wpkg_copyright.h"
      37             : #include    "libdebpackages/wpkg_stream.h"
      38             : #include    "libdebpackages/advgetopt.h"
      39             : #include    "libdebpackages/debian_packages.h"
      40             : #include    "libdebpackages/debian_version.h"
      41             : #include    "license.h"
      42             : #include    "zlib.h"
      43             : #include    "bzlib.h"
      44             : #include    "libtld/tld.h"
      45             : #include    "controlled_vars/controlled_vars_version.h"
      46             : #include    <errno.h>
      47             : #include    <signal.h>
      48             : #include    <algorithm>
      49             : #ifdef MO_WINDOWS
      50             : #   include    <time.h>
      51             : #else
      52             : #   include    <unistd.h>
      53             : #endif
      54             : 
      55             : #ifdef _MSC_VER
      56             : // "unknown pragma"
      57             : #pragma warning(disable: 4068)
      58             : #endif
      59             : 
      60             : 
      61             : namespace
      62             : {
      63             : 
      64             : char **g_argv;
      65             : 
      66             : 
      67             : /** \brief Whether Ctrl-C was pressed.
      68             :  *
      69             :  * The wpkg tool protects itself from being interrupted by Ctrl-C. If that
      70             :  * happens, the g_interrupted variable is set to true and the process
      71             :  * continues up to the next interruptable point. This allows for a much
      72             :  * safer processing of the wpkg database when one is being accessed.
      73             :  *
      74             :  * Also this way the Ctrl-C interruption makes use of an exception meaning
      75             :  * that the stack gets unwinded as expected before wpkg exists.
      76             :  */
      77             : bool g_interrupted(false);
      78             : 
      79             : 
      80             : /** \brief Implementation of the wpkgar_interrupt.
      81             :  *
      82             :  * This class is an implementation of the wpkgar_interrupt interface so
      83             :  * we can safely interrupt a process while the library is running. This
      84             :  * means packages being installed or removed will continue to be working
      85             :  * as expected.
      86             :  *
      87             :  * This implementation makes use of the g_interrupted variable which is
      88             :  * set to true whenever the user presses Ctrl-C.
      89             :  */
      90        1485 : class wpkg_interrupt : public wpkgar::wpkgar_interrupt
      91             : {
      92             : public:
      93       57174 :     virtual bool stop_now()
      94             :     {
      95       57174 :         return g_interrupted;
      96             :     }
      97             : };
      98             : 
      99             : // we never release this object, doesn't make any difference at this point
     100        1485 : wpkg_interrupt interrupt;
     101             : 
     102             : 
     103             : 
     104             : /** \brief Handling of the library output.
     105             :  *
     106             :  * This class is the output handler of the wpkg tool.
     107             :  *
     108             :  * It outputs the data to the console and when --output-log is used, it
     109             :  * also copies the data in a log file in a computer readable format
     110             :  * (i.e. quotes inside strings are backslashed, etc.)
     111             :  *
     112             :  * The class is also responsible for keeping track of the wpkg exit code.
     113             :  * Namely, if an error is detected (as indicated by the level of a message)
     114             :  * then the exit code becomes 1 instead of 0.
     115             :  */
     116             : class tool_output : public wpkg_output::output
     117             : {
     118             : public:
     119             :     tool_output();
     120             :     ~tool_output();
     121             : 
     122             :     void close_output();
     123             :     void set_output_file(const std::string& filename);
     124             :     const std::string& get_output_file() const;
     125             :     void set_level(wpkg_output::level_t level);
     126             : 
     127             :     int exit_code() const;
     128             : 
     129             : protected:
     130             :     virtual void log_message( const wpkg_output::message_t& msg ) const;
     131             :     virtual void output_message( const wpkg_output::message_t& msg ) const;
     132             : 
     133             : private:
     134             :     std::string                             f_output_filename;
     135             :     wpkg_stream::fstream                    f_output;
     136             :     wpkg_output::level_t                    f_log_level;
     137             :     mutable wpkg_output::level_t            f_highest_level;
     138             : };
     139             : 
     140        1485 : tool_output::tool_output()
     141             :     //: f_output_filename("") -- auto-init
     142             :     //: f_output() -- auto-init
     143             :     : f_log_level(wpkg_output::level_warning)
     144        1485 :     , f_highest_level(wpkg_output::level_debug)
     145             : {
     146        1485 : }
     147             : 
     148        1485 : tool_output::~tool_output()
     149             : {
     150        1485 :     close_output();
     151        1485 : }
     152             : 
     153        1485 : void tool_output::close_output()
     154             : {
     155        1485 :     f_output.close();
     156        1485 :     f_output_filename.clear();
     157        1485 : }
     158             : 
     159           0 : void tool_output::set_output_file(const std::string& filename)
     160             : {
     161           0 :     close_output();
     162           0 :     f_output_filename = filename;
     163           0 :     f_output.append(filename);
     164           0 :     if(!f_output.good())
     165             :     {
     166           0 :         fprintf(stderr, "wpkg:error: could not open the log file for writing.\n");
     167             :     }
     168             :     else
     169             :     {
     170             :         wpkg_output::log("wpkg started")
     171           0 :             .debug(wpkg_output::debug_flags::debug_progress)
     172           0 :             .level(wpkg_output::level_info) // restore level
     173           0 :             .action("log");
     174             :     }
     175           0 : }
     176             : 
     177        1494 : const std::string& tool_output::get_output_file() const
     178             : {
     179        1494 :     return f_output_filename;
     180             : }
     181             : 
     182        9535 : void tool_output::log_message(const wpkg_output::message_t& msg) const
     183             : {
     184        9535 :     if(f_output.good())
     185             :     {
     186           0 :         std::string message(msg.get_full_message(false));
     187           0 :         f_output.write(message.c_str(), message.length());
     188           0 :         if(message.length() > 0 && message[message.length() - 1] != '\n')
     189             :         {
     190           0 :             f_output.write("\n", 1);
     191           0 :         }
     192             :     }
     193        9535 : }
     194             : 
     195        1125 : void tool_output::output_message( const wpkg_output::message_t& msg ) const
     196             : {
     197        1125 :     const wpkg_output::level_t level = msg.get_level();
     198             :     //
     199        1125 :     if(level > f_highest_level)
     200             :     {
     201         388 :         f_highest_level = level;
     202             :     }
     203        1125 :     if(wpkg_output::compare_levels(level, f_log_level) >= 0 || (msg.get_debug_flags() & wpkg_output::debug_flags::debug_progress) != 0)
     204             :     {
     205         617 :         fprintf(stderr, "%s\n", msg.get_full_message(true).c_str());
     206             :     }
     207        1125 : }
     208             : 
     209          17 : void tool_output::set_level(wpkg_output::level_t level)
     210             : {
     211          17 :     f_log_level = level;
     212          17 : }
     213             : 
     214         719 : int tool_output::exit_code() const
     215             : {
     216         719 :     return f_highest_level >= wpkg_output::level_error ? 1 : 0;
     217             : }
     218             : 
     219             : 
     220             : // we never release this object, doesn't make any difference at this point
     221        1485 : tool_output g_output;
     222             : 
     223             : 
     224             : /** \brief Wrapper class to handle the wpkg command line arguments.
     225             :  *
     226             :  * This class is a wrapper that helps in handling the extremely large
     227             :  * number of parameters that the wpkg tool accepts on its command line.
     228             :  * This includes converting the command (or mix of commands) in a
     229             :  * command_t value.
     230             :  */
     231         743 : class command_line
     232             : {
     233             : public:
     234             :     enum command_t
     235             :     {
     236             :         command_unknown,
     237             :         command_add_hooks,
     238             :         command_add_sources,
     239             :         command_architecture,
     240             :         command_atleast_version,
     241             :         command_atleast_wpkg_version,
     242             :         command_audit,
     243             :         command_autoremove,
     244             :         command_build,
     245             :         command_build_and_install,
     246             :         command_canonicalize_version,
     247             :         command_cflags,
     248             :         command_check_install,
     249             :         command_compare_versions,
     250             :         command_compress,
     251             :         command_configure,
     252             :         command_contents,
     253             :         command_control,
     254             :         command_copyright,
     255             :         command_create_admindir,
     256             :         command_create_database_lock,
     257             :         command_create_index,
     258             :         command_database_is_locked,
     259             :         command_decompress,
     260             :         command_deconfigure,
     261             :         command_directory_size,
     262             :         command_exact_version,
     263             :         command_extract,
     264             :         command_field,
     265             :         command_fsys_tarfile,
     266             :         command_help,
     267             :         command_increment_build_number,
     268             :         command_info,
     269             :         command_install,
     270             :         command_install_size,
     271             :         command_is_installed,
     272             :         command_libs,
     273             :         command_license,
     274             :         command_list,
     275             :         command_list_all,
     276             :         command_listfiles,
     277             :         command_list_hooks,
     278             :         command_list_index_packages,
     279             :         command_list_sources,
     280             :         command_max_version,
     281             :         command_md5sums,
     282             :         command_md5sums_check,
     283             :         command_modversion,
     284             :         command_os,
     285             :         command_print_architecture,
     286             :         command_print_build_number,
     287             :         command_print_variables,
     288             :         command_processor,
     289             :         command_purge,
     290             :         command_reconfigure,
     291             :         command_remove,
     292             :         command_remove_database_lock,
     293             :         command_remove_hooks,
     294             :         command_remove_sources,
     295             :         command_rollback,
     296             :         command_search,
     297             :         command_set_selection,
     298             :         command_show,
     299             :         command_package_status,
     300             :         command_triplet,
     301             :         command_unpack,
     302             :         command_update,
     303             :         command_update_status,
     304             :         command_upgrade,
     305             :         command_upgrade_info,
     306             :         command_variable,
     307             :         command_verify_control,
     308             :         command_verify_project,
     309             :         command_vendor,
     310             :         command_version
     311             :     };
     312             : 
     313             :     command_line(int argc, char *argv[], std::vector<std::string> configuration_files);
     314             : 
     315             :     const advgetopt::getopt& opt() const;
     316             :     advgetopt::getopt& opt();
     317             :     command_t command() const;
     318             :     int size() const; // # of filenames, fields, package names...
     319             :     wpkg_filename::uri_filename filename(int idx) const;
     320             :     std::string argument(int idx) const;
     321             :     std::string get_string(const std::string& name, int idx = 0) const;
     322             :     bool quiet() const;
     323             :     bool verbose() const;
     324             :     bool dry_run(bool msg = true) const;
     325             :     int zlevel() const;
     326             :     memfile::memory_file::file_format_t compressor() const;
     327             : 
     328             :     void add_filename(const std::string& option, const std::string& repository_filename);
     329             : 
     330             : private:
     331             :     void set_command(command_t c);
     332             : 
     333             :     typedef std::vector<std::string> filename_vector_t;
     334             :     typedef controlled_vars::limited_auto_init<char, 1, 9, 9> zlevel_t;
     335             :     typedef controlled_vars::limited_auto_init<command_t, command_unknown, command_version, command_unknown> zcommand_t;
     336             :     typedef controlled_vars::limited_auto_init<memfile::memory_file::file_format_t, memfile::memory_file::file_format_undefined, memfile::memory_file::file_format_other, memfile::memory_file::file_format_best> zcompressor_t;
     337             : 
     338             :     advgetopt::getopt                       f_opt;
     339             :     zcommand_t                              f_command;
     340             :     controlled_vars::flbool_t               f_quiet;
     341             :     controlled_vars::flbool_t               f_verbose;
     342             :     controlled_vars::flbool_t               f_dry_run;
     343             :     zlevel_t                                f_zlevel;
     344             :     wpkg_output::debug_flags::safe_debug_t  f_debug_flags;
     345             :     memfile::memory_file::file_format_t     f_compressor;
     346             :     std::string                             f_option;
     347             :     filename_vector_t                       f_filenames;        // if not empty, use this list instead of opt.get_string("filename", idx)
     348             : };
     349             : 
     350             : const advgetopt::getopt::option wpkg_options[] =
     351             : {
     352             :     {
     353             :         '\0',
     354             :         advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
     355             :         NULL,
     356             :         NULL,
     357             :         "Usage: wpkg -<command> [-<opt>] <filename> | <package-name> | <field> ...",
     358             :         advgetopt::getopt::help_argument
     359             :     },
     360             :     // COMMANDS
     361             :     {
     362             :         '\0',
     363             :         0,
     364             :         NULL,
     365             :         NULL,
     366             :         "commands:",
     367             :         advgetopt::getopt::help_argument
     368             :     },
     369             :     {
     370             :         '\0',
     371             :         0,
     372             :         "add-hooks",
     373             :         NULL,
     374             :         "add one or more global hooks to your wpkg system",
     375             :         advgetopt::getopt::no_argument
     376             :     },
     377             :     {
     378             :         '\0',
     379             :         0,
     380             :         "add-sources",
     381             :         NULL,
     382             :         "add one or more sources to your core/sources.list file found in your administration directory",
     383             :         advgetopt::getopt::no_argument
     384             :     },
     385             :     {
     386             :         '\0',
     387             :         0,
     388             :         "architecture",
     389             :         NULL,
     390             :         "architecture wpkg was compiled with (and expected to be the target of your packages)",
     391             :         advgetopt::getopt::no_argument
     392             :     },
     393             :     {
     394             :         '\0',
     395             :         advgetopt::getopt::GETOPT_FLAG_ALIAS,
     396             :         "atleast-pkgconfig-version", // note though that the version is "wrong" compared to the pkg-config tool itself
     397             :         NULL,
     398             :         "atleast-wpkg-version",
     399             :         advgetopt::getopt::required_argument
     400             :     },
     401             :     {
     402             :         '\0',
     403             :         0,
     404             :         "atleast-version",
     405             :         NULL,
     406             :         "check whether the version of a package is at least what is specified right after this command",
     407             :         advgetopt::getopt::required_argument
     408             :     },
     409             :     {
     410             :         '\0',
     411             :         0,
     412             :         "atleast-wpkg-version",
     413             :         NULL,
     414             :         "check that wpkg is at least a certain version, if so exit with 0, otherwise exit with 1",
     415             :         advgetopt::getopt::required_argument
     416             :     },
     417             :     {
     418             :         'C',
     419             :         0,
     420             :         "audit",
     421             :         NULL,
     422             :         "audit a wpkg installation target",
     423             :         advgetopt::getopt::no_argument
     424             :     },
     425             :     {
     426             :         '\0',
     427             :         0,
     428             :         "autoremove",
     429             :         NULL,
     430             :         "automatically remove all implicitly installed packages that are not depended on anymore; may be used with --purge to completely remove those packages",
     431             :         advgetopt::getopt::no_argument
     432             :     },
     433             :     {
     434             :         'b',
     435             :         0,
     436             :         "build",
     437             :         NULL,
     438             :         "build a wpkg package",
     439             :         advgetopt::getopt::no_argument
     440             :     },
     441             :     {
     442             :         '\0',
     443             :         0,
     444             :         "build-and-install",
     445             :         NULL,
     446             :         "build and install a wpkg package",
     447             :         advgetopt::getopt::no_argument
     448             :     },
     449             :     {
     450             :         '\0',
     451             :         0,
     452             :         "canonalize-version",
     453             :         NULL,
     454             :         NULL, // keep my blunder hidden
     455             :         advgetopt::getopt::required_argument
     456             :     },
     457             :     {
     458             :         '\0',
     459             :         0,
     460             :         "canonicalize-version",
     461             :         NULL,
     462             :         "canonicalize a version by removing unecessary values",
     463             :         advgetopt::getopt::required_argument
     464             :     },
     465             :     {
     466             :         '\0',
     467             :         0,
     468             :         "cflags",
     469             :         NULL,
     470             :         "print out the C/C++ command line options necessary to compile against the specified packages",
     471             :         advgetopt::getopt::no_argument
     472             :     },
     473             :     {
     474             :         '\0',
     475             :         0,
     476             :         "check-install",
     477             :         NULL,
     478             :         "check that a set of packages can be installed",
     479             :         advgetopt::getopt::required_multiple_argument
     480             :     },
     481             :     {
     482             :         '\0',
     483             :         0,
     484             :         "compare-versions",
     485             :         NULL,
     486             :         "compare two versions against each others using the specified operator (v1 op v2)",
     487             :         advgetopt::getopt::required_multiple_argument
     488             :     },
     489             :     {
     490             :         '\0',
     491             :         0,
     492             :         "compress",
     493             :         NULL,
     494             :         "compress files; specify the filename with the compression extension",
     495             :         advgetopt::getopt::no_argument
     496             :     },
     497             :     {
     498             :         '\0',
     499             :         0,
     500             :         "configure",
     501             :         NULL,
     502             :         "configure a package that was unpacked earlier",
     503             :         advgetopt::getopt::required_multiple_argument
     504             :     },
     505             :     {
     506             :         'c',
     507             :         0,
     508             :         "contents",
     509             :         NULL,
     510             :         "list of the files available in this package",
     511             :         advgetopt::getopt::required_argument
     512             :     },
     513             :     {
     514             :         'e',
     515             :         0,
     516             :         "control",
     517             :         NULL,
     518             :         "extract the entire control archive",
     519             :         advgetopt::getopt::required_argument
     520             :     },
     521             :     {
     522             :         '\0',
     523             :         0,
     524             :         "copyright",
     525             :         NULL,
     526             :         "prints out the copyright file of a package",
     527             :         advgetopt::getopt::required_argument
     528             :     },
     529             :     {
     530             :         '\0',
     531             :         0,
     532             :         "create-admindir",
     533             :         NULL,
     534             :         "prepare the administration directory (database)",
     535             :         advgetopt::getopt::required_argument
     536             :     },
     537             :     {
     538             :         '\0',
     539             :         0,
     540             :         "create-database-lock",
     541             :         NULL,
     542             :         "create the database lock file (so an external tool can safely work on the wpkg database)",
     543             :         advgetopt::getopt::no_argument
     544             :     },
     545             :     {
     546             :         '\0',
     547             :         0,
     548             :         "create-index",
     549             :         NULL,
     550             :         "create an index file from a list of Debian packages",
     551             :         advgetopt::getopt::required_argument
     552             :     },
     553             :     {
     554             :         '\0',
     555             :         0,
     556             :         "database-is-locked",
     557             :         NULL,
     558             :         "check whether the database is currently locked",
     559             :         advgetopt::getopt::no_argument
     560             :     },
     561             :     {
     562             :         '\0',
     563             :         0,
     564             :         "decompress",
     565             :         NULL,
     566             :         "decompress files; specify the filename with the compression extension, it will be removed",
     567             :         advgetopt::getopt::no_argument
     568             :     },
     569             :     {
     570             :         '\0',
     571             :         0,
     572             :         "deconfigure",
     573             :         NULL,
     574             :         "decongigure the packages specified on the command line",
     575             :         advgetopt::getopt::required_multiple_argument
     576             :     },
     577             :     {
     578             :         '\0',
     579             :         0,
     580             :         "directory-size",
     581             :         NULL,
     582             :         "compute the size of a directory and print the result in stdout",
     583             :         advgetopt::getopt::required_argument
     584             :     },
     585             :     {
     586             :         '\0',
     587             :         0,
     588             :         "exact-version",
     589             :         NULL,
     590             :         "check whether the version of a package is exactly what is specified right after this command",
     591             :         advgetopt::getopt::required_argument
     592             :     },
     593             :     {
     594             :         '\0',
     595             :         advgetopt::getopt::GETOPT_FLAG_ALIAS,
     596             :         "exists",
     597             :         NULL,
     598             :         "is-installed",
     599             :         advgetopt::getopt::required_argument
     600             :     },
     601             :     {
     602             :         'x',
     603             :         0,
     604             :         "extract",
     605             :         NULL,
     606             :         "extract files from a wpkg package",
     607             :         advgetopt::getopt::no_argument
     608             :     },
     609             :     {
     610             :         'f',
     611             :         0,
     612             :         "field",
     613             :         NULL,
     614             :         "show the value of the specified fields",
     615             :         advgetopt::getopt::required_argument
     616             :     },
     617             :     {
     618             :         '\0',
     619             :         0,
     620             :         "fsys-tarfile",
     621             :         NULL,
     622             :         "print the decompressed data.tar.gz file to stdout so it can directly be piped to tar",
     623             :         advgetopt::getopt::required_argument
     624             :     },
     625             :     {
     626             :         'h',
     627             :         advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
     628             :         "help",
     629             :         NULL,
     630             :         "print the help message about all the wpkg commands and options; for more information, try: wpkg --help help",
     631             :         advgetopt::getopt::no_argument
     632             :     },
     633             :     {
     634             :         '\0',
     635             :         advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
     636             :         "help-nobr",
     637             :         NULL,
     638             :         NULL, // hide from --help screen
     639             :         advgetopt::getopt::no_argument
     640             :     },
     641             :     {
     642             :         '\0',
     643             :         0,
     644             :         "increment-build-number",
     645             :         NULL,
     646             :         "increment the build number defined in a build number file; by default the file is wpkg/build-number; you may specify another file too",
     647             :         advgetopt::getopt::no_argument
     648             :     },
     649             :     {
     650             :         'I',
     651             :         0,
     652             :         "info",
     653             :         NULL,
     654             :         "show detailed information about this package",
     655             :         advgetopt::getopt::required_argument
     656             :     },
     657             :     {
     658             :         'i',
     659             :         0,
     660             :         "install",
     661             :         NULL,
     662             :         "install a wpkg compatible package",
     663             :         advgetopt::getopt::required_multiple_argument
     664             :     },
     665             :     {
     666             :         '\0',
     667             :         0,
     668             :         "install-size",
     669             :         NULL,
     670             :         "retrieve the Installed-Size field from the specified packages and return the total sum",
     671             :         advgetopt::getopt::required_multiple_argument
     672             :     },
     673             :     {
     674             :         '\0',
     675             :         0,
     676             :         "is-installed",
     677             :         NULL,
     678             :         "check whether a package is currently installed",
     679             :         advgetopt::getopt::required_argument
     680             :     },
     681             :     {
     682             :         '\0',
     683             :         0,
     684             :         "libs",
     685             :         NULL,
     686             :         "retrieve the list of libraries to link against to make use of this package",
     687             :         advgetopt::getopt::no_argument
     688             :     },
     689             :     {
     690             :         '\0',
     691             :         0,
     692             :         "license",
     693             :         NULL,
     694             :         "displays the license of this tool",
     695             :         advgetopt::getopt::no_argument
     696             :     },
     697             :     {
     698             :         '\0',
     699             :         0,
     700             :         "licence", // French spelling
     701             :         NULL,
     702             :         NULL, // hidden argument in --help screen
     703             :         advgetopt::getopt::no_argument
     704             :     },
     705             :     {
     706             :         'l',
     707             :         0,
     708             :         "list",
     709             :         NULL,
     710             :         "displays the list of installed packages, optionally add a shell pattern to limit the list",
     711             :         advgetopt::getopt::optional_argument
     712             :     },
     713             :     {
     714             :         '\0',
     715             :         0,
     716             :         "list-all",
     717             :         NULL,
     718             :         "display all the installed packages a la pkg-config (package name, description)",
     719             :         advgetopt::getopt::no_argument
     720             :     },
     721             :     {
     722             :         'L',
     723             :         0,
     724             :         "listfiles",
     725             :         NULL,
     726             :         "displays the list of files installed by the named packages",
     727             :         advgetopt::getopt::required_multiple_argument
     728             :     },
     729             :     {
     730             :         '\0',
     731             :         0,
     732             :         "list-hooks",
     733             :         NULL,
     734             :         "list the currently installed global and package hooks",
     735             :         advgetopt::getopt::no_argument
     736             :     },
     737             :     {
     738             :         '\0',
     739             :         0,
     740             :         "list-index-packages",
     741             :         NULL,
     742             :         "displays the list of packages from a package index (see --create-index)",
     743             :         advgetopt::getopt::required_multiple_argument
     744             :     },
     745             :     {
     746             :         '\0',
     747             :         0,
     748             :         "list-sources",
     749             :         NULL,
     750             :         "displays the list of sources from a sources.list file",
     751             :         advgetopt::getopt::optional_multiple_argument
     752             :     },
     753             :     {
     754             :         '\0',
     755             :         0,
     756             :         "max-version",
     757             :         NULL,
     758             :         "check whether the version of a package is at most what is specified right after this command",
     759             :         advgetopt::getopt::required_argument
     760             :     },
     761             :     {
     762             :         '\0',
     763             :         0,
     764             :         "md5sums",
     765             :         NULL,
     766             :         "create an md5sums file from the files defined on the command line",
     767             :         advgetopt::getopt::no_argument
     768             :     },
     769             :     {
     770             :         '\0',
     771             :         0,
     772             :         "md5sums-check",
     773             :         NULL,
     774             :         "check files against their md5sums; the name of the md5sums file, as created by the --md5sums, is expected right after this command, followed by the files to check",
     775             :         advgetopt::getopt::required_argument
     776             :     },
     777             :     {
     778             :         '\0',
     779             :         0,
     780             :         "modversion",
     781             :         NULL,
     782             :         "retrieve the version of a package from its pkgconfig file",
     783             :         advgetopt::getopt::no_argument
     784             :     },
     785             :     {
     786             :         '\0',
     787             :         0,
     788             :         "os",
     789             :         NULL,
     790             :         "print to stdout the name of the os wpkg was compiled with",
     791             :         advgetopt::getopt::no_argument
     792             :     },
     793             :     {
     794             :         '\0',
     795             :         0,
     796             :         "package-status",
     797             :         NULL,
     798             :         "display the current status of a package (processed X-Status and other fields)",
     799             :         advgetopt::getopt::required_multiple_argument
     800             :     },
     801             :     {
     802             :         '\0',
     803             :         0,
     804             :         "print-architecture",
     805             :         NULL,
     806             :         "print installation architecture",
     807             :         advgetopt::getopt::no_argument
     808             :     },
     809             :     {
     810             :         'p',
     811             :         0,
     812             :         "print-avail",
     813             :         NULL,
     814             :         "print installed package control file",
     815             :         advgetopt::getopt::required_argument
     816             :     },
     817             :     {
     818             :         '\0',
     819             :         0,
     820             :         "print-build-number",
     821             :         NULL,
     822             :         "read the build number file and print its contents",
     823             :         advgetopt::getopt::no_argument
     824             :     },
     825             :     {
     826             :         '\0',
     827             :         0,
     828             :         "print-variables",
     829             :         NULL,
     830             :         "print the list of variables defined in a .pc file",
     831             :         advgetopt::getopt::no_argument
     832             :     },
     833             :     {
     834             :         '\0',
     835             :         0,
     836             :         "processor",
     837             :         NULL,
     838             :         "print processor wpkg was compiled with; use --verbose to print out the running machine",
     839             :         advgetopt::getopt::no_argument
     840             :     },
     841             :     {
     842             :         'P',
     843             :         0,
     844             :         "purge",
     845             :         NULL,
     846             :         "purge the packages specified on the command line",
     847             :         advgetopt::getopt::required_multiple_argument
     848             :     },
     849             :     {
     850             :         '\0',
     851             :         0,
     852             :         "reconfigure",
     853             :         NULL,
     854             :         "reconfigure a package by deconfiguring it, reinstalling the initial configuration files, and configuring it with those initial files",
     855             :         advgetopt::getopt::required_multiple_argument
     856             :     },
     857             :     {
     858             :         'r',
     859             :         0,
     860             :         "remove",
     861             :         NULL,
     862             :         "remove the packages specified on the command line",
     863             :         advgetopt::getopt::required_multiple_argument
     864             :     },
     865             :     {
     866             :         '\0',
     867             :         0,
     868             :         "remove-database-lock",
     869             :         NULL,
     870             :         "delete the database lock file (if the packager crashed without cleaning up properly)",
     871             :         advgetopt::getopt::no_argument
     872             :     },
     873             :     {
     874             :         '\0',
     875             :         0,
     876             :         "remove-hooks",
     877             :         NULL,
     878             :         "remove one or more global hooks from your wpkg system",
     879             :         advgetopt::getopt::no_argument
     880             :     },
     881             :     {
     882             :         '\0',
     883             :         0,
     884             :         "remove-sources",
     885             :         NULL,
     886             :         "remove one or more sources to your core/sources.list file found in your administration directory",
     887             :         advgetopt::getopt::no_argument
     888             :     },
     889             :     {
     890             :         '\0',
     891             :         0,
     892             :         "rollback",
     893             :         NULL,
     894             :         "run a rollback script to restore the status of a target system",
     895             :         advgetopt::getopt::required_argument
     896             :     },
     897             :     {
     898             :         'S',
     899             :         0,
     900             :         "search",
     901             :         NULL,
     902             :         "search installed packages for the specified file",
     903             :         advgetopt::getopt::required_argument
     904             :     },
     905             :     {
     906             :         '\0',
     907             :         0,
     908             :         "set-selection",
     909             :         NULL,
     910             :         "set the selection mode of a package (auto, manual, normal, hold)",
     911             :         advgetopt::getopt::required_argument
     912             :     },
     913             :     {
     914             :         'W',
     915             :         0,
     916             :         "show",
     917             :         NULL,
     918             :         "show basic information about packages",
     919             :         advgetopt::getopt::required_argument
     920             :     },
     921             :     {
     922             :         's',
     923             :         advgetopt::getopt::GETOPT_FLAG_ALIAS,
     924             :         "status",
     925             :         NULL,
     926             :         "field",
     927             :         advgetopt::getopt::required_argument
     928             :     },
     929             :     {
     930             :         '\0',
     931             :         0,
     932             :         "triplet",
     933             :         NULL,
     934             :         "print to stdout the architecture triplet as it would appear in the Architecture field",
     935             :         advgetopt::getopt::no_argument
     936             :     },
     937             :     {
     938             :         '\0',
     939             :         0,
     940             :         "unpack",
     941             :         NULL,
     942             :         "unpack the files of the specfied packages, this is similar to --install without --configure",
     943             :         advgetopt::getopt::required_multiple_argument
     944             :     },
     945             :     {
     946             :         '\0',
     947             :         0,
     948             :         "update",
     949             :         NULL,
     950             :         "update the index files from the different sources",
     951             :         advgetopt::getopt::no_argument
     952             :     },
     953             :     {
     954             :         '\0',
     955             :         0,
     956             :         "update-status",
     957             :         NULL,
     958             :         "print out the current status of the last update",
     959             :         advgetopt::getopt::no_argument
     960             :     },
     961             :     {
     962             :         '\0',
     963             :         0,
     964             :         "upgrade",
     965             :         NULL,
     966             :         "upgrade your current target with all newer available packages",
     967             :         advgetopt::getopt::no_argument
     968             :     },
     969             :     {
     970             :         '\0',
     971             :         0,
     972             :         "upgrade-info",
     973             :         NULL,
     974             :         "list the packages that can be upgraded with --upgrade",
     975             :         advgetopt::getopt::no_argument
     976             :     },
     977             :     {
     978             :         '\0',
     979             :         0,
     980             :         "upgrade-urgent",
     981             :         NULL,
     982             :         "upgrade your current target with packages that have an urgency of high or greater",
     983             :         advgetopt::getopt::no_argument
     984             :     },
     985             :     {
     986             :         '\0',
     987             :         0,
     988             :         "variable",
     989             :         NULL,
     990             :         "print the content of the named variable found in the .pc file of the listed packages",
     991             :         advgetopt::getopt::required_argument
     992             :     },
     993             :     {
     994             :         '\0',
     995             :         0,
     996             :         "vendor",
     997             :         NULL,
     998             :         "print to stdout the name of the vendor of this version of wpkg",
     999             :         advgetopt::getopt::no_argument
    1000             :     },
    1001             :     {
    1002             :         '\0',
    1003             :         0,
    1004             :         "verify",
    1005             :         NULL,
    1006             :         "check the archive validity",
    1007             :         advgetopt::getopt::required_argument
    1008             :     },
    1009             :     {
    1010             :         '\0',
    1011             :         0,
    1012             :         "verify-control",
    1013             :         NULL,
    1014             :         "validate control or control info files",
    1015             :         advgetopt::getopt::no_argument
    1016             :     },
    1017             :     {
    1018             :         '\0',
    1019             :         0,
    1020             :         "verify-project",
    1021             :         NULL,
    1022             :         "validate a project to prepare it for the wpkg environment; you must be in the root directory of the project to start this command",
    1023             :         advgetopt::getopt::no_argument
    1024             :     },
    1025             :     {
    1026             :         '\0',
    1027             :         advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
    1028             :         "version",
    1029             :         NULL,
    1030             :         "show the version of wpkg",
    1031             :         advgetopt::getopt::no_argument
    1032             :     },
    1033             :     {
    1034             :         'X',
    1035             :         0,
    1036             :         "vextract",
    1037             :         NULL,
    1038             :         "extract and list files from a wpkg package",
    1039             :         advgetopt::getopt::no_argument
    1040             :     },
    1041             :     // OPTIONS
    1042             :     {
    1043             :         '\0',
    1044             :         0,
    1045             :         NULL,
    1046             :         NULL,
    1047             :         "options:",
    1048             :         advgetopt::getopt::help_argument
    1049             :     },
    1050             :     {
    1051             :         '\0',
    1052             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1053             :         "admindir",
    1054             :         "var/lib/wpkg",
    1055             :         "define the administration directory (i.e. wpkg database folder), default is /var/lib/wpkg",
    1056             :         advgetopt::getopt::required_argument
    1057             :     },
    1058             :     {
    1059             :         '\0',
    1060             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1061             :         "build-number-filename",
    1062             :         NULL,
    1063             :         "define the name of the build number file; the default is \"wpkg/build_number\"",
    1064             :         advgetopt::getopt::required_argument
    1065             :     },
    1066             :     {
    1067             :         '\0',
    1068             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1069             :         "clear-exceptions",
    1070             :         NULL,
    1071             :         "remove all the exceptions and thus include all the files found in the control folder to the output .deb archive",
    1072             :         advgetopt::getopt::no_argument
    1073             :     },
    1074             :     {
    1075             :         '\0',
    1076             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1077             :         "cmake-generator",
    1078             :         NULL,
    1079             :         "define the generator to use with cmake; in most cases \"Unix Makefiles\" under Unix systems and \"NMake Makefiles\" using the MS-Windows Visual Studio development system",
    1080             :         advgetopt::getopt::required_argument
    1081             :     },
    1082             :     {
    1083             :         'Z',
    1084             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1085             :         "compressor",
    1086             :         "gzip",
    1087             :         "type of compression to use (gzip, bzip2, lzma, xz, none); default is best available",
    1088             :         advgetopt::getopt::required_argument
    1089             :     },
    1090             :     {
    1091             :         'D',
    1092             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1093             :         "debug",
    1094             :         NULL,
    1095             :         "define a set of debug to be printed out while wpkg works",
    1096             :         advgetopt::getopt::required_argument
    1097             :     },
    1098             :     {
    1099             :         '\0',
    1100             :         advgetopt::getopt::GETOPT_FLAG_ALIAS,
    1101             :         "define-variable",
    1102             :         NULL,
    1103             :         "field-variables",
    1104             :         advgetopt::getopt::required_multiple_argument
    1105             :     },
    1106             :     {
    1107             :         '\0',
    1108             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1109             :         "dry-run",
    1110             :         NULL,
    1111             :         "run all the validations of the command, do not actually run the process",
    1112             :         advgetopt::getopt::no_argument
    1113             :     },
    1114             :     {
    1115             :         '\0',
    1116             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1117             :         "enforce-path-length-limit",
    1118             :         NULL,
    1119             :         "while building a package, generate an error if a paths length is over this length (range 64 to 65536); to get warnings instead of errors use --path-length-limit instead",
    1120             :         advgetopt::getopt::required_argument
    1121             :     },
    1122             :     {
    1123             :         '\0',
    1124             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1125             :         "exception",
    1126             :         NULL,
    1127             :         "add one exception to the list of files not to add in a data.tar.gz file (i.e. \".svn\" or \"*.bak\")",
    1128             :         advgetopt::getopt::required_multiple_argument
    1129             :     },
    1130             :     {
    1131             :         'V',
    1132             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1133             :         "field-variables",
    1134             :         NULL,
    1135             :         "define field variables (list of <name>=<value> entries)",
    1136             :         advgetopt::getopt::required_multiple_argument
    1137             :     },
    1138             :     {
    1139             :         '\0',
    1140             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1141             :         "force-all",
    1142             :         NULL,
    1143             :         "turn on all the --force-... options",
    1144             :         advgetopt::getopt::no_argument
    1145             :     },
    1146             :     {
    1147             :         '\0',
    1148             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1149             :         "force-architecture",
    1150             :         NULL,
    1151             :         "force the installation of a package even if it has an incompatible architecture",
    1152             :         advgetopt::getopt::no_argument
    1153             :     },
    1154             :     {
    1155             :         '\0',
    1156             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1157             :         "force-breaks",
    1158             :         NULL,
    1159             :         "force the installation of a package even if it breaks another",
    1160             :         advgetopt::getopt::no_argument
    1161             :     },
    1162             :     {
    1163             :         '\0',
    1164             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1165             :         "force-configure-any",
    1166             :         NULL,
    1167             :         "force the configuration of packages that are dependencies not yet configured",
    1168             :         advgetopt::getopt::no_argument
    1169             :     },
    1170             :     {
    1171             :         '\0',
    1172             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1173             :         "force-conflicts",
    1174             :         NULL,
    1175             :         "force the installation of a package even if it is in conflicts",
    1176             :         advgetopt::getopt::no_argument
    1177             :     },
    1178             :     {
    1179             :         '\0',
    1180             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1181             :         "force-depends",
    1182             :         NULL,
    1183             :         "force the installation or removal of a package even if dependencies are not all properly satisfied",
    1184             :         advgetopt::getopt::no_argument
    1185             :     },
    1186             :     {
    1187             :         '\0',
    1188             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1189             :         "force-depends-version",
    1190             :         NULL,
    1191             :         "force the installation of a package even if the versions do not match",
    1192             :         advgetopt::getopt::no_argument
    1193             :     },
    1194             :     {
    1195             :         '\0',
    1196             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1197             :         "force-distribution",
    1198             :         NULL,
    1199             :         "allow the installation of packages from any distribution",
    1200             :         advgetopt::getopt::no_argument
    1201             :     },
    1202             :     {
    1203             :         '\0',
    1204             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1205             :         "force-downgrade",
    1206             :         NULL,
    1207             :         "allow downgrading packages (i.e. install packages with a smaller version of those already installed)",
    1208             :         advgetopt::getopt::no_argument
    1209             :     },
    1210             :     {
    1211             :         '\0',
    1212             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1213             :         "force-file-info",
    1214             :         NULL,
    1215             :         "allow file information (chmod/chown) to fail on installation of packages",
    1216             :         advgetopt::getopt::no_argument
    1217             :     },
    1218             :     {
    1219             :         '\0',
    1220             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1221             :         "force-hold",
    1222             :         NULL,
    1223             :         "force an upgrade or downgrade even if the package is marked as being on hold",
    1224             :         advgetopt::getopt::no_argument
    1225             :     },
    1226             :     {
    1227             :         '\0',
    1228             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1229             :         "force-overwrite",
    1230             :         NULL,
    1231             :         "force the installation of a package even if it means some files get overwritten",
    1232             :         advgetopt::getopt::no_argument
    1233             :     },
    1234             :     {
    1235             :         '\0',
    1236             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1237             :         "force-overwrite-dir",
    1238             :         NULL,
    1239             :         "force the installation of a package even if it means some directory get overwritten by a file",
    1240             :         advgetopt::getopt::no_argument
    1241             :     },
    1242             :     {
    1243             :         '\0',
    1244             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1245             :         "force-remove-essential",
    1246             :         NULL,
    1247             :         "allow the removal of essential packages, this is forbidden by default",
    1248             :         advgetopt::getopt::no_argument
    1249             :     },
    1250             :     {
    1251             :         '\0',
    1252             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1253             :         "force-rollback",
    1254             :         NULL,
    1255             :         "rollback all installation processes if any one of them fails",
    1256             :         advgetopt::getopt::no_argument
    1257             :     },
    1258             :     {
    1259             :         '\0',
    1260             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1261             :         "force-upgrade-any-version",
    1262             :         NULL,
    1263             :         "force the installation of a package even if the already installed package has a version smaller than the new version of the package minimum upgradable version field",
    1264             :         advgetopt::getopt::no_argument
    1265             :     },
    1266             :     {
    1267             :         '\0',
    1268             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1269             :         "force-vendor",
    1270             :         NULL,
    1271             :         "force the installation of a package even if the vendor of the package does not match the target vendor string",
    1272             :         advgetopt::getopt::no_argument
    1273             :     },
    1274             :     {
    1275             :         '\0',
    1276             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1277             :         "ignore-empty-package",
    1278             :         NULL,
    1279             :         "silently exit with 0 status when there are no files to package in a build process",
    1280             :         advgetopt::getopt::no_argument
    1281             :     },
    1282             :     {
    1283             :         '\0',
    1284             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1285             :         "install-prefix",
    1286             :         NULL,
    1287             :         "define the installation prefix to build binary packages from a source package",
    1288             :         advgetopt::getopt::required_argument
    1289             :     },
    1290             :     {
    1291             :         '\0',
    1292             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1293             :         "instdir",
    1294             :         "",
    1295             :         "specify the installation directory, where files get unpacked, by default the root is used",
    1296             :         advgetopt::getopt::required_argument
    1297             :     },
    1298             :     {
    1299             :         '\0',
    1300             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1301             :         "interactive",
    1302             :         "no-interactions",
    1303             :         "let wpkg know that it is interactive",
    1304             :         advgetopt::getopt::required_argument
    1305             :     },
    1306             :     {
    1307             :         '\0',
    1308             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1309             :         "log-output",
    1310             :         NULL,
    1311             :         "specify an output filename where logs get saved; the log level is ignored with this one, all logs get saved in this file",
    1312             :         advgetopt::getopt::required_argument
    1313             :     },
    1314             :     {
    1315             :         '\0',
    1316             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1317             :         "make-tool",
    1318             :         NULL,
    1319             :         "define the name of the make tool to use to build things after cmake generated files; usually make or nmake",
    1320             :         advgetopt::getopt::required_argument
    1321             :     },
    1322             :     {
    1323             :         '\0',
    1324             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1325             :         "no-act",
    1326             :         NULL,
    1327             :         "run all the validations of the command, do not actually run the process",
    1328             :         advgetopt::getopt::no_argument
    1329             :     },
    1330             :     {
    1331             :         '\0',
    1332             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1333             :         "no-force-all",
    1334             :         NULL,
    1335             :         "turn off all the --force-... options",
    1336             :         advgetopt::getopt::no_argument
    1337             :     },
    1338             :     {
    1339             :         '\0',
    1340             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1341             :         "no-force-architecture",
    1342             :         NULL,
    1343             :         "prevent the action of the --force-architecture option",
    1344             :         advgetopt::getopt::no_argument
    1345             :     },
    1346             :     {
    1347             :         '\0',
    1348             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1349             :         "no-force-breaks",
    1350             :         NULL,
    1351             :         "prevent the action of the --force-breaks option",
    1352             :         advgetopt::getopt::no_argument
    1353             :     },
    1354             :     {
    1355             :         '\0',
    1356             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1357             :         "no-force-configure-any",
    1358             :         NULL,
    1359             :         "prevent the action of the --force-configure-any option",
    1360             :         advgetopt::getopt::no_argument
    1361             :     },
    1362             :     {
    1363             :         '\0',
    1364             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1365             :         "no-force-conflicts",
    1366             :         NULL,
    1367             :         "prevent the action of the --force-conflicts option",
    1368             :         advgetopt::getopt::no_argument
    1369             :     },
    1370             :     {
    1371             :         '\0',
    1372             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1373             :         "no-force-depends",
    1374             :         NULL,
    1375             :         "prevent the action of the --force-depends option",
    1376             :         advgetopt::getopt::no_argument
    1377             :     },
    1378             :     {
    1379             :         '\0',
    1380             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1381             :         "no-force-depends-version",
    1382             :         NULL,
    1383             :         "prevent the action of the --force-depends-version option",
    1384             :         advgetopt::getopt::no_argument
    1385             :     },
    1386             :     {
    1387             :         '\0',
    1388             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1389             :         "no-force-distribution",
    1390             :         NULL,
    1391             :         "prevent the action of the --force-distribution option",
    1392             :         advgetopt::getopt::no_argument
    1393             :     },
    1394             :     {
    1395             :         '\0',
    1396             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1397             :         "no-force-downgrade",
    1398             :         NULL,
    1399             :         "prevent the action of the --force-downgrade option",
    1400             :         advgetopt::getopt::no_argument
    1401             :     },
    1402             :     {
    1403             :         '\0',
    1404             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1405             :         "no-force-file-info",
    1406             :         NULL,
    1407             :         "make sure to fail if file information (chmod/chown) fails on installation of packages",
    1408             :         advgetopt::getopt::no_argument
    1409             :     },
    1410             :     {
    1411             :         '\0',
    1412             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1413             :         "no-force-hold",
    1414             :         NULL,
    1415             :         "prevent upgrades and downgrades of packages marked as being on hold",
    1416             :         advgetopt::getopt::no_argument
    1417             :     },
    1418             :     {
    1419             :         '\0',
    1420             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1421             :         "no-force-overwrite",
    1422             :         NULL,
    1423             :         "prevent the action of the --force-overwrite option",
    1424             :         advgetopt::getopt::no_argument
    1425             :     },
    1426             :     {
    1427             :         '\0',
    1428             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1429             :         "no-force-overwrite-dir",
    1430             :         NULL,
    1431             :         "prevent the action of the --force-overwrite-dir option",
    1432             :         advgetopt::getopt::no_argument
    1433             :     },
    1434             :     {
    1435             :         '\0',
    1436             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1437             :         "no-force-remove-essential",
    1438             :         NULL,
    1439             :         "prevent the action of the --force-remove-essential option",
    1440             :         advgetopt::getopt::no_argument
    1441             :     },
    1442             :     {
    1443             :         '\0',
    1444             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1445             :         "no-force-rollback",
    1446             :         NULL,
    1447             :         "prevent the action of the --force-rollback option",
    1448             :         advgetopt::getopt::no_argument
    1449             :     },
    1450             :     {
    1451             :         '\0',
    1452             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1453             :         "no-force-upgrade-any-version",
    1454             :         NULL,
    1455             :         "prevent the action of the --force-upgrade-any-version option",
    1456             :         advgetopt::getopt::no_argument
    1457             :     },
    1458             :     {
    1459             :         '\0',
    1460             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1461             :         "no-force-vendor",
    1462             :         NULL,
    1463             :         "prevent the action of the --force-vendor option",
    1464             :         advgetopt::getopt::no_argument
    1465             :     },
    1466             :     {
    1467             :         '\0',
    1468             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1469             :         "numbers",
    1470             :         NULL,
    1471             :         "show numbers instead of user/group names and mode flags",
    1472             :         advgetopt::getopt::no_argument
    1473             :     },
    1474             :     {
    1475             :         '\0',
    1476             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1477             :         "output-dir",
    1478             :         NULL,
    1479             :         "save the package being built in the specified directory",
    1480             :         advgetopt::getopt::required_argument
    1481             :     },
    1482             :     {
    1483             :         '\0',
    1484             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1485             :         "output-filename",
    1486             :         NULL,
    1487             :         "force the output filename of a package being built",
    1488             :         advgetopt::getopt::required_argument
    1489             :     },
    1490             :     {
    1491             :         '\0',
    1492             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1493             :         "output-repository-dir",
    1494             :         NULL,
    1495             :         "define the repository directory where source and binary packages shall be saved",
    1496             :         advgetopt::getopt::required_argument
    1497             :     },
    1498             :     {
    1499             :         '\0',
    1500             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1501             :         "path-length-limit",
    1502             :         NULL,
    1503             :         "while building a package, warn about paths that are over this length (range 64 to 65536); to get an error instead of a warning use --enforce-path-length-limit instead",
    1504             :         advgetopt::getopt::required_argument
    1505             :     },
    1506             :     {
    1507             :         'q',
    1508             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1509             :         "quiet",
    1510             :         NULL,
    1511             :         "prevent printing informational and warning messages; in some cases, avoid some lesser errors from being printed too",
    1512             :         advgetopt::getopt::no_argument
    1513             :     },
    1514             :     {
    1515             :         'R',
    1516             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1517             :         "recursive",
    1518             :         NULL,
    1519             :         "install: enable recursivity of repository directories (i.e. sub-directories are also scanned); remove: automatically allow removal of dependencies",
    1520             :         advgetopt::getopt::no_argument
    1521             :     },
    1522             :     {
    1523             :         '\0',
    1524             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1525             :         "refuse-all",
    1526             :         NULL,
    1527             :         "turn off all the --force-... options",
    1528             :         advgetopt::getopt::no_argument
    1529             :     },
    1530             :     {
    1531             :         '\0',
    1532             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1533             :         "refuse-architecture",
    1534             :         NULL,
    1535             :         "prevent the action of the --force-architecture option",
    1536             :         advgetopt::getopt::no_argument
    1537             :     },
    1538             :     {
    1539             :         '\0',
    1540             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1541             :         "refuse-breaks",
    1542             :         NULL,
    1543             :         "prevent the action of the --force-breaks option",
    1544             :         advgetopt::getopt::no_argument
    1545             :     },
    1546             :     {
    1547             :         '\0',
    1548             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1549             :         "refuse-configure-any",
    1550             :         NULL,
    1551             :         "prevent the action of the --force-configure-any option",
    1552             :         advgetopt::getopt::no_argument
    1553             :     },
    1554             :     {
    1555             :         '\0',
    1556             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1557             :         "refuse-conflicts",
    1558             :         NULL,
    1559             :         "prevent the action of the --force-conflicts option",
    1560             :         advgetopt::getopt::no_argument
    1561             :     },
    1562             :     {
    1563             :         '\0',
    1564             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1565             :         "refuse-depends",
    1566             :         NULL,
    1567             :         "prevent the action of the --force-depends option",
    1568             :         advgetopt::getopt::no_argument
    1569             :     },
    1570             :     {
    1571             :         '\0',
    1572             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1573             :         "refuse-depends-version",
    1574             :         NULL,
    1575             :         "prevent the action of the --force-depends-version option",
    1576             :         advgetopt::getopt::no_argument
    1577             :     },
    1578             :     {
    1579             :         '\0',
    1580             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1581             :         "refuse-distribution",
    1582             :         NULL,
    1583             :         "prevent the action of the --force-distribution option",
    1584             :         advgetopt::getopt::no_argument
    1585             :     },
    1586             :     {
    1587             :         'G',
    1588             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1589             :         "refuse-downgrade",
    1590             :         NULL,
    1591             :         "prevent the action of the --force-downgrade option",
    1592             :         advgetopt::getopt::no_argument
    1593             :     },
    1594             :     {
    1595             :         '\0',
    1596             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1597             :         "refuse-file-info",
    1598             :         NULL,
    1599             :         "make sure to fail if file information (chmod/chown) fails on installation of packages",
    1600             :         advgetopt::getopt::no_argument
    1601             :     },
    1602             :     {
    1603             :         '\0',
    1604             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1605             :         "refuse-hold",
    1606             :         NULL,
    1607             :         "prevent upgrades and downgrades of packages marked as being on hold",
    1608             :         advgetopt::getopt::no_argument
    1609             :     },
    1610             :     {
    1611             :         '\0',
    1612             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1613             :         "refuse-overwrite",
    1614             :         NULL,
    1615             :         "prevent the action of the --force-overwrite option",
    1616             :         advgetopt::getopt::no_argument
    1617             :     },
    1618             :     {
    1619             :         '\0',
    1620             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1621             :         "refuse-overwrite-dir",
    1622             :         NULL,
    1623             :         "prevent the action of the --force-overwrite-dir option",
    1624             :         advgetopt::getopt::no_argument
    1625             :     },
    1626             :     {
    1627             :         '\0',
    1628             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1629             :         "refuse-remove-essential",
    1630             :         NULL,
    1631             :         "prevent the action of the --force-remove-essential option",
    1632             :         advgetopt::getopt::no_argument
    1633             :     },
    1634             :     {
    1635             :         '\0',
    1636             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1637             :         "refuse-rollback",
    1638             :         NULL,
    1639             :         "prevent the action of the --force-rollback option",
    1640             :         advgetopt::getopt::no_argument
    1641             :     },
    1642             :     {
    1643             :         '\0',
    1644             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1645             :         "refuse-upgrade-any-version",
    1646             :         NULL,
    1647             :         "prevent the action of the --force-upgrade-any-version option",
    1648             :         advgetopt::getopt::no_argument
    1649             :     },
    1650             :     {
    1651             :         '\0',
    1652             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1653             :         "refuse-vendor",
    1654             :         NULL,
    1655             :         "prevent the action of the --force-vendor option",
    1656             :         advgetopt::getopt::no_argument
    1657             :     },
    1658             :     {
    1659             :         '\0',
    1660             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1661             :         "repository",
    1662             :         NULL,
    1663             :         "define the path to a directory filled with packages, and automatically install dependencies if such are missing",
    1664             :         advgetopt::getopt::required_multiple_argument
    1665             :     },
    1666             :     {
    1667             :         '\0',
    1668             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1669             :         "root",
    1670             :         "/",
    1671             :         "define the root directory (i.e. where everything is installed), default is /",
    1672             :         advgetopt::getopt::required_argument
    1673             :     },
    1674             :     {
    1675             :         '\0',
    1676             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1677             :         "run-unit-tests",
    1678             :         NULL,
    1679             :         "run the unit tests of a package right after building a package from its source package and before creating its binary packages",
    1680             :         advgetopt::getopt::no_argument
    1681             :     },
    1682             :     {
    1683             :         '\0',
    1684             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1685             :         "showformat",
    1686             :         NULL,
    1687             :         "format used with the --show command; variables can be referenced as ${field:[-]width}",
    1688             :         advgetopt::getopt::required_argument
    1689             :     },
    1690             :     {
    1691             :         '\0',
    1692             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1693             :         "simulate",
    1694             :         NULL,
    1695             :         "run all the validations of the command, do not actually run the process",
    1696             :         advgetopt::getopt::no_argument
    1697             :     },
    1698             :     {
    1699             :         'E',
    1700             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1701             :         "skip-same-version",
    1702             :         NULL,
    1703             :         "skip intalling packages that are already installed (i.e. version is the same)",
    1704             :         advgetopt::getopt::no_argument
    1705             :     },
    1706             :     {
    1707             :         '\0',
    1708             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1709             :         "tmpdir",
    1710             :         NULL,
    1711             :         "define the temporary directory (i.e. /tmp under a Unix syste,), the default is dynamically determined",
    1712             :         advgetopt::getopt::required_argument
    1713             :     },
    1714             :     {
    1715             :         '\0',
    1716             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1717             :         "tracking-journal",
    1718             :         NULL,
    1719             :         "explicitly specify the filename of the tracking journal; in which case the journal does not get deleted",
    1720             :         advgetopt::getopt::no_argument
    1721             :     },
    1722             :     {
    1723             :         '\0',
    1724             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE | advgetopt::getopt::GETOPT_FLAG_ALIAS,
    1725             :         "validate-fields",
    1726             :         NULL,
    1727             :         "verify-fields",
    1728             :         advgetopt::getopt::required_multiple_argument
    1729             :     },
    1730             :     {
    1731             :         'v',
    1732             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1733             :         "verbose",
    1734             :         NULL,
    1735             :         "print additional information as available",
    1736             :         advgetopt::getopt::no_argument
    1737             :     },
    1738             :     {
    1739             :         '\0',
    1740             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1741             :         "verify-fields",
    1742             :         NULL,
    1743             :         "validate control file fields (used along --verify or --install)",
    1744             :         advgetopt::getopt::required_multiple_argument
    1745             :     },
    1746             :     {
    1747             :         'z',
    1748             :         advgetopt::getopt::GETOPT_FLAG_ENVIRONMENT_VARIABLE | advgetopt::getopt::GETOPT_FLAG_CONFIGURATION_FILE,
    1749             :         "zlevel",
    1750             :         "9",
    1751             :         "compression level when building (1-9), default is 9",
    1752             :         advgetopt::getopt::required_argument
    1753             :     },
    1754             :     {
    1755             :         '\0',
    1756             :         0,
    1757             :         "running-copy",
    1758             :         NULL,
    1759             :         NULL, // hidden argument in --help screen
    1760             :         advgetopt::getopt::no_argument
    1761             :     },
    1762             :     {
    1763             :         '\0',
    1764             :         0,
    1765             :         "filename",
    1766             :         NULL,
    1767             :         NULL, // hidden argument in --help screen
    1768             :         advgetopt::getopt::default_multiple_argument
    1769             :     },
    1770             :     {
    1771             :         '\0',
    1772             :         0,
    1773             :         NULL,
    1774             :         NULL,
    1775             :         NULL,
    1776             :         advgetopt::getopt::end_of_options
    1777             :     }
    1778             : };
    1779             : 
    1780             : 
    1781           1 : void version(command_line& cl)
    1782             : {
    1783           1 :     if(cl.size() != 0)
    1784             :     {
    1785           0 :         cl.opt().usage(advgetopt::getopt::error, "The --version option does not take any other arguments");
    1786             :         /*NOTREACHED*/
    1787             :     }
    1788             : 
    1789           1 :     if(cl.verbose())
    1790             :     {
    1791             :         printf("wpkg %s (built on %s)\nbzip2 %s\nzlib %s\nlibtld %s\ncontrolled_vars %s\n",
    1792             :             debian_packages_version_string(), debian_packages_build_time(),
    1793             :             BZ2_bzlibVersion(),
    1794             :             zlibVersion(),
    1795             :             tld_version(),
    1796             :             controlled_vars::controlled_vars_version()
    1797           0 :         );
    1798             :     }
    1799             :     else
    1800             :     {
    1801           1 :         printf("%s\n", debian_packages_version_string());
    1802             :     }
    1803             : 
    1804           1 :     exit(1);
    1805             : }
    1806             : 
    1807             : 
    1808             : 
    1809             : struct help_t;
    1810             : 
    1811             : typedef void (*help_func_t)(command_line& cl, const help_t *h);
    1812             : 
    1813             : /** \brief Structure used to define help entries.
    1814             :  *
    1815             :  * This structure is used to define the help entries of the advanced
    1816             :  * help in wpkg. It includes a name, a function when that specific
    1817             :  * help entry is specified on the command line, and a description
    1818             :  * of this entry.
    1819             :  */
    1820             : struct help_t
    1821             : {
    1822             :     const char *    f_name;
    1823             :     help_func_t     f_func;
    1824             :     const char *    f_help;
    1825             : };
    1826             : 
    1827             : // pre-declaration for help_list()
    1828             : extern const help_t advanced_help[];
    1829             : 
    1830             : 
    1831           0 : void help_output_control_field(command_line& cl, wpkg_control::control_file::field_factory_map_t::const_iterator& f)
    1832             : {
    1833           0 :     if(cl.verbose())
    1834             :     {
    1835           0 :         printf("%s:", f->second->name());
    1836           0 :         wpkg_field::field_file::field_factory_t::name_list_t e(f->second->equivalents());
    1837           0 :         if(!e.empty())
    1838             :         {
    1839           0 :             size_t max(e.size());
    1840           0 :             for(size_t i(0); i < max; ++i)
    1841             :             {
    1842           0 :                 printf(" (or %s)", e[i].c_str());
    1843             :             }
    1844             :         }
    1845           0 :         printf("\n  %s\n\n", f->second->help());
    1846             :     }
    1847           0 :     else if(cl.quiet())
    1848             :     {
    1849           0 :         printf("%s\n", f->second->name());
    1850             :     }
    1851             :     else
    1852             :     {
    1853           0 :         printf("%-32s: %.43s...\n", f->second->name(), f->second->help());
    1854             :     }
    1855           0 : }
    1856             : 
    1857           0 : void help_control_field(command_line& cl, const help_t *h)
    1858             : {
    1859           0 :     const wpkg_control::control_file::field_factory_map_t *fields(wpkg_control::control_file::field_factory_map());
    1860             : 
    1861           0 :     const size_t max(cl.size());
    1862           0 :     if(max > 1)
    1863             :     {
    1864             :         // idx = 0 is the command: "field"
    1865           0 :         for(size_t idx(1); idx < max; ++idx)
    1866             :         {
    1867           0 :             const case_insensitive::case_insensitive_string name(cl.get_string("filename", static_cast<int>(idx)));
    1868           0 :             wpkg_control::control_file::field_factory_map_t::const_iterator f(fields->find(name));
    1869           0 :             if(f == fields->end())
    1870             :             {
    1871           0 :                 printf("wpkg:warning: unknown field \"%s\".\n", name.c_str());
    1872             :             }
    1873             :             else
    1874             :             {
    1875           0 :                 help_output_control_field(cl, f);
    1876             :             }
    1877           0 :         }
    1878             :     }
    1879             :     else
    1880             :     {
    1881           0 :         for(wpkg_control::control_file::field_factory_map_t::const_iterator f(fields->begin()); f != fields->end(); ++f)
    1882             :         {
    1883           0 :             help_output_control_field(cl, f);
    1884             :         }
    1885             :     }
    1886           0 : }
    1887             : 
    1888             : 
    1889             : 
    1890           0 : void help_output_copyright_field(command_line& cl, wpkg_copyright::copyright_file::field_factory_map_t::const_iterator& f)
    1891             : {
    1892           0 :     if(cl.verbose())
    1893             :     {
    1894           0 :         printf("%s:", f->second->name());
    1895           0 :         wpkg_field::field_file::field_factory_t::name_list_t e(f->second->equivalents());
    1896           0 :         if(!e.empty())
    1897             :         {
    1898           0 :             size_t max(e.size());
    1899           0 :             for(size_t i(0); i < max; ++i)
    1900             :             {
    1901           0 :                 printf(" (or %s)", e[i].c_str());
    1902             :             }
    1903             :         }
    1904           0 :         printf("\n  %s\n\n", f->second->help());
    1905             :     }
    1906           0 :     else if(cl.quiet())
    1907             :     {
    1908           0 :         printf("%s\n", f->second->name());
    1909             :     }
    1910             :     else
    1911             :     {
    1912           0 :         printf("%-32s: %.43s...\n", f->second->name(), f->second->help());
    1913             :     }
    1914           0 : }
    1915             : 
    1916           0 : void help_copyright_field(command_line& cl, const help_t *h)
    1917             : {
    1918           0 :     const wpkg_copyright::copyright_file::field_factory_map_t *fields(wpkg_copyright::copyright_file::field_factory_map());
    1919             : 
    1920           0 :     const size_t max(cl.size());
    1921           0 :     if(max > 1)
    1922             :     {
    1923             :         // idx = 0 is the command: "field"
    1924           0 :         for(size_t idx(1); idx < max; ++idx)
    1925             :         {
    1926           0 :             const case_insensitive::case_insensitive_string name(cl.get_string("filename", static_cast<int>(idx)));
    1927           0 :             wpkg_copyright::copyright_file::field_factory_map_t::const_iterator f(fields->find(name));
    1928           0 :             if(f == fields->end())
    1929             :             {
    1930           0 :                 printf("wpkg:warning: unknown copyright field \"%s\".\n", name.c_str());
    1931             :             }
    1932             :             else
    1933             :             {
    1934           0 :                 help_output_copyright_field(cl, f);
    1935             :             }
    1936           0 :         }
    1937             :     }
    1938             :     else
    1939             :     {
    1940           0 :         for(wpkg_copyright::copyright_file::field_factory_map_t::const_iterator f(fields->begin()); f != fields->end(); ++f)
    1941             :         {
    1942           0 :             help_output_copyright_field(cl, f);
    1943             :         }
    1944             :     }
    1945           0 : }
    1946             : 
    1947             : 
    1948             : 
    1949           0 : void help_list_of_terms(command_line& cl, const char *msg, const wpkg_control::control_file::list_of_terms_t *t)
    1950             : {
    1951           0 :     if(!cl.quiet())
    1952             :     {
    1953           0 :         printf("%s:\n", msg);
    1954             :     }
    1955           0 :     for(; t->f_term != NULL; ++t)
    1956             :     {
    1957           0 :         if(cl.verbose())
    1958             :         {
    1959           0 :             printf("%s:\n%s\n\n", t->f_term, t->f_help);
    1960             :         }
    1961             :         else
    1962             :         {
    1963           0 :             printf("%s\n", t->f_term);
    1964             :         }
    1965             :     }
    1966           0 : }
    1967             : 
    1968             : 
    1969           0 : void help_build_validations(command_line& cl, const help_t *h)
    1970             : {
    1971           0 :     help_list_of_terms(cl, "List of validations used against a project to build its source package", wpkgar::wpkgar_build::source_validation::list());
    1972           0 : }
    1973             : 
    1974           0 : void help_priorities(command_line& cl, const help_t *h)
    1975             : {
    1976           0 :     help_list_of_terms(cl, "List of properties", wpkg_control::control_file::field_priority_t::list());
    1977           0 : }
    1978             : 
    1979           0 : void help_sections(command_line& cl, const help_t *h)
    1980             : {
    1981           0 :     help_list_of_terms(cl, "List of sections", wpkg_control::control_file::field_section_t::list());
    1982           0 : }
    1983             : 
    1984           0 : void help_urgencies(command_line& cl, const help_t *h)
    1985             : {
    1986           0 :     help_list_of_terms(cl, "List of urgency terms", wpkg_control::control_file::field_urgency_t::list());
    1987           0 : }
    1988             : 
    1989           0 : void help_list(command_line& cl, const help_t *h)
    1990             : {
    1991           0 :     if(!cl.quiet())
    1992             :     {
    1993           0 :         printf("List of help commands:\n");
    1994             :     }
    1995           0 :     for(const help_t *all(advanced_help); all->f_name != NULL; ++all)
    1996             :     {
    1997           0 :         if(cl.verbose())
    1998             :         {
    1999           0 :             printf("%s:\n%s\n\n", all->f_name, all->f_help);
    2000             :         }
    2001             :         else
    2002             :         {
    2003           0 :             printf("%s\n", all->f_name);
    2004             :         }
    2005             :     }
    2006           0 : }
    2007             : 
    2008           0 : void help_help(command_line& cl, const help_t *h)
    2009             : {
    2010             :     // note that when f_name is NULL, f_help is still defined
    2011             :     // (i.e. we have a default help in case the user did not enter a
    2012             :     // name we know about)
    2013           0 :     printf("%s\n", h->f_help);
    2014           0 : }
    2015             : 
    2016             : 
    2017             : 
    2018             : const help_t advanced_help[] =
    2019             : {
    2020             :     {
    2021             :         "build-validations",
    2022             :         help_build_validations,
    2023             :         "List the validations used to check a project source directory before "
    2024             :         "creating a source package with wpkg with:\n"
    2025             :         "   wpkg --build\n\n"
    2026             :         "The packager will create the source package only after all those "
    2027             :         "validations ran successfully. If you are interested in just testing "
    2028             :         "whether your project is ready, then you can use:\n"
    2029             :         "   wpkg --verify-project\n"
    2030             :         "which will give you detailed information about each validation that "
    2031             :         "fails."
    2032             :     },
    2033             :     {
    2034             :         "copyright",
    2035             :         help_copyright_field,
    2036             :         "Print help about a copyright field. To have detailed help about "
    2037             :         "one specific field enter its name after the help command:\n"
    2038             :         "   wpkg --help copyright files\n"
    2039             :         "Note that copyright field names are case insensitive."
    2040             :     },
    2041             :     {
    2042             :         "field",
    2043             :         help_control_field,
    2044             :         "Print help about a control file field. To have detailed help about "
    2045             :         "a specific field enter its name after the help command:\n"
    2046             :         "   wpkg --help field architecture\n"
    2047             :         "Note that field names are case insensitive."
    2048             :     },
    2049             :     {
    2050             :         "help",
    2051             :         help_help,
    2052             :         "The advanced help system gives you additional help directly from "
    2053             :         "your command line. Note that if you have Internet access the "
    2054             :         "website help is certainly a lot more practical as it gives you "
    2055             :         "links between all the items, see http://windowspackager.org/ for "
    2056             :         "details.\n\n"
    2057             :         "To use this help system use the --help command followed by the "
    2058             :         "name of the help you are interested in. For example:\n"
    2059             :         "   wpkg --help help\n\n"
    2060             :         "The list of commands can be found with:\n"
    2061             :         "   wpkg --help help-list"
    2062             :     },
    2063             :     {
    2064             :         "help-list",
    2065             :         help_list,
    2066             :         "List all the help commands that you can use with:\n"
    2067             :         "   wpkg --help <command>\n"
    2068             :     },
    2069             :     {
    2070             :         "priorities",
    2071             :         help_priorities,
    2072             :         "List of priority terms that can be used in the Priority field. "
    2073             :         "This defines how important a package is in regard to an "
    2074             :         "installation environment."
    2075             :     },
    2076             :     {
    2077             :         "sections",
    2078             :         help_sections,
    2079             :         "List the name of valid Debian sections which can be used with the "
    2080             :         "Section field. Note that only those sections are valid."
    2081             :     },
    2082             :     {
    2083             :         "urgencies",
    2084             :         help_urgencies,
    2085             :         "List of valid urgency terms that can be used with the Urgency "
    2086             :         "field. Note that Urgency levels have very specific meaning."
    2087             :     },
    2088             :     {
    2089             :         NULL,
    2090             :         help_help,
    2091             :         "This help function was not found, to get a list "
    2092             :         "of valid help functions try:\n"
    2093             :         "   wpkg --help help-list"
    2094             :     }
    2095             : };
    2096             : 
    2097             : 
    2098             : 
    2099             : 
    2100           0 : void help(command_line& cl)
    2101             : {
    2102           0 :     const case_insensitive::case_insensitive_string cmd(cl.get_string("filename", 0));
    2103             : 
    2104           0 :     for(const help_t *h(advanced_help);; ++h)
    2105             :     {
    2106           0 :         if(h->f_name == NULL || cmd == h->f_name)
    2107             :         {
    2108           0 :             h->f_func(cl, h);
    2109           0 :             break;
    2110             :         }
    2111             :     }
    2112             : 
    2113             :     // we do not return
    2114           0 :     exit(1);
    2115             : }
    2116             : 
    2117             : 
    2118        1494 : command_line::command_line(int argc, char *argv[], std::vector<std::string> configuration_files)
    2119             :     : f_opt(argc, argv, wpkg_options, configuration_files, "WPKG_OPTIONS")
    2120             :     , f_command(static_cast<int>(command_unknown)) // TODO: cast because of enum handling in controlled_vars...
    2121             :     //, f_quiet(false) -- auto-init
    2122             :     //, f_verbose(false) -- auto-init
    2123             :     //, f_dry_run(false) -- auto-init
    2124             :     , f_zlevel(9)
    2125             :     //, f_debug_flags(debug_none)
    2126             :     , f_compressor(memfile::memory_file::file_format_best)
    2127        1494 :     , f_option("filename")
    2128             :     //, f_filenames() -- auto-init
    2129             : {
    2130             : // these two flags may be tweaked by commands
    2131        1494 :     f_quiet = f_opt.is_defined("quiet");
    2132        1494 :     f_verbose = f_opt.is_defined("verbose");
    2133        1494 :     f_dry_run = f_opt.is_defined("dry-run") || f_opt.is_defined("no-act") || f_opt.is_defined("simulate");
    2134             : 
    2135             : // define the interactive mode between wpkg and the administrator
    2136             : // (default is no-interactions); needs to be done early on
    2137        1494 :     std::string interactive(f_opt.get_string("interactive"));
    2138        1494 :     if(interactive == "no-interactions")
    2139             :     {
    2140        1494 :         wpkg_filename::uri_filename::set_interactive(wpkg_filename::uri_filename::wpkgar_interactive_mode_no_interactions);
    2141             :     }
    2142           0 :     else if(interactive == "console")
    2143             :     {
    2144           0 :         wpkg_filename::uri_filename::set_interactive(wpkg_filename::uri_filename::wpkgar_interactive_mode_console);
    2145             :     }
    2146           0 :     else if(interactive == "gui")
    2147             :     {
    2148           0 :         wpkg_filename::uri_filename::set_interactive(wpkg_filename::uri_filename::wpkgar_interactive_mode_gui);
    2149             :     }
    2150             :     else
    2151             :     {
    2152           0 :         f_opt.usage(advgetopt::getopt::error, "the --interactive option only accepts \"no-interactions\", \"console\", or \"gui\"");
    2153             :         /*NOTREACHED*/
    2154             :     }
    2155             : 
    2156             : // determine command
    2157             :     // first we check all the commands and determine which
    2158             :     // command the user used, if the user specified multiple
    2159             :     // commands then it is an error except in a few cases where
    2160             :     // two commands get "merged" (i.e. --autoremove + --purge,
    2161             :     // --build + --install, --build --create-index, etc.)
    2162             : 
    2163             :     //
    2164             :     // The following accepts:
    2165             :     //    --autoremove
    2166             :     //    --purge
    2167             :     //    --autoremove --purge
    2168             :     //
    2169        1494 :     if(f_opt.is_defined("autoremove"))
    2170             :     {
    2171           4 :         set_command(command_autoremove);
    2172             :     }
    2173        1490 :     else if(f_opt.is_defined("purge"))
    2174             :     {
    2175          30 :         set_command(command_purge);
    2176             :     }
    2177             : 
    2178             :     //
    2179             :     // The following can be merged as following
    2180             :     //    --build
    2181             :     //    --build --install   <=>   --build-and-install
    2182             :     //    --build --create-index
    2183             :     //    --build --install --create-index
    2184             :     //
    2185             :     // Other combos generate an error, for example:
    2186             :     //    --build --build-and-install
    2187             :     //    --install --build-and-install
    2188             :     //    --install --create-index
    2189             :     //
    2190        1494 :     if(f_opt.is_defined("build"))
    2191             :     {
    2192         310 :         if(f_opt.is_defined("build-and-install"))
    2193             :         {
    2194             :             // generate an error on purpose
    2195           0 :             set_command(command_build);
    2196           0 :             set_command(command_build_and_install);
    2197             :         }
    2198         310 :         else if(f_opt.is_defined("install"))
    2199             :         {
    2200           0 :             set_command(command_build_and_install);
    2201             :         }
    2202             :         else
    2203             :         {
    2204         310 :             set_command(command_build);
    2205             :         }
    2206             :     }
    2207        1184 :     else if(f_opt.is_defined("build-and-install"))
    2208             :     {
    2209           0 :         set_command(command_build_and_install);
    2210           0 :         if(f_opt.is_defined("install"))
    2211             :         {
    2212             :             // generate an error on purpose
    2213           0 :             set_command(command_install);
    2214             :         }
    2215             :     }
    2216        1184 :     else if(f_opt.is_defined("create-index"))
    2217             :     {
    2218          10 :         set_command(command_create_index);
    2219          10 :         if(f_opt.is_defined("install"))
    2220             :         {
    2221             :             // generate an error on purpose
    2222           0 :             set_command(command_install);
    2223             :         }
    2224             :     }
    2225        1174 :     else if(f_opt.is_defined("install"))
    2226             :     {
    2227         329 :         set_command(command_install);
    2228             :     }
    2229             : 
    2230        1494 :     if(f_opt.is_defined("add-hooks"))
    2231             :     {
    2232           1 :         set_command(command_add_hooks);
    2233             :     }
    2234        1494 :     if(f_opt.is_defined("add-sources"))
    2235             :     {
    2236           0 :         set_command(command_add_sources);
    2237             :     }
    2238        1494 :     if(f_opt.is_defined("architecture"))
    2239             :     {
    2240           0 :         set_command(command_architecture);
    2241             :     }
    2242        1494 :     if(f_opt.is_defined("atleast-version"))
    2243             :     {
    2244           0 :         set_command(command_atleast_version);
    2245             :     }
    2246        1494 :     if(f_opt.is_defined("atleast-wpkg-version"))
    2247             :     {
    2248           0 :         set_command(command_atleast_wpkg_version);
    2249             :     }
    2250        1494 :     if(f_opt.is_defined("audit"))
    2251             :     {
    2252           0 :         set_command(command_audit);
    2253             :     }
    2254             : 
    2255        4482 :     if(f_opt.is_defined("canonicalize-version")
    2256        2988 :     || f_opt.is_defined("canonalize-version"))
    2257             :     {
    2258           0 :         set_command(command_canonicalize_version);
    2259             :     }
    2260        1494 :     if(f_opt.is_defined("cflags"))
    2261             :     {
    2262           0 :         set_command(command_cflags);
    2263             :     }
    2264        1494 :     if(f_opt.is_defined("check-install"))
    2265             :     {
    2266           0 :         set_command(command_check_install);
    2267             :     }
    2268        1494 :     if(f_opt.is_defined("compare-versions"))
    2269             :     {
    2270         750 :         set_command(command_compare_versions);
    2271             :     }
    2272        1494 :     if(f_opt.is_defined("compress"))
    2273             :     {
    2274           0 :         set_command(command_compress);
    2275             :     }
    2276        1494 :     if(f_opt.is_defined("configure"))
    2277             :     {
    2278           0 :         set_command(command_configure);
    2279             :     }
    2280        1494 :     if(f_opt.is_defined("contents"))
    2281             :     {
    2282           0 :         set_command(command_contents);
    2283             :     }
    2284        1494 :     if(f_opt.is_defined("control"))
    2285             :     {
    2286           0 :         set_command(command_control);
    2287             :     }
    2288        1494 :     if(f_opt.is_defined("copyright"))
    2289             :     {
    2290           0 :         set_command(command_copyright);
    2291             :     }
    2292        1494 :     if(f_opt.is_defined("create-admindir"))
    2293             :     {
    2294          26 :         set_command(command_create_admindir);
    2295             :     }
    2296        1494 :     if(f_opt.is_defined("create-database-lock"))
    2297             :     {
    2298           0 :         set_command(command_create_database_lock);
    2299             :     }
    2300        1494 :     if(f_opt.is_defined("database-is-locked"))
    2301             :     {
    2302           0 :         set_command(command_database_is_locked);
    2303             :     }
    2304        1494 :     if(f_opt.is_defined("decompress"))
    2305             :     {
    2306           0 :         set_command(command_decompress);
    2307             :     }
    2308        1494 :     if(f_opt.is_defined("deconfigure"))
    2309             :     {
    2310           0 :         set_command(command_deconfigure);
    2311             :     }
    2312        1494 :     if(f_opt.is_defined("directory-size"))
    2313             :     {
    2314           0 :         set_command(command_directory_size);
    2315             :     }
    2316        1494 :     if(f_opt.is_defined("exact-version"))
    2317             :     {
    2318           0 :         set_command(command_exact_version);
    2319             :     }
    2320        1494 :     if(f_opt.is_defined("extract"))
    2321             :     {
    2322           0 :         set_command(command_extract);
    2323             :     }
    2324        1494 :     if(f_opt.is_defined("field"))
    2325             :     {
    2326           0 :         set_command(command_field);
    2327             :     }
    2328        1494 :     if(f_opt.is_defined("fsys-tarfile"))
    2329             :     {
    2330           0 :         set_command(command_fsys_tarfile);
    2331             :     }
    2332        1494 :     if(f_opt.is_defined("help"))
    2333             :     {
    2334           0 :         set_command(command_help);
    2335             :     }
    2336        1494 :     if(f_opt.is_defined("help-nobr"))
    2337             :     {
    2338           0 :         set_command(command_help);
    2339             :     }
    2340        1494 :     if(f_opt.is_defined("increment-build-number"))
    2341             :     {
    2342           0 :         set_command(command_increment_build_number);
    2343             :     }
    2344        1494 :     if(f_opt.is_defined("info"))
    2345             :     {
    2346           0 :         set_command(command_info);
    2347             :     }
    2348        1494 :     if(f_opt.is_defined("install-size"))
    2349             :     {
    2350           0 :         set_command(command_install_size);
    2351             :     }
    2352        1494 :     if(f_opt.is_defined("is-installed"))
    2353             :     {
    2354           0 :         set_command(command_is_installed);
    2355             :     }
    2356        1494 :     if(f_opt.is_defined("libs"))
    2357             :     {
    2358           0 :         set_command(command_libs);
    2359             :     }
    2360        1494 :     if(f_opt.is_defined("license") || f_opt.is_defined("licence"))
    2361             :     {
    2362           0 :         set_command(command_license);
    2363             :     }
    2364        1494 :     if(f_opt.is_defined("list"))
    2365             :     {
    2366           0 :         set_command(command_list);
    2367             :     }
    2368        1494 :     if(f_opt.is_defined("list-all"))
    2369             :     {
    2370           0 :         set_command(command_list_all);
    2371             :     }
    2372        1494 :     if(f_opt.is_defined("listfiles"))
    2373             :     {
    2374           0 :         set_command(command_listfiles);
    2375             :     }
    2376        1494 :     if(f_opt.is_defined("list-hooks"))
    2377             :     {
    2378           2 :         set_command(command_list_hooks);
    2379             :     }
    2380        1494 :     if(f_opt.is_defined("list-index-packages"))
    2381             :     {
    2382           0 :         set_command(command_list_index_packages);
    2383             :     }
    2384        1494 :     if(f_opt.is_defined("list-sources"))
    2385             :     {
    2386           0 :         set_command(command_list_sources);
    2387             :     }
    2388        1494 :     if(f_opt.is_defined("max-version"))
    2389             :     {
    2390           0 :         set_command(command_max_version);
    2391             :     }
    2392        1494 :     if(f_opt.is_defined("md5sums"))
    2393             :     {
    2394           2 :         set_command(command_md5sums);
    2395             :     }
    2396        1494 :     if(f_opt.is_defined("md5sums-check"))
    2397             :     {
    2398           4 :         set_command(command_md5sums_check);
    2399             :     }
    2400        1494 :     if(f_opt.is_defined("modversion"))
    2401             :     {
    2402           0 :         set_command(command_modversion);
    2403             :     }
    2404        1494 :     if(f_opt.is_defined("os"))
    2405             :     {
    2406           0 :         set_command(command_os);
    2407             :     }
    2408        1494 :     if(f_opt.is_defined("package_status"))
    2409             :     {
    2410           0 :         set_command(command_package_status);
    2411             :     }
    2412        1494 :     if(f_opt.is_defined("print-architecture"))
    2413             :     {
    2414           0 :         set_command(command_print_architecture);
    2415             :     }
    2416        1494 :     if(f_opt.is_defined("print-avail"))
    2417             :     {
    2418           0 :         set_command(command_info);
    2419             :     }
    2420        1494 :     if(f_opt.is_defined("print-build-number"))
    2421             :     {
    2422           0 :         set_command(command_print_build_number);
    2423             :     }
    2424        1494 :     if(f_opt.is_defined("print-variables"))
    2425             :     {
    2426           0 :         set_command(command_print_variables);
    2427             :     }
    2428        1494 :     if(f_opt.is_defined("processor"))
    2429             :     {
    2430           0 :         set_command(command_processor);
    2431             :     }
    2432        1494 :     if(f_opt.is_defined("reconfigure"))
    2433             :     {
    2434           0 :         set_command(command_reconfigure);
    2435             :     }
    2436        1494 :     if(f_opt.is_defined("remove"))
    2437             :     {
    2438          23 :         set_command(command_remove);
    2439             :     }
    2440        1494 :     if(f_opt.is_defined("remove-database-lock"))
    2441             :     {
    2442           0 :         set_command(command_remove_database_lock);
    2443             :     }
    2444        1494 :     if(f_opt.is_defined("remove-hooks"))
    2445             :     {
    2446           1 :         set_command(command_remove_hooks);
    2447             :     }
    2448        1494 :     if(f_opt.is_defined("remove-sources"))
    2449             :     {
    2450           0 :         set_command(command_remove_sources);
    2451             :     }
    2452        1494 :     if(f_opt.is_defined("rollback"))
    2453             :     {
    2454           0 :         set_command(command_rollback);
    2455             :     }
    2456        1494 :     if(f_opt.is_defined("search"))
    2457             :     {
    2458           0 :         set_command(command_search);
    2459             :     }
    2460        1494 :     if(f_opt.is_defined("set-selection"))
    2461             :     {
    2462           1 :         set_command(command_set_selection);
    2463             :     }
    2464        1494 :     if(f_opt.is_defined("show"))
    2465             :     {
    2466           0 :         set_command(command_show);
    2467             :     }
    2468        1494 :     if(f_opt.is_defined("status"))
    2469             :     {
    2470           0 :         set_command(command_field);
    2471             :     }
    2472        1494 :     if(f_opt.is_defined("triplet"))
    2473             :     {
    2474           0 :         set_command(command_triplet);
    2475             :     }
    2476        1494 :     if(f_opt.is_defined("unpack"))
    2477             :     {
    2478           0 :         set_command(command_unpack);
    2479             :     }
    2480        1494 :     if(f_opt.is_defined("update"))
    2481             :     {
    2482           0 :         set_command(command_update);
    2483             :     }
    2484        1494 :     if(f_opt.is_defined("update-status"))
    2485             :     {
    2486           0 :         set_command(command_update_status);
    2487             :     }
    2488        1494 :     if(f_opt.is_defined("upgrade"))
    2489             :     {
    2490           0 :         set_command(command_upgrade);
    2491             :     }
    2492        1494 :     if(f_opt.is_defined("upgrade-info"))
    2493             :     {
    2494           0 :         set_command(command_upgrade_info);
    2495             :     }
    2496        1494 :     if(f_opt.is_defined("upgrade-urgent"))
    2497             :     {
    2498           0 :         set_command(command_upgrade);
    2499             :     }
    2500        1494 :     if(f_opt.is_defined("variable"))
    2501             :     {
    2502           0 :         set_command(command_variable);
    2503             :     }
    2504        1494 :     if(f_opt.is_defined("verify-control"))
    2505             :     {
    2506           0 :         set_command(command_verify_control);
    2507             :     }
    2508        1494 :     if(f_opt.is_defined("verify-project"))
    2509             :     {
    2510           0 :         set_command(command_verify_project);
    2511             :     }
    2512        1494 :     if(f_opt.is_defined("vendor"))
    2513             :     {
    2514           0 :         set_command(command_vendor);
    2515             :     }
    2516        1494 :     if(f_opt.is_defined("vextract"))
    2517             :     {
    2518           0 :         set_command(command_extract);
    2519           0 :         f_verbose = true;
    2520             :     }
    2521        1494 :     if(f_opt.is_defined("verify"))
    2522             :     {
    2523             :         // we always verify when we load a package, just make it quiet
    2524           0 :         set_command(command_info);
    2525           0 :         f_quiet = true;
    2526             :     }
    2527        1494 :     if(f_opt.is_defined("version"))
    2528             :     {
    2529           1 :         set_command(command_version);
    2530             :     }
    2531             : 
    2532             : // parse options
    2533             : 
    2534             :     // compression level (1-9)
    2535        1494 :     f_zlevel = f_opt.get_long("zlevel", 0, 1, 9);
    2536             : 
    2537             :     // compressor name (none, best, gzip, bzip2, xz, lzma)
    2538        1494 :     if(f_opt.is_defined("compressor"))
    2539             :     {
    2540           0 :         std::string name(f_opt.get_string("compressor"));
    2541           0 :         if(name != "best" && name != "default")
    2542             :         {
    2543           0 :             if(name == "gz" || name == "gzip")
    2544             :             {
    2545           0 :                 f_compressor = memfile::memory_file::file_format_gz;
    2546             :             }
    2547           0 :             else if(name == "bz2" || name == "bzip2")
    2548             :             {
    2549           0 :                 f_compressor = memfile::memory_file::file_format_bz2;
    2550             :             }
    2551           0 :             else if(name == "xz" || name == "7z")
    2552             :             {
    2553           0 :                 f_compressor = memfile::memory_file::file_format_xz;
    2554             :             }
    2555           0 :             else if(name == "lzma")
    2556             :             {
    2557           0 :                 f_compressor = memfile::memory_file::file_format_lzma;
    2558             :             }
    2559           0 :             else if(name == "none")
    2560             :             {
    2561           0 :                 f_compressor = memfile::memory_file::file_format_other;
    2562             :             }
    2563             :             else
    2564             :             {
    2565           0 :                 f_opt.usage(advgetopt::getopt::error, "supported compressors: gzip, bzip2, lzma, xz, none");
    2566             :                 /*NOTREACHED*/
    2567             :             }
    2568           0 :         }
    2569             :     }
    2570             : 
    2571             :     // output for log info
    2572        1494 :     g_output.set_program_name(f_opt.get_program_name());
    2573        1494 :     if(g_output.get_output_file().empty() && f_opt.is_defined("log-output"))
    2574             :     {
    2575           0 :         g_output.set_output_file(f_opt.get_string("log-output"));
    2576             :     }
    2577        1494 :     if(f_verbose)
    2578             :     {
    2579           6 :         f_debug_flags |= wpkg_output::debug_flags::debug_progress;
    2580           6 :         g_output.set_level(wpkg_output::level_info);
    2581             :     }
    2582        1488 :     else if(f_quiet)
    2583             :     {
    2584           0 :         g_output.set_level(wpkg_output::level_error);
    2585             :     }
    2586             : 
    2587             :     // check for debug flags
    2588        1494 :     if(f_opt.is_defined("debug"))
    2589             :     {
    2590          11 :         std::string debug(f_opt.get_string("debug"));
    2591          11 :         if(debug.find_first_not_of(debug[0] == '0' ? "01234567" : "0123456789") != std::string::npos)
    2592             :         {
    2593           0 :             f_opt.usage(advgetopt::getopt::error, "the --debug option (-D) only accepts valid decimal or octal numbers");
    2594             :             /*NOTREACHED*/
    2595             :         }
    2596          11 :         f_debug_flags |= strtol(debug.c_str(), NULL, 0);
    2597          11 :         g_output.set_level(wpkg_output::level_debug);
    2598             :     }
    2599        1494 :     g_output.set_debug(f_debug_flags);
    2600             : 
    2601             :     // if the default files is turn on, keep the temporary files
    2602        1494 :     if(f_debug_flags & wpkg_output::debug_flags::debug_detail_files)
    2603             :     {
    2604          11 :         wpkg_filename::temporary_uri_filename::keep_files();
    2605             :     }
    2606             : 
    2607             :     // check for a user defined temporary directory
    2608        1494 :     if(f_opt.is_defined("tmpdir"))
    2609             :     {
    2610           0 :         wpkg_filename::temporary_uri_filename::set_tmpdir(f_opt.get_string("tmpdir"));
    2611             :     }
    2612             : 
    2613             :     // execute the immediate commands
    2614        1494 :     switch(f_command)
    2615             :     {
    2616             :     case command_unknown:
    2617           0 :         f_opt.usage(advgetopt::getopt::error, "At least one of the command line options must be a command");
    2618             :         /*NOTREACHED*/
    2619           0 :         break;
    2620             : 
    2621             :     case command_help:
    2622           0 :         if(f_opt.size("filename") >= 1)
    2623             :         {
    2624           0 :             help(*this);
    2625             :             /*NOTREACHED*/
    2626             :         }
    2627           0 :         f_opt.usage(f_opt.is_defined("help-nobr") ? advgetopt::getopt::no_error_nobr : advgetopt::getopt::no_error,
    2628           0 :                 "Usage: wpkg -<command> [-<opt>] <filename> | <package-name> | <field> ...\nFor detailed help try: wpkg --help help");
    2629             :         /*NOTREACHED*/
    2630           0 :         break;
    2631             : 
    2632             :     case command_version:
    2633           1 :         version(*this);
    2634             :         /*NOTREACHED*/
    2635           0 :         break;
    2636             : 
    2637             :     case command_license:
    2638           0 :         license::license();
    2639           0 :         exit(1);
    2640             :         /*NOTREACHED*/
    2641             :         break;
    2642             : 
    2643             :     default:
    2644             :         // other commands are dealt with later
    2645        1493 :         break;
    2646             : 
    2647        1493 :     }
    2648        1493 : }
    2649             : 
    2650        1494 : void command_line::set_command(command_t c)
    2651             : {
    2652        1494 :     if(c == command_unknown)
    2653             :     {
    2654        1494 :         return;
    2655             :     }
    2656        1494 :     if(command_unknown != f_command)
    2657             :     {
    2658           0 :         f_opt.usage(advgetopt::getopt::error, "only one command can be specified in your list of arguments");
    2659             :         /*NOTREACHED*/
    2660             :     }
    2661             :     // TODO: static_cast<> is  to avoid a warning, but the controlled_vars
    2662             :     //       should allow better handling of enumerations
    2663        1494 :     f_command = static_cast<int>(c);
    2664             : }
    2665             : 
    2666        1474 : const advgetopt::getopt& command_line::opt() const
    2667             : {
    2668        1474 :     return f_opt;
    2669             : }
    2670             : 
    2671       23451 : advgetopt::getopt& command_line::opt()
    2672             : {
    2673       23451 :     return f_opt;
    2674             : }
    2675             : 
    2676        1484 : command_line::command_t command_line::command() const
    2677             : {
    2678        1484 :     return f_command;
    2679             : }
    2680             : 
    2681         934 : int command_line::size() const
    2682             : {
    2683         934 :     if(f_option == "filename" || f_filenames.empty())
    2684             :     {
    2685         934 :         return f_opt.size("filename");
    2686             :     }
    2687         934 :     return static_cast<int>(f_filenames.size());
    2688             : }
    2689             : 
    2690         304 : wpkg_filename::uri_filename command_line::filename(int idx) const
    2691             : {
    2692         304 :     if(f_option == "filename" || f_filenames.empty())
    2693             :     {
    2694         304 :         return f_opt.get_string("filename", idx);
    2695             :     }
    2696         304 :     return f_filenames.at(idx);
    2697             : }
    2698             : 
    2699           3 : std::string command_line::argument(int idx) const
    2700             : {
    2701             :     // do NOT canonicalize an argument
    2702           3 :     if(f_option == "filename" || f_filenames.empty())
    2703             :     {
    2704           3 :         return f_opt.get_string("filename", idx);
    2705             :     }
    2706           3 :     return f_filenames.at(idx);
    2707             : }
    2708             : 
    2709         776 : std::string command_line::get_string(const std::string& name, int idx) const
    2710             : {
    2711         776 :     if(f_option != name || f_filenames.empty())
    2712             :     {
    2713         776 :         return f_opt.get_string(name, idx);
    2714             :     }
    2715         776 :     return f_filenames.at(idx);
    2716             : }
    2717             : 
    2718           0 : bool command_line::quiet() const
    2719             : {
    2720           0 :     return f_quiet;
    2721             : }
    2722             : 
    2723         751 : bool command_line::verbose() const
    2724             : {
    2725         751 :     return f_verbose;
    2726             : }
    2727             : 
    2728         347 : bool command_line::dry_run(bool msg) const
    2729             : {
    2730         347 :     if(msg && f_dry_run)
    2731             :     {
    2732             :         wpkg_output::log("the --dry-run option was used; stopping process now")
    2733           0 :             .action("wpkg-dryrun");
    2734             :     }
    2735         347 :     return f_dry_run;
    2736             : }
    2737             : 
    2738         310 : int command_line::zlevel() const
    2739             : {
    2740         310 :     return f_zlevel;
    2741             : }
    2742             : 
    2743         310 : memfile::memory_file::file_format_t command_line::compressor() const
    2744             : {
    2745         310 :     return f_compressor;
    2746             : }
    2747             : 
    2748           0 : void command_line::add_filename(const std::string& option, const std::string& repository_filename)
    2749             : {
    2750           0 :     f_option = option;
    2751           0 :     f_filenames.push_back(repository_filename);
    2752           0 : }
    2753             : 
    2754             : 
    2755             : } // no name namespace
    2756             : 
    2757             : 
    2758             : 
    2759             : 
    2760         737 : void define_wpkg_running_and_copy(const command_line& cl, wpkg_filename::uri_filename& wpkg_running, wpkg_filename::uri_filename& wpkg_copy)
    2761             : {
    2762         737 :     wpkg_running.set_filename(cl.opt().get_program_fullname());
    2763         737 :     wpkg_filename::uri_filename wpkg_dir(wpkg_running.dirname());
    2764         737 :     wpkg_filename::uri_filename program_name(cl.opt().get_program_name());
    2765         737 :     if(program_name.segment_size() == 0)
    2766             :     {
    2767           0 :         throw std::runtime_error("the program name is an empty string");
    2768             :     }
    2769         737 :     std::string filename(program_name.segment(program_name.segment_size() - 1));
    2770         737 :     case_insensitive::case_insensitive_string pn(filename.substr(0, 8));
    2771         737 :     if(pn != "copy-of-")
    2772             :     {
    2773         734 :         program_name = program_name.dirname();
    2774         734 :         program_name = program_name.append_child("copy-of-" + filename);
    2775             :     }
    2776         737 :     if(program_name.is_absolute())
    2777             :     {
    2778           0 :         wpkg_copy = program_name.path_only();
    2779             :     }
    2780             :     else
    2781             :     {
    2782         737 :         wpkg_copy = wpkg_dir.append_child(program_name.path_only());
    2783         737 :     }
    2784         737 : }
    2785             : 
    2786         737 : void init_manager(command_line& cl, wpkgar::wpkgar_manager& manager, const std::string& option)
    2787             : {
    2788             :     // add self so we can deal with the case when we're upgrading ourself
    2789             :     //
    2790             :     // if you write an application that links against the libdebpackages
    2791             :     // library and you want to allow for auto-upgrades, then you will need
    2792             :     // to add all your dependencies to your instance of the manager. This
    2793             :     // includes your package, its direct dependencies, the dependencies
    2794             :     // of those dependencies, etc. However, you probably do not want to
    2795             :     // implement a copy because you'd need to copy your application plus
    2796             :     // all the DLLs it needs to run. If you implement an upgrade for your
    2797             :     // application, you may want to run wpkg using execvp() as shown below.
    2798             :     // Although at this point there is no way for you to restart your
    2799             :     // application afterward with wpkg itself, you could write a small
    2800             :     // shell script or batch file and run that with the right information
    2801             :     // and the last command line would be used to restart your app.
    2802         737 :     manager.add_self("wpkg");
    2803             : 
    2804             :     {
    2805             :         // if wpkg upgraded itself then it created a copy of itself; these
    2806             :         // few lines of code check for the existance of that copy and
    2807             :         // if it exists deletes it
    2808         737 :         wpkg_filename::uri_filename wpkg_running;
    2809         737 :         wpkg_filename::uri_filename wpkg_copy;
    2810         737 :         define_wpkg_running_and_copy(cl, wpkg_running, wpkg_copy);
    2811        1471 :         if(!same_file(wpkg_running.os_filename().get_utf8(), wpkg_copy.os_filename().get_utf8())
    2812         734 :         && wpkg_copy.exists())
    2813             :         {
    2814           2 :             wpkg_copy.os_unlink();
    2815         737 :         }
    2816             :     }
    2817             : 
    2818         737 :     manager.set_interrupt_handler(&interrupt);
    2819             : 
    2820             :     // all these directories have a default if not specified on the command line
    2821         737 :     manager.set_root_path(cl.opt().get_string("root"));
    2822         737 :     manager.set_inst_path(cl.opt().get_string("instdir"));
    2823         737 :     manager.set_database_path(cl.opt().get_string("admindir"));
    2824             : 
    2825         737 :     std::shared_ptr<wpkgar::wpkgar_tracker> tracker;
    2826         737 :     if(cl.opt().is_defined("tracking-journal"))
    2827             :     {
    2828           0 :         const std::string journal(cl.opt().get_string("tracking-journal"));
    2829           0 :         tracker.reset(new wpkgar::wpkgar_tracker(&manager, journal));
    2830           0 :         tracker->keep_file(true);
    2831           0 :         manager.set_tracker(tracker);
    2832           0 :         manager.track("# tracking " + option + " on " + wpkg_output::generate_timestamp());
    2833             :         wpkg_output::log("tracking journal: %1")
    2834           0 :                 .quoted_arg(journal)
    2835           0 :             .level(wpkg_output::level_info)
    2836           0 :             .action("log");
    2837             :     }
    2838             : 
    2839         737 :     if(cl.opt().is_defined("repository"))
    2840             :     {
    2841         165 :         std::string repositories("repositories ");
    2842         165 :         int max_repository(cl.opt().size("repository"));
    2843         317 :         for(int i(0); i < max_repository; ++i)
    2844             :         {
    2845             :             // no need to protect " inside f_repository names
    2846             :             // since that character is not legal (because it
    2847             :             // is not legal under MS-Windows.)
    2848         165 :             repositories += " \"" + cl.opt().get_string("repository", i) + "\"";
    2849             : 
    2850         165 :             manager.add_repository(cl.opt().get_string("repository", i));
    2851             :         }
    2852         152 :         if(tracker)
    2853             :         {
    2854           0 :             manager.track(repositories);
    2855         165 :         }
    2856         737 :     }
    2857         724 : }
    2858             : 
    2859             : 
    2860         329 : void init_installer
    2861             :     ( command_line& cl
    2862             :     , wpkgar::wpkgar_manager& manager
    2863             :     , wpkgar::wpkgar_install& pkg_install
    2864             :     , const std::string& option
    2865             :     , const wpkg_filename::uri_filename& package_name = wpkg_filename::uri_filename()
    2866             :     )
    2867             : {
    2868         329 :     init_manager(cl, manager, option);
    2869             : 
    2870         316 :     const int max(cl.opt().size(option));
    2871         316 :     if(max == 0)
    2872             :     {
    2873           0 :         throw std::runtime_error("--" + option + " requires at least one parameter");
    2874             :     }
    2875             : 
    2876             :     // add the force, no-force/refuse parameters
    2877             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_architecture,
    2878         948 :         (cl.opt().is_defined("force-architecture") || cl.opt().is_defined("force-all"))
    2879         316 :                             && !cl.opt().is_defined("no-force-architecture")
    2880         316 :                             && !cl.opt().is_defined("refuse-architecture")
    2881         632 :                             && !cl.opt().is_defined("refuse-all"));
    2882             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_breaks,
    2883         947 :         (cl.opt().is_defined("force-breaks") || cl.opt().is_defined("force-all"))
    2884         317 :                             && !cl.opt().is_defined("no-force-breaks")
    2885         317 :                             && !cl.opt().is_defined("refuse-breaks")
    2886         633 :                             && !cl.opt().is_defined("refuse-all"));
    2887             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_configure_any,
    2888         948 :         (cl.opt().is_defined("force-configure-any") || cl.opt().is_defined("force-all"))
    2889         316 :                             && !cl.opt().is_defined("no-force-configure-any")
    2890         316 :                             && !cl.opt().is_defined("refuse-configure-any")
    2891         632 :                             && !cl.opt().is_defined("refuse-all"));
    2892             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_conflicts,
    2893         947 :         (cl.opt().is_defined("force-conflicts") || cl.opt().is_defined("force-all"))
    2894         317 :                             && !cl.opt().is_defined("no-force-conflicts")
    2895         317 :                             && !cl.opt().is_defined("refuse-conflicts")
    2896         633 :                             && !cl.opt().is_defined("refuse-all"));
    2897             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_depends,
    2898         948 :         (cl.opt().is_defined("force-depends") || cl.opt().is_defined("force-all"))
    2899         316 :                             && !cl.opt().is_defined("no-force-depends")
    2900         316 :                             && !cl.opt().is_defined("refuse-depends")
    2901         632 :                             && !cl.opt().is_defined("refuse-all"));
    2902             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_depends_version,
    2903         948 :         (cl.opt().is_defined("force-depends-version") || cl.opt().is_defined("force-all"))
    2904         316 :                             && !cl.opt().is_defined("no-force-depends-version")
    2905         316 :                             && !cl.opt().is_defined("refuse-depends-version")
    2906         632 :                             && !cl.opt().is_defined("refuse-all"));
    2907             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_distribution,
    2908         946 :         (cl.opt().is_defined("force-distribution") || cl.opt().is_defined("force-all"))
    2909         318 :                             && !cl.opt().is_defined("no-force-distribution")
    2910         318 :                             && !cl.opt().is_defined("refuse-distribution")
    2911         634 :                             && !cl.opt().is_defined("refuse-all"));
    2912             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_downgrade,
    2913         948 :         (cl.opt().is_defined("force-downgrade") || cl.opt().is_defined("force-all"))
    2914         316 :                             && !cl.opt().is_defined("no-force-downgrade")
    2915         316 :                             && !cl.opt().is_defined("refuse-downgrade")
    2916         632 :                             && !cl.opt().is_defined("refuse-all"));
    2917             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_file_info,
    2918         948 :         (cl.opt().is_defined("force-file-info") || cl.opt().is_defined("force-all"))
    2919         316 :                             && !cl.opt().is_defined("no-force-file-info")
    2920         316 :                             && !cl.opt().is_defined("refuse-file-info")
    2921         632 :                             && !cl.opt().is_defined("refuse-all"));
    2922             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_hold,
    2923         946 :         (cl.opt().is_defined("force-hold") || cl.opt().is_defined("force-all"))
    2924         318 :                             && !cl.opt().is_defined("no-force-hold")
    2925         318 :                             && !cl.opt().is_defined("refuse-hold")
    2926         634 :                             && !cl.opt().is_defined("refuse-all"));
    2927             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_upgrade_any_version,
    2928         947 :         (cl.opt().is_defined("force-upgrade-any-version") || cl.opt().is_defined("force-all"))
    2929         317 :                             && !cl.opt().is_defined("no-force-upgrade-any-version")
    2930         317 :                             && !cl.opt().is_defined("refuse-upgrade-any-version")
    2931         633 :                             && !cl.opt().is_defined("refuse-all"));
    2932             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_overwrite,
    2933         947 :         (cl.opt().is_defined("force-overwrite") || cl.opt().is_defined("force-all"))
    2934         317 :                             && !cl.opt().is_defined("no-force-overwrite")
    2935         317 :                             && !cl.opt().is_defined("refuse-overwrite")
    2936         633 :                             && !cl.opt().is_defined("refuse-all"));
    2937             :     // overwriting directories is just way too ugly to include in --force-all
    2938             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_overwrite_dir,
    2939         632 :         (cl.opt().is_defined("force-overwrite-dir") /*|| cl.opt().is_defined("force-all")*/)
    2940         316 :                             && !cl.opt().is_defined("no-force-overwrite-dir")
    2941         316 :                             && !cl.opt().is_defined("refuse-overwrite-dir")
    2942         316 :                             && !cl.opt().is_defined("refuse-all"));
    2943             :     // the rollback is kind of a positive thing so we don't use it on --force-all
    2944             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_rollback,
    2945         632 :         (cl.opt().is_defined("force-rollback") /*|| cl.opt().is_defined("force-all")*/)
    2946         316 :                             && !cl.opt().is_defined("no-force-rollback")
    2947         316 :                             && !cl.opt().is_defined("refuse-rollback")
    2948         316 :                             && !cl.opt().is_defined("refuse-all"));
    2949             :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_force_vendor,
    2950         948 :         (cl.opt().is_defined("force-vendor") || cl.opt().is_defined("force-all"))
    2951         316 :                             && !cl.opt().is_defined("no-force-vendor")
    2952         316 :                             && !cl.opt().is_defined("refuse-vendor")
    2953         632 :                             && !cl.opt().is_defined("refuse-all"));
    2954             : 
    2955             :     // some additional parameters
    2956         316 :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_skip_same_version, cl.opt().is_defined("skip-same-version"));
    2957         316 :     pkg_install.set_parameter(wpkgar::wpkgar_install::wpkgar_install_recursive, cl.opt().is_defined("recursive"));
    2958             : 
    2959             :     // add the list of verify-fields expressions if any
    2960         316 :     if(cl.opt().is_defined("verify-fields"))
    2961             :     {
    2962         121 :         const int fields_max(cl.opt().size("verify-fields"));
    2963         242 :         for(int i(0); i < fields_max; ++i)
    2964             :         {
    2965         121 :             pkg_install.add_field_validation(cl.opt().get_string("verify-fields", i));
    2966             :         }
    2967             :     }
    2968             : 
    2969             :     // add the list of package names
    2970         316 :     if(package_name.empty())
    2971             :     {
    2972         751 :         for(int i(0); i < max; ++i)
    2973             :         {
    2974         435 :             pkg_install.add_package(cl.get_string(option, i));
    2975             :         }
    2976             :     }
    2977             :     else
    2978             :     {
    2979           0 :         pkg_install.add_package(package_name.full_path());
    2980             :     }
    2981         316 : }
    2982             : 
    2983             : 
    2984         310 : void init_field_variables
    2985             :     ( command_line& cl
    2986             :     , wpkgar::wpkgar_manager& manager
    2987             :     , wpkg_field::field_file *field
    2988             :     )
    2989             : {
    2990         310 :     const int max = cl.opt().size("field-variables");
    2991         310 :     for(int i(0); i < max; ++i)
    2992             :     {
    2993           0 :         std::string fv(cl.opt().get_string("field-variables", i));
    2994           0 :         std::string::size_type p(fv.find('='));
    2995           0 :         if(p == std::string::npos)
    2996             :         {
    2997           0 :             cl.opt().usage(advgetopt::getopt::error, "--field-variables (-V) only accepts variable definitions that include an equal sign");
    2998             :             /*NOTREACHED*/
    2999             :         }
    3000           0 :         if(p == 0)
    3001             :         {
    3002           0 :             cl.opt().usage(advgetopt::getopt::error, "the name of a variable in --field-variables (-V) cannot be empty (name expected before the equal sign)");
    3003             :             /*NOTREACHED*/
    3004             :         }
    3005           0 :         std::string name(fv.substr(0, p));
    3006           0 :         std::string value(fv.substr(p + 1));
    3007           0 :         if(value.length() > 1 && value[0] == '"' && *value.rbegin() == '"')
    3008             :         {
    3009           0 :             value = value.substr(1, value.length() - 2);
    3010             :         }
    3011           0 :         else if(value.length() > 1 && value[0] == '\'' && *value.rbegin() == '\'')
    3012             :         {
    3013           0 :             value = value.substr(1, value.length() - 2);
    3014             :         }
    3015           0 :         if(field) // directly to a control file list of variables
    3016             :         {
    3017           0 :             field->set_variable(name, value);
    3018             :         }
    3019             :         else
    3020             :         {
    3021           0 :             manager.set_field_variable(name, value);
    3022             :         }
    3023           0 :     }
    3024         310 : }
    3025             : 
    3026           0 : void check_install(command_line& cl)
    3027             : {
    3028           0 :     wpkgar::wpkgar_manager manager;
    3029           0 :     wpkgar::wpkgar_install pkg_install(&manager);
    3030           0 :     init_installer(cl, manager, pkg_install, "check-install");
    3031           0 :     pkg_install.set_installing();
    3032             : 
    3033             :     bool result;
    3034             :     {
    3035           0 :         wpkgar::wpkgar_lock lock_wpkg(&manager, "Verifying");
    3036           0 :         result = pkg_install.validate();
    3037             :     }
    3038           0 :     exit(result ? 0 : 1);
    3039             : }
    3040             : 
    3041         329 : void install(command_line& cl, const wpkg_filename::uri_filename package_name = wpkg_filename::uri_filename(), const std::string& option = "install")
    3042             : {
    3043         329 :     wpkgar::wpkgar_manager manager;
    3044         329 :     wpkgar::wpkgar_install pkg_install(&manager);
    3045         329 :     init_installer(cl, manager, pkg_install, option, package_name);
    3046         316 :     pkg_install.set_installing();
    3047             : 
    3048         316 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Installing");
    3049         316 :     if(pkg_install.validate() && !cl.dry_run())
    3050             :     {
    3051         296 :         if(manager.is_self() && !cl.opt().is_defined("running-copy"))
    3052             :         {
    3053             :             // in this case we drop the lock; our copy will re-create a lock as required
    3054           0 :             lock_wpkg.unlock();
    3055             : 
    3056             :             wpkg_output::log("wpkg is trying to upgrade itself; wpkg is starting a copy of itself to ensure proper functionality")
    3057           0 :                 .level(wpkg_output::level_warning)
    3058           0 :                 .module(wpkg_output::module_validate_installation)
    3059           0 :                 .package("wpkg")
    3060           0 :                 .action("upgrade-initialization");
    3061             : 
    3062             :             // we test as "is self" and not "running copy" to determine
    3063             :             // that we're doing an upgrade of self; we do not attempt to
    3064             :             // check whether the executable itself would be replaced
    3065           0 :             wpkg_filename::uri_filename wpkg_running;
    3066           0 :             wpkg_filename::uri_filename wpkg_copy;
    3067           0 :             define_wpkg_running_and_copy(cl, wpkg_running, wpkg_copy);
    3068           0 :             if(same_file(wpkg_running.os_filename().get_utf8(), wpkg_copy.os_filename().get_utf8()))
    3069             :             {
    3070             :                 // this should not happen, but we cannot really prevent it from happening
    3071             :                 wpkg_output::log("it looks like wpkg was inadvertendly started from a copy of itself while attempting to upgrade itself")
    3072           0 :                     .level(wpkg_output::level_fatal)
    3073           0 :                     .module(wpkg_output::module_validate_installation)
    3074           0 :                     .package("wpkg")
    3075           0 :                     .action("upgrade-initialization");
    3076             :                 return;
    3077             :             }
    3078           0 :             if(wpkg_copy.exists())
    3079             :             {
    3080             :                 wpkg_output::log("somehow the file %1 already exists so wpkg cannot upgrade itself at this time")
    3081           0 :                         .quoted_arg(wpkg_copy)
    3082           0 :                     .level(wpkg_output::level_fatal)
    3083           0 :                     .module(wpkg_output::module_validate_installation)
    3084           0 :                     .package("wpkg")
    3085           0 :                     .action("upgrade-initialization");
    3086             :                 return;
    3087             :             }
    3088             :             // copy the file
    3089           0 :             memfile::memory_file wpkg_binary;
    3090           0 :             wpkg_binary.read_file(wpkg_running);
    3091           0 :             wpkg_binary.write_file(wpkg_copy);
    3092             :             // start the copy with the same arguments + "--running-copy"
    3093             : #ifdef MO_WINDOWS
    3094             :             // to be Unicode compliant under MS-Windows we have to convert
    3095             :             // all the parameters to wide character strings
    3096             :             std::vector<std::wstring> wargs;
    3097             :             for(char **v = g_argv; *v != NULL; ++v)
    3098             :             {
    3099             :                 // Yeah! Windows is weird, we pass the exact arguments, but we still
    3100             :                 // need to ourselves quote them...
    3101             :                 std::wstring warg(libutf8::mbstowcs(wpkg_util::make_safe_console_string(*v)));
    3102             :                 wargs.push_back(warg);
    3103             :             }
    3104             :             //
    3105             :             // *** WARNING ***
    3106             :             // DO NOT MERGE THESE TWO LOOPS!!!
    3107             :             // *** WARNING ***
    3108             :             //
    3109             :             std::vector<wchar_t *> wargv;
    3110             :             for(std::vector<std::wstring>::const_iterator it(wargs.begin()); it != wargs.end(); ++it)
    3111             :             {
    3112             :                 wargv.push_back(const_cast<wchar_t *>(it->c_str()));
    3113             :             }
    3114             :             std::wstring cmdline(libutf8::mbstowcs(wpkg_copy.path_only()));
    3115             :             wargv[0] = const_cast<wchar_t *>(cmdline.c_str());
    3116             :             wargv.push_back(const_cast<wchar_t *>(L"--running-copy"));
    3117             :             wargv.push_back(NULL);
    3118             :             _wexecvp(wargv[0], &wargv[0]);
    3119             : #else
    3120           0 :             if(chmod(wpkg_copy.os_filename().get_utf8().c_str(), 600) != 0)
    3121             :             {
    3122             :                 wpkg_output::log("we could not set the execution permission on the wpkg copy: %1")
    3123           0 :                         .quoted_arg(wpkg_copy)
    3124           0 :                     .level(wpkg_output::level_fatal)
    3125           0 :                     .module(wpkg_output::module_validate_installation)
    3126           0 :                     .package("wpkg")
    3127           0 :                     .action("upgrade-initialization");
    3128             :                 return;
    3129             :             }
    3130           0 :             std::vector<char *> argv;
    3131           0 :             for(char **v(g_argv); *v != NULL; ++v)
    3132             :             {
    3133           0 :                 argv.push_back(*v);
    3134             :             }
    3135           0 :             std::string cmdline(wpkg_copy.path_only());
    3136           0 :             argv[0] = const_cast<char *>(cmdline.c_str());
    3137           0 :             argv.push_back(const_cast<char *>("--running-copy"));
    3138           0 :             argv.push_back(NULL);
    3139           0 :             execvp(argv[0], &argv[0]);
    3140             : #endif
    3141           0 :             perror("execvp to run a wpkg copy failed");
    3142           0 :             wpkg_copy.os_unlink();
    3143             :             wpkg_output::log("execution of the wpkg copy executable somehow failed; original executable: %1")
    3144           0 :                     .quoted_arg(wpkg_running)
    3145           0 :                 .level(wpkg_output::level_fatal)
    3146           0 :                 .module(wpkg_output::module_validate_installation)
    3147           0 :                 .package("wpkg")
    3148           0 :                 .action("upgrade-initialization");
    3149           0 :             return;
    3150             :         }
    3151         296 :         if(pkg_install.pre_configure())
    3152             :         {
    3153         747 :             for(;;)
    3154             :             {
    3155         729 :                 manager.check_interrupt();
    3156             : 
    3157         729 :                 const int i(pkg_install.unpack());
    3158         728 :                 if(i < 0)
    3159             :                 {
    3160         295 :                     break;
    3161             :                 }
    3162         433 :                 if(!pkg_install.configure(i))
    3163             :                 {
    3164           0 :                     break;
    3165             :                 }
    3166             :             }
    3167             :         }
    3168         329 :     }
    3169             : }
    3170             : 
    3171             : 
    3172           0 : void install_size(command_line& cl)
    3173             : {
    3174           0 :     int max(cl.opt().size("install-size"));
    3175           0 :     if(max == 0)
    3176             :     {
    3177           0 :         throw std::runtime_error("--install-size requires at least one package name");
    3178             :     }
    3179             : 
    3180           0 :     wpkgar::wpkgar_manager manager;
    3181           0 :     init_manager(cl, manager, "contents");
    3182             : 
    3183           0 :     unsigned long total(0);
    3184           0 :     for(int i(0); i < max; ++i)
    3185             :     {
    3186           0 :         const std::string name(cl.opt().get_string("install-size", i));
    3187           0 :         if(name.find_first_of("_/") == std::string::npos)
    3188             :         {
    3189             :             // TODO: support already installed packages?
    3190           0 :             cl.opt().usage(advgetopt::getopt::error, "--install-size does not work with already installed packages");
    3191             :             /*NOTREACHED*/
    3192             :         }
    3193             :         // make sure the package is loaded
    3194           0 :         manager.load_package(name);
    3195           0 :         if(manager.field_is_defined(name, "Installed-Size"))
    3196             :         {
    3197           0 :             total += manager.get_field_integer(name, "Installed-Size");
    3198             :         }
    3199           0 :     }
    3200             : 
    3201           0 :     printf("%lu\n", total);
    3202           0 : }
    3203             : 
    3204           0 : void unpack(command_line& cl)
    3205             : {
    3206           0 :     wpkgar::wpkgar_manager manager;
    3207           0 :     wpkgar::wpkgar_install pkg_install(&manager);
    3208           0 :     init_installer(cl, manager, pkg_install, "unpack");
    3209           0 :     pkg_install.set_unpacking();
    3210             : 
    3211           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Installing");
    3212           0 :     if(pkg_install.validate() && !cl.dry_run())
    3213             :     {
    3214           0 :         for(;;)
    3215             :         {
    3216           0 :             manager.check_interrupt();
    3217             : 
    3218           0 :             if(pkg_install.unpack() < 0)
    3219             :             {
    3220           0 :                 break;
    3221             :             }
    3222             :         }
    3223           0 :     }
    3224           0 : }
    3225             : 
    3226           0 : void update_status(command_line& cl)
    3227             : {
    3228           0 :     wpkgar::wpkgar_manager manager;
    3229           0 :     init_manager(cl, manager, "update-status");
    3230           0 :     wpkgar::wpkgar_repository repository(&manager);
    3231             : 
    3232           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Updating");
    3233           0 :     const wpkgar::wpkgar_repository::update_entry_vector_t *index_entries(repository.load_index_list());
    3234           0 :     if(index_entries == NULL)
    3235             :     {
    3236           0 :         printf("The --update command line option was never used.\n");
    3237             :     }
    3238           0 :     else if(index_entries->size() == 0)
    3239             :     {
    3240           0 :         printf("The sources.list file is empty and no repository index was loaded.\n");
    3241             :     }
    3242             :     else
    3243             :     {
    3244           0 :         size_t max(index_entries->size());
    3245           0 :         for(size_t i(0); i < max; ++i)
    3246             :         {
    3247           0 :             const wpkgar::wpkgar_repository::update_entry_t& e(index_entries->at(i));
    3248           0 :             printf("%3d. %s\n", e.get_index(), e.get_uri().c_str());
    3249             :             const char *status;
    3250           0 :             switch(e.get_status())
    3251             :             {
    3252             :             case wpkgar::wpkgar_repository::update_entry_t::status_unknown:
    3253           0 :                 status = "unknown";
    3254           0 :                 break;
    3255             : 
    3256             :             case wpkgar::wpkgar_repository::update_entry_t::status_ok:
    3257           0 :                 status = "ok";
    3258           0 :                 break;
    3259             : 
    3260             :             case wpkgar::wpkgar_repository::update_entry_t::status_failed:
    3261           0 :                 status = "failed";
    3262           0 :                 break;
    3263             : 
    3264             :             default:
    3265           0 :                 status = "?undefined?";
    3266           0 :                 break;
    3267             : 
    3268             :             }
    3269           0 :             printf("     Last Status: %s\n", status);
    3270           0 :             printf("     First Try On: %s\n", wpkg_util::rfc2822_date(e.get_time(wpkgar::wpkgar_repository::update_entry_t::first_try)).c_str());
    3271           0 :             if(e.get_time(wpkgar::wpkgar_repository::update_entry_t::first_success) == 0)
    3272             :             {
    3273           0 :                 printf("     Never Succeeded.\n");
    3274             :             }
    3275             :             else
    3276             :             {
    3277           0 :                 printf("     First Success On: %s\n", wpkg_util::rfc2822_date(e.get_time(wpkgar::wpkgar_repository::update_entry_t::first_success)).c_str());
    3278           0 :                 printf("     Last Success On: %s\n", wpkg_util::rfc2822_date(e.get_time(wpkgar::wpkgar_repository::update_entry_t::last_success)).c_str());
    3279             :             }
    3280           0 :             if(e.get_time(wpkgar::wpkgar_repository::update_entry_t::last_failure) == 0)
    3281             :             {
    3282           0 :                 printf("     Never Failed.\n");
    3283             :             }
    3284             :             else
    3285             :             {
    3286           0 :                 printf("     Last Failure On: %s\n", wpkg_util::rfc2822_date(e.get_time(wpkgar::wpkgar_repository::update_entry_t::last_failure)).c_str());
    3287             :             }
    3288             :         }
    3289           0 :     }
    3290           0 : }
    3291             : 
    3292           0 : void update(command_line& cl)
    3293             : {
    3294             :     // TODO -- we want to run repository.update(cl.dry_run()) instead... (once implemented)
    3295           0 :     if(cl.dry_run())
    3296             :     {
    3297           0 :         update_status(cl);
    3298             :     }
    3299             :     else
    3300             :     {
    3301           0 :         wpkgar::wpkgar_manager manager;
    3302           0 :         init_manager(cl, manager, "update");
    3303           0 :         wpkgar::wpkgar_repository repository(&manager);
    3304             : 
    3305           0 :         wpkgar::wpkgar_lock lock_wpkg(&manager, "Updating");
    3306           0 :         repository.update();
    3307             :     }
    3308           0 : }
    3309             : 
    3310           0 : void upgrade_info(command_line& cl)
    3311             : {
    3312           0 :     if(cl.size() != 0)
    3313             :     {
    3314           0 :         cl.opt().usage(advgetopt::getopt::error, "--upgrade-info cannot be used with any filenames");
    3315             :         /*NOTREACHED*/
    3316             :     }
    3317             : 
    3318           0 :     wpkgar::wpkgar_manager manager;
    3319           0 :     init_manager(cl, manager, "upgrade-info");
    3320           0 :     wpkgar::wpkgar_repository repository(&manager);
    3321             : 
    3322           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Upgrading");
    3323           0 :     const wpkgar::wpkgar_repository::wpkgar_package_list_t& list(repository.upgrade_list());
    3324           0 :     size_t max(list.size());
    3325           0 :     for(size_t i(0); i < max; ++i)
    3326             :     {
    3327           0 :         const char *package_name(list[i].get_name().c_str());
    3328           0 :         switch(list[i].get_status())
    3329             :         {
    3330             :         case wpkgar::wpkgar_repository::package_item_t::not_installed:
    3331           0 :             if(cl.verbose())
    3332             :             {
    3333           0 :                 printf("package \"%s\" version %s is available for installation.\n", package_name, list[i].get_version().c_str());
    3334             :             }
    3335           0 :             break;
    3336             : 
    3337             :         case wpkgar::wpkgar_repository::package_item_t::need_upgrade:
    3338             :             {
    3339           0 :                 case_insensitive::case_insensitive_string urgency(list[i].field_is_defined("Urgency") ? list[i].get_field("Urgency") : "low");
    3340           0 :                 bool urgent(urgency == "high" || urgency == "emergency" || urgency == "critical");
    3341             :                 printf("package \"%s\" will be upgraded to version %s the next time you run with --upgrade%s\n",
    3342           0 :                     package_name, list[i].get_version().c_str(),
    3343           0 :                     urgent ? " or --upgrade-urgent" : "");
    3344           0 :                 if(cl.verbose())
    3345             :                 {
    3346           0 :                     printf("   full URI is \"%s\"\n", list[i].get_info().get_uri().full_path().c_str());
    3347           0 :                 }
    3348             :             }
    3349           0 :             break;
    3350             : 
    3351             :         case wpkgar::wpkgar_repository::package_item_t::blocked_upgrade:
    3352           0 :             printf("package \"%s\" will NOT be upgraded because auto-upgrades are currently blocked\n", package_name);
    3353           0 :             break;
    3354             : 
    3355             :         case wpkgar::wpkgar_repository::package_item_t::installed:
    3356           0 :             if(cl.verbose())
    3357             :             {
    3358           0 :                 printf("package \"%s\" is installed from the newest available version.\n", package_name);
    3359             :             }
    3360           0 :             break;
    3361             : 
    3362             :         case wpkgar::wpkgar_repository::package_item_t::invalid:
    3363           0 :             if(cl.verbose())
    3364             :             {
    3365           0 :                 printf("package \"%s\" is considered invalid: %s\n", package_name, list[i].get_cause_for_rejection().c_str());
    3366             :             }
    3367           0 :             break;
    3368             : 
    3369             :         }
    3370           0 :     }
    3371           0 : }
    3372             : 
    3373           0 : void upgrade(command_line& cl)
    3374             : {
    3375           0 :     bool urgent_only(cl.opt().is_defined("upgrade-urgent"));
    3376           0 :     const char *cmd(urgent_only ? "upgrade-urgent" : "upgrade");
    3377             : 
    3378           0 :     if(cl.size() != 0)
    3379             :     {
    3380           0 :         cl.opt().usage(advgetopt::getopt::error, "--%s cannot be used with any filenames", cmd);
    3381             :         /*NOTREACHED*/
    3382             :     }
    3383           0 :     if(cl.opt().is_defined("force-hold"))
    3384             :     {
    3385           0 :         cl.opt().usage(advgetopt::getopt::error, "--%s cannot be used with --force-hold", cmd);
    3386             :         /*NOTREACHED*/
    3387             :     }
    3388             : 
    3389           0 :     if(cl.dry_run())
    3390             :     {
    3391           0 :         upgrade_info(cl);
    3392           0 :         return;
    3393             :     }
    3394             : 
    3395           0 :     wpkgar::wpkgar_manager manager;
    3396           0 :     init_manager(cl, manager, cmd);
    3397           0 :     wpkgar::wpkgar_repository repository(&manager);
    3398             : 
    3399             :     {
    3400             :         // the install() call creates its own lock, we need to have this
    3401             :         // one removed before we can move on
    3402           0 :         wpkgar::wpkgar_lock lock_wpkg(&manager, "Upgrading");
    3403           0 :         const wpkgar::wpkgar_repository::wpkgar_package_list_t& list(repository.upgrade_list());
    3404           0 :         size_t max(list.size());
    3405           0 :         for(size_t i(0); i < max; ++i)
    3406             :         {
    3407           0 :             if(list[i].get_status() == wpkgar::wpkgar_repository::package_item_t::need_upgrade)
    3408             :             {
    3409           0 :                 bool skip(urgent_only);
    3410           0 :                 if(skip)
    3411             :                 {
    3412           0 :                     case_insensitive::case_insensitive_string urgency(list[i].field_is_defined("Urgency") ? list[i].get_field("Urgency") : "low");
    3413           0 :                     skip = urgency != "high" && urgency != "emergency" && urgency != "critical";
    3414             :                 }
    3415           0 :                 if(!skip)
    3416             :                 {
    3417           0 :                     const memfile::memory_file::file_info& info(list[i].get_info());
    3418           0 :                     const wpkg_filename::uri_filename filename(info.get_uri());
    3419           0 :                     cl.add_filename(cmd, filename.full_path());
    3420             : 
    3421             :                     // show info if --verbose specified
    3422             :                     wpkg_output::log("package %1 marked for upgrade to version %2")
    3423           0 :                             .quoted_arg(filename.full_path())
    3424           0 :                             .arg(list[i].get_version())
    3425           0 :                         .module(wpkg_output::module_repository)
    3426           0 :                         .package(filename)
    3427           0 :                         .action("upgrade-initialization");
    3428             :                 }
    3429             :             }
    3430           0 :         }
    3431             :     }
    3432             : 
    3433           0 :     if(cl.size() == 0)
    3434             :     {
    3435             :         wpkg_output::log("no packages to upgrade at this time")
    3436           0 :             .level(wpkg_output::level_warning)
    3437           0 :             .module(wpkg_output::module_repository)
    3438           0 :             .action("upgrade");
    3439             :         return;
    3440             :     }
    3441             : 
    3442             :     // the install function will use a new manager (defined inside the
    3443             :     // install() function itself) to make sure we do not leak unwanted
    3444             :     // data from the ugprade list computation
    3445           0 :     install(cl, wpkg_filename::uri_filename(), cmd);
    3446             : }
    3447             : 
    3448           0 : void vendor(command_line& cl)
    3449             : {
    3450           0 :     if(cl.verbose())
    3451             :     {
    3452             :         // if you create a fork, change the [original] entry with information
    3453             :         // about your own version, for example: [fork of 0.7.3]
    3454           0 :         printf("%s (%s) [original]\n", debian_packages_vendor(), debian_packages_version_string());
    3455             :     }
    3456             :     else
    3457             :     {
    3458           0 :         printf("%s\n", debian_packages_vendor());
    3459             :     }
    3460           0 : }
    3461             : 
    3462           0 : void configure(command_line& cl)
    3463             : {
    3464           0 :     wpkgar::wpkgar_manager manager;
    3465           0 :     wpkgar::wpkgar_install pkg_install(&manager);
    3466           0 :     init_installer(cl, manager, pkg_install, "configure");
    3467           0 :     pkg_install.set_configuring();
    3468             : 
    3469             :     // if pending is set then we want to read the database and configure any
    3470             :     // half-installed packages
    3471             : 
    3472           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Installing");
    3473           0 :     if(pkg_install.validate() && !cl.dry_run())
    3474             :     {
    3475             :         // TODO: test that all the specified packages are indeed unpacked
    3476             :         //       before attempting to configure them
    3477           0 :         const int max(pkg_install.count());
    3478           0 :         for(int i(0); i < max; ++i)
    3479             :         {
    3480           0 :             manager.check_interrupt();
    3481             : 
    3482             :             // TODO: the order is wrong because we do need to first
    3483             :             //       configure packages that don't have unpacked
    3484             :             //       dependencies
    3485           0 :             if(!pkg_install.configure(i))
    3486             :             {
    3487           0 :                 break;
    3488             :             }
    3489             :         }
    3490           0 :     }
    3491           0 : }
    3492             : 
    3493           0 : void reconfigure(command_line& cl)
    3494             : {
    3495           0 :     wpkgar::wpkgar_manager manager;
    3496           0 :     wpkgar::wpkgar_install pkg_install(&manager);
    3497           0 :     init_installer(cl, manager, pkg_install, "reconfigure");
    3498           0 :     pkg_install.set_reconfiguring();
    3499             : 
    3500           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Installing");
    3501           0 :     if(pkg_install.validate() && !cl.dry_run())
    3502             :     {
    3503           0 :         for(;;)
    3504             :         {
    3505           0 :             manager.check_interrupt();
    3506             : 
    3507           0 :             int i(pkg_install.reconfigure());
    3508           0 :             if(i < 0)
    3509             :             {
    3510           0 :                 break;
    3511             :             }
    3512           0 :             if(!pkg_install.configure(i))
    3513             :             {
    3514           0 :                 break;
    3515             :             }
    3516             :         }
    3517           0 :     }
    3518           0 : }
    3519             : 
    3520           0 : void is_installed(command_line& cl)
    3521             : {
    3522           0 :     wpkgar::wpkgar_manager manager;
    3523           0 :     init_manager(cl, manager, "is-installed");
    3524           0 :     std::string name(cl.get_string("is-installed"));
    3525           0 :     if(manager.safe_package_status(name) == wpkgar::wpkgar_manager::installed)
    3526             :     {
    3527             :         // true, it is installed
    3528           0 :         if(cl.verbose())
    3529             :         {
    3530           0 :             printf("true\n");
    3531             :         }
    3532           0 :         exit(0);
    3533             :     }
    3534             :     // "error," it is not installed
    3535           0 :     if(cl.verbose())
    3536             :     {
    3537           0 :         printf("false\n");
    3538             :     }
    3539           0 :     exit(1);
    3540             : }
    3541             : 
    3542           1 : void add_hooks(command_line& cl)
    3543             : {
    3544           1 :     const int max(cl.size());
    3545           1 :     if(max == 0)
    3546             :     {
    3547           0 :         cl.opt().usage(advgetopt::getopt::error, "--add-hooks expects at least one global hook script filename");
    3548             :         /*NOTREACHED*/
    3549             :     }
    3550             : 
    3551           1 :     wpkgar::wpkgar_manager manager;
    3552           1 :     init_manager(cl, manager, "add-hooks");
    3553           2 :     for(int i(0); i < max; ++i)
    3554             :     {
    3555           1 :         manager.add_global_hook(cl.argument(i).c_str());
    3556           1 :     }
    3557           1 : }
    3558             : 
    3559           1 : void remove_hooks(command_line& cl)
    3560             : {
    3561           1 :     const int max(cl.size());
    3562           1 :     if(max == 0)
    3563             :     {
    3564           0 :         cl.opt().usage(advgetopt::getopt::error, "--remove-hooks expects at least one global hook script name");
    3565             :         /*NOTREACHED*/
    3566             :     }
    3567             : 
    3568           1 :     wpkgar::wpkgar_manager manager;
    3569           1 :     init_manager(cl, manager, "remove-hooks");
    3570           2 :     for(int i(0); i < max; ++i)
    3571             :     {
    3572           1 :         if(!manager.remove_global_hook(cl.argument(i).c_str()))
    3573             :         {
    3574             :             wpkg_output::log("global hook %1 could not be removed because it was not installed.")
    3575           0 :                     .quoted_arg(cl.argument(i))
    3576           0 :                 .level(wpkg_output::level_warning)
    3577           0 :                 .action("pkg-config");
    3578             :         }
    3579           1 :     }
    3580           1 : }
    3581             : 
    3582           2 : void list_hooks(command_line& cl)
    3583             : {
    3584           2 :     if(cl.size() != 0)
    3585             :     {
    3586           0 :         cl.opt().usage(advgetopt::getopt::error, "--list-hooks does not expects any parameter");
    3587             :         /*NOTREACHED*/
    3588             :     }
    3589             : 
    3590           2 :     wpkgar::wpkgar_manager manager;
    3591           2 :     init_manager(cl, manager, "list-hooks");
    3592           2 :     wpkgar::wpkgar_manager::hooks_t hooks(manager.list_hooks());
    3593           2 :     const wpkgar::wpkgar_manager::hooks_t::size_type max(hooks.size());
    3594           2 :     bool first(true);
    3595           4 :     for(wpkgar::wpkgar_manager::hooks_t::size_type i(0); i < max; ++i)
    3596             :     {
    3597           2 :         const std::string name(hooks[i]);
    3598           2 :         if(name.substr(0, 5) == "core_")
    3599             :         {
    3600           1 :             if(first)
    3601             :             {
    3602           1 :                 first = false;
    3603           1 :                 printf("Global Hooks:\n");
    3604             :             }
    3605           1 :             printf("  %s\n", name.substr(5).c_str());
    3606             :         }
    3607           2 :     }
    3608           2 :     first = true;
    3609           4 :     for(wpkgar::wpkgar_manager::hooks_t::size_type i(0); i < max; ++i)
    3610             :     {
    3611           2 :         const std::string name(hooks[i]);
    3612           2 :         if(name.substr(0, 5) != "core_")
    3613             :         {
    3614           1 :             if(first)
    3615             :             {
    3616           1 :                 first = false;
    3617           1 :                 printf("Package Hooks:\n");
    3618             :             }
    3619           1 :             printf("  %s\n", name.c_str());
    3620             :         }
    3621           4 :     }
    3622           2 : }
    3623             : 
    3624           0 : void add_sources(command_line& cl)
    3625             : {
    3626           0 :     int max(cl.size());
    3627           0 :     if(max == 0)
    3628             :     {
    3629           0 :         cl.opt().usage(advgetopt::getopt::error, "--add-sources expects at least one entry");
    3630             :         /*NOTREACHED*/
    3631             :     }
    3632             : 
    3633           0 :     wpkgar::wpkgar_manager manager;
    3634           0 :     init_manager(cl, manager, "add-sources");
    3635           0 :     wpkg_filename::uri_filename name(manager.get_database_path());
    3636           0 :     name = name.append_child("core/sources.list");
    3637           0 :     wpkgar::wpkgar_repository repository(&manager);
    3638           0 :     wpkgar::wpkgar_repository::source_vector_t sources;
    3639           0 :     memfile::memory_file sources_file;
    3640           0 :     if(name.exists())
    3641             :     {
    3642           0 :         sources_file.read_file(name);
    3643           0 :         sources_file.printf("\n");
    3644             :     }
    3645             :     else
    3646             :     {
    3647           0 :         sources_file.create(memfile::memory_file::file_format_other);
    3648             :     }
    3649           0 :     for(int i(0); i < max; ++i)
    3650             :     {
    3651           0 :         sources_file.printf("%s\n", cl.argument(i).c_str());
    3652             :     }
    3653           0 :     repository.read_sources(sources_file, sources);
    3654           0 :     sources_file.create(memfile::memory_file::file_format_other);
    3655           0 :     repository.write_sources(sources_file, sources);
    3656           0 :     sources_file.write_file(name);
    3657           0 : }
    3658             : 
    3659           0 : void architecture(command_line& cl)
    3660             : {
    3661           0 :     if(cl.size() != 0)
    3662             :     {
    3663           0 :         cl.opt().usage(advgetopt::getopt::error, "--architecture does not take any parameters.");
    3664             :         /*NOTREACHED*/
    3665             :     }
    3666             : 
    3667           0 :     if(cl.verbose())
    3668             :     {
    3669           0 :         printf("%s (%s)\n", debian_packages_architecture(), debian_packages_machine());
    3670             :     }
    3671             :     else
    3672             :     {
    3673           0 :         printf("%s\n", debian_packages_architecture());
    3674             :     }
    3675           0 : }
    3676             : 
    3677           0 : void atleast_version(command_line& cl)
    3678             : {
    3679           0 :     if(cl.size() != 1)
    3680             :     {
    3681           0 :         cl.opt().usage(advgetopt::getopt::error, "--atleast-version expects exactly two parameters: wpkg --atleast-version <version> <package name>.");
    3682             :         /*NOTREACHED*/
    3683             :     }
    3684             : 
    3685           0 :     wpkgar::wpkgar_manager manager;
    3686           0 :     init_manager(cl, manager, "atleast-version");
    3687           0 :     const std::string package_name(cl.argument(0));
    3688           0 :     manager.load_package(package_name);
    3689           0 :     const std::string version(manager.get_field(package_name, wpkg_control::control_file::field_version_factory_t::canonicalized_name()));
    3690             : 
    3691           0 :     if(wpkg_util::versioncmp(version, cl.opt().get_string("atleast-version")) < 0)
    3692             :     {
    3693             :         // version is too small
    3694           0 :         exit(1);
    3695           0 :     }
    3696           0 : }
    3697             : 
    3698           0 : void atleast_wpkg_version(command_line& cl)
    3699             : {
    3700           0 :     if(cl.size() != 0)
    3701             :     {
    3702           0 :         cl.opt().usage(advgetopt::getopt::error, "--atleast-wpkg-version takes exactly one parameter.");
    3703             :         /*NOTREACHED*/
    3704             :     }
    3705             : 
    3706           0 :     if(wpkg_util::versioncmp(debian_packages_version_string(), cl.opt().get_string("atleast-wpkg-version")) < 0)
    3707             :     {
    3708             :         // version is too small
    3709           0 :         exit(1);
    3710             :     }
    3711           0 : }
    3712             : 
    3713           0 : void exact_version(command_line& cl)
    3714             : {
    3715           0 :     if(cl.size() != 1)
    3716             :     {
    3717           0 :         cl.opt().usage(advgetopt::getopt::error, "--exact-version expects exactly two parameters: wpkg --exact-version <version> <package name>.");
    3718             :         /*NOTREACHED*/
    3719             :     }
    3720             : 
    3721           0 :     wpkgar::wpkgar_manager manager;
    3722           0 :     init_manager(cl, manager, "exact-version");
    3723           0 :     const std::string package_name(cl.argument(0));
    3724           0 :     manager.load_package(package_name);
    3725           0 :     const std::string version(manager.get_field(package_name, wpkg_control::control_file::field_version_factory_t::canonicalized_name()));
    3726             : 
    3727           0 :     if(wpkg_util::versioncmp(version, cl.opt().get_string("exact-version")) != 0)
    3728             :     {
    3729             :         // version is not equal
    3730           0 :         exit(1);
    3731           0 :     }
    3732           0 : }
    3733             : 
    3734           0 : void max_version(command_line& cl)
    3735             : {
    3736           0 :     if(cl.size() != 1)
    3737             :     {
    3738           0 :         cl.opt().usage(advgetopt::getopt::error, "--max-version expects exactly two parameters: wpkg --max-version <version> <package name>.");
    3739             :         /*NOTREACHED*/
    3740             :     }
    3741             : 
    3742           0 :     wpkgar::wpkgar_manager manager;
    3743           0 :     init_manager(cl, manager, "max-version");
    3744           0 :     const std::string package_name(cl.argument(0));
    3745           0 :     manager.load_package(package_name);
    3746           0 :     const std::string version(manager.get_field(package_name, wpkg_control::control_file::field_version_factory_t::canonicalized_name()));
    3747             : 
    3748           0 :     if(wpkg_util::versioncmp(version, cl.opt().get_string("max-version")) > 0)
    3749             :     {
    3750             :         // version is not equal
    3751           0 :         exit(1);
    3752           0 :     }
    3753           0 : }
    3754             : 
    3755           0 : void processor(command_line& cl)
    3756             : {
    3757           0 :     if(cl.size() != 0)
    3758             :     {
    3759           0 :         cl.opt().usage(advgetopt::getopt::error, "--processor does not take any parameters.");
    3760             :         /*NOTREACHED*/
    3761             :     }
    3762             : 
    3763           0 :     if(cl.verbose())
    3764             :     {
    3765           0 :         printf("%s (%s)\n", debian_packages_processor(), debian_packages_machine());
    3766             :     }
    3767             :     else
    3768             :     {
    3769           0 :         printf("%s\n", debian_packages_processor());
    3770             :     }
    3771           0 : }
    3772             : 
    3773           0 : void audit(command_line& cl)
    3774             : {
    3775           0 :     int max(cl.size());
    3776           0 :     if(max != 0)
    3777             :     {
    3778             :         printf("error:%s: --audit does not take any parameters.\n",
    3779           0 :             cl.opt().get_program_name().c_str());
    3780           0 :         exit(1);
    3781             :     }
    3782             : 
    3783             :     // TODO: check that directories exist as expected by the module
    3784             :     // TODO: check file attributes (under Win32 it would be the read-only flag)
    3785             :     // TODO: offer help to fix the problems when -v is used
    3786           0 :     int err(0);
    3787             :     {
    3788             :         // we must have the manager within a sub-block to make sure that the
    3789             :         // database lock gets removed before we call exit()
    3790           0 :         wpkgar::wpkgar_manager manager;
    3791           0 :         init_manager(cl, manager, "audit");
    3792             :         // auditing is very similar to listing so at this point we use that status
    3793           0 :         wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    3794           0 :         wpkgar::wpkgar_manager::package_list_t list;
    3795           0 :         manager.list_installed_packages(list);
    3796             : 
    3797           0 :         const wpkg_filename::uri_filename package_path(manager.get_inst_path());
    3798           0 :         for(wpkgar::wpkgar_manager::package_list_t::const_iterator it(list.begin());
    3799           0 :                 it != list.end(); ++it)
    3800             :         {
    3801             :             try
    3802             :             {
    3803           0 :                 if(cl.verbose())
    3804             :                 {
    3805           0 :                     printf("working on %s\n", it->c_str());
    3806             :                 }
    3807           0 :                 wpkgar::wpkgar_manager::package_status_t status(manager.package_status(*it));
    3808           0 :                 bool check_md5sums(false);
    3809           0 :                 switch(status)
    3810             :                 {
    3811             :                 case wpkgar::wpkgar_manager::not_installed:
    3812             :                 case wpkgar::wpkgar_manager::config_files:
    3813             :                 case wpkgar::wpkgar_manager::installing:
    3814             :                 case wpkgar::wpkgar_manager::upgrading:
    3815             :                 case wpkgar::wpkgar_manager::removing:
    3816             :                 case wpkgar::wpkgar_manager::purging:
    3817           0 :                     break;
    3818             : 
    3819             :                 case wpkgar::wpkgar_manager::unpacked:
    3820             :                 case wpkgar::wpkgar_manager::installed:
    3821           0 :                     check_md5sums = true;
    3822           0 :                     break;
    3823             : 
    3824             :                 case wpkgar::wpkgar_manager::no_package:
    3825           0 :                     printf("%s: package is missing\n", it->c_str());
    3826           0 :                     ++err;
    3827           0 :                     break;
    3828             : 
    3829             :                 case wpkgar::wpkgar_manager::unknown:
    3830           0 :                     printf("%s: package could not be loaded\n", it->c_str());
    3831           0 :                     ++err;
    3832           0 :                     break;
    3833             : 
    3834             :                 case wpkgar::wpkgar_manager::half_installed:
    3835           0 :                     printf("%s: package is half installed\n", it->c_str());
    3836           0 :                     ++err;
    3837           0 :                     break;
    3838             : 
    3839             :                 case wpkgar::wpkgar_manager::half_configured:
    3840           0 :                     printf("%s: package is half configured\n", it->c_str());
    3841           0 :                     ++err;
    3842             :                     // although in a bad state, all the files are expected to
    3843             :                     // be properly unpacked for this one
    3844           0 :                     check_md5sums = true;
    3845           0 :                     break;
    3846             : 
    3847             :                 // unexpected status for a package
    3848             :                 case wpkgar::wpkgar_manager::listing:
    3849             :                 case wpkgar::wpkgar_manager::verifying:
    3850             :                 case wpkgar::wpkgar_manager::ready:
    3851           0 :                     printf("%s: package has an invalid status\n", it->c_str());
    3852           0 :                     ++err;
    3853           0 :                     break;
    3854             : 
    3855             :                 }
    3856           0 :                 if(check_md5sums)
    3857             :                 {
    3858             :                     // the package is already loaded, just get the md5sums file
    3859             :                     // and the wpkgar file
    3860           0 :                     memfile::memory_file md5sums_file;
    3861           0 :                     wpkg_util::md5sums_map_t md5sums;
    3862           0 :                     if(manager.has_control_file(*it, "md5sums"))
    3863             :                     {
    3864             :                         // if the file is not present there should be no regular
    3865             :                         // or continuous files in the package... (just dirs?!)
    3866           0 :                         std::string md5filename("md5sums");
    3867           0 :                         manager.get_control_file(md5sums_file, *it, md5filename, false);
    3868           0 :                         wpkg_util::parse_md5sums(md5sums, md5sums_file);
    3869             :                     }
    3870             :                     memfile::memory_file *wpkgar_file;
    3871           0 :                     manager.get_wpkgar_file(*it, wpkgar_file);
    3872           0 :                     wpkgar_file->set_package_path(package_path);
    3873           0 :                     wpkgar_file->dir_rewind();
    3874           0 :                     for(;;)
    3875             :                     {
    3876           0 :                         memfile::memory_file::file_info info;
    3877           0 :                         memfile::memory_file data;
    3878           0 :                         if(!wpkgar_file->dir_next(info, &data))
    3879             :                         {
    3880             :                             break;
    3881             :                         }
    3882           0 :                         std::string filename(info.get_filename());
    3883           0 :                         if(filename[0] == '/')
    3884             :                         {
    3885           0 :                             switch(info.get_file_type())
    3886             :                             {
    3887             :                             case memfile::memory_file::file_info::regular_file:
    3888             :                             case memfile::memory_file::file_info::continuous:
    3889             :                                 {
    3890           0 :                                     const wpkg_filename::uri_filename fullname(package_path.append_child(filename));
    3891             :                                     //printf("%s: %s\n", it->c_str(), fullname.c_str());
    3892           0 :                                     filename.erase(0, 1);
    3893           0 :                                     if(md5sums.find(filename) != md5sums.end())
    3894             :                                     {
    3895           0 :                                         std::string sum(data.md5sum());
    3896           0 :                                         if(md5sums[filename] != sum)
    3897             :                                         {
    3898           0 :                                             if(!manager.is_conffile(*it, filename))
    3899             :                                             {
    3900             :                                                 printf("%s: file \"%s\" md5sum differs\n",
    3901             :                                                         it->c_str(),
    3902           0 :                                                         fullname.original_filename().c_str());
    3903           0 :                                                 ++err;
    3904             :                                             }
    3905           0 :                                             else if(cl.verbose())
    3906             :                                             {
    3907           0 :                                                 printf("%s: configuration file \"%s\" was modified\n", it->c_str(), fullname.original_filename().c_str());
    3908             :                                             }
    3909             :                                         }
    3910             :                                         // remove the entry so we can err in case some
    3911             :                                         // md5sums were not used up (why are they defined?)
    3912           0 :                                         md5sums.erase(md5sums.find(filename));
    3913             :                                     }
    3914             :                                     else
    3915             :                                     {
    3916             :                                         printf("%s: file \"%s\" is not defined in the list of md5sums\n",
    3917             :                                                     it->c_str(),
    3918           0 :                                                     fullname.original_filename().c_str());
    3919           0 :                                         ++err;
    3920           0 :                                     }
    3921             :                                 }
    3922           0 :                                 break;
    3923             : 
    3924             :                             default:
    3925             :                                 // other types are not checked they don't have
    3926             :                                 // an md5sum anyway
    3927           0 :                                 break;
    3928             : 
    3929             :                             }
    3930             :                         }
    3931           0 :                     }
    3932           0 :                     if(!md5sums.empty())
    3933             :                     {
    3934           0 :                         for(wpkg_util::md5sums_map_t::const_iterator m5(md5sums.begin());
    3935           0 :                                 m5 != md5sums.end(); ++m5)
    3936             :                         {
    3937           0 :                             const wpkg_filename::uri_filename fullname(package_path.append_child(m5->first));
    3938             :                             printf("%s: package has file \"%s\" in its md5sums file but not in its wpkgar index\n",
    3939           0 :                                 it->c_str(), fullname.original_filename().c_str());
    3940           0 :                             ++err;
    3941           0 :                         }
    3942           0 :                     }
    3943             :                 }
    3944             :             }
    3945           0 :             catch(const std::exception&)
    3946             :             {
    3947           0 :                 printf("%s: package could not be loaded\n", it->c_str());
    3948           0 :                 ++err;
    3949             :             }
    3950           0 :         }
    3951             :     }
    3952           0 :     if(cl.verbose() && err > 0)
    3953             :     {
    3954           0 :         printf("%d error%s found while auditing\n", err, (err != 1 ? "s" : ""));
    3955             :     }
    3956             : 
    3957             :     // exit with an error if anything failed while auditing
    3958           0 :     exit(err == 0 ? 0 : 1);
    3959             : }
    3960             : 
    3961             : 
    3962          10 : void create_index(command_line& cl)
    3963             : {
    3964          10 :     wpkgar::wpkgar_manager manager;
    3965          10 :     wpkgar::wpkgar_repository pkg_repository(&manager);
    3966          10 :     init_manager(cl, manager, "create-index");
    3967             : 
    3968          10 :     pkg_repository.set_parameter(wpkgar::wpkgar_repository::wpkgar_repository_recursive, cl.opt().is_defined("recursive"));
    3969             : 
    3970             :     // check for a set of repository names
    3971          10 :     if(manager.get_repositories().empty())
    3972             :     {
    3973           0 :         cl.opt().usage(advgetopt::getopt::error, "--create-index requires at least one --repository name");
    3974             :         /*NOTREACHED*/
    3975             :     }
    3976             : 
    3977             :     // check that the extension matches as expected
    3978          10 :     std::string archive(cl.get_string("create-index"));
    3979          10 :     memfile::memory_file::file_format_t ar_format(memfile::memory_file::filename_extension_to_format(archive, true));
    3980          10 :     switch(ar_format)
    3981             :     {
    3982             :     case memfile::memory_file::file_format_tar:
    3983          10 :         break;
    3984             : 
    3985             :     case memfile::memory_file::file_format_ar:
    3986             :     case memfile::memory_file::file_format_zip:
    3987             :     case memfile::memory_file::file_format_7z:
    3988             :     case memfile::memory_file::file_format_wpkg:
    3989           0 :         cl.opt().usage(advgetopt::getopt::error, "unsupported archive file extension (we only support .tar for a repository index)");
    3990             :         /*NOTREACHED*/
    3991           0 :         break;
    3992             : 
    3993             :     default:
    3994           0 :         cl.opt().usage(advgetopt::getopt::error, "unsupported archive file extension (we support .deb, .a, .tar)");
    3995             :         /*NOTREACHED*/
    3996           0 :         break;
    3997             : 
    3998             :     }
    3999             : 
    4000             :     // create the output
    4001          10 :     memfile::memory_file index;
    4002          10 :     pkg_repository.create_index(index);
    4003             : 
    4004          10 :     if(index.size() == 0)
    4005             :     {
    4006           0 :         cl.opt().usage(advgetopt::getopt::error, "the resulting index is empty; please specify the right repository(ies) and the --recursive option if necessary");
    4007             :         /*NOTREACHED*/
    4008             :     }
    4009             : 
    4010             :     // check whether a compression is defined
    4011          10 :     memfile::memory_file::file_format_t format(memfile::memory_file::filename_extension_to_format(archive));
    4012          10 :     switch(format)
    4013             :     {
    4014             :     case memfile::memory_file::file_format_gz:
    4015             :     case memfile::memory_file::file_format_bz2:
    4016             :     case memfile::memory_file::file_format_lzma:
    4017             :     case memfile::memory_file::file_format_xz:
    4018             :         {
    4019          10 :             memfile::memory_file compressed;
    4020          10 :             index.compress(compressed, format);
    4021          10 :             compressed.write_file(archive);
    4022             :         }
    4023          10 :         break;
    4024             : 
    4025             :     default: // we don't prevent any extension here
    4026           0 :         index.write_file(archive);
    4027           0 :         break;
    4028             : 
    4029          10 :     }
    4030          10 : }
    4031             : 
    4032             : 
    4033         310 : void build(command_line& cl, wpkg_filename::uri_filename& package_name, const std::string& option = "build")
    4034             : {
    4035         310 :     const bool do_create_index(cl.opt().is_defined("create-index"));
    4036         310 :     if(do_create_index && !cl.opt().is_defined("output-repository-dir"))
    4037             :     {
    4038           0 :         cl.opt().usage(advgetopt::getopt::error, "when --build is used with --create-index, then --output-repository-dir must be defined.");
    4039             :         /*NOTREACHED*/
    4040             :     }
    4041             : 
    4042         310 :     bool need_lock(false);
    4043         310 :     wpkgar::wpkgar_manager manager;
    4044         310 :     init_manager(cl, manager, option);
    4045         310 :     std::shared_ptr<wpkgar::wpkgar_build> pkg_build;
    4046         310 :     if(cl.size() == 0)
    4047             :     {
    4048             :         // build a source package; `pwd` is the root of the project
    4049           6 :         pkg_build.reset(new wpkgar::wpkgar_build(&manager, ""));
    4050             :     }
    4051             :     else
    4052             :     {
    4053             :         // build a binary package
    4054         304 :         pkg_build.reset(new wpkgar::wpkgar_build(&manager, cl.get_string("filename", 0)));
    4055         304 :         if(cl.size() == 2)
    4056             :         {
    4057             :             // binary package is created from a control file
    4058           0 :             pkg_build->set_extra_path(cl.filename(1));
    4059             :         }
    4060         304 :         else if(cl.size() != 1)
    4061             :         {
    4062           0 :             cl.opt().usage(advgetopt::getopt::error, "--build accepts zero, one, or two file parameters.");
    4063             :             /*NOTREACHED*/
    4064             :         }
    4065             :         else
    4066             :         {
    4067         304 :             wpkg_filename::uri_filename filename(cl.filename(0));
    4068             : #ifdef WINDOWS
    4069             :             case_insensitive::case_insensitive_string ext(filename.extension());
    4070             : #else
    4071         304 :             std::string ext(filename.extension());
    4072             : #endif
    4073         304 :             if(ext == "deb")
    4074             :             {
    4075             :                 // if compiling a source package, check a few more options
    4076           6 :                 pkg_build->set_parameter(wpkgar::wpkgar_build::wpkgar_build_recursive, cl.opt().is_defined("recursive"));
    4077           6 :                 pkg_build->set_parameter(wpkgar::wpkgar_build::wpkgar_build_run_unit_tests, cl.opt().is_defined("run-unit-tests"));
    4078           6 :                 pkg_build->set_parameter(wpkgar::wpkgar_build::wpkgar_build_force_file_info, cl.opt().is_defined("force-file-info"));
    4079           6 :                 if(cl.opt().is_defined("install-prefix"))
    4080             :                 {
    4081           0 :                     pkg_build->set_install_prefix(cl.opt().get_string("install-prefix"));
    4082             :                 }
    4083           6 :                 need_lock = true;
    4084         304 :             }
    4085             :         }
    4086             :     }
    4087             : 
    4088         310 :     pkg_build->set_zlevel(cl.zlevel());
    4089         310 :     pkg_build->set_compressor(cl.compressor());
    4090         310 :     if(cl.opt().is_defined("enforce-path-length-limit"))
    4091             :     {
    4092           0 :         if(cl.opt().is_defined("path-length-limit"))
    4093             :         {
    4094           0 :             cl.opt().usage(advgetopt::getopt::error, "--enforce-path-length-limit and --path-length-limit cannot be used together.");
    4095             :             /*NOTREACHED*/
    4096             :         }
    4097           0 :         pkg_build->set_path_length_limit(-cl.opt().get_long("enforce-path-length-limit"));
    4098             :     }
    4099         310 :     else if(cl.opt().is_defined("path-length-limit"))
    4100             :     {
    4101           0 :         pkg_build->set_path_length_limit(cl.opt().get_long("path-length-limit"));
    4102             :     }
    4103         310 :     if(cl.opt().is_defined("output-filename"))
    4104             :     {
    4105           0 :         pkg_build->set_filename(cl.opt().get_string("output-filename", 0));
    4106             :     }
    4107         310 :     if(cl.opt().is_defined("output-dir"))
    4108             :     {
    4109         297 :         pkg_build->set_output_dir(cl.opt().get_string("output-dir", 0));
    4110             :     }
    4111         310 :     if(cl.opt().is_defined("output-repository-dir"))
    4112             :     {
    4113          13 :         pkg_build->set_output_repository_dir(cl.opt().get_string("output-repository-dir", 0));
    4114             :     }
    4115         310 :     if(cl.opt().is_defined("cmake-generator"))
    4116             :     {
    4117           0 :         pkg_build->set_cmake_generator(cl.opt().get_string("cmake-generator"));
    4118             :     }
    4119         310 :     if(cl.opt().is_defined("make-tool"))
    4120             :     {
    4121           0 :         pkg_build->set_make_tool(cl.opt().get_string("make-tool"));
    4122             :     }
    4123         310 :     if(cl.opt().is_defined("build-number-filename"))
    4124             :     {
    4125           0 :         pkg_build->set_build_number_filename(cl.opt().get_string("build-number-filename"));
    4126             :     }
    4127         310 :     pkg_build->set_parameter(wpkgar::wpkgar_build::wpkgar_build_ignore_empty_packages, cl.opt().is_defined("ignore-empty-packages"));
    4128         310 :     if(cl.opt().is_defined("clear-exceptions"))
    4129             :     {
    4130           0 :         pkg_build->add_exception("");
    4131             :     }
    4132         310 :     const int max(cl.opt().size("exception"));
    4133         310 :     for(int i(0); i < max; ++i)
    4134             :     {
    4135           0 :         std::string e(cl.opt().get_string("exception", i));
    4136           0 :         pkg_build->add_exception(e);
    4137           0 :     }
    4138         310 :     pkg_build->set_program_fullname(cl.opt().get_program_fullname());
    4139         310 :     init_field_variables(cl, manager, NULL);
    4140             : 
    4141             :     {
    4142         310 :         std::shared_ptr<wpkgar::wpkgar_lock> lock_wpkg;
    4143         310 :         if(need_lock)
    4144             :         {
    4145           6 :             lock_wpkg.reset(new wpkgar::wpkgar_lock(&manager, "Building"));
    4146             :         }
    4147         310 :         pkg_build->build();
    4148             : 
    4149             :         // we have to reset the tracker now or the rollback happens at
    4150             :         // the wrong time (i.e. after the manager gets unlocked)
    4151         310 :         const std::shared_ptr<wpkgar::wpkgar_tracker> null_tracker;
    4152         310 :         manager.set_tracker(null_tracker);
    4153             :     }
    4154             : 
    4155         310 :     if(do_create_index)
    4156             :     {
    4157             :         // TBD: do we really want that? shall we share the list from the
    4158             :         //      main() function?
    4159           9 :         std::vector<std::string> configuration_files;
    4160           9 :         configuration_files.push_back("/etc/wpkg/wpkg.conf");
    4161           9 :         configuration_files.push_back("~/.config/wpkg/wpkg.conf");
    4162             : 
    4163           9 :         const std::string repository_directory(cl.opt().get_string("output-repository-dir"));
    4164           9 :         wpkg_filename::uri_filename output_dir(repository_directory);
    4165           9 :         output_dir = output_dir.append_child(cl.opt().get_string("create-index"));
    4166           9 :         const std::string create_index_param(output_dir.full_path());
    4167             :         const char *argv[] =
    4168             :         {
    4169             :             "wpkg",
    4170             :             "--create-index",
    4171           9 :             create_index_param.c_str(),
    4172             :             "--recursive",
    4173             :             "--repository",
    4174           9 :             repository_directory.c_str(),
    4175             :             NULL
    4176          27 :         };
    4177           9 :         printf("wpkg --create-index %s --recursive --repository %s\n", create_index_param.c_str(), repository_directory.c_str());
    4178           9 :         command_line sub_cl(sizeof(argv) / sizeof(argv[0]) - 1, const_cast<char **>(argv), configuration_files);
    4179           9 :         create_index(sub_cl);
    4180             :     }
    4181             : 
    4182             :     // for the build_and_install() function
    4183         310 :     package_name = pkg_build->get_package_name();
    4184         310 : }
    4185             : 
    4186           0 : void build_and_install(command_line& cl)
    4187             : {
    4188           0 :     wpkg_filename::uri_filename package_name;
    4189           0 :     build(cl, package_name, "build-and-install");
    4190           0 :     if(!package_name.empty())
    4191             :     {
    4192             :         // we install only if the build did not find out that the package
    4193             :         // was empty (if empty then the name remains undefined)
    4194           0 :         install(cl, package_name, "build-and-install");
    4195           0 :     }
    4196           0 : }
    4197             : 
    4198           0 : void verify_control(command_line& cl)
    4199             : {
    4200           0 :     const int max(cl.size());
    4201           0 :     if(max == 0)
    4202             :     {
    4203           0 :         cl.opt().usage(advgetopt::getopt::error, "--verify-control must be used with at least one control filename.");
    4204             :         /*NOTREACHED*/
    4205             :     }
    4206             : 
    4207           0 :     for(int i(0); i < max; ++i)
    4208             :     {
    4209           0 :         memfile::memory_file ctrl_input;
    4210           0 :         ctrl_input.read_file(cl.filename(i));
    4211           0 :         wpkg_control::binary_control_file ctrl(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::control_file_state_t));
    4212           0 :         ctrl.set_input_file(&ctrl_input);
    4213           0 :         ctrl.read();
    4214           0 :         ctrl.set_input_file(NULL);
    4215           0 :         printf("Verified %s\n", ctrl.get_field(wpkg_control::control_file::field_package_factory_t::canonicalized_name()).c_str());
    4216           0 :     }
    4217           0 : }
    4218             : 
    4219           0 : void verify_project(command_line& cl)
    4220             : {
    4221           0 :     wpkgar::wpkgar_manager manager;
    4222           0 :     init_manager(cl, manager, "verify-project");
    4223           0 :     std::shared_ptr<wpkgar::wpkgar_build> pkg_build;
    4224           0 :     if(cl.size() != 0)
    4225             :     {
    4226           0 :         cl.opt().usage(advgetopt::getopt::error, "--verify-project does not accept any arguments.");
    4227             :         /*NOTREACHED*/
    4228             :     }
    4229             :     // validate a project environement; `pwd` is the root of the project
    4230           0 :     pkg_build.reset(new wpkgar::wpkgar_build(&manager, ""));
    4231             : 
    4232           0 :     if(cl.opt().is_defined("clear-exceptions"))
    4233             :     {
    4234           0 :         pkg_build->add_exception("");
    4235             :     }
    4236           0 :     const int max(cl.opt().size("exception"));
    4237           0 :     for(int i(0); i < max; ++i)
    4238             :     {
    4239           0 :         std::string e(cl.opt().get_string("exception", i));
    4240           0 :         pkg_build->add_exception(e);
    4241           0 :     }
    4242           0 :     init_field_variables(cl, manager, NULL);
    4243             : 
    4244             :     // now run the validation of the source
    4245           0 :     wpkgar::wpkgar_build::source_validation sv;
    4246           0 :     wpkg_control::source_control_file controlinfo_fields;
    4247           0 :     if(!pkg_build->validate_source(sv, controlinfo_fields))
    4248             :     {
    4249           0 :         const wpkgar::wpkgar_build::source_validation::source_properties_t& p(sv.get_properties());
    4250           0 :         for(wpkgar::wpkgar_build::source_validation::source_properties_t::const_iterator i(p.begin()); i != p.end(); ++i)
    4251             :         {
    4252             :             // if unknown it was not yet worked on, avoid the error message for now
    4253           0 :             if(i->second.get_status() != wpkgar::wpkgar_build::source_validation::source_property::SOURCE_VALIDATION_STATUS_VALID
    4254           0 :             && i->second.get_status() != wpkgar::wpkgar_build::source_validation::source_property::SOURCE_VALIDATION_STATUS_UNKNOWN)
    4255             :             {
    4256           0 :                 printf("\n%s is not valid:\n  %s\n", i->second.get_name(), i->second.get_help());
    4257             :             }
    4258             :         }
    4259           0 :         return;
    4260             :     }
    4261             : 
    4262           0 :     if(cl.verbose())
    4263             :     {
    4264           0 :         printf("Your project is valid. You can build a source package with: wpkg --build\n");
    4265           0 :     }
    4266             : }
    4267             : 
    4268             : 
    4269           0 : bool is_letter(char c)
    4270             : {
    4271             :     return (c >= 'a' && c <= 'z')
    4272           0 :         || (c >= 'A' && c <= 'Z');
    4273             : }
    4274             : 
    4275           0 : void canonicalize_version(command_line& cl)
    4276             : {
    4277           0 :     if(cl.opt().size("canonicalize-version") != 1)
    4278             :     {
    4279             :         fprintf(stderr, "error:%s: --canonicalize-version expects exactly 1 parameter.\n",
    4280           0 :             cl.opt().get_program_name().c_str());
    4281           0 :         exit(1);
    4282             :     }
    4283             :     char err[256];
    4284           0 :     std::string org(cl.opt().get_string("canonicalize-version", 0));
    4285           0 :     debian_version_handle_t v(string_to_debian_version(org.c_str(), err, sizeof(err)));
    4286           0 :     if(v == NULL)
    4287             :     {
    4288             :         fprintf(stderr, "error:%s: version \"%s\" is not a valid Debian version: %s.\n",
    4289           0 :                 cl.opt().get_program_name().c_str(), org.c_str(), err);
    4290           0 :         exit(1);
    4291             :     }
    4292             :     char version[256];
    4293           0 :     int r(debian_version_to_string(v, version, sizeof(version)));
    4294           0 :     if(r == -1)
    4295             :     {
    4296             :         fprintf(stderr, "error:%s: version \"%s\" could not be canonicalized (too long? %d).\n",
    4297           0 :                 cl.opt().get_program_name().c_str(), org.c_str(), errno);
    4298           0 :         exit(1);
    4299             :     }
    4300           0 :     printf("%s\n", version);
    4301           0 : }
    4302             : 
    4303         750 : void compare_versions(command_line& cl)
    4304             : {
    4305         750 :     if(cl.opt().size("compare-versions") != 3)
    4306             :     {
    4307             :         fprintf(stderr, "error:%s: --compare-versions expects exactly 3 parameters.\n",
    4308           0 :             cl.opt().get_program_name().c_str());
    4309           0 :         exit(255);
    4310             :     }
    4311             : 
    4312             :     char err[256];
    4313         750 :     std::string v1(cl.opt().get_string("compare-versions", 0));
    4314         750 :     std::string v2(cl.opt().get_string("compare-versions", 2));
    4315         750 :     int c(0);
    4316         750 :     if(!v1.empty() && !v2.empty())
    4317             :     {
    4318         660 :         debian_version_handle_t a(string_to_debian_version(v1.c_str(), err, sizeof(err)));
    4319         660 :         if(a == NULL)
    4320             :         {
    4321             :             fprintf(stderr, "error:%s: version \"%s\" is not a valid Debian version: %s.\n",
    4322           0 :                     cl.opt().get_program_name().c_str(), v1.c_str(), err);
    4323           0 :             exit(255);
    4324             :         }
    4325         660 :         debian_version_handle_t b(string_to_debian_version(v2.c_str(), err, sizeof(err)));
    4326         660 :         if(b == NULL)
    4327             :         {
    4328             :             fprintf(stderr, "error:%s: version \"%s\" is not a valid Debian version: %s.\n",
    4329           0 :                     cl.opt().get_program_name().c_str(), v2.c_str(), err);
    4330           0 :             exit(255);
    4331             :         }
    4332             : 
    4333         660 :         c = debian_versions_compare(a, b);
    4334             :     }
    4335             :     else
    4336             :     {
    4337          90 :         if(v1.empty())
    4338             :         {
    4339          60 :             c = v2.empty() ? 0 : -1;
    4340             :         }
    4341             :         else /*if(v2.empty()) -- this must be true here */
    4342             :         {
    4343          30 :             c = 1;
    4344             :         }
    4345             :     }
    4346             : 
    4347         750 :     std::string op(cl.opt().get_string("compare-versions", 1));
    4348         750 :     int r(0);
    4349         750 :     if(op == "=" || op == "==" || op == "eq")
    4350             :     {
    4351          75 :         r = c == 0;
    4352             :     }
    4353         675 :     else if(op == "!=" || op == "<>" || op == "ne")
    4354             :     {
    4355             :         // op != and <> are not Debian compatible
    4356          75 :         r = c != 0;
    4357             :     }
    4358         600 :     else if(op == "<=" || op == "le")
    4359             :     {
    4360          75 :         r = c <= 0;
    4361             :     }
    4362         525 :     else if(op == "<" || op == "<<" || op == "lt")
    4363             :     {
    4364          75 :         r = c < 0;
    4365             :     }
    4366         450 :     else if(op == ">=" || op == "ge")
    4367             :     {
    4368          75 :         r = c >= 0;
    4369             :     }
    4370         375 :     else if(op == ">" || op == ">>" || op == "gt")
    4371             :     {
    4372          75 :         r = c > 0;
    4373             :     }
    4374         300 :     else if(op == "lt-nl")
    4375             :     {
    4376          75 :         if(v1.empty() || v2.empty())
    4377             :         {
    4378           9 :             r = c > 0;
    4379             :         }
    4380             :         else
    4381             :         {
    4382          66 :             r = c < 0;
    4383             :         }
    4384             :     }
    4385         225 :     else if(op == "le-nl")
    4386             :     {
    4387          75 :         if(v1.empty() || v2.empty())
    4388             :         {
    4389           9 :             r = c >= 0;
    4390             :         }
    4391             :         else
    4392             :         {
    4393          66 :             r = c <= 0;
    4394             :         }
    4395             :     }
    4396         150 :     else if(op == "gt-nl")
    4397             :     {
    4398          75 :         if(v1.empty() || v2.empty())
    4399             :         {
    4400           9 :             r = c < 0;
    4401             :         }
    4402             :         else
    4403             :         {
    4404          66 :             r = c > 0;
    4405             :         }
    4406             :     }
    4407          75 :     else if(op == "ge-nl")
    4408             :     {
    4409          75 :         if(v1.empty() || v2.empty())
    4410             :         {
    4411           9 :             r = c <= 0;
    4412             :         }
    4413             :         else
    4414             :         {
    4415          66 :             r = c >= 0;
    4416             :         }
    4417             :     }
    4418             : 
    4419         750 :     if(cl.verbose())
    4420             :     {
    4421           0 :         printf("%s\n", r ? "true" : "false");
    4422             :     }
    4423             : 
    4424         750 :     exit(r ? 0 : 1);
    4425             : }
    4426             : 
    4427           0 : void compress(command_line& cl)
    4428             : {
    4429           0 :     int max(cl.size());
    4430           0 :     if(max == 0)
    4431             :     {
    4432           0 :         cl.opt().usage(advgetopt::getopt::error, "--compress expects at least one parameter on the command line");
    4433             :         /*NOTREACHED*/
    4434             :     }
    4435           0 :     const bool force_hold((cl.opt().is_defined("force-hold") || cl.opt().is_defined("force-all"))
    4436           0 :                             && !cl.opt().is_defined("no-force-hold")
    4437           0 :                             && !cl.opt().is_defined("refuse-hold")
    4438           0 :                             && !cl.opt().is_defined("refuse-all"));
    4439           0 :     const bool force_overwrite((cl.opt().is_defined("force-overwrite") || cl.opt().is_defined("force-all"))
    4440           0 :                             && !cl.opt().is_defined("no-force-overwrite")
    4441           0 :                             && !cl.opt().is_defined("refuse-overwrite")
    4442           0 :                             && !cl.opt().is_defined("refuse-all"));
    4443           0 :     std::string output;
    4444           0 :     if(cl.opt().is_defined("output-filename"))
    4445             :     {
    4446           0 :         if(max == 1)
    4447             :         {
    4448           0 :             output = cl.opt().get_string("output-filename");
    4449             :         }
    4450             :         else
    4451             :         {
    4452           0 :             cl.opt().usage(advgetopt::getopt::error, "--output-filename can only be used if --compress is used with a single filename");
    4453             :             /*NOTREACHED*/
    4454             :         }
    4455             :     }
    4456           0 :     for(int i(0); i < max; ++i)
    4457             :     {
    4458           0 :         wpkg_filename::uri_filename filename(cl.get_string("filename"));
    4459           0 :         memfile::memory_file::file_format_t format(cl.compressor());
    4460           0 :         if(format == memfile::memory_file::file_format_best)
    4461             :         {
    4462           0 :             if(output.empty())
    4463             :             {
    4464           0 :                 format = memfile::memory_file::filename_extension_to_format(filename);
    4465             :             }
    4466             :             else
    4467             :             {
    4468           0 :                 format = memfile::memory_file::filename_extension_to_format(output);
    4469             :             }
    4470             :         }
    4471           0 :         switch(format)
    4472             :         {
    4473             :         case memfile::memory_file::file_format_gz:
    4474             :         case memfile::memory_file::file_format_bz2:
    4475             :         case memfile::memory_file::file_format_lzma:
    4476             :         case memfile::memory_file::file_format_xz:
    4477             :             {
    4478           0 :                 wpkg_filename::uri_filename old_filename;
    4479           0 :                 wpkg_filename::uri_filename new_filename;
    4480           0 :                 if(cl.compressor() == memfile::memory_file::file_format_best
    4481           0 :                 && (output.empty() || format == memfile::memory_file::file_format_best))
    4482             :                 {
    4483           0 :                     if(!output.empty())
    4484             :                     {
    4485           0 :                         cl.opt().usage(advgetopt::getopt::error, "--output-filename can only be used if --compress is used with --compressor when no known extension is used");
    4486             :                         /*NOTREACHED*/
    4487             :                     }
    4488           0 :                     wpkg_filename::uri_filename dir(filename.dirname());
    4489           0 :                     old_filename = dir.append_child(filename.basename(true));
    4490           0 :                     new_filename = filename;
    4491             :                 }
    4492             :                 else
    4493             :                 {
    4494           0 :                     old_filename = filename;
    4495           0 :                     if(output.empty())
    4496             :                     {
    4497           0 :                         switch(cl.compressor())
    4498             :                         {
    4499             :                         case memfile::memory_file::file_format_gz:
    4500           0 :                             new_filename.set_filename(filename.full_path() + ".gz");
    4501           0 :                             break;
    4502             : 
    4503             :                         case memfile::memory_file::file_format_bz2:
    4504           0 :                             new_filename.set_filename(filename.full_path() + ".bz2");
    4505           0 :                             break;
    4506             : 
    4507             :                         case memfile::memory_file::file_format_lzma:
    4508           0 :                             new_filename.set_filename(filename.full_path() + ".lzma");
    4509           0 :                             break;
    4510             : 
    4511             :                         case memfile::memory_file::file_format_xz:
    4512           0 :                             new_filename.set_filename(filename.full_path() + ".xz");
    4513           0 :                             break;
    4514             : 
    4515             :                         default:
    4516           0 :                             throw std::logic_error("the file format from --compressor is not supported");
    4517             : 
    4518             :                         }
    4519             :                     }
    4520             :                     else
    4521             :                     {
    4522           0 :                         new_filename = output;
    4523             :                     }
    4524             :                 }
    4525             : 
    4526             :                 // TODO: add warning and/or support for --force-overwrite?
    4527           0 :                 if(!new_filename.exists() || force_overwrite)
    4528             :                 {
    4529           0 :                     if(new_filename.exists())
    4530             :                     {
    4531           0 :                         printf("wpkg:warning: overwriting \"%s\" with compressed version.\n", new_filename.full_path().c_str());
    4532             :                     }
    4533           0 :                     memfile::memory_file decompressed;
    4534           0 :                     if(cl.verbose())
    4535             :                     {
    4536           0 :                         printf("wpkg: compress \"%s\" to \"%s\".\n", old_filename.full_path().c_str(), new_filename.full_path().c_str());
    4537             :                     }
    4538           0 :                     decompressed.read_file(old_filename);
    4539           0 :                     memfile::memory_file compressed;
    4540           0 :                     decompressed.compress(compressed, format, cl.zlevel());
    4541           0 :                     compressed.write_file(new_filename);
    4542           0 :                     if(!force_hold)
    4543             :                     {
    4544           0 :                         old_filename.os_unlink();
    4545           0 :                     }
    4546             :                 }
    4547           0 :                 else if(cl.verbose())
    4548             :                 {
    4549           0 :                     printf("wpkg: file \"%s\" already exists, no compression performed.\n", filename.full_path().c_str());
    4550           0 :                 }
    4551             :             }
    4552           0 :             break;
    4553             : 
    4554             :         default: // silently ignore others
    4555           0 :             if(cl.verbose())
    4556             :             {
    4557           0 :                 printf("wpkg: unknown compression extension, ignoring \"%s\".\n", filename.full_path().c_str());
    4558             :             }
    4559           0 :             break;
    4560             : 
    4561             :         }
    4562           0 :     }
    4563           0 : }
    4564             : 
    4565           0 : void decompress(command_line& cl)
    4566             : {
    4567           0 :     int max(cl.size());
    4568           0 :     if(max == 0)
    4569             :     {
    4570           0 :         cl.opt().usage(advgetopt::getopt::error, "--decompress expects at least one parameter on the command line");
    4571             :         /*NOTREACHED*/
    4572             :     }
    4573           0 :     const bool force_hold((cl.opt().is_defined("force-hold") || cl.opt().is_defined("force-all"))
    4574           0 :                             && !cl.opt().is_defined("no-force-hold")
    4575           0 :                             && !cl.opt().is_defined("refuse-hold")
    4576           0 :                             && !cl.opt().is_defined("refuse-all"));
    4577           0 :     const bool force_overwrite((cl.opt().is_defined("force-overwrite") || cl.opt().is_defined("force-all"))
    4578           0 :                             && !cl.opt().is_defined("no-force-overwrite")
    4579           0 :                             && !cl.opt().is_defined("refuse-overwrite")
    4580           0 :                             && !cl.opt().is_defined("refuse-all"));
    4581           0 :     std::string output;
    4582           0 :     if(cl.opt().is_defined("output-filename"))
    4583             :     {
    4584           0 :         if(max == 1)
    4585             :         {
    4586           0 :             output = cl.opt().get_string("output-filename");
    4587             :         }
    4588             :         else
    4589             :         {
    4590           0 :             cl.opt().usage(advgetopt::getopt::error, "--output-filename can only be used if --decompress is used with a single filename");
    4591             :             /*NOTREACHED*/
    4592             :         }
    4593             :     }
    4594           0 :     for(int i(0); i < max; ++i)
    4595             :     {
    4596           0 :         wpkg_filename::uri_filename filename(cl.get_string("filename"));
    4597           0 :         memfile::memory_file::file_format_t format(memfile::memory_file::filename_extension_to_format(filename));
    4598           0 :         switch(format)
    4599             :         {
    4600             :         case memfile::memory_file::file_format_gz:
    4601             :         case memfile::memory_file::file_format_bz2:
    4602             :         case memfile::memory_file::file_format_lzma:
    4603             :         case memfile::memory_file::file_format_xz:
    4604             :             {
    4605           0 :                 wpkg_filename::uri_filename dir(filename.dirname());
    4606           0 :                 wpkg_filename::uri_filename new_filename(output.empty() ? dir.append_child(filename.basename(true)) : output);
    4607           0 :                 if(!new_filename.exists() || force_overwrite)
    4608             :                 {
    4609           0 :                     if(new_filename.exists())
    4610             :                     {
    4611           0 :                         printf("wpkg:warning: overwriting \"%s\" from compressed version.\n", new_filename.full_path().c_str());
    4612             :                     }
    4613           0 :                     if(cl.verbose())
    4614             :                     {
    4615           0 :                         printf("wpkg: decompress \"%s\" to \"%s\".\n", filename.full_path().c_str(), new_filename.full_path().c_str());
    4616             :                     }
    4617           0 :                     memfile::memory_file compressed;
    4618           0 :                     compressed.read_file(filename);
    4619           0 :                     memfile::memory_file decompressed;
    4620           0 :                     compressed.decompress(decompressed);
    4621           0 :                     decompressed.write_file(new_filename);
    4622           0 :                     if(!force_hold)
    4623             :                     {
    4624           0 :                         filename.os_unlink();
    4625           0 :                     }
    4626             :                 }
    4627           0 :                 else if(cl.verbose())
    4628             :                 {
    4629           0 :                     printf("wpkg: file \"%s\" already exists, no decompression performed.\n", filename.full_path().c_str());
    4630           0 :                 }
    4631             :             }
    4632           0 :             break;
    4633             : 
    4634             :         default: // silently ignore others
    4635           0 :             if(cl.verbose())
    4636             :             {
    4637           0 :                 printf("wpkg: unknown compression extension or already uncompressed file, ignoring \"%s\".\n", filename.full_path().c_str());
    4638             :             }
    4639           0 :             break;
    4640             : 
    4641             :         }
    4642           0 :     }
    4643           0 : }
    4644             : 
    4645           0 : void contents(command_line& cl)
    4646             : {
    4647             :     // TODO: support listing contents of more than one package?
    4648           0 :     if(cl.size() != 0)
    4649             :     {
    4650             :         fprintf(stderr, "error:%s: too many parameters on the command line for --contents.\n",
    4651           0 :             cl.opt().get_program_name().c_str());
    4652           0 :         exit(1);
    4653             :     }
    4654           0 :     wpkgar::wpkgar_manager manager;
    4655           0 :     init_manager(cl, manager, "contents");
    4656           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    4657           0 :     const wpkg_filename::uri_filename name(cl.get_string("contents"));
    4658           0 :     if(name.is_deb())
    4659             :     {
    4660           0 :         cl.opt().usage(advgetopt::getopt::error, "you cannot extract the files of the data.tar.gz file from an installed package");
    4661             :         /*NOTREACHED*/
    4662             :     }
    4663           0 :     bool numbers(cl.opt().is_defined("numbers"));
    4664           0 :     manager.load_package(name);
    4665           0 :     memfile::memory_file p;
    4666           0 :     std::string data_filename("data.tar");
    4667           0 :     manager.get_control_file(p, name, data_filename, false);
    4668           0 :     bool use_drive_letter(false);
    4669           0 :     if(manager.field_is_defined(name, "X-Drive-Letter"))
    4670             :     {
    4671           0 :         use_drive_letter = manager.get_field_boolean(name, "X-Drive-Letter");
    4672             :     }
    4673           0 :     p.dir_rewind();
    4674           0 :     for(;;)
    4675             :     {
    4676           0 :         memfile::memory_file::file_info info;
    4677           0 :         memfile::memory_file data;
    4678           0 :         if(!p.dir_next(info, &data))
    4679             :         {
    4680             :             break;
    4681             :         }
    4682           0 :         std::string filename(info.get_filename());
    4683           0 :         if(filename.length() >= 2 && filename[0] == '.' && filename[1] == '/')
    4684             :         {
    4685           0 :             filename.erase(0, 1);
    4686             :         }
    4687           0 :         if(use_drive_letter && filename.length() >= 3 && filename[0] == '/' && is_letter(filename[1]) && filename[2] == '/')
    4688             :         {
    4689           0 :             filename[0] = filename[1] & 0x5F; // capital letter for drives
    4690           0 :             filename[1] = ':';
    4691             :         }
    4692           0 :         if(!cl.quiet())
    4693             :         {
    4694           0 :             if(numbers)
    4695             :             {
    4696           0 :                 printf("%3o ", info.get_mode());
    4697             :             }
    4698             :             else
    4699             :             {
    4700           0 :                 printf("%s ", info.get_mode_flags().c_str());
    4701             :             }
    4702           0 :             std::string user(info.get_user());
    4703           0 :             std::string group(info.get_group());
    4704           0 :             if(numbers || user.empty() || group.empty())
    4705             :             {
    4706           0 :                 printf("%4d/%-4d", info.get_uid(), info.get_gid());
    4707             :             }
    4708             :             else
    4709             :             {
    4710           0 :                 printf("%8.8s/%-8.8s", user.c_str(), group.c_str());
    4711             :             }
    4712           0 :             if(info.get_file_type() == memfile::memory_file::file_info::character_special
    4713           0 :             || info.get_file_type() == memfile::memory_file::file_info::block_special)
    4714             :             {
    4715           0 :                 printf(" %3d,%3d", info.get_dev_major(), info.get_dev_minor());
    4716             :             }
    4717             :             else
    4718             :             {
    4719           0 :                 printf(" %7d", info.get_size());
    4720             :             }
    4721             :             printf("  %s %c%s",
    4722             :                 info.get_date().c_str(),
    4723           0 :                 manager.is_conffile(name, filename) ? '*' : ' ',
    4724           0 :                 filename.c_str());
    4725           0 :             if(info.get_file_type() == memfile::memory_file::file_info::symbolic_link)
    4726             :             {
    4727           0 :                 printf(" -> %s", info.get_link().c_str());
    4728             :             }
    4729           0 :             printf("\n");
    4730             :         }
    4731             :         else
    4732             :         {
    4733           0 :             printf("%s\n", filename.c_str());
    4734             :         }
    4735           0 :     }
    4736           0 : }
    4737             : 
    4738           0 : void control(command_line& cl)
    4739             : {
    4740           0 :     if(cl.size() > 1)
    4741             :     {
    4742             :         printf("error:%s: too many parameters on the command line for --control.\n",
    4743           0 :             cl.opt().get_program_name().c_str());
    4744           0 :         exit(1);
    4745             :     }
    4746           0 :     wpkgar::wpkgar_manager manager;
    4747           0 :     init_manager(cl, manager, "control");
    4748           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    4749           0 :     std::string name(cl.get_string("control"));
    4750           0 :     manager.load_package(name);
    4751           0 :     memfile::memory_file p;
    4752           0 :     std::string control_filename("control.tar");
    4753           0 :     manager.get_control_file(p, name, control_filename);
    4754           0 :     if(cl.size() == 1)
    4755             :     {
    4756             :         // if an output folder is specified, extract the files there
    4757           0 :         const wpkg_filename::uri_filename output_path(cl.filename(0));
    4758             :         // reset the filename
    4759           0 :         control_filename = "control.tar";
    4760           0 :         manager.get_control_file(p, name, control_filename, false);
    4761           0 :         p.dir_rewind();
    4762           0 :         for(;;)
    4763             :         {
    4764           0 :             memfile::memory_file::file_info info;
    4765           0 :             memfile::memory_file data;
    4766           0 :             if(!p.dir_next(info, &data))
    4767             :             {
    4768             :                 break;
    4769             :             }
    4770           0 :             const wpkg_filename::uri_filename out(output_path.append_safe_child(info.get_filename()));
    4771           0 :             if(cl.verbose())
    4772             :             {
    4773           0 :                 printf("%s\n", out.original_filename().c_str());
    4774             :             }
    4775           0 :             switch(info.get_file_type())
    4776             :             {
    4777             :             case memfile::memory_file::file_info::regular_file:
    4778             :             case memfile::memory_file::file_info::continuous:
    4779           0 :                 data.write_file(out, true);
    4780           0 :                 break;
    4781             : 
    4782             :             case memfile::memory_file::file_info::symbolic_link:
    4783             :                 {
    4784           0 :                     const wpkg_filename::uri_filename link(info.get_link());
    4785           0 :                     link.os_symlink(out);
    4786             :                 }
    4787           0 :                 break;
    4788             : 
    4789             :             default:
    4790             :                 // other file types are ignored here
    4791           0 :                 break;
    4792             : 
    4793             :             }
    4794           0 :         }
    4795             :     }
    4796             :     else
    4797             :     {
    4798             :         // NOTE: instead dpkg creates a directory named DEBIAN by default
    4799           0 :         p.write_file(control_filename);
    4800           0 :     }
    4801           0 : }
    4802             : 
    4803           0 : void copyright(command_line& cl)
    4804             : {
    4805           0 :     if(cl.size() != 0)
    4806             :     {
    4807             :         printf("error:%s: --copyright expects exactly one package name.\n",
    4808           0 :             cl.opt().get_program_name().c_str());
    4809           0 :         exit(1);
    4810             :     }
    4811           0 :     wpkgar::wpkgar_manager manager;
    4812           0 :     init_manager(cl, manager, "copyright");
    4813           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    4814           0 :     const wpkg_filename::uri_filename name(cl.get_string("copyright"));
    4815           0 :     if(name.is_deb())
    4816             :     {
    4817             :         // already installed package, check in the installation tree
    4818           0 :         wpkg_filename::uri_filename copyright_filename(manager.get_root_path());
    4819           0 :         copyright_filename = copyright_filename.append_child("usr/share/doc");
    4820           0 :         copyright_filename = copyright_filename.append_child(name.path_only());
    4821           0 :         copyright_filename = copyright_filename.append_child("copyright");
    4822           0 :         if(copyright_filename.exists())
    4823             :         {
    4824           0 :             memfile::memory_file data;
    4825           0 :             data.read_file(copyright_filename);
    4826           0 :             int offset(0);
    4827           0 :             std::string line;
    4828           0 :             while(data.read_line(offset, line))
    4829             :             {
    4830           0 :                 printf("%s\n", line.c_str());
    4831             :             }
    4832           0 :             return;
    4833           0 :         }
    4834             :     }
    4835             :     else
    4836             :     {
    4837           0 :         manager.load_package(name);
    4838           0 :         memfile::memory_file p;
    4839           0 :         std::string data_filename("data.tar");
    4840           0 :         manager.get_control_file(p, name, data_filename, false);
    4841           0 :         p.dir_rewind();
    4842             :         // TODO: do we need to check the package name validity or was it done
    4843             :         //       in the control file already?
    4844           0 :         std::string package(manager.get_field(name, "Package"));
    4845           0 :         case_insensitive::case_insensitive_string copyright_filename("usr/share/doc/" + package + "/copyright");
    4846           0 :         for(;;)
    4847             :         {
    4848           0 :             memfile::memory_file::file_info info;
    4849           0 :             memfile::memory_file data;
    4850           0 :             if(!p.dir_next(info, &data))
    4851             :             {
    4852             :                 break;
    4853             :             }
    4854           0 :             std::string filename(info.get_filename());
    4855           0 :             if(filename[0] == '.' && filename[1] == '/')
    4856             :             {
    4857           0 :                 filename = filename.substr(2);
    4858             :             }
    4859           0 :             if(copyright_filename == filename.c_str())
    4860             :             {
    4861             :                 // found the file, print it in stdout
    4862           0 :                 int offset(0);
    4863           0 :                 std::string line;
    4864           0 :                 while(data.read_line(offset, line))
    4865             :                 {
    4866           0 :                     printf("%s\n", line.c_str());
    4867             :                 }
    4868           0 :                 return;
    4869             :             }
    4870           0 :         }
    4871             :     }
    4872             :     // this is not exactly an error under MS-Windows
    4873           0 :     fprintf(stderr, "error: the copyright file was not found (it is not mandatory because MS-Windows is not as restricted as Linux.)\n");
    4874           0 :     exit(1);
    4875             :     /*NOTREACHED*/
    4876             : }
    4877             : 
    4878          26 : void create_admindir(command_line& cl)
    4879             : {
    4880          26 :     wpkgar::wpkgar_manager manager;
    4881          26 :     init_manager(cl, manager, "create-admindir");
    4882          26 :     manager.create_database(cl.get_string("create-admindir"));
    4883          26 : }
    4884             : 
    4885           0 : void create_database_lock(command_line& cl)
    4886             : {
    4887           0 :     wpkgar::wpkgar_manager manager;
    4888           0 :     init_manager(cl, manager, "create-database-lock");
    4889             :     try {
    4890             :         // in this case we keep the status set as "Ready"
    4891           0 :         manager.lock("Ready");
    4892           0 :         if(cl.verbose())
    4893             :         {
    4894           0 :             printf("database lock was created.\n");
    4895             :         }
    4896           0 :         exit(0);
    4897             :     }
    4898           0 :     catch(...)
    4899             :     {
    4900           0 :         fprintf(stderr, "error: that database could not be locked, maybe it is already locked.\n");
    4901           0 :         exit(1);
    4902           0 :     }
    4903             : }
    4904             : 
    4905           0 : void database_is_locked(command_line& cl)
    4906             : {
    4907           0 :     wpkgar::wpkgar_manager manager;
    4908           0 :     init_manager(cl, manager, "database-is-locked");
    4909           0 :     if(manager.is_locked())
    4910             :     {
    4911           0 :         if(cl.verbose())
    4912             :         {
    4913           0 :             printf("true\n");
    4914             :         }
    4915           0 :         exit(0);
    4916             :     }
    4917             :     else
    4918             :     {
    4919           0 :         if(cl.verbose())
    4920             :         {
    4921           0 :             printf("false\n");
    4922             :         }
    4923           0 :         exit(1);
    4924           0 :     }
    4925             : }
    4926             : 
    4927           0 : void directory_size(command_line& cl)
    4928             : {
    4929             :     // this function is mainly for debug purposes in case we wanted to fix the
    4930             :     // version used by the build so it works more like what we need for our
    4931             :     // packages (wpkg --directory-size <dirname>)
    4932           0 :     memfile::memory_file in;
    4933           0 :     long total_size(0);
    4934           0 :     std::string dir_name(cl.get_string("directory-size"));
    4935           0 :     in.dir_rewind(dir_name, true);
    4936           0 :     for(;;)
    4937             :     {
    4938           0 :         memfile::memory_file::file_info info;
    4939           0 :         if(!in.dir_next(info, NULL))
    4940             :         {
    4941             :             break;
    4942             :         }
    4943           0 :         memfile::memory_file::file_info::file_type_t type(info.get_file_type());
    4944           0 :         if(type == memfile::memory_file::file_info::regular_file
    4945             :         || type == memfile::memory_file::file_info::continuous)
    4946             :         {
    4947             :             // round up the size to the next block
    4948             :             // TODO: let users define the block size
    4949           0 :             long size((info.get_size() + 511) & -512);
    4950           0 :             if(cl.verbose())
    4951             :             {
    4952           0 :                 printf("%9ld %s\n", size, info.get_filename().c_str());
    4953             :             }
    4954           0 :             total_size += size;
    4955             :         }
    4956           0 :     }
    4957           0 :     if(cl.verbose())
    4958             :     {
    4959           0 :         printf("%9ld\n", total_size);
    4960             :     }
    4961             :     else
    4962             :     {
    4963           0 :         printf("%ld\n", total_size);
    4964           0 :     }
    4965           0 : }
    4966             : 
    4967           0 : void os(command_line& cl)
    4968             : {
    4969           0 :     if(cl.verbose())
    4970             :     {
    4971           0 :         printf("%s by %s [%s]\n", debian_packages_os(), debian_packages_vendor(), debian_packages_processor());
    4972             :     }
    4973             :     else
    4974             :     {
    4975           0 :         printf("%s\n", debian_packages_os());
    4976             :     }
    4977           0 : }
    4978             : 
    4979           0 : void triplet(command_line& /*cl*/)
    4980             : {
    4981             :     // triplet as you'd want to have it in the Architecture field
    4982           0 :     printf("%s-%s-%s\n", debian_packages_os(), debian_packages_vendor(), debian_packages_processor());
    4983           0 : }
    4984             : 
    4985           0 : void print_field(const std::string& field_name, const std::string& value)
    4986             : {
    4987           0 :     if(!field_name.empty())
    4988             :     {
    4989           0 :         printf("%s: ", field_name.c_str());
    4990             :     }
    4991           0 :     for(const char *s(value.c_str()); *s != '\0'; ++s)
    4992             :     {
    4993           0 :         printf("%c", *s);
    4994           0 :         if(*s == '\n')
    4995             :         {
    4996           0 :             printf(" ");
    4997             :         }
    4998             :     }
    4999           0 :     printf("\n");
    5000           0 : }
    5001             : 
    5002           0 : void field(command_line& cl)
    5003             : {
    5004             :     // TBD: The fields are printed whatever the current status of
    5005             :     //      the package; should we warn/err if the package is not
    5006             :     //      properly unpacked, installed, and a few other states?
    5007             :     //      The user can use --is-installed first though.
    5008           0 :     wpkgar::wpkgar_manager manager;
    5009           0 :     init_manager(cl, manager, "field");
    5010           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    5011           0 :     std::string name(cl.get_string("field"));
    5012           0 :     manager.load_package(name);
    5013           0 :     int max(cl.size());
    5014           0 :     if(max == 0)
    5015             :     {
    5016             :         // if no field specified, show them all
    5017           0 :         max = manager.number_of_fields(name);
    5018           0 :         for(int i(0); i < max; ++i)
    5019             :         {
    5020           0 :             std::string field_name(manager.get_field_name(name, i));
    5021           0 :             std::string value(manager.get_field(name, field_name));
    5022           0 :             if(field_name != "X-Status" || value != "unknown")
    5023             :             {
    5024           0 :                 print_field(field_name, value);
    5025             :             }
    5026           0 :         }
    5027             :     }
    5028           0 :     else if(max == 1)
    5029             :     {
    5030           0 :         std::string field_name(cl.argument(0));
    5031           0 :         std::string value(manager.get_field(name, field_name));
    5032           0 :         print_field("", value);
    5033             :     }
    5034             :     else
    5035             :     {
    5036             :         // only read those fields (throw if not available)
    5037           0 :         for(int i(0); i < max; ++i)
    5038             :         {
    5039           0 :             std::string field_name(cl.argument(i));
    5040           0 :             std::string value(manager.get_field(name, field_name));
    5041           0 :             print_field(field_name, value);
    5042           0 :         }
    5043           0 :     }
    5044           0 : }
    5045             : 
    5046           0 : void display_pkgconfig(command_line& cl, const std::string& field_name, const std::string& option)
    5047             : {
    5048           0 :     int max(cl.size());
    5049           0 :     if(max == 0)
    5050             :     {
    5051           0 :         cl.opt().usage(advgetopt::getopt::error, "%s expects at least one package name", option.c_str());
    5052             :         /*NOTREACHED*/
    5053             :     }
    5054             : 
    5055           0 :     wpkgar::wpkgar_manager manager;
    5056           0 :     init_manager(cl, manager, option);
    5057             : 
    5058           0 :     std::string paths(wpkg_util::utf8_getenv("PKG_CONFIG_PATH", ""));
    5059           0 :     std::vector<std::string> path_list;
    5060             : #if defined(MO_WINDOWS) || defined(MO_MINGW32)
    5061             :     const char sep(';');
    5062             : #else
    5063           0 :     const char sep(':');
    5064             : #endif
    5065           0 :     if(!paths.empty())
    5066             :     {
    5067           0 :         paths += sep;
    5068             :     }
    5069             :     // TODO: how do we NOT add the /usr part? under MS-Windows we are not
    5070             :     //       expected to have a /usr
    5071           0 :     paths += "/usr/lib/pkgconfig";
    5072           0 :     paths += sep;
    5073           0 :     paths += "/usr/share/pkgconfig"; // default always defined (but put last)
    5074             :     const char *n;
    5075           0 :     for(const char *start(paths.c_str()); *start != '\0'; start = n)
    5076             :     {
    5077           0 :         for(n = start; *n != sep && *n != '\0'; ++n);
    5078           0 :         path_list.push_back(std::string(start, n - start));
    5079           0 :         for(; *n == sep; ++n);
    5080             :     }
    5081             : 
    5082           0 :     class pkgconfig_state_t : public wpkg_field::field_file::field_file_state_t
    5083             :     {
    5084             :     public:
    5085           0 :         virtual bool allow_transformations() const
    5086             :         {
    5087           0 :             return true;
    5088             :         }
    5089             : 
    5090           0 :         virtual bool accept_sub_packages() const
    5091             :         {
    5092           0 :             return false;
    5093             :         }
    5094             :     };
    5095             : 
    5096             :     // check all the named packages
    5097           0 :     bool first(true);
    5098           0 :     const wpkg_filename::uri_filename instdir(manager.get_inst_path());
    5099           0 :     for(int i(0); i < max; ++i)
    5100             :     {
    5101           0 :         bool found(false);
    5102           0 :         std::string package_name(cl.argument(i));
    5103             : 
    5104           0 :         std::shared_ptr<wpkg_field::field_file::field_file_state_t> state(std::shared_ptr<wpkg_field::field_file::field_file_state_t>(new pkgconfig_state_t));
    5105           0 :         for(std::vector<std::string>::const_iterator p(path_list.begin()); p != path_list.end(); ++p)
    5106             :         {
    5107           0 :             const wpkg_filename::uri_filename path(*p);
    5108           0 :             wpkg_filename::uri_filename pcfile;
    5109           0 :             if(path.is_absolute())
    5110             :             {
    5111           0 :                 pcfile = path.append_child(package_name + ".pc");
    5112             :             }
    5113             :             else
    5114             :             {
    5115           0 :                 pcfile = instdir.append_child(*p).append_child(package_name + ".pc");
    5116             :             }
    5117           0 :             if(pcfile.exists())
    5118             :             {
    5119           0 :                 wpkg_field::field_file field(state);
    5120           0 :                 init_field_variables(cl, manager, &field);
    5121             : 
    5122           0 :                 memfile::memory_file pkgconfig;
    5123           0 :                 pkgconfig.read_file(pcfile);
    5124           0 :                 field.set_input_file(&pkgconfig);
    5125             :                 // we loop over because it is legal in .pc files to have
    5126             :                 // empty lines
    5127           0 :                 do
    5128             :                 {
    5129           0 :                     field.read();
    5130             :                 }
    5131           0 :                 while(!field.eof());
    5132           0 :                 field.set_input_file(NULL);
    5133             : 
    5134           0 :                 std::string source_project_name(package_name);
    5135           0 :                 if(field.field_is_defined("Source-Project"))
    5136             :                 {
    5137           0 :                     source_project_name = field.get_field("Source-Project");
    5138             :                 }
    5139             : 
    5140           0 :                 if(manager.safe_package_status(source_project_name) == wpkgar::wpkgar_manager::installed)
    5141             :                 {
    5142           0 :                     manager.load_package(source_project_name);
    5143           0 :                     field.auto_transform_variables();
    5144           0 :                     field.set_variable("rootdir", manager.get_root_path().full_path());
    5145           0 :                     field.set_variable("instdir", instdir.full_path());
    5146           0 :                     field.set_variable("admindir", manager.get_database_path().full_path());
    5147           0 :                     field.set_variable("name", manager.get_field(source_project_name, wpkg_control::control_file::field_package_factory_t::canonicalized_name()));
    5148           0 :                     field.set_variable("version", manager.get_field(source_project_name, wpkg_control::control_file::field_version_factory_t::canonicalized_name()));
    5149           0 :                     field.set_variable("description", manager.get_field_first_line(source_project_name, wpkg_control::control_file::field_description_factory_t::canonicalized_name()));
    5150           0 :                     if(manager.field_is_defined(source_project_name, wpkg_control::control_file::field_homepage_factory_t::canonicalized_name()))
    5151             :                     {
    5152           0 :                         field.set_variable("homepage", manager.get_field(source_project_name, wpkg_control::control_file::field_homepage_factory_t::canonicalized_name()));
    5153             :                     }
    5154           0 :                     std::string install_prefix;
    5155           0 :                     if(manager.field_is_defined(source_project_name, wpkg_control::control_file::field_installprefix_factory_t::canonicalized_name()))
    5156             :                     {
    5157           0 :                         install_prefix = manager.get_field(source_project_name, wpkg_control::control_file::field_installprefix_factory_t::canonicalized_name());
    5158           0 :                         if(!install_prefix.empty() && install_prefix[0] != '/')
    5159             :                         {
    5160           0 :                             install_prefix = "/" + install_prefix;
    5161             :                         }
    5162             :                     }
    5163           0 :                     field.set_variable("install_prefix", install_prefix);
    5164             : 
    5165           0 :                     if(cl.opt().is_defined("print-variables"))
    5166             :                     {
    5167             :                         // print the list of variables
    5168           0 :                         if(!first)
    5169             :                         {
    5170             :                             // package separator
    5171           0 :                             printf("\n");
    5172             :                         }
    5173           0 :                         int max_variables(field.number_of_variables());
    5174           0 :                         for(int j(0); j < max_variables; ++j)
    5175             :                         {
    5176             :                             // variables defined in the .pc file
    5177           0 :                             const std::string& name(field.get_variable_name(j));
    5178           0 :                             printf("%s\n", name.c_str());
    5179             :                         }
    5180             :                     }
    5181           0 :                     else if(cl.opt().is_defined("variable"))
    5182             :                     {
    5183           0 :                         if(!first)
    5184             :                         {
    5185           0 :                             printf(" ");
    5186             :                         }
    5187           0 :                         const std::string variable_name(cl.opt().get_string("variable"));
    5188           0 :                         std::string value(field.get_variable(variable_name, true));
    5189           0 :                         field.transform_dynamic_variables(field.get_variable_info(variable_name).get(), value);
    5190           0 :                         printf("%s", value.c_str());
    5191             :                     }
    5192           0 :                     else if(field.field_is_defined(field_name))
    5193             :                     {
    5194           0 :                         std::string value(field.get_field(field_name));
    5195           0 :                         printf("%s\n", value.c_str());
    5196             :                     }
    5197             :                     else
    5198             :                     {
    5199             :                         // field is not defined, print an empty line
    5200           0 :                         printf("\n");
    5201             :                     }
    5202           0 :                     found = true;
    5203           0 :                     break;
    5204           0 :                 }
    5205             :             }
    5206           0 :         }
    5207             : 
    5208           0 :         if(!found)
    5209             :         {
    5210             :             wpkg_output::log("no .pc file found for package %1; please check that the package --is-installed or that you defined PKG_CONFIG_PATH to the correct directory.")
    5211           0 :                     .quoted_arg(package_name)
    5212           0 :                 .level(wpkg_output::level_warning)
    5213           0 :                 .action("pkg-config");
    5214             :         }
    5215             : 
    5216           0 :         first = false;
    5217           0 :     }
    5218             : 
    5219           0 :     if(cl.opt().is_defined("variable"))
    5220             :     {
    5221           0 :         printf("\n");
    5222           0 :     }
    5223           0 : }
    5224             : 
    5225           0 : void fsys_tarfile(command_line& cl)
    5226             : {
    5227           0 :     if(cl.size() != 0)
    5228             :     {
    5229             :         printf("error:%s: too many parameters on the command line for --fsys-tarfile.\n",
    5230           0 :             cl.opt().get_program_name().c_str());
    5231           0 :         exit(1);
    5232             :     }
    5233           0 :     wpkgar::wpkgar_manager manager;
    5234           0 :     init_manager(cl, manager, "fsys-tarfile");
    5235           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    5236           0 :     const wpkg_filename::uri_filename name(cl.get_string("fsys-tarfile"));
    5237           0 :     if(name.is_deb())
    5238             :     {
    5239           0 :         cl.opt().usage(advgetopt::getopt::error, "you cannot extract the data.tar.gz file from an installed package");
    5240             :         /*NOTREACHED*/
    5241             :     }
    5242           0 :     manager.load_package(name);
    5243           0 :     memfile::memory_file p;
    5244           0 :     std::string data_filename("data.tar");
    5245             :     // get the uncompressed data in p
    5246           0 :     manager.get_control_file(p, name, data_filename, false);
    5247             : 
    5248             :     // print this in stdout so one can pipe it through tar
    5249             :     // (we send the decompressed version)
    5250             :     char buf[memfile::memory_file::block_manager::BLOCK_MANAGER_BUFFER_SIZE];
    5251           0 :     for(int sz(p.size()), offset(0), r(0); sz > 0; sz -= r, offset += r)
    5252             :     {
    5253             :         int size(sz > memfile::memory_file::block_manager::BLOCK_MANAGER_BUFFER_SIZE
    5254             :             ? memfile::memory_file::block_manager::BLOCK_MANAGER_BUFFER_SIZE
    5255           0 :             : sz);
    5256           0 :         r = p.read(buf, offset, size);
    5257           0 :         fwrite(buf, r, 1, stdout);
    5258           0 :     }
    5259           0 : }
    5260             : 
    5261           0 : void info(command_line& cl)
    5262             : {
    5263           0 :     int max(cl.size());
    5264           0 :     bool print_avail(false);
    5265             : 
    5266           0 :     wpkgar::wpkgar_manager manager;
    5267           0 :     init_manager(cl, manager, cl.opt().is_defined("info") ? "info"
    5268           0 :                             : cl.opt().is_defined("verify") ? "verify"
    5269           0 :                             : "print-avail");
    5270           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    5271           0 :     std::string name;
    5272           0 :     if(cl.opt().is_defined("info"))
    5273             :     {
    5274           0 :         name = cl.get_string("info");
    5275             :     }
    5276           0 :     else if(cl.opt().is_defined("verify"))
    5277             :     {
    5278             :         // Note: while reading the package we check the debian-binary file
    5279             :         //       (if not "2.0\n" then we throw) and we extract the control
    5280             :         //       and data tarballs so we do not need to get them to make
    5281             :         //       sure they exist; also decompressing the whole data
    5282             :         //       file is done for verification (see last if() block)
    5283           0 :         name = cl.get_string("verify");
    5284           0 :         if(max != 0)
    5285             :         {
    5286             :             fprintf(stderr, "error:%s: too many parameters on the command line for --verify.\n",
    5287           0 :                 cl.opt().get_program_name().c_str());
    5288           0 :             exit(1);
    5289             :         }
    5290             :     }
    5291           0 :     else if(cl.opt().is_defined("print-avail"))
    5292             :     {
    5293           0 :         name = cl.get_string("print-avail");
    5294           0 :         if(max != 0)
    5295             :         {
    5296             :             // actually in case of --print-avail we should support multiple
    5297             :             // package name on the command line
    5298             :             fprintf(stderr, "error:%s: too many parameters on the command line for --print-avail.\n",
    5299           0 :                 cl.opt().get_program_name().c_str());
    5300           0 :             exit(1);
    5301             :         }
    5302           0 :         print_avail = true;
    5303             :     }
    5304             :     else
    5305             :     {
    5306             :         // this should not be reached
    5307           0 :         throw std::logic_error("unknown command line option used to reach info()");
    5308             :     }
    5309           0 :     int size(-1);
    5310             :     try {
    5311           0 :         memfile::memory_file::file_info deb_info;
    5312           0 :         memfile::memory_file::disk_file_to_info(name, deb_info);
    5313           0 :         size = deb_info.get_size();
    5314             :     }
    5315           0 :     catch(const memfile::memfile_exception_io& /*e*/)
    5316             :     {
    5317             :         // size could not be determined
    5318             :         // (maybe the user is checking an installed package)
    5319             :     }
    5320           0 :     manager.load_package(name);
    5321           0 :     memfile::memory_file p;
    5322           0 :     std::string control_filename("control.tar");
    5323           0 :     manager.get_control_file(p, name, control_filename);
    5324           0 :     memfile::memory_file ctrl;
    5325           0 :     control_filename = "control.tar";
    5326           0 :     manager.get_control_file(ctrl, name, control_filename, false);
    5327             : 
    5328             :     // we only support the new format so we can print that as is at this point
    5329           0 :     if(!cl.quiet() && !print_avail)
    5330             :     {
    5331           0 :         if(size == -1)
    5332             :         {
    5333           0 :             printf(" installed package\n");
    5334             :         }
    5335           0 :         else if(max == 0)
    5336             :         {
    5337           0 :             printf(" new debian package, version 2.0\n");
    5338           0 :             printf(" size %d bytes: control archive= %d bytes (%d uncompressed).\n", size, p.size(), ctrl.size());
    5339             :         }
    5340             :     }
    5341             : 
    5342           0 :     bool has_control(false), has_md5sums(false);
    5343           0 :     memfile::memory_file control_info_file, md5sums_file;
    5344           0 :     std::vector<bool> found_files;
    5345           0 :     found_files.resize(max);
    5346           0 :     ctrl.dir_rewind();
    5347           0 :     for(;;)
    5348             :     {
    5349             :         // TODO: it should in alphabetical order...
    5350             :         //       we could use our wpkg index to get the files?
    5351           0 :         memfile::memory_file::file_info info;
    5352           0 :         memfile::memory_file data;
    5353           0 :         if(!ctrl.dir_next(info, &data))
    5354             :         {
    5355             :             break;
    5356             :         }
    5357           0 :         switch(info.get_file_type())
    5358             :         {
    5359             :         case memfile::memory_file::file_info::regular_file:
    5360             :         case memfile::memory_file::file_info::continuous:
    5361             :             {
    5362           0 :                 std::string filename(info.get_filename());
    5363           0 :                 if(filename.length() > 2 && filename[0] == '.' && filename[1] == '/')
    5364             :                 {
    5365           0 :                     filename.erase(0, 2);
    5366             :                 }
    5367           0 :                 if(max > 0)
    5368             :                 {
    5369             :                     // mark whether we find the control and md5sums files
    5370           0 :                     if(filename == "control")
    5371             :                     {
    5372           0 :                         if(has_control)
    5373             :                         {
    5374           0 :                             cl.opt().usage(advgetopt::getopt::error, "\"control\" file found twice in the control archive");
    5375             :                             /*NOTREACHED*/
    5376             :                         }
    5377           0 :                         has_control = true;
    5378             :                     }
    5379           0 :                     else if(filename == "md5sums")
    5380             :                     {
    5381           0 :                         if(has_md5sums)
    5382             :                         {
    5383           0 :                             cl.opt().usage(advgetopt::getopt::error, "\"md5sums\" file found twice in the control archive");
    5384             :                             /*NOTREACHED*/
    5385             :                         }
    5386           0 :                         has_md5sums = true;
    5387             :                     }
    5388             :                     // TODO: dpkg writes the files in the order specified on the
    5389             :                     //       command line instead of the archive order
    5390           0 :                     for(int i(0); i < max; ++i)
    5391             :                     {
    5392           0 :                         if(filename == cl.argument(i))
    5393             :                         {
    5394             :                             // just print the file in the output
    5395           0 :                             int offset(0);
    5396           0 :                             std::string line;
    5397           0 :                             while(data.read_line(offset, line))
    5398             :                             {
    5399           0 :                                 printf("%s\n", line.c_str());
    5400             :                             }
    5401           0 :                             found_files[i] = true;
    5402           0 :                             break;
    5403             :                         }
    5404             :                     }
    5405             :                 }
    5406             :                 else
    5407             :                 {
    5408             :                     // we assume that each is a text file, count lines
    5409           0 :                     int count(0);
    5410           0 :                     std::string cmd;
    5411           0 :                     std::string line;
    5412           0 :                     int offset(0);
    5413           0 :                     if(data.read_line(offset, line))
    5414             :                     {
    5415           0 :                         ++count;
    5416             :                     }
    5417           0 :                     char type = ' ';
    5418           0 :                     if(line.length() > 2 && line[0] == '#' && line[1] == '!')
    5419             :                     {
    5420           0 :                         type = '*';
    5421           0 :                         cmd = line;
    5422             :                     }
    5423           0 :                     for(; data.read_line(offset, line); ++count);
    5424           0 :                     if(filename == "control")
    5425             :                     {
    5426             :                         // keep a copy so we can print it afterward
    5427           0 :                         if(has_control)
    5428             :                         {
    5429           0 :                             cl.opt().usage(advgetopt::getopt::error, "\"control\" file found twice in the control archive");
    5430             :                             /*NOTREACHED*/
    5431             :                         }
    5432           0 :                         data.copy(control_info_file);
    5433           0 :                         has_control = true;
    5434             :                     }
    5435           0 :                     else if(filename == "md5sums")
    5436             :                     {
    5437             :                         // keep a copy so we can check against file md5sum
    5438             :                         // when --verify-ing
    5439           0 :                         if(has_md5sums)
    5440             :                         {
    5441           0 :                             cl.opt().usage(advgetopt::getopt::error, "\"md5sums\" file found twice in the control archive");
    5442             :                             /*NOTREACHED*/
    5443             :                         }
    5444           0 :                         data.copy(md5sums_file);
    5445           0 :                         has_md5sums = true;
    5446             :                     }
    5447             : 
    5448             :                     // print result
    5449           0 :                     if(!cl.quiet() && !print_avail)
    5450             :                     {
    5451             :                         printf(" %7d bytes, %5d lines   %c  %-21s%s\n",
    5452           0 :                                 data.size(), count, type, filename.c_str(), cmd.c_str());
    5453           0 :                     }
    5454           0 :                 }
    5455             :             }
    5456           0 :             break;
    5457             : 
    5458             :         default:
    5459             :             // all the info is in regular files
    5460           0 :             break;
    5461             : 
    5462             :         }
    5463           0 :     }
    5464             : 
    5465           0 :     for(int i(0); i < max; ++i)
    5466             :     {
    5467           0 :         if(!found_files[i])
    5468             :         {
    5469           0 :             cl.opt().usage(advgetopt::getopt::warning, "\"%s\" not found in the control tarball of this package", cl.argument(i).c_str());
    5470             :             /*NOTREACHED*/
    5471             :         }
    5472             :     }
    5473             : 
    5474           0 :     int err(0);
    5475           0 :     if(has_control)
    5476             :     {
    5477           0 :         if(max == 0)
    5478             :         {
    5479           0 :             int offset(0);
    5480           0 :             std::string line;
    5481           0 :             while(control_info_file.read_line(offset, line))
    5482             :             {
    5483           0 :                 if(!cl.quiet())
    5484             :                 {
    5485           0 :                     printf(" %s\n", line.c_str());
    5486             :                 }
    5487             :             }
    5488           0 :             if(cl.opt().is_defined("verify") && cl.opt().is_defined("verify-fields"))
    5489             :             {
    5490             :                 // user wanted some extra field validation
    5491           0 :                 wpkg_control::binary_control_file validate_ctrl(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::control_file_state_t));
    5492           0 :                 validate_ctrl.set_input_file(&control_info_file);
    5493           0 :                 validate_ctrl.read();
    5494           0 :                 validate_ctrl.set_input_file(NULL);
    5495           0 :                 int fields_max(cl.opt().size("verify-fields"));
    5496           0 :                 for(int i(0); i < fields_max; ++i)
    5497             :                 {
    5498           0 :                     std::string v(cl.opt().get_string("verify-fields", i));
    5499           0 :                     if(!validate_ctrl.validate_fields(v))
    5500             :                     {
    5501             :                         fprintf(stderr, "error:%s: field validation failed with: \"%s\".\n",
    5502           0 :                                     cl.opt().get_program_name().c_str(), v.c_str());
    5503           0 :                         ++err;
    5504             :                     }
    5505           0 :                 }
    5506           0 :             }
    5507             :         }
    5508             :     }
    5509             :     else
    5510             :     {
    5511             :         fprintf(stderr, "error:%s: no control file found in the control archive.\n",
    5512           0 :                     cl.opt().get_program_name().c_str());
    5513           0 :         ++err;
    5514             :     }
    5515             : 
    5516           0 :     if(!has_md5sums)
    5517             :     {
    5518             :         fprintf(stderr, "error:%s: no md5sums file found in the control archive.\n",
    5519           0 :                 cl.opt().get_program_name().c_str());
    5520           0 :         ++err;
    5521             :     }
    5522             : 
    5523             :     // verification includes reading the entire data.tar file
    5524             :     // which validates the tarball!
    5525           0 :     if(cl.opt().is_defined("verify"))
    5526             :     {
    5527           0 :         memfile::memory_file data;
    5528           0 :         std::string data_filename("data.tar");
    5529           0 :         manager.get_control_file(data, name, data_filename, false);
    5530             : 
    5531           0 :         wpkg_util::md5sums_map_t md5sums;
    5532           0 :         if(has_md5sums)
    5533             :         {
    5534             :             // transform the md5sums file in a map
    5535           0 :             wpkg_util::parse_md5sums(md5sums, md5sums_file);
    5536             :         }
    5537             : #ifdef WIN32
    5538             :         std::map<case_insensitive::case_insensitive_string, bool> md5sums_found;
    5539             : #else
    5540           0 :         std::map<std::string, bool> md5sums_found;
    5541             : #endif
    5542             : 
    5543           0 :         data.dir_rewind();
    5544           0 :         for(;;)
    5545             :         {
    5546           0 :             memfile::memory_file::file_info info;
    5547           0 :             memfile::memory_file input_data;
    5548           0 :             if(!data.dir_next(info, &input_data))
    5549             :             {
    5550             :                 break;
    5551             :             }
    5552             :             // TODO: we should canonicalize the filename for this test
    5553           0 :             std::string filename(info.get_filename());
    5554           0 :             if(md5sums_found.find(filename) != md5sums_found.end())
    5555             :             {
    5556             :                 fprintf(stderr, "error:%s: file \"%s\" is defined multiple times in the data archive\n",
    5557           0 :                         cl.opt().get_program_name().c_str(),
    5558           0 :                         filename.c_str());
    5559           0 :                 ++err;
    5560             :             }
    5561             :             else
    5562             :             {
    5563           0 :                 md5sums_found[filename] = true;
    5564             :             }
    5565             :             // directory, special files, etc. do not have an md5sum
    5566           0 :             switch(info.get_file_type())
    5567             :             {
    5568             :             case memfile::memory_file::file_info::regular_file:
    5569             :             case memfile::memory_file::file_info::continuous:
    5570           0 :                 if(has_md5sums)
    5571             :                 {
    5572           0 :                     if(md5sums.find(filename) != md5sums.end())
    5573             :                     {
    5574           0 :                         std::string sum(input_data.md5sum());
    5575           0 :                         if(md5sums[filename] != sum)
    5576             :                         {
    5577             :                             fprintf(stderr, "error:%s: file \"%s\" md5sum is not valid\n",
    5578           0 :                                     cl.opt().get_program_name().c_str(),
    5579           0 :                                     filename.c_str());
    5580           0 :                             ++err;
    5581             :                         }
    5582             :                         // remove the entry so we can err in case some
    5583             :                         // md5sums were not used up (why are they defined?)
    5584           0 :                         md5sums.erase(md5sums.find(filename));
    5585             :                     }
    5586             :                     else
    5587             :                     {
    5588             :                         fprintf(stderr, "error:%s: file \"%s\" is not defined in the list of md5sums\n",
    5589           0 :                                     cl.opt().get_program_name().c_str(),
    5590           0 :                                     filename.c_str());
    5591           0 :                         ++err;
    5592             :                     }
    5593             :                 }
    5594           0 :                 break;
    5595             : 
    5596             :             default:
    5597             :                 // md5sums are in regular files only
    5598           0 :                 break;
    5599             : 
    5600             :             }
    5601           0 :         }
    5602           0 :         if(!md5sums.empty())
    5603             :         {
    5604             :             fprintf(stderr, "error:%s: more md5sums defined than there are files in the data archive.",
    5605           0 :                         cl.opt().get_program_name().c_str());
    5606           0 :             ++err;
    5607           0 :         }
    5608             :     }
    5609           0 :     if(err != 0)
    5610             :     {
    5611           0 :         exit(1);
    5612           0 :     }
    5613           0 : }
    5614             : 
    5615           0 : void increment_build_number(command_line& cl)
    5616             : {
    5617           0 :     int max(cl.size());
    5618           0 :     if(max > 1)
    5619             :     {
    5620             :         printf("error:%s: too many parameters on the command line for --increment-build-number.\n",
    5621           0 :             cl.opt().get_program_name().c_str());
    5622           0 :         exit(1);
    5623             :     }
    5624           0 :     wpkgar::wpkgar_manager manager;
    5625           0 :     init_manager(cl, manager, "verify-project");
    5626           0 :     wpkgar::wpkgar_build pkg_build(&manager, "");
    5627           0 :     if(cl.opt().is_defined("build-number-filename"))
    5628             :     {
    5629           0 :         if(max == 1)
    5630             :         {
    5631             :             printf("error:%s: the build number filename cannot be defined more than once; please remove the --build-number-filename parameter.\n",
    5632           0 :                 cl.opt().get_program_name().c_str());
    5633           0 :             exit(1);
    5634             :         }
    5635           0 :         pkg_build.set_build_number_filename(cl.opt().get_string("build-number-filename"));
    5636             :     }
    5637           0 :     else if(max == 1)
    5638             :     {
    5639             :         // set user defined filename if defined
    5640           0 :         pkg_build.set_build_number_filename(cl.opt().get_string("increment-build-number"));
    5641             :     }
    5642           0 :     pkg_build.increment_build_number();
    5643             : 
    5644           0 :     if(cl.verbose())
    5645             :     {
    5646           0 :         int build_number(0);
    5647           0 :         if(pkg_build.load_build_number(build_number, false))
    5648             :         {
    5649           0 :             printf("%d\n", build_number);
    5650             :         }
    5651             :         else
    5652             :         {
    5653             :             printf("error:%s: could not read the build number back.\n",
    5654           0 :                 cl.opt().get_program_name().c_str());
    5655           0 :             exit(1);
    5656             :         }
    5657           0 :     }
    5658           0 : }
    5659             : 
    5660           0 : void list(command_line& cl)
    5661             : {
    5662           0 :     int max(cl.size());
    5663           0 :     if(max > 1)
    5664             :     {
    5665             :         printf("error:%s: too many parameters on the command line for --list.\n",
    5666           0 :             cl.opt().get_program_name().c_str());
    5667           0 :         exit(1);
    5668             :     }
    5669           0 :     const std::string& pattern_str(cl.opt().get_string("list"));
    5670           0 :     const char *pattern = pattern_str.c_str();
    5671             : 
    5672           0 :     wpkgar::wpkgar_manager manager;
    5673           0 :     init_manager(cl, manager, "list");
    5674           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    5675           0 :     wpkgar::wpkgar_manager::package_list_t list;
    5676           0 :     manager.list_installed_packages(list);
    5677             : 
    5678           0 :     bool first(true);
    5679           0 :     for(wpkgar::wpkgar_manager::package_list_t::const_iterator it(list.begin());
    5680           0 :             it != list.end(); ++it)
    5681             :     {
    5682           0 :         if(*pattern != '\0')
    5683             :         {
    5684           0 :             const wpkg_filename::uri_filename filename(it->c_str());
    5685           0 :             if(!filename.glob(pattern))
    5686             :             {
    5687             :                 // it doesn't match, skip it
    5688           0 :                 continue;
    5689           0 :             }
    5690             :         }
    5691           0 :         if(first)
    5692             :         {
    5693           0 :             first = false;
    5694             :             printf("Desired=Unknown/Install/Remove/Purge/Hold/reJect\n"
    5695             :                    "| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/Working\n"
    5696             :                    "|/ Err?=(none)/Configure\n"
    5697             :                    "||/ Name                                  Version                          Description\n"
    5698           0 :                    "+++-=====================================-================================-======================================================================\n");
    5699             :         }
    5700             :         try {
    5701             :             char flags[4];
    5702           0 :             memcpy(flags, "i- \0", sizeof(flags));
    5703           0 :             manager.load_package(*it);
    5704           0 :             if(manager.field_is_defined(*it, wpkg_control::control_file::field_xselection_factory_t::canonicalized_name()))
    5705             :             {
    5706           0 :                 const wpkg_control::control_file::field_xselection_t::selection_t selection(wpkg_control::control_file::field_xselection_t::validate_selection(manager.get_field(*it, wpkg_control::control_file::field_xselection_factory_t::canonicalized_name())));
    5707           0 :                 if(selection == wpkg_control::control_file::field_xselection_t::selection_hold)
    5708             :                 {
    5709           0 :                     flags[0] = 'h';
    5710             :                 }
    5711           0 :                 else if(selection == wpkg_control::control_file::field_xselection_t::selection_reject)
    5712             :                 {
    5713           0 :                     flags[0] = 'j';
    5714             :                 }
    5715             :             }
    5716           0 :             const wpkgar::wpkgar_manager::package_status_t status(manager.package_status(*it));
    5717           0 :             switch(status)
    5718             :             {
    5719             :             case wpkgar::wpkgar_manager::not_installed:
    5720           0 :                 flags[0] = flags[0] == 'j' ? 'j' : 'p';
    5721           0 :                 flags[1] = 'n';
    5722           0 :                 break;
    5723             : 
    5724             :             case wpkgar::wpkgar_manager::config_files:
    5725           0 :                 flags[0] = flags[0] == 'j' ? 'j' : 'r';
    5726           0 :                 flags[1] = 'c';
    5727           0 :                 break;
    5728             : 
    5729             :             case wpkgar::wpkgar_manager::unpacked:
    5730           0 :                 flags[1] = 'U';
    5731           0 :                 break;
    5732             : 
    5733             :             case wpkgar::wpkgar_manager::installed:
    5734           0 :                 flags[1] = 'i';
    5735           0 :                 break;
    5736             : 
    5737             :             case wpkgar::wpkgar_manager::no_package:
    5738           0 :                 flags[0] = 'u';
    5739           0 :                 flags[1] = 'n';
    5740           0 :                 break;
    5741             : 
    5742             :             case wpkgar::wpkgar_manager::unknown:
    5743           0 :                 flags[0] = '?';
    5744           0 :                 flags[1] = '?';
    5745           0 :                 break;
    5746             : 
    5747             :             case wpkgar::wpkgar_manager::installing:
    5748             :             case wpkgar::wpkgar_manager::upgrading: // could be downgrading
    5749           0 :                 flags[1] = 'w';
    5750           0 :                 break;
    5751             : 
    5752             :             case wpkgar::wpkgar_manager::half_installed:
    5753           0 :                 flags[1] = 'H';
    5754           0 :                 break;
    5755             : 
    5756             :             case wpkgar::wpkgar_manager::half_configured:
    5757           0 :                 flags[1] = 'F';
    5758           0 :                 flags[2] = 'c';
    5759           0 :                 break;
    5760             : 
    5761             :             case wpkgar::wpkgar_manager::removing:
    5762           0 :                 flags[0] = 'r';
    5763           0 :                 flags[1] = 'w';
    5764           0 :                 break;
    5765             : 
    5766             :             case wpkgar::wpkgar_manager::purging:
    5767           0 :                 flags[0] = 'p';
    5768           0 :                 flags[1] = 'w';
    5769           0 :                 break;
    5770             : 
    5771             :             // unexpected status for a package
    5772             :             case wpkgar::wpkgar_manager::listing:
    5773             :             case wpkgar::wpkgar_manager::verifying:
    5774             :             case wpkgar::wpkgar_manager::ready:
    5775           0 :                 flags[0] = 'u';
    5776           0 :                 flags[1] = '*';
    5777           0 :                 break;
    5778             : 
    5779             :             }
    5780           0 :             const std::string version(manager.get_field(*it, "Version"));
    5781           0 :             std::string long_description;
    5782           0 :             const std::string description(manager.get_description(*it, "Description", long_description));
    5783             :             printf("%s %-37.37s %-32.32s %-70.70s\n", flags,
    5784           0 :                     it->c_str(), version.c_str(), description.c_str());
    5785             :         }
    5786           0 :         catch(const std::exception& e)
    5787             :         {
    5788             :             fprintf(stderr, "error:%s: installed package \"%s\" could not be loaded (%s).\n",
    5789           0 :                     cl.opt().get_program_name().c_str(), it->c_str(), e.what());
    5790             :         }
    5791             :     }
    5792           0 :     if(first)
    5793             :     {
    5794           0 :         if(*pattern == '\0' || pattern_str == "*")
    5795             :         {
    5796           0 :             fprintf(stderr, "No package installed in this environment.\n");
    5797             :         }
    5798             :         else
    5799             :         {
    5800           0 :             fprintf(stderr, "No package found matching \"%s\".\n", pattern);
    5801             :         }
    5802           0 :     }
    5803           0 : }
    5804             : 
    5805           0 : void list_all(command_line& cl)
    5806             : {
    5807           0 :     if(cl.size() != 0)
    5808             :     {
    5809           0 :         cl.opt().usage(advgetopt::getopt::error, "--list-all does not take any parameters.");
    5810             :         /*NOTREACHED*/
    5811             :     }
    5812             : 
    5813           0 :     wpkgar::wpkgar_manager manager;
    5814           0 :     init_manager(cl, manager, "list-all");
    5815           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    5816           0 :     wpkgar::wpkgar_manager::package_list_t list;
    5817           0 :     manager.list_installed_packages(list);
    5818             : 
    5819           0 :     for(wpkgar::wpkgar_manager::package_list_t::const_iterator it(list.begin());
    5820           0 :             it != list.end(); ++it)
    5821             :     {
    5822           0 :         manager.load_package(*it);
    5823           0 :         const wpkgar::wpkgar_manager::package_status_t status(manager.package_status(*it));
    5824           0 :         switch(status)
    5825             :         {
    5826             :         case wpkgar::wpkgar_manager::installed:
    5827           0 :             printf("%-31s %s\n", it->c_str(), manager.get_field_first_line(*it, wpkg_control::control_file::field_description_factory_t::canonicalized_name()).c_str());
    5828           0 :             break;
    5829             : 
    5830             :         case wpkgar::wpkgar_manager::unpacked:
    5831           0 :             printf("? %-29s %s\n", it->c_str(), manager.get_field_first_line(*it, wpkg_control::control_file::field_description_factory_t::canonicalized_name()).c_str());
    5832           0 :             break;
    5833             : 
    5834             :         case wpkgar::wpkgar_manager::config_files:
    5835           0 :             printf("! %-29s %s\n", it->c_str(), manager.get_field_first_line(*it, wpkg_control::control_file::field_description_factory_t::canonicalized_name()).c_str());
    5836           0 :             break;
    5837             : 
    5838             :         case wpkgar::wpkgar_manager::not_installed:
    5839             :         case wpkgar::wpkgar_manager::no_package:
    5840             :         case wpkgar::wpkgar_manager::unknown:
    5841             :         case wpkgar::wpkgar_manager::installing:
    5842             :         case wpkgar::wpkgar_manager::upgrading:
    5843             :         case wpkgar::wpkgar_manager::half_installed:
    5844             :         case wpkgar::wpkgar_manager::half_configured:
    5845             :         case wpkgar::wpkgar_manager::removing:
    5846             :         case wpkgar::wpkgar_manager::purging:
    5847             :         case wpkgar::wpkgar_manager::listing:
    5848             :         case wpkgar::wpkgar_manager::verifying:
    5849             :         case wpkgar::wpkgar_manager::ready:
    5850             :             // not properly installed we ignore them completely here
    5851           0 :             break;
    5852             : 
    5853             :         }
    5854           0 :     }
    5855           0 : }
    5856             : 
    5857           0 : void listfiles(command_line& cl)
    5858             : {
    5859           0 :     int max(cl.opt().size("listfiles"));
    5860           0 :     if(max == 0)
    5861             :     {
    5862             :         printf("error:%s: --listfiles expects at least one installed package name.\n",
    5863           0 :             cl.opt().get_program_name().c_str());
    5864           0 :         exit(1);
    5865             :     }
    5866           0 :     wpkgar::wpkgar_manager manager;
    5867           0 :     init_manager(cl, manager, "listfiles");
    5868           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    5869             : 
    5870           0 :     bool first(true);
    5871           0 :     for(int i(0); i < max; ++i)
    5872             :     {
    5873           0 :         const std::string& name(cl.opt().get_string("listfiles", i));
    5874           0 :         manager.load_package(name);
    5875             :         memfile::memory_file *wpkgar_file;
    5876           0 :         manager.get_wpkgar_file(name, wpkgar_file);
    5877           0 :         if(!first)
    5878             :         {
    5879           0 :             printf("\n");
    5880             :         }
    5881           0 :         if(cl.verbose())
    5882             :         {
    5883           0 :             printf("%s:\n", name.c_str());
    5884             :         }
    5885           0 :         wpkgar_file->dir_rewind();
    5886           0 :         for(;;)
    5887             :         {
    5888           0 :             memfile::memory_file::file_info info;
    5889           0 :             if(!wpkgar_file->dir_next(info, NULL))
    5890             :             {
    5891             :                 break;
    5892             :             }
    5893           0 :             std::string filename(info.get_filename());
    5894           0 :             if(filename[0] == '/')
    5895             :             {
    5896           0 :                 printf("%s\n", filename.c_str());
    5897             :             }
    5898           0 :         }
    5899           0 :         first = false;
    5900           0 :     }
    5901           0 : }
    5902             : 
    5903           0 : void list_index_packages(command_line& cl)
    5904             : {
    5905           0 :     if(cl.size() != 0)
    5906             :     {
    5907             :         printf("error:%s: --list-index-packages does not take extra parameters.\n",
    5908           0 :             cl.opt().get_program_name().c_str());
    5909           0 :         exit(1);
    5910             :     }
    5911             : 
    5912           0 :     int max(cl.opt().size("list-index-packages"));
    5913           0 :     if(max == 0)
    5914             :     {
    5915             :         printf("error:%s: --list-index-packages expects at least one package index name.\n",
    5916           0 :             cl.opt().get_program_name().c_str());
    5917           0 :         exit(1);
    5918             :     }
    5919           0 :     wpkgar::wpkgar_manager manager;
    5920           0 :     init_manager(cl, manager, "list-index-packages");
    5921           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    5922             : 
    5923           0 :     for(int i(0); i < max; ++i)
    5924             :     {
    5925           0 :         const std::string& name(cl.opt().get_string("list-index-packages", i));
    5926           0 :         memfile::memory_file package_index;
    5927           0 :         package_index.read_file(name);
    5928           0 :         wpkgar::wpkgar_repository repository(&manager);
    5929           0 :         wpkgar::wpkgar_repository::entry_vector_t entries;
    5930           0 :         repository.load_index(package_index, entries);
    5931             : 
    5932           0 :         for(wpkgar::wpkgar_repository::entry_vector_t::const_iterator it(entries.begin()); it != entries.end(); ++it)
    5933             :         {
    5934             :             printf("%7d  %s  %s\n",
    5935           0 :                  it->f_info.get_size(),
    5936           0 :                  it->f_info.get_date().c_str(),
    5937           0 :                  it->f_info.get_filename().c_str());
    5938             :         }
    5939           0 :     }
    5940           0 : }
    5941             : 
    5942           0 : void list_sources(command_line& cl)
    5943             : {
    5944           0 :     if(cl.size() != 0)
    5945             :     {
    5946             :         printf("error:%s: --list-source does not take extra parameters.\n",
    5947           0 :             cl.opt().get_program_name().c_str());
    5948           0 :         exit(1);
    5949             :     }
    5950             : 
    5951           0 :     int max(cl.opt().size("list-sources"));
    5952           0 :     if(max <= 0)
    5953             :     {
    5954             :         printf("error:%s: --list-sources expects at least one package index name.\n",
    5955           0 :             cl.opt().get_program_name().c_str());
    5956           0 :         exit(1);
    5957             :     }
    5958           0 :     wpkgar::wpkgar_manager manager;
    5959           0 :     init_manager(cl, manager, "list-sources");
    5960           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    5961             : 
    5962           0 :     for(int i(0); i < max; ++i)
    5963             :     {
    5964           0 :         wpkg_filename::uri_filename name(cl.opt().get_string("list-sources", i));
    5965           0 :         if(name.empty())
    5966             :         {
    5967           0 :             name = manager.get_database_path();
    5968           0 :             name = name.append_child("core/sources.list");
    5969             :         }
    5970           0 :         wpkgar::wpkgar_repository repository(&manager);
    5971           0 :         wpkgar::wpkgar_repository::source_vector_t sources;
    5972           0 :         memfile::memory_file sources_file;
    5973           0 :         sources_file.read_file(name);
    5974           0 :         repository.read_sources(sources_file, sources);
    5975             : 
    5976           0 :         if(cl.verbose())
    5977             :         {
    5978           0 :             printf("file: \"%s\"\n", name.original_filename().c_str());
    5979             :         }
    5980             : 
    5981           0 :         int line(1);
    5982           0 :         for(wpkgar::wpkgar_repository::source_vector_t::const_iterator it(sources.begin()); it != sources.end(); ++it, ++line)
    5983             :         {
    5984           0 :             if(cl.verbose())
    5985             :             {
    5986           0 :                 printf("%3d. ", line);
    5987             :             }
    5988           0 :             printf("%s", it->get_type().c_str());
    5989           0 :             wpkgar::wpkgar_repository::source::parameter_map_t params(it->get_parameters());
    5990           0 :             if(!params.empty())
    5991             :             {
    5992           0 :                 printf(" [ ");
    5993           0 :                 for(wpkgar::wpkgar_repository::source::parameter_map_t::const_iterator p(params.begin()); p != params.end(); ++p)
    5994             :                 {
    5995           0 :                     printf("%s=%s ", p->first.c_str(), p->second.c_str());
    5996             :                 }
    5997           0 :                 printf("]");
    5998             :             }
    5999           0 :             printf(" %s %s", it->get_uri().c_str(), it->get_distribution().c_str());
    6000             : 
    6001           0 :             int cnt(it->get_component_size());
    6002           0 :             for(int j(0); j < cnt; ++j)
    6003             :             {
    6004           0 :                 printf(" %s", it->get_component(j).c_str());
    6005             :             }
    6006             : 
    6007           0 :             printf("\n");
    6008           0 :         }
    6009           0 :     }
    6010           0 : }
    6011             : 
    6012           2 : void md5sums(command_line& cl)
    6013             : {
    6014           2 :     int max(cl.size());
    6015           2 :     if(max == 0)
    6016             :     {
    6017           0 :         cl.opt().usage(advgetopt::getopt::error, "--md5sums expects at least one filename");
    6018             :         /*NOTREACHED*/
    6019             :     }
    6020             : 
    6021         222 :     for(int i(0); i < max; ++i)
    6022             :     {
    6023         220 :         std::string filename(cl.opt().get_string("filename", i));
    6024         220 :         memfile::memory_file file;
    6025         220 :         file.read_file(filename);
    6026         220 :         printf("%s %c%s\n", file.md5sum().c_str(), file.is_text() ? ' ' : '*', filename.c_str());
    6027         220 :     }
    6028           2 : }
    6029             : 
    6030           4 : void md5sums_check(command_line& cl)
    6031             : {
    6032           4 :     int max(cl.size());
    6033           4 :     if(max == 0)
    6034             :     {
    6035           0 :         cl.opt().usage(advgetopt::getopt::error, "--md5sums-check expects at least two filenames: the md5sums file and a file to check");
    6036             :         /*NOTREACHED*/
    6037             :     }
    6038             : 
    6039             :     // read the md5sums; if invalid it will fail
    6040           4 :     std::string md5sums_filename(cl.opt().get_string("md5sums-check"));
    6041           4 :     memfile::memory_file md5sums_file;
    6042           4 :     md5sums_file.read_file(md5sums_filename);
    6043           4 :     wpkg_util::md5sums_map_t md5sums;
    6044           4 :     wpkg_util::parse_md5sums(md5sums, md5sums_file);
    6045             : 
    6046             :     // now check the specified files
    6047         444 :     for(int i(0); i < max; ++i)
    6048             :     {
    6049         440 :         std::string filename(cl.opt().get_string("filename", i));
    6050         440 :         wpkg_util::md5sums_map_t::const_iterator it(md5sums.find(filename));
    6051         440 :         if(it == md5sums.end())
    6052             :         {
    6053             :             // this file does not exist in the md5sums file
    6054             :             wpkg_output::log("file %1 is not defined in your list of md5sums")
    6055           0 :                     .quoted_arg(filename)
    6056           0 :                 .level(wpkg_output::level_warning)
    6057           0 :                 .action("audit-validation");
    6058             :         }
    6059             :         else
    6060             :         {
    6061         440 :             memfile::memory_file file;
    6062         440 :             file.read_file(filename);
    6063         440 :             std::string loaded_file_md5sum(file.md5sum());
    6064         440 :             if(it->second == loaded_file_md5sum)
    6065             :             {
    6066             :                 wpkg_output::log("%1 is valid")
    6067         876 :                         .quoted_arg(filename)
    6068         438 :                     .action("audit-validation");
    6069             :             }
    6070             :             else
    6071             :             {
    6072             :                 wpkg_output::log("the md5sum (%1) of file %2 does not match the one found (%3) in your list of md5sums")
    6073           4 :                         .arg(it->second)
    6074           2 :                         .quoted_arg(filename)
    6075           2 :                         .arg(loaded_file_md5sum)
    6076           2 :                     .level(wpkg_output::level_error)
    6077           2 :                     .action("audit-validation");
    6078         440 :             }
    6079             :         }
    6080         444 :     }
    6081           4 : }
    6082             : 
    6083           0 : void print_architecture(command_line& cl)
    6084             : {
    6085           0 :     wpkgar::wpkgar_manager manager;
    6086           0 :     init_manager(cl, manager, "print-architecture");
    6087           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    6088           0 :     manager.load_package("core");
    6089           0 :     std::string architecture(manager.get_field("core", "Architecture"));
    6090           0 :     printf("%s\n", architecture.c_str());
    6091           0 : }
    6092             : 
    6093           0 : void print_build_number(command_line& cl)
    6094             : {
    6095           0 :     wpkgar::wpkgar_manager manager;
    6096           0 :     init_manager(cl, manager, "print-build-number");
    6097           0 :     wpkgar::wpkgar_build pkg_build(&manager, "");
    6098           0 :     if(cl.opt().is_defined("build-number-filename"))
    6099             :     {
    6100             :         // set user defined filename if defined
    6101           0 :         pkg_build.set_build_number_filename(cl.opt().get_string("build-number-filename"));
    6102             :     }
    6103             : 
    6104           0 :     int build_number(0);
    6105           0 :     if(pkg_build.load_build_number(build_number, false))
    6106             :     {
    6107           0 :         printf("%d\n", build_number);
    6108             :     }
    6109             :     else
    6110             :     {
    6111             :         printf("error:%s: could not read the build number back.\n",
    6112           0 :             cl.opt().get_program_name().c_str());
    6113           0 :         exit(1);
    6114           0 :     }
    6115           0 : }
    6116             : 
    6117          57 : void init_remover(command_line& cl, wpkgar::wpkgar_manager& manager, wpkgar::wpkgar_remove& pkg_remove, const std::string& option)
    6118             : {
    6119          57 :     init_manager(cl, manager, option);
    6120             : 
    6121          57 :     int max(cl.opt().size(option));
    6122          57 :     if(max == 0)
    6123             :     {
    6124           0 :         throw std::runtime_error("--" + option + " requires at least one parameter");
    6125             :     }
    6126             : 
    6127             :     // add the force, no-force/refuse parameters
    6128             :     pkg_remove.set_parameter(wpkgar::wpkgar_remove::wpkgar_remove_force_depends,
    6129         171 :         (cl.opt().is_defined("force-depends") || cl.opt().is_defined("force-all"))
    6130          57 :                             && !cl.opt().is_defined("no-force-depends")
    6131          57 :                             && !cl.opt().is_defined("refuse-depends")
    6132         114 :                             && !cl.opt().is_defined("refuse-all"));
    6133             :     pkg_remove.set_parameter(wpkgar::wpkgar_remove::wpkgar_remove_force_hold,
    6134         170 :         (cl.opt().is_defined("force-hold") || cl.opt().is_defined("force-all"))
    6135          58 :                             && !cl.opt().is_defined("no-force-hold")
    6136          58 :                             && !cl.opt().is_defined("refuse-hold")
    6137         115 :                             && !cl.opt().is_defined("refuse-all"));
    6138             :     pkg_remove.set_parameter(wpkgar::wpkgar_remove::wpkgar_remove_force_remove_essentials,
    6139         169 :         (cl.opt().is_defined("force-remove-essential") || cl.opt().is_defined("force-all"))
    6140          59 :                             && !cl.opt().is_defined("no-force-remove-essential")
    6141          59 :                             && !cl.opt().is_defined("refuse-remove-essential")
    6142         116 :                             && !cl.opt().is_defined("refuse-all"));
    6143             : 
    6144             :     // some additional parameters
    6145          57 :     pkg_remove.set_parameter(wpkgar::wpkgar_remove::wpkgar_remove_recursive, cl.opt().is_defined("recursive"));
    6146             : 
    6147             :     // add the list of package names
    6148         114 :     for(int i(0); i < max; ++i)
    6149             :     {
    6150          57 :         pkg_remove.add_package(cl.opt().get_string(option, i));
    6151             :     }
    6152          57 : }
    6153             : 
    6154          23 : void remove(command_line& cl)
    6155             : {
    6156          23 :     wpkgar::wpkgar_manager manager;
    6157          23 :     wpkgar::wpkgar_remove pkg_remove(&manager);
    6158          23 :     init_remover(cl, manager, pkg_remove, "remove");
    6159             : 
    6160          23 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Removing");
    6161          23 :     if(pkg_remove.validate() && !cl.dry_run())
    6162             :     {
    6163          20 :         if(manager.is_self())
    6164             :         {
    6165             :             // trying to remove self?!
    6166             :             wpkg_output::log("you cannot remove wpkg, even if it is not marked as required because under MS-Windows it is just not possible to delete a running executable")
    6167           2 :                 .level(wpkg_output::level_fatal)
    6168           1 :                 .module(wpkg_output::module_validate_removal)
    6169           1 :                 .package("wpkg")
    6170           1 :                 .action("remove-validation");
    6171             :         }
    6172             :         else
    6173             :         {
    6174          39 :             for(;;)
    6175             :             {
    6176          38 :                 manager.check_interrupt();
    6177             : 
    6178          38 :                 int i(pkg_remove.remove());
    6179          38 :                 if(i < 0)
    6180             :                 {
    6181          19 :                     break;
    6182             :                 }
    6183             :                 // keep all configuration files
    6184             :             }
    6185             :         }
    6186          23 :     }
    6187          23 : }
    6188             : 
    6189          30 : void purge(command_line& cl)
    6190             : {
    6191          30 :     wpkgar::wpkgar_manager manager;
    6192          30 :     wpkgar::wpkgar_remove pkg_remove(&manager);
    6193          30 :     pkg_remove.set_purging();
    6194          30 :     init_remover(cl, manager, pkg_remove, "purge");
    6195             : 
    6196          30 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Removing");
    6197          30 :     if(pkg_remove.validate() && !cl.dry_run())
    6198             :     {
    6199          27 :         if(manager.is_self())
    6200             :         {
    6201             :             // trying to remove self?!
    6202             :             wpkg_output::log("you cannot purge wpkg, even if it is not marked as required because under MS-Windows it is just not possible to delete a running executable")
    6203           2 :                 .level(wpkg_output::level_fatal)
    6204           1 :                 .module(wpkg_output::module_validate_removal)
    6205           1 :                 .package("wpkg")
    6206           1 :                 .action("remove-validation");
    6207             :         }
    6208             :         else
    6209             :         {
    6210          53 :             for(;;)
    6211             :             {
    6212          52 :                 manager.check_interrupt();
    6213             : 
    6214          52 :                 int i(pkg_remove.remove());
    6215          52 :                 if(i < 0)
    6216             :                 {
    6217          26 :                     break;
    6218             :                 }
    6219          26 :                 if(!pkg_remove.deconfigure(i))
    6220             :                 {
    6221           0 :                     break;
    6222             :                 }
    6223             :             }
    6224             :         }
    6225          30 :     }
    6226          30 : }
    6227             : 
    6228           0 : void deconfigure(command_line& cl)
    6229             : {
    6230           0 :     wpkgar::wpkgar_manager manager;
    6231           0 :     wpkgar::wpkgar_remove pkg_remove(&manager);
    6232           0 :     pkg_remove.set_deconfiguring();
    6233           0 :     init_remover(cl, manager, pkg_remove, "deconfigure");
    6234             : 
    6235           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Removing");
    6236           0 :     if(pkg_remove.validate() && !cl.dry_run())
    6237             :     {
    6238           0 :         if(manager.is_self())
    6239             :         {
    6240             :             // trying to remove self?!
    6241             :             wpkg_output::log("you cannot deconfigure wpkg, even if it is not marked as required because under MS-Windows it is just not possible to delete a running executable")
    6242           0 :                 .level(wpkg_output::level_fatal)
    6243           0 :                 .module(wpkg_output::module_deconfigure_package)
    6244           0 :                 .package("wpkg")
    6245           0 :                 .action("deconfigure-validation");
    6246             :         }
    6247             :         else
    6248             :         {
    6249             :             // TODO: this is a bit weak although the validation
    6250             :             //       should be enough I'm not 100% sure that the
    6251             :             //       order in which to deconfigure is important
    6252             :             //       or not (TBD.)
    6253           0 :             int max(pkg_remove.count());
    6254           0 :             for(int i(0); i < max; ++i)
    6255             :             {
    6256           0 :                 manager.check_interrupt();
    6257             : 
    6258           0 :                 if(!pkg_remove.deconfigure(i))
    6259             :                 {
    6260           0 :                     break;
    6261             :                 }
    6262             :             }
    6263             :         }
    6264           0 :     }
    6265           0 : }
    6266             : 
    6267           4 : void autoremove(command_line& cl)
    6268             : {
    6269           4 :     if(cl.size() != 0)
    6270             :     {
    6271           0 :         throw std::runtime_error("--autoremove does not take any parameter");
    6272             :     }
    6273             : 
    6274           4 :     wpkgar::wpkgar_manager manager;
    6275           4 :     wpkgar::wpkgar_remove pkg_remove(&manager);
    6276           4 :     if(cl.opt().is_defined("purge"))
    6277             :     {
    6278           0 :         pkg_remove.set_purging();
    6279             :     }
    6280           4 :     init_remover(cl, manager, pkg_remove, "autoremove");
    6281             : 
    6282           4 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Removing");
    6283           4 :     pkg_remove.autoremove(cl.dry_run());
    6284           4 : }
    6285             : 
    6286           0 : void remove_database_lock(command_line& cl)
    6287             : {
    6288           0 :     wpkgar::wpkgar_manager manager;
    6289           0 :     init_manager(cl, manager, "remove-database-lock");
    6290           0 :     if(manager.remove_lock())
    6291             :     {
    6292           0 :         if(cl.verbose())
    6293             :         {
    6294           0 :             printf("database lock was removed.\n");
    6295             :         }
    6296           0 :         exit(0);
    6297             :     }
    6298             :     else
    6299             :     {
    6300           0 :         fprintf(stderr, "error: that database was not locked.\n");
    6301           0 :         exit(1);
    6302           0 :     }
    6303             : }
    6304             : 
    6305           0 : void remove_sources(command_line& cl)
    6306             : {
    6307           0 :     int max(cl.size());
    6308           0 :     if(max == 0)
    6309             :     {
    6310           0 :         cl.opt().usage(advgetopt::getopt::error, "--remove-sources expects at least one number");
    6311             :         /*NOTREACHED*/
    6312             :     }
    6313             : 
    6314           0 :     wpkgar::wpkgar_manager manager;
    6315           0 :     init_manager(cl, manager, "remove-sources");
    6316           0 :     wpkg_filename::uri_filename name(manager.get_database_path());
    6317           0 :     name = name.append_child("core/sources.list");
    6318           0 :     wpkgar::wpkgar_repository repository(&manager);
    6319           0 :     wpkgar::wpkgar_repository::source_vector_t sources;
    6320           0 :     memfile::memory_file sources_file;
    6321           0 :     sources_file.read_file(name);
    6322           0 :     sources_file.printf("\n");
    6323           0 :     repository.read_sources(sources_file, sources);
    6324             : 
    6325             :     // we need to have all the line references in order so we can delete the
    6326             :     // last one first; otherwise the position would be invalid
    6327           0 :     std::vector<int> lines;
    6328           0 :     for(int i(0); i < max; ++i)
    6329             :     {
    6330           0 :         lines.push_back(cl.opt().get_long("filename", i, 1, static_cast<int>(sources.size())));
    6331             :     }
    6332           0 :     std::sort(lines.begin(), lines.end());
    6333             : 
    6334           0 :     max = static_cast<int>(lines.size());
    6335           0 :     for(int i(max - 1); i >= 0; --i)
    6336             :     {
    6337           0 :         sources.erase(sources.begin() + lines[i]);
    6338             :     }
    6339             : 
    6340           0 :     sources_file.create(memfile::memory_file::file_format_other);
    6341           0 :     repository.write_sources(sources_file, sources);
    6342           0 :     sources_file.write_file(name);
    6343           0 : }
    6344             : 
    6345           0 : void rollback(command_line& cl)
    6346             : {
    6347           0 :     int max(cl.opt().size("filename"));
    6348           0 :     if(max != 0)
    6349             :     {
    6350           0 :         cl.opt().usage(advgetopt::getopt::error, "--rollback expects exactly one parameter.\n");
    6351             :         /*NOTREACHED*/
    6352             :     }
    6353             : 
    6354           0 :     wpkgar::wpkgar_manager manager;
    6355           0 :     init_manager(cl, manager, "rollback");
    6356           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Removing");
    6357             : 
    6358           0 :     wpkgar::wpkgar_tracker tracker(&manager, cl.opt().get_string("rollback"));
    6359           0 :     tracker.keep_file(true);
    6360           0 : }
    6361             : 
    6362           0 : void search(command_line& cl)
    6363             : {
    6364           0 :     int max(cl.opt().size("search"));
    6365           0 :     if(max == 0)
    6366             :     {
    6367           0 :         cl.opt().usage(advgetopt::getopt::error, "--search expects at least one pattern or filename.\n");
    6368             :         /*NOTREACHED*/
    6369             :     }
    6370           0 :     wpkgar::wpkgar_manager manager;
    6371           0 :     init_manager(cl, manager, "search");
    6372           0 :     wpkgar::wpkgar_lock lock_wpkg(&manager, "Listing");
    6373           0 :     wpkgar::wpkgar_manager::package_list_t list;
    6374           0 :     manager.list_installed_packages(list);
    6375             : 
    6376           0 :     int count(0);
    6377           0 :     for(wpkgar::wpkgar_manager::package_list_t::const_iterator it(list.begin());
    6378           0 :             it != list.end(); ++it)
    6379             :     {
    6380           0 :         manager.load_package(*it);
    6381             :         memfile::memory_file *wpkgar_file;
    6382           0 :         manager.get_wpkgar_file(*it, wpkgar_file);
    6383             : 
    6384           0 :         bool first(true);
    6385           0 :         wpkgar_file->dir_rewind();
    6386           0 :         for(;;)
    6387             :         {
    6388           0 :             memfile::memory_file::file_info info;
    6389           0 :             if(!wpkgar_file->dir_next(info, NULL))
    6390             :             {
    6391             :                 break;
    6392             :             }
    6393           0 :             const wpkg_filename::uri_filename filename(info.get_filename());
    6394           0 :             if(filename.is_absolute())
    6395             :             {
    6396           0 :                 for(int i(0); i < max; ++i)
    6397             :                 {
    6398           0 :                     const std::string& pattern(cl.opt().get_string("search", i));
    6399           0 :                     if(filename.glob(pattern.c_str()))
    6400             :                     {
    6401           0 :                         if(cl.verbose())
    6402             :                         {
    6403           0 :                             if(first)
    6404             :                             {
    6405           0 :                                 printf("%s:\n", it->c_str());
    6406             :                             }
    6407           0 :                             printf("%s\n", filename.original_filename().c_str());
    6408             :                         }
    6409             :                         else
    6410             :                         {
    6411           0 :                             printf("%s: %s\n", it->c_str(), filename.original_filename().c_str());
    6412             :                         }
    6413           0 :                         first = false;
    6414           0 :                         ++count;
    6415             :                     }
    6416           0 :                 }
    6417             :             }
    6418           0 :         }
    6419             :     }
    6420             : 
    6421           0 :     if(cl.verbose())
    6422             :     {
    6423           0 :         printf("%d file%s found.\n", count, (count != 1 ? "s" : ""));
    6424           0 :     }
    6425           0 : }
    6426             : 
    6427           1 : void set_selection(command_line& cl)
    6428             : {
    6429           1 :     int max(cl.size());
    6430           1 :     if(max == 0)
    6431             :     {
    6432           0 :         cl.opt().usage(advgetopt::getopt::error, "--set-selection expects at least one package name");
    6433             :         /*NOTREACHED*/
    6434             :     }
    6435             : 
    6436           1 :     std::string value(cl.get_string("set-selection"));
    6437           1 :     wpkg_control::control_file::field_xselection_t::selection_t selection(wpkg_control::control_file::field_xselection_t::validate_selection(value));
    6438           1 :     if(selection == wpkg_control::control_file::field_xselection_t::selection_unknown)
    6439             :     {
    6440           0 :         cl.opt().usage(advgetopt::getopt::error, "unexpected selection name, we currently support 'auto', 'manual', 'normal', 'hold', and 'reject'");
    6441             :         /*NOTREACHED*/
    6442             :     }
    6443             : 
    6444           1 :     wpkgar::wpkgar_manager manager;
    6445           1 :     init_manager(cl, manager, "set-selection");
    6446           1 :     if(selection == wpkg_control::control_file::field_xselection_t::selection_reject)
    6447             :     {
    6448             :         // the Reject is a special case...
    6449           0 :         for(int i(0); i < max; ++i)
    6450             :         {
    6451           0 :             std::string name(cl.argument(i));
    6452           0 :             manager.set_package_selection_to_reject(name);
    6453           0 :         }
    6454             :     }
    6455             :     else
    6456             :     {
    6457           2 :         for(int i(0); i < max; ++i)
    6458             :         {
    6459           1 :             std::string name(cl.argument(i));
    6460           1 :             manager.load_package(name);
    6461           1 :             manager.set_field(name, wpkg_control::control_file::field_xselection_factory_t::canonicalized_name(), value, true);
    6462           1 :         }
    6463           1 :     }
    6464           1 : }
    6465             : 
    6466           0 : void show(command_line& cl)
    6467             : {
    6468           0 :     int max(cl.size());
    6469           0 :     if(max != 0)
    6470             :     {
    6471             :         printf("error:%s: too many parameters on the command line for --show.\n",
    6472           0 :             cl.opt().get_program_name().c_str());
    6473           0 :         exit(1);
    6474             :     }
    6475           0 :     wpkgar::wpkgar_manager manager;
    6476           0 :     init_manager(cl, manager, "show");
    6477           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    6478           0 :     std::string name(cl.get_string("show"));
    6479           0 :     manager.load_package(name);
    6480           0 :     if(cl.opt().is_defined("showformat"))
    6481             :     {
    6482             :         // the format is defined, retrieve the values
    6483           0 :         const std::string& showformat(cl.opt().get_string("showformat"));
    6484           0 :         const char *s(showformat.c_str());
    6485           0 :         while(*s != '\0')
    6486             :         {
    6487           0 :             if(*s == '$' && s[1] == '{')
    6488             :             {
    6489           0 :                 s += 2;
    6490           0 :                 const char *start(s);
    6491           0 :                 while(*s != '\0' && *s != ':' && *s != '}')
    6492             :                 {
    6493           0 :                     ++s;
    6494             :                 }
    6495           0 :                 std::string field_name(start, s - start);
    6496           0 :                 int width(0);
    6497           0 :                 if(*s == ':')
    6498             :                 {
    6499           0 :                     ++s;
    6500           0 :                     int sign(1);
    6501           0 :                     if(*s == '-')
    6502             :                     {
    6503           0 :                         sign = -1;
    6504           0 :                         ++s;
    6505             :                     }
    6506           0 :                     while(*s >= '0' && *s <= '9')
    6507             :                     {
    6508           0 :                         width = width * 10 + *s - '0';
    6509           0 :                         ++s;
    6510             :                     }
    6511           0 :                     if(width >= 1024)
    6512             :                     {
    6513           0 :                         throw std::overflow_error("width too large in format");
    6514             :                     }
    6515           0 :                     width *= sign;
    6516             :                 }
    6517           0 :                 if(*s != '}')
    6518             :                 {
    6519           0 :                     throw std::overflow_error("invalid field in --showformat, } expected at the end");
    6520             :                 }
    6521           0 :                 ++s;
    6522           0 :                 std::string value("undefined");
    6523           0 :                 if(manager.field_is_defined(name, field_name))
    6524             :                 {
    6525           0 :                     value = manager.get_field(name, field_name);
    6526             :                 }
    6527           0 :                 if(width != 0)
    6528             :                 {
    6529             :                     char buf[32];
    6530           0 :                     snprintf(buf, sizeof(buf), "%%%ds", width);
    6531             : #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6)
    6532             : #pragma GCC diagnostic push
    6533             : #pragma GCC diagnostic ignored "-Wformat-nonliteral"
    6534             : #endif
    6535             :                     // buf is under control
    6536           0 :                     printf(buf, value.c_str());
    6537             : #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6)
    6538             : #pragma GCC diagnostic pop
    6539             : #endif
    6540             :                 }
    6541             :                 else
    6542             :                 {
    6543           0 :                     printf("%s", value.c_str());
    6544           0 :                 }
    6545             :             }
    6546           0 :             else if(*s == '\\')
    6547             :             {
    6548           0 :                 ++s;
    6549           0 :                 switch(*s)
    6550             :                 {
    6551             :                 case '\\':
    6552           0 :                     printf("\\");
    6553           0 :                     ++s;
    6554           0 :                     break;
    6555             : 
    6556             :                 case 'n':
    6557           0 :                     printf("\n");
    6558           0 :                     ++s;
    6559           0 :                     break;
    6560             : 
    6561             :                 case 'r':
    6562           0 :                     printf("\r");
    6563           0 :                     ++s;
    6564           0 :                     break;
    6565             : 
    6566             :                 case 't':
    6567           0 :                     printf("\t");
    6568           0 :                     ++s;
    6569           0 :                     break;
    6570             : 
    6571             :                 case '"':
    6572             :                     // because DOS batches are this bad
    6573           0 :                     printf("\"");
    6574           0 :                     ++s;
    6575           0 :                     break;
    6576             : 
    6577             :                 // others?
    6578             :                 }
    6579             :             }
    6580             :             else
    6581             :             {
    6582           0 :                 printf("%c", *s);
    6583           0 :                 ++s;
    6584             :             }
    6585           0 :         }
    6586             :     }
    6587             :     else
    6588             :     {
    6589             :         // if no format specified, show Package + Version
    6590           0 :         std::string package_name(manager.get_field(name, "Package"));
    6591           0 :         std::string version(manager.get_field(name, "Version"));
    6592           0 :         printf("%s\t%s\n", package_name.c_str(), version.c_str());
    6593           0 :     }
    6594           0 : }
    6595             : 
    6596           0 : void package_status(command_line& cl)
    6597             : {
    6598           0 :     int max(cl.opt().size("package-status"));
    6599           0 :     if(max == 0)
    6600             :     {
    6601           0 :         throw std::runtime_error("--package-status requires at least one parameter");
    6602             :     }
    6603           0 :     wpkgar::wpkgar_manager manager;
    6604           0 :     init_manager(cl, manager, "package-status");
    6605             : 
    6606           0 :     for(int i(0); i < max; ++i)
    6607             :     {
    6608           0 :         std::string name(cl.opt().get_string("package-status", i));
    6609           0 :         const char *status(NULL);
    6610           0 :         switch(manager.package_status(name))
    6611             :         {
    6612             :         case wpkgar::wpkgar_manager::no_package:
    6613           0 :             status = "error: package not found";
    6614           0 :             break;
    6615             : 
    6616             :         case wpkgar::wpkgar_manager::unknown:
    6617           0 :             status = "error: package is not known";
    6618           0 :             break;
    6619             : 
    6620             :         case wpkgar::wpkgar_manager::not_installed:
    6621           0 :             status = "not-installed";
    6622           0 :             break;
    6623             : 
    6624             :         case wpkgar::wpkgar_manager::config_files:
    6625           0 :             status = "config-files";
    6626           0 :             break;
    6627             : 
    6628             :         case wpkgar::wpkgar_manager::installing:
    6629           0 :             status = "installing";
    6630           0 :             break;
    6631             : 
    6632             :         case wpkgar::wpkgar_manager::upgrading:
    6633           0 :             status = "upgrading";
    6634           0 :             break;
    6635             : 
    6636             :         case wpkgar::wpkgar_manager::half_installed:
    6637           0 :             status = "half-installed";
    6638           0 :             break;
    6639             : 
    6640             :         case wpkgar::wpkgar_manager::unpacked:
    6641           0 :             status = "unpacked";
    6642           0 :             break;
    6643             : 
    6644             :         case wpkgar::wpkgar_manager::half_configured:
    6645           0 :             status = "half-configured";
    6646           0 :             break;
    6647             : 
    6648             :         case wpkgar::wpkgar_manager::installed:
    6649           0 :             status = "installed";
    6650           0 :             break;
    6651             : 
    6652             :         case wpkgar::wpkgar_manager::removing:
    6653           0 :             status = "removing";
    6654           0 :             break;
    6655             : 
    6656             :         case wpkgar::wpkgar_manager::purging:
    6657           0 :             status = "purging";
    6658           0 :             break;
    6659             : 
    6660             :         case wpkgar::wpkgar_manager::listing:
    6661           0 :             status = "listing";
    6662           0 :             break;
    6663             : 
    6664             :         case wpkgar::wpkgar_manager::verifying:
    6665           0 :             status = "verifying";
    6666           0 :             break;
    6667             : 
    6668             :         case wpkgar::wpkgar_manager::ready:
    6669           0 :             status = "ready";
    6670           0 :             break;
    6671             : 
    6672             :         }
    6673           0 :         if(status != NULL)
    6674             :         {
    6675           0 :             printf("status: %s: %s\n", name.c_str(), status);
    6676             :         }
    6677           0 :     }
    6678           0 : }
    6679             : 
    6680           0 : void extract(command_line& cl)
    6681             : {
    6682           0 :     int max(cl.size());
    6683           0 :     if(max != 2)
    6684             :     {
    6685           0 :         cl.opt().usage(advgetopt::getopt::error, "the extract command expects exactly two parameters: package name and a destination folder");
    6686             :         /*NOTREACHED*/
    6687             :     }
    6688           0 :     wpkgar::wpkgar_manager manager;
    6689           0 :     init_manager(cl, manager, cl.verbose() ? "vextract" : "extract");
    6690           0 :     manager.set_control_file_state(std::shared_ptr<wpkg_control::control_file::control_file_state_t>(new wpkg_control::control_file::contents_control_file_state_t));
    6691           0 :     const wpkg_filename::uri_filename name(cl.filename(0));
    6692           0 :     if(name.is_deb())
    6693             :     {
    6694           0 :         cl.opt().usage(advgetopt::getopt::error, "you cannot extract the files of the data.tar.gz file from an installed package");
    6695             :         /*NOTREACHED*/
    6696             :     }
    6697           0 :     manager.load_package(name);
    6698           0 :     memfile::memory_file p;
    6699           0 :     std::string data_filename("data.tar");
    6700           0 :     manager.get_control_file(p, name, data_filename, false);
    6701           0 :     const wpkg_filename::uri_filename output_path(cl.filename(1));
    6702           0 :     p.dir_rewind();
    6703           0 :     for(;;)
    6704             :     {
    6705           0 :         memfile::memory_file::file_info info;
    6706           0 :         memfile::memory_file data;
    6707           0 :         if(!p.dir_next(info, &data))
    6708             :         {
    6709             :             break;
    6710             :         }
    6711           0 :         const wpkg_filename::uri_filename out(output_path.append_safe_child(info.get_filename()));
    6712           0 :         if(cl.verbose())
    6713             :         {
    6714           0 :             printf("%s\n", out.original_filename().c_str());
    6715             :         }
    6716           0 :         switch(info.get_file_type())
    6717             :         {
    6718             :         case memfile::memory_file::file_info::regular_file:
    6719             :         case memfile::memory_file::file_info::continuous:
    6720           0 :             data.write_file(out, true);
    6721           0 :             break;
    6722             : 
    6723             :         case memfile::memory_file::file_info::symbolic_link:
    6724             :             {
    6725           0 :                 const wpkg_filename::uri_filename link(info.get_link());
    6726           0 :                 link.os_symlink(out);
    6727             :             }
    6728           0 :             break;
    6729             : 
    6730             :         default:
    6731             :             // nothing to do with other file types because MS-Windows
    6732             :             // does not support them
    6733           0 :             break;
    6734             : 
    6735             :         }
    6736           0 :     }
    6737           0 : }
    6738             : 
    6739           0 : void wpkg_break()
    6740             : {
    6741           0 :     g_interrupted = true;
    6742           0 :     fprintf(stderr, "\nwpkg:%d: *** User break\n", static_cast<int>(getpid()));
    6743             : 
    6744             :     // resume normal execution on return; if possible the normal
    6745             :     // execution stream will stop pretty quickly
    6746             :     //
    6747             :     // note that we do not re-establish the signal callback so
    6748             :     // if the user punches Ctrl-C again the process stops at once
    6749           0 : }
    6750             : 
    6751        1485 : void setup_interrupt()
    6752             : {
    6753             : #if defined(MO_WINDOWS)
    6754             :     signal(SIGINT, reinterpret_cast<void (__cdecl *)(int)>(wpkg_break));
    6755             :     signal(SIGTERM, reinterpret_cast<void (__cdecl *)(int)>(wpkg_break));
    6756             : #elif defined(MO_LINUX) || defined(MO_DARWIN) || defined(MO_CYGWIN) || defined(MO_SUNOS) || defined(MO_FREEBSD)
    6757        1485 :     signal(SIGINT, reinterpret_cast<void (*)(int)>(wpkg_break));
    6758        1485 :     signal(SIGTERM, reinterpret_cast<void (*)(int)>(wpkg_break));
    6759             : #else
    6760             :     signal(SIGINT, wpkg_break);
    6761             :     signal(SIGTERM, wpkg_break);
    6762             : #endif
    6763        1485 : }
    6764             : 
    6765             : 
    6766             : 
    6767             : #ifdef MO_WINDOWS
    6768             : int utf8_main(int argc, char *argv[])
    6769             : #else
    6770        1485 : int main(int argc, char *argv[])
    6771             : #endif
    6772             : {
    6773        1485 :     bool log_ready(false);
    6774        1485 :     g_argv = argv;
    6775             : 
    6776             :     // by now the g_output is ready so save it in the log object
    6777        1485 :     wpkg_output::set_output(&g_output);
    6778             : 
    6779             :     // we have a top try/catch to ensure stack unwinding and thus
    6780             :     // have true RAII at all levels whatever the compiler.
    6781             :     try
    6782             :     {
    6783        1485 :         setup_interrupt();
    6784             : 
    6785        1485 :         std::vector<std::string> configuration_files;
    6786        1485 :         configuration_files.push_back("/etc/wpkg/wpkg.conf");
    6787             :         // TODO: add wpkg location + "../etc/wpkg/wpkg.conf" under MS-Windows
    6788        1485 :         configuration_files.push_back("~/.config/wpkg/wpkg.conf");
    6789             : 
    6790             :         // support lone one character flags as in /h
    6791             :         // because windows users are used to use those
    6792        1485 :         if(argc == 2 && argv[1][0] == '/' && argv[1][1] != '\0' && argv[1][2] == '\0')
    6793             :         {
    6794           0 :             argv[1][0] = '-';
    6795             :         }
    6796        1485 :         command_line cl(argc, argv, configuration_files);
    6797        1484 :         log_ready = true;
    6798             : 
    6799        1484 :         switch(cl.command())
    6800             :         {
    6801             :         case command_line::command_add_hooks:
    6802           1 :             add_hooks(cl);
    6803           1 :             break;
    6804             : 
    6805             :         case command_line::command_add_sources:
    6806           0 :             add_sources(cl);
    6807           0 :             break;
    6808             : 
    6809             :         case command_line::command_architecture:
    6810           0 :             architecture(cl);
    6811           0 :             break;
    6812             : 
    6813             :         case command_line::command_atleast_version:
    6814           0 :             atleast_version(cl);
    6815           0 :             break;
    6816             : 
    6817             :         case command_line::command_atleast_wpkg_version:
    6818           0 :             atleast_wpkg_version(cl);
    6819           0 :             break;
    6820             : 
    6821             :         case command_line::command_audit:
    6822           0 :             audit(cl);
    6823           0 :             break;
    6824             : 
    6825             :         case command_line::command_autoremove:
    6826           4 :             autoremove(cl);
    6827           4 :             break;
    6828             : 
    6829             :         case command_line::command_build:
    6830             :             {
    6831         310 :                 wpkg_filename::uri_filename package_name;
    6832         310 :                 build(cl, package_name);
    6833             :             }
    6834         310 :             break;
    6835             : 
    6836             :         case command_line::command_build_and_install:
    6837           0 :             build_and_install(cl);
    6838           0 :             break;
    6839             : 
    6840             :         case command_line::command_canonicalize_version:
    6841           0 :             canonicalize_version(cl);
    6842           0 :             break;
    6843             : 
    6844             :         case command_line::command_cflags:
    6845           0 :             display_pkgconfig(cl, "Cflags", "cflags");
    6846           0 :             break;
    6847             : 
    6848             :         case command_line::command_check_install:
    6849           0 :             check_install(cl);
    6850           0 :             break;
    6851             : 
    6852             :         case command_line::command_compare_versions:
    6853         750 :             compare_versions(cl);
    6854           0 :             break;
    6855             : 
    6856             :         case command_line::command_compress:
    6857           0 :             compress(cl);
    6858           0 :             break;
    6859             : 
    6860             :         case command_line::command_configure:
    6861           0 :             configure(cl);
    6862           0 :             break;
    6863             : 
    6864             :         case command_line::command_contents:
    6865           0 :             contents(cl);
    6866           0 :             break;
    6867             : 
    6868             :         case command_line::command_control:
    6869           0 :             control(cl);
    6870           0 :             break;
    6871             : 
    6872             :         case command_line::command_copyright:
    6873           0 :             copyright(cl);
    6874           0 :             break;
    6875             : 
    6876             :         case command_line::command_create_admindir:
    6877          26 :             create_admindir(cl);
    6878          26 :             break;
    6879             : 
    6880             :         case command_line::command_create_database_lock:
    6881           0 :             create_database_lock(cl);
    6882           0 :             break;
    6883             : 
    6884             :         case command_line::command_create_index:
    6885           1 :             create_index(cl);
    6886           1 :             break;
    6887             : 
    6888             :         case command_line::command_database_is_locked:
    6889           0 :             database_is_locked(cl);
    6890           0 :             break;
    6891             : 
    6892             :         case command_line::command_decompress:
    6893           0 :             decompress(cl);
    6894           0 :             break;
    6895             : 
    6896             :         case command_line::command_deconfigure:
    6897           0 :             deconfigure(cl);
    6898           0 :             break;
    6899             : 
    6900             :         case command_line::command_directory_size:
    6901           0 :             directory_size(cl);
    6902           0 :             break;
    6903             : 
    6904             :         case command_line::command_exact_version:
    6905           0 :             exact_version(cl);
    6906           0 :             break;
    6907             : 
    6908             :         case command_line::command_extract:
    6909           0 :             extract(cl);
    6910           0 :             break;
    6911             : 
    6912             :         case command_line::command_field:
    6913           0 :             field(cl);
    6914           0 :             break;
    6915             : 
    6916             :         case command_line::command_fsys_tarfile:
    6917           0 :             fsys_tarfile(cl);
    6918           0 :             break;
    6919             : 
    6920             :         case command_line::command_increment_build_number:
    6921           0 :             increment_build_number(cl);
    6922           0 :             break;
    6923             : 
    6924             :         case command_line::command_info:
    6925           0 :             info(cl);
    6926           0 :             break;
    6927             : 
    6928             :         case command_line::command_install:
    6929         329 :             install(cl);
    6930         314 :             break;
    6931             : 
    6932             :         case command_line::command_install_size:
    6933           0 :             install_size(cl);
    6934           0 :             break;
    6935             : 
    6936             :         case command_line::command_is_installed:
    6937           0 :             is_installed(cl);
    6938           0 :             break;
    6939             : 
    6940             :         case command_line::command_libs:
    6941           0 :             display_pkgconfig(cl, "Libs", "libs");
    6942           0 :             break;
    6943             : 
    6944             :         case command_line::command_list:
    6945           0 :             list(cl);
    6946           0 :             break;
    6947             : 
    6948             :         case command_line::command_list_all:
    6949           0 :             list_all(cl);
    6950           0 :             break;
    6951             : 
    6952             :         case command_line::command_listfiles:
    6953           0 :             listfiles(cl);
    6954           0 :             break;
    6955             : 
    6956             :         case command_line::command_list_hooks:
    6957           2 :             list_hooks(cl);
    6958           2 :             break;
    6959             : 
    6960             :         case command_line::command_list_index_packages:
    6961           0 :             list_index_packages(cl);
    6962           0 :             break;
    6963             : 
    6964             :         case command_line::command_list_sources:
    6965           0 :             list_sources(cl);
    6966           0 :             break;
    6967             : 
    6968             :         case command_line::command_max_version:
    6969           0 :             max_version(cl);
    6970           0 :             break;
    6971             : 
    6972             :         case command_line::command_md5sums:
    6973           2 :             md5sums(cl);
    6974           2 :             break;
    6975             : 
    6976             :         case command_line::command_md5sums_check:
    6977           4 :             md5sums_check(cl);
    6978           4 :             break;
    6979             : 
    6980             :         case command_line::command_modversion:
    6981           0 :             display_pkgconfig(cl, "Version", "modversion");
    6982           0 :             break;
    6983             : 
    6984             :         case command_line::command_os:
    6985           0 :             os(cl);
    6986           0 :             break;
    6987             : 
    6988             :         case command_line::command_print_architecture:
    6989           0 :             print_architecture(cl);
    6990           0 :             break;
    6991             : 
    6992             :         case command_line::command_print_build_number:
    6993           0 :             print_build_number(cl);
    6994           0 :             break;
    6995             : 
    6996             :         case command_line::command_print_variables:
    6997           0 :             display_pkgconfig(cl, "*variables*", "print-variables");
    6998           0 :             break;
    6999             : 
    7000             :         case command_line::command_processor:
    7001           0 :             processor(cl);
    7002           0 :             break;
    7003             : 
    7004             :         case command_line::command_purge:
    7005          30 :             purge(cl);
    7006          30 :             break;
    7007             : 
    7008             :         case command_line::command_reconfigure:
    7009           0 :             reconfigure(cl);
    7010           0 :             break;
    7011             : 
    7012             :         case command_line::command_remove:
    7013          23 :             remove(cl);
    7014          23 :             break;
    7015             : 
    7016             :         case command_line::command_remove_database_lock:
    7017           0 :             remove_database_lock(cl);
    7018           0 :             break;
    7019             : 
    7020             :         case command_line::command_remove_hooks:
    7021           1 :             remove_hooks(cl);
    7022           1 :             break;
    7023             : 
    7024             :         case command_line::command_remove_sources:
    7025           0 :             remove_sources(cl);
    7026           0 :             break;
    7027             : 
    7028             :         case command_line::command_rollback:
    7029           0 :             rollback(cl);
    7030           0 :             break;
    7031             : 
    7032             :         case command_line::command_search:
    7033           0 :             search(cl);
    7034           0 :             break;
    7035             : 
    7036             :         case command_line::command_set_selection:
    7037           1 :             set_selection(cl);
    7038           1 :             break;
    7039             : 
    7040             :         case command_line::command_show:
    7041           0 :             show(cl);
    7042           0 :             break;
    7043             : 
    7044             :         case command_line::command_package_status:
    7045           0 :             package_status(cl);
    7046           0 :             break;
    7047             : 
    7048             :         case command_line::command_triplet:
    7049           0 :             triplet(cl);
    7050           0 :             break;
    7051             : 
    7052             :         case command_line::command_unpack:
    7053           0 :             unpack(cl);
    7054           0 :             break;
    7055             : 
    7056             :         case command_line::command_update:
    7057           0 :             update(cl);
    7058           0 :             break;
    7059             : 
    7060             :         case command_line::command_update_status:
    7061           0 :             update_status(cl);
    7062           0 :             break;
    7063             : 
    7064             :         case command_line::command_upgrade:
    7065           0 :             upgrade(cl);
    7066           0 :             break;
    7067             : 
    7068             :         case command_line::command_variable:
    7069           0 :             display_pkgconfig(cl, "*variable*", "variable");
    7070           0 :             break;
    7071             : 
    7072             :         case command_line::command_verify_control:
    7073           0 :             verify_control(cl);
    7074           0 :             break;
    7075             : 
    7076             :         case command_line::command_verify_project:
    7077           0 :             verify_project(cl);
    7078           0 :             break;
    7079             : 
    7080             :         case command_line::command_upgrade_info:
    7081           0 :             upgrade_info(cl);
    7082           0 :             break;
    7083             : 
    7084             :         case command_line::command_vendor:
    7085           0 :             vendor(cl);
    7086           0 :             break;
    7087             : 
    7088             :         default:
    7089           0 :             throw std::logic_error("internal error: unhandled command line function");
    7090             : 
    7091         734 :         }
    7092             :     }
    7093             :     // under windows the default for an exception is to be silent
    7094          15 :     catch(const std::exception& e)
    7095             :     {
    7096          15 :         if(log_ready)
    7097             :         {
    7098             :             wpkg_output::log("%1")
    7099          30 :                     .arg(e.what())
    7100          15 :                 .level(wpkg_output::level_fatal)
    7101          15 :                 .action("exception");
    7102             :         }
    7103             :         else
    7104             :         {
    7105           0 :             fprintf(stderr, "wpkg:error: %s\n", e.what());
    7106             :         }
    7107          15 :         wpkg_output::set_output(NULL);
    7108          15 :         exit(1);
    7109             :     }
    7110          15 :     catch(...)
    7111             :     {
    7112             :         // nothing to do here, we're just making sure we
    7113             :         // get a full stack unwinding effect for RAII
    7114           0 :         wpkg_output::set_output(NULL);
    7115           0 :         throw;
    7116             :     }
    7117             : 
    7118         719 :     wpkg_output::set_output(NULL);
    7119         719 :     return g_output.exit_code();
    7120        4455 : }
    7121             : 
    7122             : #if defined(MO_WINDOWS) && !defined(MO_MINGW32)
    7123             : int wmain(int argc, wchar_t *wargv[])
    7124             : {
    7125             :     // transform the wchar_t strings to UTF-8 strings
    7126             :     std::vector<std::string> args;
    7127             :     for(int i(0); i < argc; ++i)
    7128             :     {
    7129             :         std::string s(libutf8::wcstombs(wargv[i]));
    7130             :         args.push_back(s);
    7131             :     }
    7132             :     //
    7133             :     // *** WARNING ***
    7134             :     // DO NOT MERGE THESE TWO LOOPS!!!
    7135             :     // *** WARNING ***
    7136             :     //
    7137             :     // the reason for the separation is because the push_back() may reallocate
    7138             :     // the buffer and as a result may move the string pointers; once the vector
    7139             :     // is complete, however, the strings won't move anymore so we can go ahead
    7140             :     // and create an array of char * from the std::string
    7141             :     //
    7142             :     std::vector<char *> argv;
    7143             :     for(int i(0); i < argc; ++i)
    7144             :     {
    7145             :         // we use const char here because we do not want to
    7146             :         // use char const * const * argv for utf8_main()
    7147             :         // (because it makes things more complicated than necessary)
    7148             :         argv.push_back(const_cast<char *>(args[i].c_str()));
    7149             :     }
    7150             :     argv.push_back(NULL);
    7151             :     return utf8_main(argc, &argv[0]);
    7152             : }
    7153             : #endif
    7154             : 
    7155             : #ifdef MO_MINGW32
    7156             : int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR lpCmdLine, int nCmdShow)
    7157             : {
    7158             :     int argc;
    7159             :     LPWSTR *wargv(CommandLineToArgvW(GetCommandLineW(), &argc));
    7160             : 
    7161             :     // transform the wchar_t strings to UTF-8 strings
    7162             :     std::vector<std::string> args;
    7163             :     for(int i(0); i < argc; ++i)
    7164             :     {
    7165             :         std::string s(libutf8::wcstombs(wargv[i]));
    7166             :         args.push_back(s);
    7167             :     }
    7168             :     //
    7169             :     // *** WARNING ***
    7170             :     // DO NOT MERGE THESE TWO LOOPS!!!
    7171             :     // *** WARNING ***
    7172             :     //
    7173             :     // the reason for the separation is because the push_back() may reallocate
    7174             :     // the buffer and as a result may move the string pointers; once the vector
    7175             :     // is complete, however, the strings won't move anymore so we can go ahead
    7176             :     // and create an array of char * from the std::string
    7177             :     //
    7178             :     std::vector<char *> argv;
    7179             :     for(int i(0); i < argc; ++i)
    7180             :     {
    7181             :         // we use const char here because we do not want to
    7182             :         // use char const * const * argv for utf8_main()
    7183             :         // (because it makes things more complicated than necessary)
    7184             :         argv.push_back(const_cast<char *>(args[i].c_str()));
    7185             :     }
    7186             :     argv.push_back(NULL);
    7187             :     return utf8_main(argc, &argv[0]);
    7188             : }
    7189             : #endif
    7190             : 
    7191             : 
    7192             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.9

The wpkg tool is an open source tool created by Made to Order Software Corporation.