]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - tools/src/tools/configtool/standalone/common/cdl_exec.cxx
Initial revision
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / common / cdl_exec.cxx
diff --git a/tools/src/tools/configtool/standalone/common/cdl_exec.cxx b/tools/src/tools/configtool/standalone/common/cdl_exec.cxx
new file mode 100644 (file)
index 0000000..4dc1d46
--- /dev/null
@@ -0,0 +1,949 @@
+//####COPYRIGHTBEGIN####
+//                                                                          
+// ----------------------------------------------------------------------------
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 John Dallaway
+//
+// This program is part of the eCos host tools.
+//
+// This program is free software; you can redistribute it and/or modify it 
+// under the terms of the GNU General Public License as published by the Free 
+// Software Foundation; either version 2 of the License, or (at your option) 
+// any later version.
+// 
+// This program is distributed in the hope that it will be useful, but WITHOUT 
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+// more details.
+// 
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+//
+// ----------------------------------------------------------------------------
+//                                                                          
+//####COPYRIGHTEND####
+//==========================================================================
+//
+//      cdl_exec.cxx
+//
+//      The implementation of each ecosconfig command
+//
+//==========================================================================
+//==========================================================================
+//#####DESCRIPTIONBEGIN####                                             
+//
+// Author(s):           jld
+// Date:                1999-11-08
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#ifdef _MSC_VER
+#include <direct.h> /* for getcwd() */
+#else
+#include <unistd.h> /* for getcwd() */
+#endif
+#ifdef __CYGWIN__
+#include <windows.h>
+#include <sys/param.h>  /* for MAXPATHLEN */
+#include <sys/cygwin.h> /* for cygwin_conv_to_win32_path() */
+#endif
+#include "build.hxx"
+#include "cdl_exec.hxx"
+
+// ----------------------------------------------------------------------------
+bool cdl_exec::quiet            = false;
+bool cdl_exec::verbose          = false;
+bool cdl_exec::ignore_errors    = false;
+bool cdl_exec::no_updates       = false;
+bool cdl_exec::debug_level_set  = false;
+int  cdl_exec::debug_level      = 0;
+
+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 ();
+}
+
+void
+cdl_exec::set_quiet_mode(bool new_val)
+{
+    quiet = new_val;
+}
+
+void
+cdl_exec::set_verbose_mode(bool new_val)
+{
+    verbose = new_val;
+    CdlPackagesDatabaseBody::set_verbose(new_val);
+}
+
+void
+cdl_exec::set_ignore_errors_mode(bool new_val)
+{
+    ignore_errors = new_val;
+}
+
+void
+cdl_exec::set_no_updates_mode(bool new_val)
+{
+    no_updates = new_val;
+}
+
+void
+cdl_exec::set_debug_level(int new_level)
+{
+    debug_level_set = true;
+    debug_level = new_level;
+}
+
+// ----------------------------------------------------------------------------
+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);
+    }
+}
+
+// ----------------------------------------------------------------------------
+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_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.
+        CdlLocalTransaction transact(config);
+        config->set_hardware(transact.get(), resolve_hardware_alias(cdl_hardware), &diagnostic_handler, &diagnostic_handler);
+        config->set_template(transact.get(), cdl_template, cdl_version, &diagnostic_handler, &diagnostic_handler);
+        transact.body();
+        transact.destroy();
+
+        if (debug_level_set) {
+            this->update_debug_level();
+        }
+        
+        // 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();
+        }
+
+        // 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.
+        if (!no_updates) {
+            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 (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_resolve) {
+            CdlTransactionBody::set_callback_fn(&transaction_callback);
+            config->resolve_all_conflicts();
+        }
+        report_conflicts();
+        if (!no_updates) {
+            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_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 (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_resolve) {
+            CdlTransactionBody::set_callback_fn(&transaction_callback);
+            config->resolve_all_conflicts();
+        }
+        report_conflicts();
+        if (!no_updates) {
+            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 {
+        init(true);
+        if (debug_level_set) {
+            this->update_debug_level();
+        }
+        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())) {
+            if (!no_updates) {
+                config->save (cdl_savefile, /* minimal = */ true);
+            }
+            status = true;
+        }
+    } catch (CdlStringException exception) {
+        exception_handler (exception);
+    } catch (...) {
+        exception_handler ();
+    }
+
+    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 (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_resolve) {
+            CdlTransactionBody::set_callback_fn(&transaction_callback);
+            config->resolve_all_conflicts();
+        }
+        report_conflicts();
+        if (!no_updates) {
+            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<std::string> 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 (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_resolve) {
+            CdlTransactionBody::set_callback_fn(&transaction_callback);
+            config->resolve_all_conflicts();
+        }
+        report_conflicts();
+        if (!no_updates) {
+            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_remove (const std::vector<std::string> 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 (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_resolve) {
+            CdlTransactionBody::set_callback_fn(&transaction_callback);
+            config->resolve_all_conflicts();
+        }
+        report_conflicts();
+        if (!no_updates) {
+            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_version (const std::string cdl_version, const std::vector<std::string> 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 (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_resolve) {
+            CdlTransactionBody::set_callback_fn(&transaction_callback);
+            config->resolve_all_conflicts();
+        }
+        report_conflicts();
+        if (!no_updates) {
+            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_tree ()
+{
+    bool status = false;
+    try {
+        init(true);
+        if (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_resolve) {
+            CdlTransactionBody::set_callback_fn(&transaction_callback);
+            config->resolve_all_conflicts();
+        }
+        report_conflicts();
+        if (!no_updates) {
+            config->save (savefile);
+        }
+        // A build tree should only be generated if there are no conflicts,
+        // and suppressed if -n is given.
+        if (no_updates) {
+            // Do nothing
+        }
+        else if (ignore_errors || (0 == config->get_all_conflicts().size())) {
+#ifdef _MSC_VER
+            char cwd [_MAX_PATH + 1];
+#else
+            char cwd [PATH_MAX + 1];
+#endif
+            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);
+#else
+            generate_build_tree (config, cwd, install_prefix);
+#endif
+            config->generate_config_headers (install_prefix.empty () ? "install/include/pkgconf" : install_prefix + "/include/pkgconf");
+            status = true;
+#ifdef __CYGWIN__
+            char buf[100];
+            strcpy(buf, "mount.exe -f -t -u x: /ecos-x");
+            //printf("Cwd_win32: %s\n", cwd_win32);
+
+            if ( cwd_win32[1] == ':' )
+            {
+                buf[19] = tolower(cwd_win32[0]);
+                buf[28] = tolower(cwd_win32[0]);
+                system(buf);
+            }
+
+            //printf("Repository: %s\n", repository.c_str());
+
+            if ( repository[1] == ':' )
+            {
+                buf[19] = tolower(repository[0]);
+                buf[28] = tolower(repository[0]);
+                system(buf);
+            }
+            if ( !install_prefix.empty() )
+            {
+                //printf("Install prefix: %s\n", install_prefix.c_str());
+                if ( install_prefix[1] == ':' )
+                {
+                    buf[19] = tolower(install_prefix[0]);
+                    buf[28] = tolower(install_prefix[0]);
+                    system(buf);
+                }
+            }
+#endif
+        } 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;
+}
+
+// ----------------------------------------------------------------------------
+bool
+cdl_exec::cmd_list ()
+{
+    bool status = false;
+    try {
+        init(false);
+
+        // list the installed packages
+        std::vector<std::string> packages = pkgdata->get_packages ();
+        std::sort (packages.begin (), packages.end ());
+        for (unsigned int package = 0; package < packages.size (); package++) {
+            const std::vector<std::string> & 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<std::string> & 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<std::string> targets = pkgdata->get_targets ();
+        std::sort (targets.begin (), targets.end ());
+        for (unsigned int target = 0; target < targets.size (); target++) {
+            const std::vector<std::string> & 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<std::string> templates = pkgdata->get_templates ();
+        std::sort (templates.begin (), templates.end ());
+        for (unsigned int templ = 0; templ < templates.size (); templ++) {
+            const std::vector<std::string> & 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 ();
+    }
+
+    delete_cdl_data ();
+    return status;
+}
+
+// ----------------------------------------------------------------------------
+bool
+cdl_exec::cmd_check ()
+{
+    bool status = false;
+    unsigned int n;
+
+    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.
+        // Enabling/disabling debugs is allowed for now because that
+        // is unlikely to introduce conflicts.
+        if (debug_level_set) {
+            this->update_debug_level();
+        }
+        if (!no_updates) {
+            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<std::string> template_packages = pkgdata->get_template_packages (config->get_template ());
+        const std::vector<std::string> & 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<CdlLoadable> & loadables = config->get_loadables ();
+        std::vector<std::string> added_packages;
+        std::vector<CdlLoadable>::const_iterator loadable_i;
+        for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) {
+            const CdlNode & node = dynamic_cast<CdlNode> (* 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<std::string> 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<CdlValuable> version_packages;
+        for (loadable_i = loadables.begin (); loadable_i != loadables.end (); loadable_i++) {
+            const CdlValuable & valuable = dynamic_cast<CdlValuable> (* 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<CdlConflict> & 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;
+}
+
+// ----------------------------------------------------------------------------
+bool
+cdl_exec::cmd_resolve ()
+{
+    bool status = false;
+
+    try {
+        init(true);
+        if (debug_level_set) {
+            this->update_debug_level();
+        }
+        CdlTransactionBody::set_callback_fn(&transaction_callback);
+        config->resolve_all_conflicts ();
+        report_conflicts();
+        if (!no_updates) {
+            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;
+}
+
+// ----------------------------------------------------------------------------
+// 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;
+}
+
+// ----------------------------------------------------------------------------
+// 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.
+    }
+}
+
+// ----------------------------------------------------------------------------
+// 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.
+
+void
+cdl_exec::transaction_callback(const CdlTransactionCallback& callback_data)
+{
+    if (quiet) {
+        return;
+    }
+
+    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()) {
+            CdlEvalContext context(0, valuable, 0);
+            CdlSimpleValue simple_val;
+            CdlSimpleValue::eval_valuable(context, valuable, simple_val);
+            std::string msg = std::string("U ") + valuable->get_name() + ", new inferred value ";
+            std::string value = simple_val.get_value();
+            if ("" == value) {
+                msg += "\"\"";
+            } else {
+                msg += value;
+            }
+            msg += "\n";
+            dump_string(4, msg);
+        }
+    }
+}
+
+// ----------------------------------------------------------------------------
+// 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<CdlConflict>& all_conflicts = config->get_all_conflicts();
+    std::list<CdlConflict>::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<std::pair<CdlValuable, CdlValue> > & soln = (*conf_i)->get_solution();
+                unsigned int i;
+                for (i = 0; i < soln.size(); i++) {
+                    CdlValuable valuable = soln[i].first;
+                    soln_msg += valuable->get_name();
+                    soln_msg += " -> ";
+                    switch(valuable->get_flavor()) {
+                      case CdlValueFlavor_Bool :
+                        if (!soln[i].second.is_enabled()) {
+                            soln_msg += "0 (disabled)";
+                        } else {
+                            soln_msg += "1 (enabled)";
+                        }
+                        break;
+                      case CdlValueFlavor_Data:
+                        soln_msg += soln[i].second.get_value();
+                        break;
+                      case CdlValueFlavor_BoolData:
+                        if (!soln[i].second.is_enabled()) {
+                            soln_msg += "0 " + soln[i].second.get_value();
+                        } else {
+                            soln_msg += "1 " + soln[i].second.get_value();
+                        }
+                        break;
+                        // An option with flavor none cannot be involved
+                        // in a solution.
+                      default:
+                        soln_msg += "<internal error>";
+                        break;
+                    }
+                    soln_msg += "\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::exception_handler (CdlStringException exception) {
+    printf ("%s\n", exception.get_message ().c_str ());
+}
+
+void
+cdl_exec::exception_handler ()
+{
+    printf ("Unknown error\n");
+}
+
+
+// ----------------------------------------------------------------------------
+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<std::string> & packages = pkgdata->get_packages (); // get packages
+        for (unsigned int n = 0; n < packages.size (); n++) { // for each package
+            const std::vector<std::string> & 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;
+
+    if (! pkgdata->is_known_target (alias)) { // if the alias is not a target name
+        const std::vector<std::string> & targets = pkgdata->get_targets (); // get targets
+        for (unsigned int n = 0; n < targets.size (); n++) { // for each target
+            const std::vector<std::string> & 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;
+}
+
+// ----------------------------------------------------------------------------
+// Enable or disable debugging in a configuration.
+void
+cdl_exec::update_debug_level()
+{
+    CdlNode node = config->lookup("CYGPKG_INFRA_DEBUG");
+    CdlValuable valuable = 0;
+    if (0 != node) {
+        valuable = dynamic_cast<CdlValuable>(node);
+    }
+    if (0 == valuable) {
+        throw CdlStringException("Cannot enable or disable debugging, the infrastructure package is absent");
+    }
+    
+    if (debug_level > 0) {
+        valuable->enable(CdlValueSource_User);
+    } else {
+        valuable->disable(CdlValueSource_User);
+    }
+}