# HG changeset patch # User jlarmour # Date 962382455 0 # Node ID 5a0cc6c243a9029e4d3ec9754e3656ef3e984c7d # Parent ad66e26a9e7c2f405953af37767386b3f2507f6c Merge from eCos master repository on 2000-06-30-08:18:49-BST diff --git a/host/libcdl/ChangeLog b/host/libcdl/ChangeLog --- a/host/libcdl/ChangeLog +++ b/host/libcdl/ChangeLog @@ -1,3 +1,17 @@ +2000-06-28 Bart Veer + + * transact.cxx, cdlcore.hxx: + Add details of the current transaction to the transaction callback + class. Previously there was no way of getting hold of the current + transaction and hence the toplevel from inside the callback + without using statics. + + * value.cxx (set_flavor): + Temporarily undo some of the previous value clean-ups, they were + causing problems at the application level. The API needs to be + changed to eliminate confusion between value and the data part + of a bool/value pair. + 2000-06-22 Bart Veer * value.cxx, interface.cxx: diff --git a/host/libcdl/TODO b/host/libcdl/TODO --- a/host/libcdl/TODO +++ b/host/libcdl/TODO @@ -18,6 +18,10 @@ 4) get limbo working 5) make cdl_interfaces into containers? How about cdl_options as well, to avoid reparenting problems? + cdl_interfaces as containers is actually a problem because interfaces + are part of the core, and hence do not know about the existence of + options and components. + 6) allow components and options to be used interchangeably in savefiles. 7) ecosconfig, create a paths file with details of the source tree @@ -156,6 +160,9 @@ 12) header file dependencies. From Jespe 13) friend packages, allowing one package to see the implementation details of another. Also, handle documentation links between these. +14) API clean-up. Eliminate the confusion between "value" and the data part of + a bool/data pair. + Major ----- diff --git a/host/libcdl/cdlcore.hxx b/host/libcdl/cdlcore.hxx --- a/host/libcdl/cdlcore.hxx +++ b/host/libcdl/cdlcore.hxx @@ -4656,11 +4656,16 @@ class CdlTransactionCallback { friend class CdlTransactionBody; public: - CdlTransactionCallback(); ~CdlTransactionCallback(); static void (*get_callback_fn())(const CdlTransactionCallback&); static void set_callback_fn(void (*)(const CdlTransactionCallback&)); + // Callback functions should be able to retrieve information + // about the current transaction and toplevel, to avoid the use + // of statics. + CdlTransaction get_transaction() const; + CdlToplevel get_toplevel() const; + // active_changes and legal_values_changes get updated as the // transaction proceeds, so a set implementation is more // efficient. The others get filled in during a commit operation. @@ -4681,7 +4686,12 @@ class CdlTransactionCallback { protected: private: - + CdlTransactionCallback(CdlTransaction); + CdlTransaction transact; + + // Illegal operation. + CdlTransactionCallback(); + enum { CdlTransactionCallback_Invalid = 0, CdlTransactionCallback_Magic = 0x0cec3a95 diff --git a/host/libcdl/transact.cxx b/host/libcdl/transact.cxx --- a/host/libcdl/transact.cxx +++ b/host/libcdl/transact.cxx @@ -66,12 +66,14 @@ // The callback class is very straightforward. The hard work is done in // the transaction class. -CdlTransactionCallback::CdlTransactionCallback() +CdlTransactionCallback::CdlTransactionCallback(CdlTransaction transact_arg) { CYG_REPORT_FUNCNAME("CdlTransactionCallback:: constructor"); - CYG_REPORT_FUNCARG1XV(this); - + CYG_REPORT_FUNCARG2XV(this, transact_arg); + CYG_PRECONDITION_CLASSC(transact_arg); + // The vectors etc. will take care of themselves. + transact = transact_arg; cdltransactioncallback_cookie = CdlTransactionCallback_Magic; CYG_POSTCONDITION_THISC(); @@ -85,6 +87,7 @@ CdlTransactionCallback::~CdlTransactionC CYG_PRECONDITION_THISC(); cdltransactioncallback_cookie = CdlTransactionCallback_Invalid; + transact = 0; value_changes.clear(); active_changes.clear(); legal_values_changes.clear(); @@ -118,6 +121,32 @@ void (*CdlTransactionCallback::get_callb return result; } +CdlTransaction +CdlTransactionCallback::get_transaction() const +{ + CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_transaction", "result %p"); + CYG_PRECONDITION_THISC(); + + CdlTransaction result = transact; + CYG_POSTCONDITION_CLASSC(result); + + CYG_REPORT_RETVAL(result); + return result; +} + +CdlToplevel +CdlTransactionCallback::get_toplevel() const +{ + CYG_REPORT_FUNCNAMETYPE("CdlTransactionCallback::get_toplevel", "result %p"); + CYG_PRECONDITION_THISC(); + + CdlToplevel result = transact->get_toplevel(); + CYG_POSTCONDITION_CLASSC(result); + + CYG_REPORT_RETVAL(result); + return result; +} + bool CdlTransactionCallback::check_this(cyg_assert_class_zeal zeal) const { @@ -1953,7 +1982,6 @@ CdlTransactionBody::commit() CYG_LOOP_INVARIANT_CLASSC(map_i->first); CYG_LOOP_INVARIANT_CLASSOC(map_i->second); parent->changes[map_i->first] = map_i->second; - for (conf_i = parent->new_conflicts.begin(); conf_i != parent->new_conflicts.end(); conf_i++) { CYG_LOOP_INVARIANT_CLASSC(*conf_i); (*conf_i)->update_solution_validity(map_i->first); @@ -2035,11 +2063,10 @@ CdlTransactionBody::commit() // should happen before any conflicts get deleted. The actual callback // is invoked at the end, once all the changes have been moved to // the toplevel. - CdlTransactionCallback all_changes; + CdlTransactionCallback all_changes(this); if (0 != callback_fn) { for (map_i = changes.begin(); map_i != changes.end(); map_i++) { - if (0 == map_i->first->get_toplevel()) { continue; } diff --git a/host/libcdl/value.cxx b/host/libcdl/value.cxx --- a/host/libcdl/value.cxx +++ b/host/libcdl/value.cxx @@ -902,7 +902,16 @@ CdlValue::set_flavor(CdlValueFlavor flav enabled[CdlValueSource_Wizard] = false; enabled[CdlValueSource_User] = false; + // BLV - keep the data part at 0 for now. There is too + // much confusion in the code between value as a string + // representation, and value as the data part of the + // bool/data pair. This needs to be fixed, but it requires + // significant API changes. +#if 0 CdlSimpleValue simple_val(cdl_int(1)); +#else + CdlSimpleValue simple_val(cdl_int(0)); +#endif values[CdlValueSource_Default] = simple_val; values[CdlValueSource_Inferred] = simple_val; values[CdlValueSource_Wizard] = simple_val; diff --git a/host/tools/configtool/ChangeLog b/host/tools/configtool/ChangeLog --- a/host/tools/configtool/ChangeLog +++ b/host/tools/configtool/ChangeLog @@ -1,3 +1,10 @@ +2000-06-27 John Dallaway + + * standalone/win32/Configtool.rc: + + Update menu item text: + "eCos Services Page" -> "eCos Product Page". + 2000-06-22 John Dallaway * standalone/common/cdl_exec.cxx: diff --git a/host/tools/configtool/standalone/common/ChangeLog b/host/tools/configtool/standalone/common/ChangeLog --- a/host/tools/configtool/standalone/common/ChangeLog +++ b/host/tools/configtool/standalone/common/ChangeLog @@ -1,3 +1,8 @@ +2000-06-28 Bart Veer + + * cdl_exec.cxx, cdl_exec.hxx, ecosconfig.cxx: + Fix up the reporting of conflicts, inference engine changes, etc. + 2000-04-10 Bart Veer * cdl_exec.cxx: diff --git a/host/tools/configtool/standalone/common/cdl_exec.cxx b/host/tools/configtool/standalone/common/cdl_exec.cxx --- a/host/tools/configtool/standalone/common/cdl_exec.cxx +++ b/host/tools/configtool/standalone/common/cdl_exec.cxx @@ -39,470 +39,747 @@ //========================================================================== #ifdef _MSC_VER - #include /* for getcwd() */ +#include /* for getcwd() */ #else - #include /* for getcwd() */ +#include /* for getcwd() */ #endif #ifdef __CYGWIN__ - #include /* for cygwin_conv_to_win32_path() */ +#include +#include /* for cygwin_conv_to_win32_path() */ #endif #include "build.hxx" #include "cdl_exec.hxx" -cdl_exec::cdl_exec (const std::string repository_tree, const std::string savefile_name, const std::string install_tree, bool no_resolve) : - pkgdata (NULL), - interp (NULL), - config (NULL) { - repository = repository_tree; - savefile = savefile_name; - install_prefix = install_tree; - CdlTransactionBody::set_inference_callback_fn (&inference_callback); - if (no_resolve) { - CdlTransactionBody::disable_automatic_inference (); - } +// ---------------------------------------------------------------------------- +bool cdl_exec::quiet = false; +bool cdl_exec::verbose = false; +bool cdl_exec::ignore_errors = false; + +cdl_exec::cdl_exec (const std::string repository_arg, const std::string savefile_arg, + const std::string install_arg, bool no_resolve_arg) + : repository(repository_arg), + savefile(savefile_arg), + install_prefix(install_arg), + no_resolve(no_resolve_arg), + pkgdata (NULL), + interp (NULL), + config (NULL) +{ + + // The inference callback does not actually do anything at present. + // In future it may be useful for diagnostic purposes. + CdlTransactionBody::set_inference_callback_fn (&inference_callback); + + // Automatic inference is always disabled. The inference engine + // only gets invoked explicitly, after a suitable transaction callback + // has been invoked. The problem here is that the transaction callback + // has to report changes made by the inference engine but there is + // no way of distinguishing between inferred values that come out of + // savefiles and inferred values determined by the inference engine. + CdlTransactionBody::disable_automatic_inference (); } -bool cdl_exec::cmd_new (const std::string cdl_hardware, const std::string cdl_template /* = "default" */, const std::string cdl_version /* = "" */) { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::make ("eCos", pkgdata, interp); - config->set_hardware (resolve_hardware_alias (cdl_hardware), &diagnostic_handler, &diagnostic_handler); - if (pkgdata->is_known_template (cdl_template) && ! cdl_version.empty ()) { - const std::vector & versions = pkgdata->get_template_versions (cdl_template); - if (versions.end () == std::find (versions.begin (), versions.end (), cdl_version)) { - throw CdlStringException ("Unknown version " + cdl_version); - } - } - config->set_template (cdl_template, cdl_version, &diagnostic_handler, &diagnostic_handler); - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } +void +cdl_exec::set_quiet_mode(bool new_val) +{ + quiet = new_val; +} + +void +cdl_exec::set_verbose_mode(bool new_val) +{ + verbose = new_val; +} - delete_cdl_data (); - return status; +void +cdl_exec::set_ignore_errors_mode(bool new_val) +{ + ignore_errors = new_val; +} + +// ---------------------------------------------------------------------------- +void +cdl_exec::init(bool load_config) +{ + pkgdata = CdlPackagesDatabaseBody::make(repository, &diagnostic_handler, &diagnostic_handler); + interp = CdlInterpreterBody::make(); + if (load_config) { + config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); + } } -bool cdl_exec::cmd_target (const std::string cdl_target) { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - config->set_hardware (resolve_hardware_alias (cdl_target), &diagnostic_handler, &diagnostic_handler); - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } - - delete_cdl_data (); - return status; +// ---------------------------------------------------------------------------- +void +cdl_exec::delete_cdl_data () +{ + if (0 != config) { + delete config; + config = 0; + } + if (0 != interp) { + delete interp; + interp = 0; + } + if (0 != pkgdata) { + delete pkgdata; + pkgdata = 0; + } } -bool cdl_exec::cmd_template (const std::string cdl_template, const std::string cdl_version /* = "" */) { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - if (pkgdata->is_known_template (cdl_template) && ! cdl_version.empty ()) { - const std::vector & versions = pkgdata->get_template_versions (cdl_template); - if (versions.end () == std::find (versions.begin (), versions.end (), cdl_version)) { - throw CdlStringException ("Unknown version " + cdl_version); - } - } - config->set_template (cdl_template, cdl_version, &diagnostic_handler, &diagnostic_handler); - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } +// ---------------------------------------------------------------------------- +bool cdl_exec::cmd_new (const std::string cdl_hardware, + const std::string cdl_template /* = "default" */, + const std::string cdl_version /* = "" */) +{ + bool status = false; + try { + init(false); + + config = CdlConfigurationBody::make ("eCos", pkgdata, interp); + + // The hardware and template should be loaded in a single transaction. + // Validating the target name etc. can be left to libcdl. + CdlTransaction transact = CdlTransactionBody::make(config); + config->set_hardware(transact, resolve_hardware_alias(cdl_hardware), &diagnostic_handler, &diagnostic_handler); + config->set_template(transact, cdl_template, cdl_version, &diagnostic_handler, &diagnostic_handler); + transact->body(); + delete transact; + + // Unless inference has been suppressed, make sure that the + // inference engine gets invoked and that its results get + // reported. + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } - delete_cdl_data (); - return status; + // Now report any conflicts which the inference engine could not report. + report_conflicts(); + + // A savefile should be generated/updated even if there are conflicts. + // Otherwise the user does not have a chance to edit the savefile + // and fix things. + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } + + delete_cdl_data (); + return status; +} + +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_target (const std::string cdl_target) +{ + bool status = false; + try { + init(true); + config->set_hardware (resolve_hardware_alias (cdl_target), &diagnostic_handler, &diagnostic_handler); + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } + + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_export (const std::string cdl_savefile) { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - config->save (cdl_savefile, /* minimal = */ true); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_template (const std::string cdl_template, const std::string cdl_version /* = "" */) +{ + bool status = false; + try { + init(true); + config->set_template (cdl_template, cdl_version, &diagnostic_handler, &diagnostic_handler); + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - delete_cdl_data (); - return status; + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_import (const std::string cdl_savefile) { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - config->add (cdl_savefile, &diagnostic_handler, &diagnostic_handler); - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_export (const std::string cdl_savefile) +{ + bool status = false; + try { + init(true); + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + // Exporting to another file should only happen if the + // configuration is conflict-free. This is different from + // updating the savefile. + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + config->save (cdl_savefile, /* minimal = */ true); + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - delete_cdl_data (); - return status; + delete_cdl_data (); + return status; +} + +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_import (const std::string cdl_savefile) +{ + bool status = false; + try { + init(true); + config->add(cdl_savefile, &diagnostic_handler, &diagnostic_handler); + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } + + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_add (const std::vector cdl_packages) { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - for (unsigned int n = 0; n < cdl_packages.size (); n++) { - config->load_package (resolve_package_alias (cdl_packages [n]), "", &diagnostic_handler, &diagnostic_handler); - } - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_add (const std::vector cdl_packages) +{ + bool status = false; + try { + init(true); + for (unsigned int n = 0; n < cdl_packages.size (); n++) { + config->load_package (resolve_package_alias (cdl_packages [n]), "", &diagnostic_handler, &diagnostic_handler); + } + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - delete_cdl_data (); - return status; + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_remove (const std::vector cdl_packages) { - unsigned int n; - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - for (n = 0; n < cdl_packages.size (); n++) { - if (! config->lookup (resolve_package_alias (cdl_packages [n]))) { - throw CdlStringException ("Unknown package " + cdl_packages [n]); - } - } - for (n = 0; n < cdl_packages.size (); n++) { - config->unload_package (resolve_package_alias (cdl_packages [n])); - } - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_remove (const std::vector cdl_packages) +{ + unsigned int n; + bool status = false; + try { + init(true); + for (n = 0; n < cdl_packages.size (); n++) { + if (! config->lookup (resolve_package_alias (cdl_packages [n]))) { + throw CdlStringException ("Unknown package " + cdl_packages [n]); + } + } + for (n = 0; n < cdl_packages.size (); n++) { + config->unload_package (resolve_package_alias (cdl_packages [n])); + } + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - delete_cdl_data (); - return status; + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_version (const std::string cdl_version, const std::vector cdl_packages) { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - for (unsigned int n = 0; n < cdl_packages.size (); n++) { - config->change_package_version (resolve_package_alias (cdl_packages [n]), cdl_version, &diagnostic_handler, &diagnostic_handler, true); - } - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_version (const std::string cdl_version, const std::vector cdl_packages) +{ + bool status = false; + try { + init(true); + for (unsigned int n = 0; n < cdl_packages.size (); n++) { + config->change_package_version(resolve_package_alias (cdl_packages [n]), cdl_version, + &diagnostic_handler, &diagnostic_handler, true); + } + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - delete_cdl_data (); - return status; + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_tree () { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_tree () +{ + bool status = false; + try { + init(true); + if (!no_resolve) { + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts(); + } + report_conflicts(); + config->save (savefile); + // A build tree should only be generated if there are no conflicts. + if (ignore_errors || (0 == config->get_all_conflicts().size())) { #ifdef _MSC_VER - char cwd [_MAX_PATH + 1]; + char cwd [_MAX_PATH + 1]; #else - char cwd [PATH_MAX + 1]; + char cwd [PATH_MAX + 1]; #endif - getcwd (cwd, sizeof cwd); + getcwd (cwd, sizeof cwd); #ifdef __CYGWIN__ - char cwd_win32 [MAXPATHLEN + 1]; - cygwin_conv_to_win32_path (cwd, cwd_win32); - generate_build_tree (config, cwd_win32, install_prefix); + char cwd_win32 [MAXPATHLEN + 1]; + cygwin_conv_to_win32_path (cwd, cwd_win32); + generate_build_tree (config, cwd_win32, install_prefix); #else - generate_build_tree (config, cwd, install_prefix); + generate_build_tree (config, cwd, install_prefix); #endif - config->generate_config_headers (install_prefix.empty () ? "install/include/pkgconf" : install_prefix + "/include/pkgconf"); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } + config->generate_config_headers (install_prefix.empty () ? "install/include/pkgconf" : install_prefix + "/include/pkgconf"); + status = true; + } else { + printf("\nUnable to generate build tree, this configuration still contains conflicts.\n"); + printf("Either resolve the conflicts or use --ignore-errors\n"); + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - delete_cdl_data (); - return status; + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_list () { - bool status = false; - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_list () +{ + bool status = false; + try { + init(false); - // list the installed packages - std::vector packages = pkgdata->get_packages (); - std::sort (packages.begin (), packages.end ()); - for (unsigned int package = 0; package < packages.size (); package++) { - const std::vector & aliases = pkgdata->get_package_aliases (packages [package]); - printf ("Package %s (%s):\n aliases:", packages [package].c_str (), aliases [0].c_str ()); - for (unsigned int alias = 1; alias < aliases.size (); alias++) { - printf (" %s", aliases [alias].c_str ()); - } - const std::vector & versions = pkgdata->get_package_versions (packages [package]); - printf ("\n versions:"); - for (unsigned int version = 0; version < versions.size (); version++) { - printf (" %s", versions [version].c_str ()); - } - printf ("\n"); - } + // list the installed packages + std::vector packages = pkgdata->get_packages (); + std::sort (packages.begin (), packages.end ()); + for (unsigned int package = 0; package < packages.size (); package++) { + const std::vector & aliases = pkgdata->get_package_aliases (packages [package]); + printf ("Package %s (%s):\n aliases:", packages [package].c_str (), aliases [0].c_str ()); + for (unsigned int alias = 1; alias < aliases.size (); alias++) { + printf (" %s", aliases [alias].c_str ()); + } + const std::vector & versions = pkgdata->get_package_versions (packages [package]); + printf ("\n versions:"); + for (unsigned int version = 0; version < versions.size (); version++) { + printf (" %s", versions [version].c_str ()); + } + printf ("\n"); + } - // list the available targets - std::vector targets = pkgdata->get_targets (); - std::sort (targets.begin (), targets.end ()); - for (unsigned int target = 0; target < targets.size (); target++) { - const std::vector & aliases = pkgdata->get_target_aliases (targets [target]); - printf ("Target %s (%s):\n aliases:", targets [target].c_str (), aliases [0].c_str ()); - for (unsigned int alias = 1; alias < aliases.size (); alias++) { - printf (" %s", aliases [alias].c_str ()); - } - printf ("\n"); - } + // list the available targets + std::vector targets = pkgdata->get_targets (); + std::sort (targets.begin (), targets.end ()); + for (unsigned int target = 0; target < targets.size (); target++) { + const std::vector & aliases = pkgdata->get_target_aliases (targets [target]); + printf ("Target %s (%s):\n aliases:", targets [target].c_str (), aliases [0].c_str ()); + for (unsigned int alias = 1; alias < aliases.size (); alias++) { + printf (" %s", aliases [alias].c_str ()); + } + printf ("\n"); + } - // list the available templates - std::vector templates = pkgdata->get_templates (); - std::sort (templates.begin (), templates.end ()); - for (unsigned int templ = 0; templ < templates.size (); templ++) { - const std::vector & versions = pkgdata->get_template_versions (templates [templ]); - printf ("Template %s:\n versions:", templates [templ].c_str ()); - for (unsigned int version = 0; version < versions.size (); version++) { - printf (" %s", versions [version].c_str ()); - } - printf ("\n"); - } + // list the available templates + std::vector templates = pkgdata->get_templates (); + std::sort (templates.begin (), templates.end ()); + for (unsigned int templ = 0; templ < templates.size (); templ++) { + const std::vector & versions = pkgdata->get_template_versions (templates [templ]); + printf ("Template %s:\n versions:", templates [templ].c_str ()); + for (unsigned int version = 0; version < versions.size (); version++) { + printf (" %s", versions [version].c_str ()); + } + printf ("\n"); + } - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } + status = true; + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - delete_cdl_data (); - return status; + delete_cdl_data (); + return status; } -bool cdl_exec::cmd_check () { - bool status = false; - unsigned int n; +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_check () +{ + bool status = false; + unsigned int n; - try { - CdlTransactionBody::disable_automatic_inference (); - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - config->save (savefile); // tidy up any manual edits + try { + init(true); + // check() should never invoke the inference engine. The user + // wants to determine the current status, which should not + // change. + // However, updating the savefile is worthwhile because it + // will now contain more accurate information about the state. + config->save (savefile); + + // report current target and template + printf ("Target: %s\n", config->get_hardware ().c_str ()); + printf ("Template: %s\n", config->get_template ().c_str ()); + std::vector template_packages = pkgdata->get_template_packages (config->get_template ()); + const std::vector & hardware_packages = pkgdata->get_target_packages (config->get_hardware ()); + for (n = 0; n < hardware_packages.size (); n++) { + template_packages.push_back (hardware_packages [n]); + } - // report current target and template - printf ("Target: %s\n", config->get_hardware ().c_str ()); - printf ("Template: %s\n", config->get_template ().c_str ()); - std::vector template_packages = pkgdata->get_template_packages (config->get_template ()); - const std::vector & hardware_packages = pkgdata->get_target_packages (config->get_hardware ()); - for (n = 0; n < hardware_packages.size (); n++) { - template_packages.push_back (hardware_packages [n]); - } + // report loaded packages not in the templates + const std::vector & loadables = config->get_loadables (); + std::vector added_packages; + std::vector::const_iterator loadable_i; + for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) { + const CdlNode & node = dynamic_cast (* loadable_i); + if (template_packages.end () == std::find (template_packages.begin (), template_packages.end (), node->get_name ())) { + added_packages.push_back (node->get_name ()); + } + } + if (added_packages.size ()) { + printf ("Added:\n"); + } + for (n = 0; n < added_packages.size (); n++) { + printf (" %s\n", added_packages [n].c_str ()); + } - // report loaded packages not in the templates - const std::vector & loadables = config->get_loadables (); - std::vector added_packages; - std::vector::const_iterator loadable_i; - for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) { - const CdlNode & node = dynamic_cast (* loadable_i); - if (template_packages.end () == std::find (template_packages.begin (), template_packages.end (), node->get_name ())) { - added_packages.push_back (node->get_name ()); - } - } - if (added_packages.size ()) { - printf ("Added:\n"); - } - for (n = 0; n < added_packages.size (); n++) { - printf (" %s\n", added_packages [n].c_str ()); - } + // report template packages not in the configuration + std::vector removed_packages; + for (n = 0; n < template_packages.size (); n++) { + if (! config->lookup (template_packages [n])) { + removed_packages.push_back (template_packages [n]); + } + } + if (removed_packages.size ()) { + printf ("Removed:\n"); + } + for (n = 0; n < removed_packages.size (); n++) { + printf (" %s\n", removed_packages [n].c_str ()); + } - // report template packages not in the configuration - std::vector removed_packages; - for (n = 0; n < template_packages.size (); n++) { - if (! config->lookup (template_packages [n])) { - removed_packages.push_back (template_packages [n]); - } - } - if (removed_packages.size ()) { - printf ("Removed:\n"); - } - for (n = 0; n < removed_packages.size (); n++) { - printf (" %s\n", removed_packages [n].c_str ()); - } + // report packages of non-default version + std::vector version_packages; + for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) { + const CdlValuable & valuable = dynamic_cast (* loadable_i); + if (pkgdata->get_package_versions (valuable->get_name ()) [0] != valuable->get_value ()) { + version_packages.push_back (valuable); + } + } + if (version_packages.size ()) { + printf ("Version(s):\n"); + } + for (n = 0; n < version_packages.size (); n++) { + printf (" %s %s\n", version_packages [n]->get_name ().c_str (), version_packages [n]->get_value ().c_str ()); + } + + // report conflicts + const std::list & conflicts = config->get_all_conflicts (); + if (conflicts.size ()) { + printf ("%u conflict(s):\n", conflicts.size ()); + } else { + printf ("No conflicts\n"); + } + report_conflicts(); + + status = true; + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } + + delete_cdl_data (); + return status; +} - // report packages of non-default version - std::vector version_packages; - for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) { - const CdlValuable & valuable = dynamic_cast (* loadable_i); - if (pkgdata->get_package_versions (valuable->get_name ()) [0] != valuable->get_value ()) { - version_packages.push_back (valuable); - } - } - if (version_packages.size ()) { - printf ("Version(s):\n"); - } - for (n = 0; n < version_packages.size (); n++) { - printf (" %s %s\n", version_packages [n]->get_name ().c_str (), version_packages [n]->get_value ().c_str ()); - } +// ---------------------------------------------------------------------------- +bool +cdl_exec::cmd_resolve () +{ + bool status = false; - // report conflicts - const std::list & conflicts = config->get_all_conflicts (); - if (conflicts.size ()) { - printf ("%u conflict(s):\n", conflicts.size ()); - } else { - printf ("No conflicts\n"); - } - std::list::const_iterator conf_i; - for (conf_i = conflicts.begin (); conf_i != conflicts.end (); conf_i++) { // for each conflict - report_conflict (* conf_i); - } + try { + init(true); + CdlTransactionBody::set_callback_fn(&transaction_callback); + config->resolve_all_conflicts (); + report_conflicts(); + config->save (savefile); + if (ignore_errors || (0 == config->get_all_conflicts().size())) { + status = true; + } + } catch (CdlStringException exception) { + exception_handler (exception); + } catch (...) { + exception_handler (); + } - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } + delete_cdl_data (); + return status; +} - delete_cdl_data (); - return status; +// ---------------------------------------------------------------------------- +// The inference callback. This could give some useful diagnostics, or it +// could do useful things when running in some interactive mode. In batch +// mode it should not do anything. + +CdlInferenceCallbackResult +cdl_exec::inference_callback (CdlTransaction transaction) +{ + return CdlInferenceCallbackResult_Continue; } -bool cdl_exec::cmd_resolve () { - bool status = false; - - try { - pkgdata = CdlPackagesDatabaseBody::make (repository, &diagnostic_handler, &diagnostic_handler); - interp = CdlInterpreterBody::make (); - config = CdlConfigurationBody::load (savefile, pkgdata, interp, &diagnostic_handler, &diagnostic_handler); - config->resolve_all_conflicts (); - config->save (savefile); - status = true; - } catch (CdlStringException exception) { - exception_handler (exception); - } catch (...) { - exception_handler (); - } - - delete_cdl_data (); - return status; +// ---------------------------------------------------------------------------- +// Output a message with indentation after newlines. +static void +dump_string(unsigned int indent, const std::string& str) +{ + bool newline_pending = false; + unsigned int i, j; + for (i = 0; i < str.size(); i++) { + if (newline_pending) { + putchar('\n'); + if ('\n' != str[i]) { + for (j = 0; j < indent; j++) { + putchar(' '); + } + } + newline_pending = false; + } + if ('\n' == str[i]) { + newline_pending = true; + } else { + putchar(str[i]); + } + } + if (newline_pending) { + putchar('\n'); // But not the indentation. + } } -CdlInferenceCallbackResult cdl_exec::inference_callback (CdlTransaction transaction) { - const std::vector & resolved_conflicts = transaction->get_resolved_conflicts (); +// ---------------------------------------------------------------------------- +// The transaction callback. This should report any changes that have been +// made to the configuration. The amount of output depends on the verbosity +// level selected by the user. +// +// 1) quiet - no output at all +// 2) default - list updates done by the inference engine. +// 3) verbose - this does not currently add anything. +// +// There is no reporting of new or resolved conflicts. Resolved +// conflicts are probably of no interest in batch mode. New conflicts +// will be handled by report_conflicts(). There is also no information +// given about active state changes, although arguably there should be +// especially in the case of containers. - // report resolved conflicts - if (resolved_conflicts.size ()) { - printf ("%u conflict(s) resolved:\n", resolved_conflicts.size ()); - } - for (unsigned int n = 0; n < resolved_conflicts.size (); n++) { - report_conflict (resolved_conflicts [n]); - } +void +cdl_exec::transaction_callback(const CdlTransactionCallback& callback_data) +{ + if (quiet) { + return; + } - // accept all changes - return CdlInferenceCallbackResult_Continue; + unsigned int i; + for (i = 0; i < callback_data.value_changes.size(); i++) { + CdlValuable valuable = callback_data.value_changes[i]; + if (CdlValueSource_Inferred == valuable->get_source()) { + std::string msg = std::string("U ") + valuable->get_name() + ", new inferred value "; + std::string value = valuable->get_value(); + if ("" == value) { + msg += "\"\""; + } else { + msg += value; + } + msg += "\n"; + dump_string(4, msg); + } + } } -void cdl_exec::report_conflict (CdlConflict conflict) { - printf (" %s:\n %s\n", conflict->get_node ()->get_name ().c_str (), conflict->get_explanation ().c_str ()); +// ---------------------------------------------------------------------------- +// Report the remaining conflicts in the configuration. These indicate +// problems that the user should fix before going further with the +// configuration, e.g. before generating a build tree. +// +// Quiet verbosity level has no effect on this, but at the verbose level +// it is a good idea to look for a possible solution to the conflict. + + +void +cdl_exec::report_conflicts() +{ + const std::list& all_conflicts = config->get_all_conflicts(); + std::list::const_iterator conf_i; + for (conf_i = all_conflicts.begin(); conf_i != all_conflicts.end(); conf_i++) { + CdlNode node = (*conf_i)->get_node(); + + std::string msg = std::string("C ") + node->get_name() + ", " + (*conf_i)->get_explanation() + "\n"; + dump_string(2, msg); + + if (verbose && (*conf_i)->resolution_implemented()) { + // See if there is a possible solution to this conflict. + // This involves creating a transaction, invoking the + // inference engine, and cancelling the transaction + // (thus making sure that nothing actually changes). + // + // NOTE: at some stage libcdl may keep track of solutions + // globally. However, although it will know when a solution + // becomes invalid it will not necessarily try to resolve + // all global conflicts after every change, so attempting + // to do this in a transaction may still be necessary. + CdlTransaction transact = CdlTransactionBody::make(config); + transact->resolve(*conf_i); + if ((*conf_i)->has_known_solution()) { + std::string soln_msg = " Possible solution:\n"; + const std::vector > & soln = (*conf_i)->get_solution(); + unsigned int i; + for (i = 0; i < soln.size(); i++) { + soln_msg += soln[i].first->get_name() + " -> " + soln[i].second.get_value() + "\n"; + } +#if 0 + // FIXME: currently this member only works for nested sub-transactions. + if (transact->user_confirmation_required()) { + msg += "This change affects previous user settings.\n"; + } +#endif + dump_string(4, soln_msg); + } + transact->cancel(); + delete transact; + } + } } -void cdl_exec::diagnostic_handler (std::string message) { - printf ("%s\n", message.c_str ()); +// ---------------------------------------------------------------------------- +void +cdl_exec::diagnostic_handler (std::string message) +{ + printf ("%s\n", message.c_str ()); } void cdl_exec::exception_handler (CdlStringException exception) { - printf ("%s\n", exception.get_message ().c_str ()); -} - -void cdl_exec::exception_handler () { - printf ("Unknown error\n"); + printf ("%s\n", exception.get_message ().c_str ()); } -void cdl_exec::delete_cdl_data () { - delete config; - config = NULL; - delete interp; - interp = NULL; - delete pkgdata; - pkgdata = NULL; +void +cdl_exec::exception_handler () +{ + printf ("Unknown error\n"); } -std::string cdl_exec::resolve_package_alias (const std::string alias) { - std::string package = alias; + +// ---------------------------------------------------------------------------- +std::string +cdl_exec::resolve_package_alias (const std::string alias) +{ + std::string package = alias; - if (! pkgdata->is_known_package (alias)) { // if the alias is not a package name - const std::vector & packages = pkgdata->get_packages (); // get packages - for (unsigned int n = 0; n < packages.size (); n++) { // for each package - const std::vector & aliases = pkgdata->get_package_aliases (packages [n]); // get package aliases - if (aliases.end () != std::find (aliases.begin (), aliases.end (), alias)) { // if alias is found - package = packages [n]; // note the package - break; - } - } - } - return package; + if (! pkgdata->is_known_package (alias)) { // if the alias is not a package name + const std::vector & packages = pkgdata->get_packages (); // get packages + for (unsigned int n = 0; n < packages.size (); n++) { // for each package + const std::vector & aliases = pkgdata->get_package_aliases (packages [n]); // get package aliases + if (aliases.end () != std::find (aliases.begin (), aliases.end (), alias)) { // if alias is found + package = packages [n]; // note the package + break; + } + } + } + return package; } -std::string cdl_exec::resolve_hardware_alias (const std::string alias) { - std::string target = alias; +std::string +cdl_exec::resolve_hardware_alias (const std::string alias) +{ + std::string target = alias; - if (! pkgdata->is_known_target (alias)) { // if the alias is not a target name - const std::vector & targets = pkgdata->get_targets (); // get targets - for (unsigned int n = 0; n < targets.size (); n++) { // for each target - const std::vector & aliases = pkgdata->get_target_aliases (targets [n]); // get target aliases - if (aliases.end () != std::find (aliases.begin (), aliases.end (), alias)) { // if alias is found - target = targets [n]; // note the target - break; - } - } - } - return target; + if (! pkgdata->is_known_target (alias)) { // if the alias is not a target name + const std::vector & targets = pkgdata->get_targets (); // get targets + for (unsigned int n = 0; n < targets.size (); n++) { // for each target + const std::vector & aliases = pkgdata->get_target_aliases (targets [n]); // get target aliases + if (aliases.end () != std::find (aliases.begin (), aliases.end (), alias)) { // if alias is found + target = targets [n]; // note the target + break; + } + } + } + return target; } diff --git a/host/tools/configtool/standalone/common/cdl_exec.hxx b/host/tools/configtool/standalone/common/cdl_exec.hxx --- a/host/tools/configtool/standalone/common/cdl_exec.hxx +++ b/host/tools/configtool/standalone/common/cdl_exec.hxx @@ -26,33 +26,43 @@ class cdl_exec { public: - cdl_exec (const std::string repository_tree, const std::string savefile_name, const std::string install_tree, bool no_resolve); - bool cmd_new (const std::string cdl_hardware, const std::string cdl_template = "default", const std::string cdl_version = ""); - bool cmd_tree (); - bool cmd_check (); - bool cmd_list (); - bool cmd_add (const std::vector cdl_packages); - bool cmd_remove (const std::vector cdl_packages); - bool cmd_version (const std::string cdl_version, const std::vector cdl_packages); - bool cmd_template (const std::string cdl_template, const std::string cdl_version = ""); - bool cmd_export (const std::string cdl_savefile); - bool cmd_import (const std::string cdl_savefile); - bool cmd_target (const std::string cdl_target); - bool cmd_resolve (); + cdl_exec (const std::string repository_tree, const std::string savefile_name, const std::string install_tree, bool no_resolve); + bool cmd_new (const std::string cdl_hardware, const std::string cdl_template = "default", const std::string cdl_version = ""); + bool cmd_tree (); + bool cmd_check (); + bool cmd_list (); + bool cmd_add (const std::vector cdl_packages); + bool cmd_remove (const std::vector cdl_packages); + bool cmd_version (const std::string cdl_version, const std::vector cdl_packages); + bool cmd_template (const std::string cdl_template, const std::string cdl_version = ""); + bool cmd_export (const std::string cdl_savefile); + bool cmd_import (const std::string cdl_savefile); + bool cmd_target (const std::string cdl_target); + bool cmd_resolve (); + static void set_quiet_mode(bool); + static void set_verbose_mode(bool); + static void set_ignore_errors_mode(bool); + protected: - std::string repository; - std::string savefile; - std::string install_prefix; - CdlPackagesDatabase pkgdata; - CdlInterpreter interp; - CdlConfiguration config; - void delete_cdl_data (); - static void diagnostic_handler (std::string message); - void exception_handler (CdlStringException exception); - void exception_handler (); - static void report_conflict (CdlConflict conflict); - static CdlInferenceCallbackResult inference_callback (CdlTransaction transaction); - std::string resolve_package_alias (const std::string alias); - std::string resolve_hardware_alias (const std::string alias); + static bool quiet; + static bool verbose; + static bool ignore_errors; + std::string repository; + std::string savefile; + std::string install_prefix; + bool no_resolve; + CdlPackagesDatabase pkgdata; + CdlInterpreter interp; + CdlConfiguration config; + void init(bool /* load */); + void delete_cdl_data (); + static void diagnostic_handler (std::string message); + void exception_handler (CdlStringException exception); + void exception_handler (); + void report_conflicts(); + static CdlInferenceCallbackResult inference_callback (CdlTransaction transaction); + static void transaction_callback(const CdlTransactionCallback&); + std::string resolve_package_alias (const std::string alias); + std::string resolve_hardware_alias (const std::string alias); }; diff --git a/host/tools/configtool/standalone/common/ecosconfig.cxx b/host/tools/configtool/standalone/common/ecosconfig.cxx --- a/host/tools/configtool/standalone/common/ecosconfig.cxx +++ b/host/tools/configtool/standalone/common/ecosconfig.cxx @@ -39,11 +39,12 @@ //========================================================================== #ifndef _MSC_VER - #include - #include /* for realpath() */ +#include +#include /* for realpath() */ #endif #ifdef __CYGWIN__ - #include /* for cygwin_conv_to_win32_path() */ +#include +#include /* for cygwin_conv_to_win32_path() */ #endif #include "cdl_exec.hxx" #include "ecosconfig.hxx" @@ -51,243 +52,376 @@ #define TOOL_VERSION "1.3.net" #define TOOL_COPYRIGHT "Copyright (c) 2000 Red Hat, Inc." #define DEFAULT_SAVE_FILE "ecos.ecc" +static char* tool = "ecosconfig"; int main (int argc, char * argv []) { - // process command qualifiers - std::string repository; // --srcdir= - std::string savefile; // --config= - std::string install_prefix; // --prefix= - bool version = false; // --version - bool no_resolve = false; // --no-resolve - int command_index; - for (command_index = 1; command_index < argc; command_index++) { // for each command line argument - if (0 == strncmp (argv [command_index], "--srcdir=", 9)) { - repository = & argv [command_index] [9]; - } else if (0 == strncmp (argv [command_index], "--config=", 9)) { - savefile = & argv [command_index] [9]; - } else if (0 == strncmp (argv [command_index], "--prefix=", 9)) { - install_prefix = & argv [command_index] [9]; - } else if (0 == strcmp (argv [command_index], "--version")) { - version = true; - } else if (0 == strcmp (argv [command_index], "--no-resolve")) { - no_resolve = true; - } else { // the argument is not a qualifier - break; // end of qualifiers - } - } + // process command qualifiers + std::string repository; // --srcdir= + std::string savefile; // --config= + std::string install_prefix; // --prefix= + bool version = false; // --version + bool no_resolve = false; // --no-resolve + bool quiet = false; // -q, --quiet + bool verbose = false; // -v, --verbose + bool ignore_errors = false; // -i, --ignore-errors + bool help = false; // --help + + // getopt() cannot easily be used here since this code has to + // build with VC++ as well. + bool args_ok = true; + int command_index; + for (command_index = 1; command_index < argc; command_index++) { // for each command line argument + char* arg = argv[command_index]; + if (0 == strcmp(arg, "--help")) { + help = true; + } else if ((0 == strcmp(arg, "-q")) || (0 == strcmp(arg, "--quiet"))) { + // Allow repeated use of -q and -v to override each other. + // This is useful in conjunction with shell aliases. + quiet = true; + verbose = false; + } else if ((0 == strcmp(arg, "-v")) || (0 == strcmp(arg, "--verbose"))) { + verbose = true; + quiet = false; + } else if ((0 == strcmp(arg, "-i")) || (0 == strcmp(arg, "--ignore-errors"))) { + // Duplicate use of -i and the other flags is harmless. + ignore_errors = true; + } else if (0 == strcmp(arg, "--version")) { + version = true; + } else if (0 == strcmp(arg, "--no-resolve")) { + no_resolve = true; + } else if (0 == strncmp(arg, "--srcdir", 8)) { + // Duplicate use of --srcdir and other data-containing options should + // be marked as an error. + if ("" != repository) { + fprintf(stderr, "%s: the `--srcdir' option should be used only once.\n", tool); + args_ok = false; + } else { + if ('=' == arg[8]) { + repository = std::string(arg + 9); + if ("" == repository) { + fprintf(stderr, "%s: missing component repository after `--srcdir='\n", tool); + args_ok = false; + } + } else if ('\0' == arg[8]) { + command_index++; + if (command_index == argc) { + fprintf(stderr, "%s: missing component repository after `--srcdir'\n", tool); + args_ok = false; + } else { + repository = argv[command_index]; + } + } else { + fprintf(stderr, "%s: invalid option `%s'\n", tool, arg); + args_ok = false; + } + } + } else if (0 == strncmp(arg, "--config", 8)) { + if ("" != savefile) { + fprintf(stderr, "%s: the `--config' option should be used only once.\n", tool); + args_ok = false; + } else { + if ('=' == arg[8]) { + savefile = std::string(arg + 9); + if ("" == savefile) { + fprintf(stderr, "%s: missing configuration savefile after `--config='\n", tool); + args_ok = false; + } + } else if ('\0' == arg[8]) { + command_index++; + if (command_index == argc) { + fprintf(stderr, "%s: missing configuration savefile after `--config'\n", tool); + args_ok = false; + } else { + savefile = argv[command_index]; + } + } else { + fprintf(stderr, "%s: invalid option `%s'\n", tool, arg); + args_ok = false; + } + } + } else if (0 == strncmp(arg, "--prefix", 8)) { + if ("" != install_prefix) { + fprintf(stderr, "%s: the `--prefix' option should be used only once.\n", tool); + args_ok = false; + } else { + if ('=' == arg[8]) { + install_prefix = std::string(arg + 9); + if ("" == install_prefix) { + fprintf(stderr, "%s: missing install prefix after `--prefix='\n", tool); + args_ok = false; + } + } else if ('\0' == arg[8]) { + command_index++; + if (command_index == argc) { + fprintf(stderr, "%s: missing install prefix after `--prefix'\n", tool); + args_ok = false; + } else { + install_prefix = argv[command_index]; + } + } else { + fprintf(stderr, "%s: invalid option `%s'\n", tool, arg); + args_ok = false; + } + } + } else { + // The argument is not a qualifier + // However, none of the sub-commands begin with a - + if ('-' == arg[0]) { + fprintf(stderr, "%s: unknown option `%s'\n", tool, arg); + args_ok = false; + } + break; // end of qualifiers + } + } - // usage message - if (command_index == argc) { // if there is no command - if (version) { // if the tool version was requested - printf ("ecosconfig %s (%s %s)\n%s\n", TOOL_VERSION, __DATE__, __TIME__, TOOL_COPYRIGHT); - } else { // the tool version was not requested - usage_message (); // print the usage message - } - return EXIT_SUCCESS; - } - - // set the default save file - if (savefile.empty ()) { // if the save file was not specified on the command line - savefile = DEFAULT_SAVE_FILE; // use the default save file - } +#if 0 + printf("args_ok is %d\n", args_ok); + printf("help is %d\n", help); + printf("version is %d\n", version); + printf("no_resolve is %d\n", no_resolve); + printf("quiet is %d\n", quiet); + printf("verbose is %d\n", verbose); + printf("ignore_errors is %d\n", ignore_errors); + printf("repository is %s\n", repository.c_str()); + printf("savefile is %s\n", savefile.c_str()); + printf("install_prefix is %s\n", install_prefix.c_str()); + exit(EXIT_SUCCESS); +#endif + + // Usually argv[command_index] will be a sub-command, unless + // --help or --version has been used. + + // Always output the version number, irrespective of subsequent + // commands or any problems. This can be useful in batch jobs. + if (version) { + printf ("ecosconfig %s (%s %s)\n%s\n", TOOL_VERSION, __DATE__, __TIME__, TOOL_COPYRIGHT); + if (command_index == argc) { + return EXIT_SUCCESS; + } + } + // Cope with --help and any user errors. If --help is used then + // subsequent arguments should be ignored, as should any problems + // with the arguments. This allows the user to type a partial + // command, then switch to --help, and use shell history editing + // to complete/correct the command. + if (help || !args_ok || (command_index == argc)) { + usage_message(); + return help ? EXIT_SUCCESS : EXIT_FAILURE; + } + + // set the default save file + if (savefile.empty ()) { // if the save file was not specified on the command line + savefile = DEFAULT_SAVE_FILE; // use the default save file + } - // find the repository - if (repository.empty ()) { // if the repository was not specified on the command line - const char * env_var = getenv ("ECOS_REPOSITORY"); - if (env_var) { // if the ECOS_REPOSITORY environment variable is defined - repository = env_var; - } else { // the ECOS_REPOSITORY environment variable is not defined - // assume that the tool is located in the root of the repository + // find the repository + if (repository.empty ()) { // if the repository was not specified on the command line + const char * env_var = getenv ("ECOS_REPOSITORY"); + if (env_var) { // if the ECOS_REPOSITORY environment variable is defined + repository = env_var; + } else { // the ECOS_REPOSITORY environment variable is not defined + // assume that the tool is located in the root of the repository #ifdef _MSC_VER - char toolpath [_MAX_PATH + 1]; - _fullpath (toolpath, argv [0], sizeof (toolpath)); // get the absolute path to the tool + char toolpath [_MAX_PATH + 1]; + _fullpath (toolpath, argv [0], sizeof (toolpath)); // get the absolute path to the tool #else - char toolpath [MAXPATHLEN + 1]; - realpath (argv [0], toolpath); // get the absolute path to the tool + // NOTE: portability problem. realpath() is not a POSIX function. + // Alternative code may be needed on some platforms. + char toolpath [MAXPATHLEN + 1]; + realpath (argv [0], toolpath); // get the absolute path to the tool #endif - repository = toolpath; - for (unsigned int n = repository.size () - 1; n > 0; n--) { // for each char starting at the tail - if (('\\' == repository [n]) || ('/' == repository [n])) { // if the char is a directory separator - repository.resize (n); // remove the filename from the filepath - break; - } - } - } - } + repository = toolpath; + for (unsigned int n = repository.size () - 1; n > 0; n--) { // for each char starting at the tail + if (('\\' == repository [n]) || ('/' == repository [n])) { // if the char is a directory separator + repository.resize (n); // remove the filename from the filepath + break; + } + } + } + } #ifdef __CYGWIN__ - // convert cygwin paths to win32 paths - char buffer [MAXPATHLEN + 1]; - cygwin_conv_to_win32_path (repository.c_str (), buffer); - repository = buffer; - cygwin_conv_to_win32_path (savefile.c_str (), buffer); - savefile = buffer; - if (! install_prefix.empty ()) { // cygwin_conv_to_win32_path() does not copy an empty string - cygwin_conv_to_win32_path (install_prefix.c_str (), buffer); - install_prefix = buffer; - } + // convert cygwin paths to win32 paths + char buffer [MAXPATHLEN + 1]; + cygwin_conv_to_win32_path (repository.c_str (), buffer); + repository = buffer; + cygwin_conv_to_win32_path (savefile.c_str (), buffer); + savefile = buffer; + if (! install_prefix.empty ()) { // cygwin_conv_to_win32_path() does not copy an empty string + cygwin_conv_to_win32_path (install_prefix.c_str (), buffer); + install_prefix = buffer; + } #endif - // process the command - cdl_exec exec (trim_path (repository), savefile, trim_path (install_prefix), no_resolve); - const std::string command = argv [command_index]; - bool status = true; - - if ("new" == command) { - if (command_index + 2 == argc) { - status = exec.cmd_new (argv [command_index + 1]); - } else if (command_index + 3 == argc) { - status = exec.cmd_new (argv [command_index + 1], argv [command_index + 2]); - } else if (command_index + 4 == argc) { - status = exec.cmd_new (argv [command_index + 1], argv [command_index + 2], argv [command_index + 3]); - } else { - status = false; - usage_message (); - } - - } else if ("tree" == command) { - if (command_index + 1 == argc) { - status = exec.cmd_tree (); - } else { - status = false; - usage_message (); - } - - } else if ("list" == command) { - if (command_index + 1 == argc) { - status = exec.cmd_list (); - } else { - status = false; - usage_message (); - } - - } else if ("check" == command) { - if (command_index + 1 == argc) { - status = exec.cmd_check (); - } else { - status = false; - usage_message (); - } - - } else if ("resolve" == command) { - if (command_index + 1 == argc) { - status = exec.cmd_resolve (); - } else { - status = false; - usage_message (); - } - - } else if ("add" == command) { - if (command_index + 1 < argc) { - std::vector packages; - for (int n = command_index + 1; n < argc; n++) { - packages.push_back (argv [n]); - } - status = exec.cmd_add (packages); - } else { - status = false; - usage_message (); - } + // Initialize the cdl_exec code (not quite sure why this needs a + // separate object rather than just a bunch of statics). + cdl_exec exec (trim_path (repository), savefile, trim_path (install_prefix), no_resolve); + cdl_exec::set_quiet_mode(quiet); + cdl_exec::set_verbose_mode(verbose); + cdl_exec::set_ignore_errors_mode(ignore_errors); + + // Now identify and process the sub-command. + const std::string command = argv [command_index]; + command_index++; + bool status = false; - } else if ("remove" == command) { - if (command_index + 1 < argc) { - std::vector packages; - for (int n = command_index + 1; n < argc; n++) { - packages.push_back (argv [n]); - } - status = exec.cmd_remove (packages); - } else { - status = false; - usage_message (); - } - - } else if ("version" == command) { - if (command_index + 2 < argc) { - std::vector packages; - for (int n = command_index + 2; n < argc; n++) { - packages.push_back (argv [n]); - } - status = exec.cmd_version (argv [command_index + 1], packages); - } else { - status = false; - usage_message (); - } - - } else if ("target" == command) { - if (command_index + 2 == argc) { - status = exec.cmd_target (argv [command_index + 1]); - } else { - status = false; - usage_message (); - } + if ("new" == command) { + // Usage: ecosconfig new [template [version]] + if ((command_index == argc) || ((command_index + 3) <= argc)) { + usage_message(); + } else { + // The default values for template and template_version + // are part of the cdl_exec class, so cdl_exec::cmd_new() has + // to be invoked with the right number of arguments. + if ((command_index + 1) == argc) { + status = exec.cmd_new(argv[command_index]); + } else if ((command_index + 2) == argc) { + status = exec.cmd_new(argv[command_index], argv[command_index + 1]); + } else { + status = exec.cmd_new(argv[command_index], argv[command_index + 1], argv[command_index + 2]); + } + } + } else if ("tree" == command) { + // Usage: ecosconfig tree + if (command_index == argc) { + status = exec.cmd_tree (); + } else { + usage_message (); + } + } else if ("list" == command) { + // Usage: ecosconfig list + if (command_index == argc) { + status = exec.cmd_list (); + } else { + usage_message (); + } + } else if ("check" == command) { + // Usage: ecosconfig check + if (command_index == argc) { + status = exec.cmd_check (); + } else { + usage_message (); + } + } else if ("resolve" == command) { + // Usage: ecosconfig resolve + if (command_index == argc) { + status = exec.cmd_resolve (); + } else { + usage_message (); + } + } else if ("add" == command) { + // Usage: ecosconfig add [ ...] + if (command_index < argc) { + std::vector packages; + for (int n = command_index; n < argc; n++) { + packages.push_back (argv [n]); + } + status = exec.cmd_add (packages); + } else { + usage_message (); + } + } else if ("remove" == command) { + // Usage: ecosconfig remove [ ...] + if (command_index < argc) { + std::vector packages; + for (int n = command_index; n < argc; n++) { + packages.push_back (argv [n]); + } + status = exec.cmd_remove (packages); + } else { + usage_message (); + } + } else if ("version" == command) { + // Usage: ecosconfig version [ ...] + // Note that it is not possible to change several packages to different versions. + if (command_index + 1 < argc) { + std::vector packages; + for (int n = command_index + 1; n < argc; n++) { + packages.push_back (argv [n]); + } + status = exec.cmd_version (argv [command_index], packages); + } else { + usage_message (); + } - } else if ("template" == command) { - if (command_index + 2 == argc) { - status = exec.cmd_template (argv [command_index + 1]); - } else if (command_index + 3 == argc) { - status = exec.cmd_template (argv [command_index + 1], argv [command_index + 2]); - } else { - status = false; - usage_message (); - } + } else if ("target" == command) { + // Usage: ecosconfig target + if (command_index + 1 == argc) { + status = exec.cmd_target (argv [command_index]); + } else { + usage_message (); + } + + } else if ("template" == command) { + // Usage: ecosconfig template