Mercurial > flash_v2
diff host/libcdl/database.cxx @ 76:435cced73e2f ecos-v1_3_1-release
eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
| author | jlarmour |
|---|---|
| date | Tue, 28 Mar 2000 14:10:45 +0000 |
| parents | |
| children | 6736c52df507 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/host/libcdl/database.cxx @@ -0,0 +1,1901 @@ +//{{{ Banner + +//============================================================================ +// +// database.cxx +// +// Temporary implementation of the CdlPackagesDatabase class +// Implementations of the temporary CdlTargetsDatabase and +// CdlTemplatesDatabase classes. +// +//============================================================================ +//####COPYRIGHTBEGIN#### +// +// ---------------------------------------------------------------------------- +// Copyright (C) 1999, 2000 Red Hat, Inc. +// +// This file 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#### +//============================================================================ +//#####DESCRIPTIONBEGIN#### +// +// Author(s): bartv +// Contact(s): bartv +// Date: 1999/01/21 +// Version: 0.02 +// +//####DESCRIPTIONEND#### +//============================================================================ + +//}}} +//{{{ #include's + +// ---------------------------------------------------------------------------- +#include "cdlconfig.h" + +// Get the infrastructure types, assertions, tracing and similar +// facilities. +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/cyg_trac.h> + +// <cdl.hxx> defines everything implemented in this module. +// It implicitly supplies <string>, <vector> and <map> because +// the class definitions rely on these headers. +#include <cdl.hxx> + +// strcmp() is useful when dealing with Tcl strings. +#include <cstring> + +//}}} + +//{{{ Statics + +// ---------------------------------------------------------------------------- +// Some test cases may want to read in a file other than +// "ecos.db", e.g. to facilitate testing the error conditions. +char* +CdlPackagesDatabaseBody::database_name = "ecos.db"; + +// ---------------------------------------------------------------------------- +// The new_package etc. commands need to store the name of the +// current package so that subsequent commands can do the right thing. +// Using constant strings as the key avoids typo problems. +const char* dbparser_current_package = "::dbparser_current_package"; +const char* dbparser_current_target = "::dbparser_current_target"; +const char* dbparser_component_repository = "::component_repository"; +const char* dbparser_database_name = "::database_name"; +const char* dbparser_pkgdir = "::pkgdir"; +const char* dbparser_current_version = "::version"; +const char* dbparser_current_script = "::script"; +const char* dbparser_database_key = "dbparser_key"; // for assoc data +const char* template_description_key = "__cdl_extract_template_description"; // ditto +const char* template_packages_key = "_cdl_extract_template_packages"; + +CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlPackagesDatabaseBody); + +//}}} +//{{{ Utility Tcl scripts + +// ---------------------------------------------------------------------------- +// Utility scripts. +// +// Given a directory and a filename relative to that directory, +// extract the contents of that file and store it in a variable +// "script". + +static char* read_file_script = " \n\ +if {[file pathtype $::database_name] != \"relative\"} { \n\ + error \"Database name \\\"$::database_name\\\" should be relative\" \n\ +} \n\ +set filename [file join $::component_repository $::database_name] \n\ +if {0 == [file exists $filename]} { \n\ + error \"Component repository database $filename does not exist\" \n\ +} \n\ +if {0 == [file readable $filename]} { \n\ + error \"Component repository database $filename is not readable\" \n\ +} \n\ +set fd \"\" \n\ +set script \"\" \n\ +set status [catch { \n\ + set fd [open $filename r] \n\ + set script [read $fd] \n\ +} message] \n\ +if {$fd != \"\"} { \n\ + close $fd \n\ +} \n\ +if { $status != 0 } { \n\ + error $message \n\ +} \n\ +"; + +//}}} +//{{{ Tcl commands for the parser + +//{{{ CdlDbParser class + +// ---------------------------------------------------------------------------- +// Commands that get invoked from inside the Tcl interpreter. These +// need access to the internals of the database objects, which can be +// achieved by making them static members of a CdlDbParser class. + +class CdlDbParser { + public: + static int new_package(CdlInterpreter, int, char**); + static int package_description(CdlInterpreter, int, char**); + static int package_alias(CdlInterpreter, int, char**); + static int package_directory(CdlInterpreter, int, char**); + static int package_script(CdlInterpreter, int, char**); + static int package_hardware(CdlInterpreter, int, char**); + + static int new_target(CdlInterpreter, int, char**); + static int target_description(CdlInterpreter, int, char**); + static int target_alias(CdlInterpreter, int, char**); + static int target_packages(CdlInterpreter, int, char**); + static int target_command_prefix(CdlInterpreter, int, char**); + static int target_cflags(CdlInterpreter, int, char**); + static int target_enable(CdlInterpreter, int, char**); + static int target_disable(CdlInterpreter, int, char**); + static int target_set_value(CdlInterpreter, int, char**); +}; + +//}}} +//{{{ CdlDbParser::package-related + +// ---------------------------------------------------------------------------- +// package <name> <body> + +int +CdlDbParser::new_package(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::new_package", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + if (3 != argc) { + interp->set_result("A package definition should include name and contents"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + std::string pkg_name = argv[1]; + std::string msg = std::string("Package ") + pkg_name + ": "; + + // Better make sure that this is not a duplicate definition. + if (std::find(db->package_names.begin(), db->package_names.end(), pkg_name) != db->package_names.end()) { + interp->set_result(msg + "a package can only be defined once"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // Add this package to the list. + db->package_names.push_back(pkg_name); + + // Also create a new package structure. This requires a default structure, + // which cannot be filled in until the body is executed. + CdlPackagesDatabaseBody::package_data tmp_struct; + db->packages[pkg_name] = tmp_struct; + + CdlPackagesDatabaseBody::package_data& package = db->packages[pkg_name]; + // aliases and versions are vectors and will take care of themselves + package.description = ""; + package.directory = ""; + package.script = ""; + package.hardware = false; + + // Sort out the commands, then invoke the script in argv[2]. There is + // no need to worry about error recovery here, any errors will be + // fatal anyway. + CdlInterpreterCommandEntry commands[] = { + CdlInterpreterCommandEntry("description", &CdlDbParser::package_description ), + CdlInterpreterCommandEntry("alias", &CdlDbParser::package_alias ), + CdlInterpreterCommandEntry("directory", &CdlDbParser::package_directory ), + CdlInterpreterCommandEntry("script", &CdlDbParser::package_script ), + CdlInterpreterCommandEntry("hardware", &CdlDbParser::package_hardware ), + CdlInterpreterCommandEntry("", 0 ) + }; + int i; + std::vector<CdlInterpreterCommandEntry> new_commands; + for (i = 0; 0 != commands[i].command; i++) { + new_commands.push_back(commands[i]); + } + std::vector<CdlInterpreterCommandEntry>* old_commands = interp->push_commands(new_commands); + interp->set_variable(dbparser_current_package, pkg_name); + std::string str_result; + if (TCL_OK != interp->eval(argv[2], str_result)) { + interp->set_result(msg + str_result); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + interp->pop_commands(old_commands); + interp->unset_variable(dbparser_current_package); + + // Some of the fields are compulsory. + if ("" == package.directory) { + interp->set_result(msg + "missing directory specification"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if ("" == package.script) { + interp->set_result(msg + "missing script specification"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if (0 == package.aliases.size()) { + interp->set_result(msg + "at least one alias should be supplied"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: description <text> +int +CdlDbParser::package_description(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::package_description", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_package); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->packages.find(name) != db->packages.end()); + + CdlPackagesDatabaseBody::package_data& package = db->packages[name]; + std::string msg = "Package " + name + ": "; + + if (2 != argc) { + interp->set_result(msg + "the package description should be a single string"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if ("" != package.description) { + interp->set_result(msg + "a package can have only one description"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + + package.description = argv[1]; + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: alias <list> +// For example: alias { "This is an alias" another_alias dummy_name } +int +CdlDbParser::package_alias(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::package_alias", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_package); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->packages.find(name) != db->packages.end()); + + CdlPackagesDatabaseBody::package_data& package = db->packages[name]; + std::string msg = "Package " + name + ": "; + + // The alias command should be used only once + if (0 < package.aliases.size()) { + interp->set_result(msg + "there should be only one list of aliases"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // There should be one argument, a list of valid packages. + if (2 != argc) { + interp->set_result(msg + "alias should be followed by a list of known aliases"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + int list_count = 0; + char** list_entries = 0; + Tcl_Interp* tcl_interp = interp->get_tcl_interpreter(); + if (TCL_OK != Tcl_SplitList(tcl_interp, argv[1], &list_count, &list_entries)) { + interp->set_result(msg + Tcl_GetStringResult(tcl_interp)); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if (0 == list_count) { + interp->set_result(msg + "at least one alias should be supplied"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + for (int i = 0; i < list_count; i++) { + package.aliases.push_back(list_entries[i]); + } + Tcl_Free((char*)list_entries); + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: directory <path> +// The path is of course relative to the component repository. +int +CdlDbParser::package_directory(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::package_directory", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabaseBody*>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_package); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->packages.find(name) != db->packages.end()); + + CdlPackagesDatabaseBody::package_data& package = db->packages[name]; + std::string msg = "Package " + name + ": "; + + // The directory command should be used only once + if ("" != package.directory) { + interp->set_result(msg + "a package can be located in only one directory"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // And there should be exactly one argument. + if (2 != argc) { + interp->set_result(msg + "only one directory can be specified"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + + package.directory = argv[1]; + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: hardware +// There are no arguments. +int +CdlDbParser::package_hardware(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::package_hardware", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabaseBody*>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_package); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->packages.find(name) != db->packages.end()); + + CdlPackagesDatabaseBody::package_data& package = db->packages[name]; + std::string msg = "Package " + name + ": "; + + if (1 != argc) { + interp->set_result(msg + "there should be no further data after hardware"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if (package.hardware) { + interp->set_result(msg + "the hardware property should be specified only once"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + package.hardware = true; + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: script <filename> +int +CdlDbParser::package_script(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::package_script", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabaseBody*>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_package); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->packages.find(name) != db->packages.end()); + + CdlPackagesDatabaseBody::package_data& package = db->packages[name]; + std::string msg = "Package " + name + ": "; + + // The script command should be used only once + if ("" != package.script) { + interp->set_result(msg + "a package can have only one starting CDL script"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // And there should be exactly one argument. + if (2 != argc) { + interp->set_result(msg + "only one CDL script can be specified"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + package.script = argv[1]; + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +//}}} +//{{{ CdlDbParser::target-related + +// ---------------------------------------------------------------------------- +// target <name> <body> + +int +CdlDbParser::new_target(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::new_target", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + if (3 != argc) { + interp->set_result("A target definition should include name and contents"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + std::string target_name = argv[1]; + std::string msg = std::string("Target ") + target_name + ": "; + + // Better make sure that this is not a duplicate definition. + if (std::find(db->target_names.begin(), db->target_names.end(), target_name) != db->target_names.end()) { + interp->set_result(msg + "a target can only be defined once"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // Add this target to the list. + db->target_names.push_back(target_name); + + // Also create a new target structure. This requires a default structure, + // which cannot be filled in until the body is executed. + CdlPackagesDatabaseBody::target_data tmp_struct; + db->targets[target_name] = tmp_struct; + + CdlPackagesDatabaseBody::target_data& target = db->targets[target_name]; + // aliases, packages and compiler_flags are vectors and will take care of themselves + target.description = ""; + target.command_prefix = ""; + + // Sort out the commands, then invoke the script in argv[2]. There is + // no need to worry about error recovery here, any errors will be + // fatal anyway. + CdlInterpreterCommandEntry commands[] = { + CdlInterpreterCommandEntry("description", &CdlDbParser::target_description ), + CdlInterpreterCommandEntry("alias", &CdlDbParser::target_alias ), + CdlInterpreterCommandEntry("packages", &CdlDbParser::target_packages ), + CdlInterpreterCommandEntry("command_prefix", &CdlDbParser::target_command_prefix ), + CdlInterpreterCommandEntry("cflags", &CdlDbParser::target_cflags ), + CdlInterpreterCommandEntry("enable", &CdlDbParser::target_enable ), + CdlInterpreterCommandEntry("disable", &CdlDbParser::target_disable ), + CdlInterpreterCommandEntry("set_value", &CdlDbParser::target_set_value ), + CdlInterpreterCommandEntry("", 0 ) + }; + int i; + std::vector<CdlInterpreterCommandEntry> new_commands; + for (i = 0; 0 != commands[i].command; i++) { + new_commands.push_back(commands[i]); + } + std::vector<CdlInterpreterCommandEntry>* old_commands = interp->push_commands(new_commands); + interp->set_variable(dbparser_current_target, target_name); + std::string str_result; + if (TCL_OK != interp->eval(argv[2], str_result)) { + interp->set_result(msg + str_result); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + interp->pop_commands(old_commands); + interp->unset_variable(dbparser_current_target); + + // Some of the fields are compulsory. + if (0 == target.aliases.size()) { + interp->set_result(msg + "at least one alias should be supplied"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } +#if 0 + // command_prefix is now handled in the configuration data. + if ("" == target.command_prefix) { + interp->set_result(msg + "missing command prefix specification"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } +#endif + // There is no check for > 0 hardware packages. This is an unlikely + // scenario but should be allowed for. + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: description <text> +int +CdlDbParser::target_description(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_description", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + if (2 != argc) { + interp->set_result(msg + "the target description should be a single string"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if ("" != target.description) { + interp->set_result(msg + "a target can have only one description"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + + target.description = argv[1]; + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: alias <list> +// For example: alias { "This is an alias" another_alias dummy_name } +int +CdlDbParser::target_alias(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_alias", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + // The alias command should be used only once + if (0 < target.aliases.size()) { + interp->set_result(msg + "there should be only one list of aliases"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // There should be one argument, a list of valid aliases + if (2 != argc) { + interp->set_result(msg + "alias should be followed by a list of known aliases"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + int list_count = 0; + char** list_entries = 0; + Tcl_Interp* tcl_interp = interp->get_tcl_interpreter(); + if (TCL_OK != Tcl_SplitList(tcl_interp, argv[1], &list_count, &list_entries)) { + interp->set_result(msg + Tcl_GetStringResult(tcl_interp)); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if (0 == list_count) { + interp->set_result(msg + "at least one alias should be supplied"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + for (int i = 0; i < list_count; i++) { + target.aliases.push_back(list_entries[i]); + } + Tcl_Free((char*)list_entries); + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: packages <list> ... +// For example: packages { CYGPKG_HAL_XXX CYGPKG_HAL_YYY } +int +CdlDbParser::target_packages(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_packages", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + // The packages command should be used only once + if (0 < target.packages.size()) { + interp->set_result(msg + "there should be only one list of packages"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // There should be one argument, a list of valid packages. + if (2 != argc) { + interp->set_result(msg + "packages should be followed by a list of known packages"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + int list_count = 0; + char** list_entries = 0; + Tcl_Interp* tcl_interp = interp->get_tcl_interpreter(); + if (TCL_OK != Tcl_SplitList(tcl_interp, argv[1], &list_count, &list_entries)) { + interp->set_result(msg + Tcl_GetStringResult(tcl_interp)); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if (0 == list_count) { + interp->set_result(msg + "at least one package should be supplied"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + for (int i = 0; i < list_count; i++) { + target.packages.push_back(list_entries[i]); + } + Tcl_Free((char*)list_entries); + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: command_prefix <string> +int +CdlDbParser::target_command_prefix(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_command_prefix", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabaseBody*>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + // The command_prefix command should be used only once + if ("" != target.command_prefix) { + interp->set_result(msg + "a target can have only one command_prefix string"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // And there should be exactly one argument. + if (2 != argc) { + interp->set_result(msg + "only one command_prefix can be specified"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + + target.command_prefix = argv[1]; + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: cflags <list of pairs> ... +// For example: cflags { ERRFLAGS "-Wall" DBGFLAGS "-g" } +int +CdlDbParser::target_cflags(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_cflags", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + // The cflags command should be used only once + if (0 < target.cflags.size()) { + interp->set_result(msg + "there should be only one set of compiler flags"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + // There should be one argument, a list of valid flags. + if (2 != argc) { + interp->set_result(msg + "cflags should be followed by a list of compiler flag/value pairs"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + int list_count = 0; + char** list_entries = 0; + Tcl_Interp* tcl_interp = interp->get_tcl_interpreter(); + if (TCL_OK != Tcl_SplitList(tcl_interp, argv[1], &list_count, &list_entries)) { + interp->set_result(msg + Tcl_GetStringResult(tcl_interp)); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + if (0 != (list_count % 2)) { + interp->set_result(msg + "compiler flags and values must occur in pairs"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + int i; + const std::vector<std::string>& valid_cflags = CdlPackagesDatabaseBody::get_valid_cflags(); + for (i = 0; i < list_count; i+= 2) { + std::vector<std::string>::const_iterator j; + for (j = valid_cflags.begin(); j != valid_cflags.end(); j++) { + if (*j == list_entries[i]) { + break; + } + if (j == valid_cflags.end()) { + interp->set_result(msg + "invalid cflag name " + list_entries[i]); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + } + } + // NOTE: do the quote marks have to be removed explicitly or is that done + // by splitlist? + for (i = 0; i < list_count; i+= 2) { + target.cflags.push_back(std::make_pair(list_entries[i], list_entries[i+1])); + } + Tcl_Free((char*)list_entries); + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: enable { opt1 opt2 ... } +// For example: enable { CYGPKG_HAL_ARM_CL7xxx_7211 } +int +CdlDbParser::target_enable(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_enable", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + // There should be one argument, a list of valid flags. + if (2 != argc) { + interp->set_result(msg + "enable should be followed by a list of CDL options"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + int list_count = 0; + char** list_entries = 0; + Tcl_Interp* tcl_interp = interp->get_tcl_interpreter(); + if (TCL_OK != Tcl_SplitList(tcl_interp, argv[1], &list_count, &list_entries)) { + interp->set_result(msg + Tcl_GetStringResult(tcl_interp)); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + for (int i = 0; i < list_count; i++) { + target.enable.push_back(list_entries[i]); + } + Tcl_Free((char *) list_entries); + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + + +// Syntax: disable { opt1 opt2 ... } +// For example: disable { CYGPKG_HAL_ARM_CL7xxx_7111 } +int +CdlDbParser::target_disable(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_disable", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + // There should be one argument, a list of valid flags. + if (2 != argc) { + interp->set_result(msg + "disable should be followed by a list of CDL options"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + int list_count = 0; + char** list_entries = 0; + Tcl_Interp* tcl_interp = interp->get_tcl_interpreter(); + if (TCL_OK != Tcl_SplitList(tcl_interp, argv[1], &list_count, &list_entries)) { + interp->set_result(msg + Tcl_GetStringResult(tcl_interp)); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + for (int i = 0; i < list_count; i++) { + target.disable.push_back(list_entries[i]); + } + Tcl_Free((char *) list_entries); + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +// Syntax: set_value <option> <value> +// For example: set_value CYGHWR_MEMSIZE 0x100000 +int +CdlDbParser::target_set_value(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("CdlDbParser::target_set_value", "result %d"); + CYG_REPORT_FUNCARG1XV(argc); + CYG_PRECONDITION_CLASSC(interp); + + CdlPackagesDatabase db = static_cast<CdlPackagesDatabase>(interp->get_assoc_data(dbparser_database_key)); + CYG_INVARIANT_CLASSC(CdlPackagesDatabaseBody, db); + + std::string name = interp->get_variable(dbparser_current_target); + CYG_ASSERTC("" != name); + CYG_ASSERTC(db->targets.find(name) != db->targets.end()); + + CdlPackagesDatabaseBody::target_data& target = db->targets[name]; + std::string msg = "Target " + name + ": "; + + // There should be one argument, a list of valid flags. + if (3 != argc) { + interp->set_result(msg + "set_value command should be followed by an option name and its value"); + CYG_REPORT_RETVAL(TCL_ERROR); + return TCL_ERROR; + } + target.set_values.push_back(std::make_pair(std::string(argv[1]), std::string(argv[2]))); + + CYG_REPORT_RETVAL(TCL_OK); + return TCL_OK; +} + +//}}} + +//}}} + +//{{{ CdlPackagesDatabase:: creation + +// ---------------------------------------------------------------------------- +// The exported interface is make(). The hard work is done inside the +// constructor. + +CdlPackagesDatabase +CdlPackagesDatabaseBody::make(std::string repo) + throw(CdlInputOutputException, std::bad_alloc) +{ + CYG_REPORT_FUNCNAMETYPE("CdlPackagesDatabase::make", "database %p"); + + // Where is the component repository? The location may come from the + // parent or from an environment variable ECOS_REPOSITORY + if ("" == repo) { + char *env = getenv("ECOS_REPOSITORY"); + if (0 == env) { + throw CdlInputOutputException(std::string("No component repository specified and no ") + + std::string("ECOS_REPOSITORY environment variable")); + } else { + repo = env; + } + } + + // Replace any backslashes in the repository with forward slashes. + // The latter are used throughout the library + // NOTE: this is not i18n-friendly. + for (unsigned int i = 0; i < repo.size(); i++) { + if ('\\' == repo[i]) { + repo[i] = '/'; + } + } + CdlPackagesDatabase result = new CdlPackagesDatabaseBody(repo); + CYG_REPORT_RETVAL(result); + return result; +} + +// ---------------------------------------------------------------------------- + +CdlPackagesDatabaseBody::CdlPackagesDatabaseBody(std::string repo) + throw(CdlInputOutputException, std::bad_alloc) +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase:: constructor"); + CYG_PRECONDITIONC("" != repo); + + // There will be calls to check_this() while the database is evaluated, + // so make sure that the database is valid first. + component_repository = repo; + cdlpackagesdatabasebody_cookie = CdlPackagesDatabaseBody_Magic; + + // We want to read in the entire packages file. Portability problems + // can be largely eliminated by using a Tcl interpreter for this, but + // under Windows there is a problem if the pathname is a cygwin one. + // For now it is assumed that the supplied pathname is acceptable to + // Tcl. + // + // A Tcl interpreter can be used to read in the file. It must not start + // off as a safe interpreter because file I/O is needed. However it has + // to be turned into a safe interpreter before the packages script is + // actually executed. + + // No need for a try/catch here, there are no resources to free yet. + CdlInterpreter interp = CdlInterpreterBody::make(); + + try { + interp->set_variable(dbparser_component_repository, repo); + interp->set_variable(dbparser_database_name, database_name); + } + catch(std::bad_alloc) { + delete interp; + throw; + } + std::string str_result; + if (TCL_OK != interp->eval(read_file_script, str_result)) { + delete interp; + throw CdlInputOutputException(str_result); + } + + // We have the script. It comes from a source that is not completely + // trusted so it can only be executed in a safe interpreter. However + // after the script is read it will still be necessary to perform + // glob commands afterwards to locate version subdirectories + // and to check for the existence of the script files. + try { + CdlInterpreterCommandEntry commands[] = + { + CdlInterpreterCommandEntry("package", &CdlDbParser::new_package ), + CdlInterpreterCommandEntry("target", &CdlDbParser::new_target ), + CdlInterpreterCommandEntry("", 0 ) + }; + unsigned int i; + std::vector<CdlInterpreterCommandEntry> new_commands; + for (i = 0; 0 != commands[i].command; i++) { + new_commands.push_back(commands[i]); + } + interp->set_assoc_data(dbparser_database_key, static_cast<ClientData>(this)); + interp->push_commands(new_commands); + + if (TCL_OK != interp->eval(" \n\ + set parser [interp create -safe] \n\ + $parser alias package ::package \n\ + $parser alias target ::target \n\ + $parser eval $script \n\ + ", str_result)) { + throw CdlInputOutputException(str_result); + } + + // There should be at least one package and target. + if (0 == package_names.size()) { + throw CdlInputOutputException("There are no packages in the database."); + } + if (0 == target_names.size()) { + throw CdlInputOutputException("There are no targets in the database."); + } + + // All of the package names should be valid CDL names. + std::vector<std::string>::const_iterator name_i; + std::vector<std::string>::const_iterator name_j; + for (name_i = package_names.begin(); name_i != package_names.end(); name_i++) { + if (!Cdl::is_valid_cdl_name(*name_i)) { + throw CdlInputOutputException("Package " + *name_i + ", this is not a valid CDL name."); + } + } + + // The ecos.db data has been read in. For each package, find + // the subdirectories and list them as versions. Each package + // should have at least one version. Any errors will be + // handled by the catch statement further down. + for (std::map<std::string,package_data>::iterator pkg_i = packages.begin(); pkg_i != packages.end(); pkg_i++) { + + std::string pkgdir = repo + "/" + pkg_i->second.directory; + std::vector<std::string> subdirs; + unsigned int i; + interp->locate_subdirs(pkgdir, subdirs); + + for (i = 0; i < subdirs.size(); i++) { + if (("CVS" != subdirs[i]) && + (interp->is_file(pkgdir + "/" + subdirs[i] + "/cdl/" + pkg_i->second.script) || + interp->is_file(pkgdir + "/" + subdirs[i] + "/" + pkg_i->second.script))) { + pkg_i->second.versions.push_back(subdirs[i]); + } + } + + if (0 == pkg_i->second.versions.size()) { + throw CdlInputOutputException("Package " + pkg_i->first + ": there are no version subdirectories"); + } + std::sort(pkg_i->second.versions.begin(), pkg_i->second.versions.end(), Cdl::version_cmp()); + } + + // Now start looking for templates. These should reside in the + // templates subdirectory of the component repository. Each template + // should be in its own directory, and inside each directory should + // be versioned template files with a .ect extension. + std::string templates_dir = repo + "/" + "templates"; + std::vector<std::string> subdirs; + interp->locate_subdirs(templates_dir, subdirs); + + for (i = 0; i < subdirs.size(); i++) { + // Do not add the template to the known ones until we are sure there is + // at least one valid template. + std::vector<std::string> files; + interp->locate_files(templates_dir + "/" + subdirs[i], files); + unsigned int j; + for (j = 0; j < files.size(); j++) { + if ((4 < files[j].size()) && (".ect" == files[j].substr(files[j].size() - 4))) { + break; + } + } + if (j != files.size()) { + this->template_names.push_back(subdirs[i]); + for ( ; j < files.size(); j++) { + if ((4 < files[j].size()) && (".ect" == files[j].substr(files[j].size() - 4))) { + this->templates[subdirs[i]].versions.push_back(files[j].substr(0, files[j].size() - 4)); + } + } + } + } + + // Consistency checks. All target-specific packages should have the + // hardware attribute. Also, all the packages should exist. + for (name_i = target_names.begin(); name_i != target_names.end(); name_i++) { + for (name_j = targets[*name_i].packages.begin(); name_j != targets[*name_i].packages.end(); name_j++) { + if (std::find(package_names.begin(), package_names.end(), *name_j) == package_names.end()) { + throw CdlInputOutputException("Target " + *name_i + " refers to an unknown package " + *name_j); + } + if (!packages[*name_j].hardware) { + throw CdlInputOutputException("Target " + *name_i + " refers to a non-hardware package " + *name_j); + } + } + } + } + catch(...) { + // Something has gone wrong. Clear out all of the data accumulated so far, as well + // as the interpreter. + delete interp; + package_names.clear(); + target_names.clear(); + template_names.clear(); + packages.clear(); + targets.clear(); + templates.clear(); + throw; + } + + delete interp; + CYGDBG_MEMLEAK_CONSTRUCTOR(); + + CYG_REPORT_RETURN(); +} + +//}}} +//{{{ CdlPackagesDatabase:: destructor + +// ---------------------------------------------------------------------------- +CdlPackagesDatabaseBody::~CdlPackagesDatabaseBody() +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase:: default destructor"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + cdlpackagesdatabasebody_cookie = CdlPackagesDatabaseBody_Invalid; + component_repository = ""; + package_names.clear(); + target_names.clear(); + template_names.clear(); + packages.clear(); + targets.clear(); + templates.clear(); + + CYGDBG_MEMLEAK_DESTRUCTOR(); + + CYG_REPORT_RETURN(); +} + +//}}} +//{{{ CdlPackagesDatabase:: check_this() + +// ---------------------------------------------------------------------------- + +bool +CdlPackagesDatabaseBody::check_this(cyg_assert_class_zeal zeal) const +{ + if (CdlPackagesDatabaseBody_Magic != cdlpackagesdatabasebody_cookie) { + return false; + } + CYGDBG_MEMLEAK_CHECKTHIS(); + + switch(zeal) { + case cyg_system_test : + case cyg_extreme : + { + std::vector<std::string>::const_iterator names_i; + std::map<std::string,package_data>::const_iterator pkgs_i; + + // Every entry in the names vector should have an entry in the packages vector. + for (names_i = package_names.begin(); names_i != package_names.end(); names_i++) { + if (packages.find(*names_i) == packages.end()) { + return false; + } + } + // The inverse should be true as well + for (pkgs_i = packages.begin(); pkgs_i != packages.end(); pkgs_i++) { + if (std::find(package_names.begin(), package_names.end(), pkgs_i->first) == package_names.end()) { + return false; + } + } + + // Repeat for targets. + std::map<std::string,target_data>::const_iterator targets_i; + for (names_i = target_names.begin(); names_i != target_names.end(); names_i++) { + if (targets.find(*names_i) == targets.end()) { + return false; + } + } + for (targets_i = targets.begin(); targets_i != targets.end(); targets_i++) { + if (std::find(target_names.begin(), target_names.end(), targets_i->first) == target_names.end()) { + return false; + } + } + + // And for templates + std::map<std::string,template_data>::const_iterator templates_i; + for (names_i = template_names.begin(); names_i != template_names.end(); names_i++) { + if (templates.find(*names_i) == templates.end()) { + return false; + } + } + // The inverse should be true as well + for (templates_i = templates.begin(); templates_i != templates.end(); templates_i++) { + if (std::find(template_names.begin(), template_names.end(), templates_i->first) == template_names.end()) { + return false; + } + } + + // Possibly the package directories should be validated as + // well, not to mention the various version subdirectories, + // but doing file I/O inside an assertion is excessive. + } + case cyg_thorough : + case cyg_quick: + if ("" == component_repository) { + return false; + } + case cyg_trivial: + case cyg_none : + break; + } + + return true; +} + +//}}} +//{{{ CdlPackagesDatabase:: misc + +// ---------------------------------------------------------------------------- + +std::string +CdlPackagesDatabaseBody::get_component_repository() const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_component_repository"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + CYG_REPORT_RETURN(); + return component_repository; +} + +//}}} +//{{{ CdlPackagesDatabase:: get package information + +// ---------------------------------------------------------------------------- + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_packages(void) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_packages"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + CYG_REPORT_RETURN(); + return package_names; +} + +bool +CdlPackagesDatabaseBody::is_known_package(std::string name) const +{ + CYG_REPORT_FUNCNAMETYPE("CdlPackagesDatabase::is_known_package", "result %d"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + bool result = false; + if (std::find(package_names.begin(), package_names.end(), name) != package_names.end()) { + result = true; + } + + CYG_REPORT_RETVAL(result); + return result; +} + +const std::string& +CdlPackagesDatabaseBody::get_package_description(std::string pkg_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_package_description"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + std::map<std::string,package_data>::const_iterator pkgs_i = packages.find(pkg_name); + if (pkgs_i != packages.end()) { + CYG_REPORT_RETURN(); + return pkgs_i->second.description; + } + + CYG_FAIL("Invalid package name passed to CdlPackagesDatabase::get_package_description()"); + static std::string dummy = ""; + return dummy; +} + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_package_aliases(std::string pkg_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_package_aliases"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + std::map<std::string,package_data>::const_iterator pkgs_i = packages.find(pkg_name); + if (pkgs_i != packages.end()) { + CYG_REPORT_RETURN(); + return pkgs_i->second.aliases; + } + + CYG_FAIL("Invalid package name passed to CdlPackagesDatabase::get_package_aliases()"); + static std::vector<std::string> dummy; + return dummy; +} + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_package_versions(std::string pkg_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_package_versions"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + std::map<std::string,package_data>::const_iterator pkgs_i = packages.find(pkg_name); + if (pkgs_i != packages.end()) { + CYG_REPORT_RETURN(); + return pkgs_i->second.versions; + } + + CYG_FAIL("Invalid package name passed to CdlPackagesDatabase::get_package_versions()"); + static std::vector<std::string> dummy; + return dummy; +} + +const std::string& +CdlPackagesDatabaseBody::get_package_directory(std::string pkg_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_package_directory"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + std::map<std::string,package_data>::const_iterator pkgs_i = packages.find(pkg_name); + if (pkgs_i != packages.end()) { + CYG_REPORT_RETURN(); + return pkgs_i->second.directory; + } + + CYG_FAIL("Invalid package name passed to CdlPackagesDatabase::get_package_directory()"); + static std::string dummy = ""; + return dummy; +} + +const std::string& +CdlPackagesDatabaseBody::get_package_script(std::string pkg_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_package_script"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + std::map<std::string,package_data>::const_iterator pkgs_i = packages.find(pkg_name); + if (pkgs_i != packages.end()) { + CYG_REPORT_RETURN(); + return pkgs_i->second.script; + } + + CYG_FAIL("Invalid package name passed to CdlPackagesDatabase::get_package_script()"); + static std::string dummy = ""; + return dummy; +} + +bool +CdlPackagesDatabaseBody::is_hardware_package(std::string pkg_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::is_hardware_package"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + std::map<std::string,package_data>::const_iterator pkgs_i = packages.find(pkg_name); + if (pkgs_i != packages.end()) { + CYG_REPORT_RETURN(); + return pkgs_i->second.hardware; + } + + CYG_FAIL("Invalid package name passed to CdlPackagesDatabase::is_hardware_package()"); + return false; +} + +//}}} +//{{{ CdlPackagesDatabase:: get target information + +// ---------------------------------------------------------------------------- + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_targets(void) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_targets"); + CYG_PRECONDITION_THISC(); + + CYG_REPORT_RETURN(); + return target_names; +} + +bool +CdlPackagesDatabaseBody::is_known_target(std::string name) const +{ + CYG_REPORT_FUNCNAMETYPE("CdlPackagesDatabase::is_known_target", "result %d"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + bool result = false; + if (std::find(target_names.begin(), target_names.end(), name) != target_names.end()) { + result = true; + } + + CYG_REPORT_RETVAL(result); + return result; +} + +const std::string& +CdlPackagesDatabaseBody::get_target_description(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_description"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = targets.find(target_name); + if (target_i != targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.description; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_description()"); + static std::string dummy = ""; + return dummy; +} + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_target_aliases(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_aliases"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = targets.find(target_name); + if (target_i != targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.aliases; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_aliases()"); + static std::vector<std::string> dummy; + return dummy; +} + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_target_packages(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_packages"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = targets.find(target_name); + if (target_i != targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.packages; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_packages()"); + static std::vector<std::string> dummy; + return dummy; +} + +const std::string& +CdlPackagesDatabaseBody::get_target_command_prefix(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_command_prefix"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = targets.find(target_name); + if (target_i != targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.command_prefix; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_command_prefix()"); + static std::string dummy = ""; + return dummy; +} + +const std::vector<std::pair<std::string,std::string> >& +CdlPackagesDatabaseBody::get_target_compiler_flags(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_compiler_flags"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = targets.find(target_name); + if (target_i != targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.cflags; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_compiler_flags()"); + static std::vector<std::pair<std::string,std::string> > dummy; + return dummy; +} + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_target_enables(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_enables"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = this->targets.find(target_name); + if (target_i != this->targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.enable; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_enables()"); + static std::vector<std::string> dummy; + return dummy; +} + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_target_disables(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_disables"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = this->targets.find(target_name); + if (target_i != this->targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.disable; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_disables()"); + static std::vector<std::string> dummy; + return dummy; +} + +const std::vector<std::pair<std::string, std::string> >& +CdlPackagesDatabaseBody::get_target_set_values(std::string target_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_target_set_values"); + CYG_PRECONDITION_THISC(); + + std::map<std::string,target_data>::const_iterator target_i = this->targets.find(target_name); + if (target_i != this->targets.end()) { + CYG_REPORT_RETURN(); + return target_i->second.set_values; + } + + CYG_FAIL("Invalid target name passed to CdlPackagesDatabase::get_target_values()"); + static std::vector<std::pair<std::string, std::string> > dummy; + return dummy; +} + +//}}} +//{{{ CdlPackagesDatabase:: get template information + +// ---------------------------------------------------------------------------- +// Templates are different from packages and targets. The ecos.db file +// does not contain all the information in one convenient file, instead +// it is necessary to trawl through a templates sub-directory of the +// component repository. There are no aliases. Descriptions can be obtained +// only by executing the template file in a suitable interpreter. + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_templates(void) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_templates"); + CYG_PRECONDITION_THISC(); + + CYG_REPORT_RETURN(); + return template_names; +} + +bool +CdlPackagesDatabaseBody::is_known_template(std::string name) const +{ + CYG_REPORT_FUNCNAMETYPE("CdlPackagesDatabase::is_known_template", "result %d"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + bool result = false; + if (std::find(template_names.begin(), template_names.end(), name) != template_names.end()) { + result = true; + } + + CYG_REPORT_RETVAL(result); + return result; +} + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_template_versions(std::string template_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_template_versions"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + std::map<std::string,template_data>::const_iterator template_i = templates.find(template_name); + if (template_i != templates.end()) { + CYG_REPORT_RETURN(); + return template_i->second.versions; + } + + CYG_FAIL("Invalid template name passed to CdlPackagesDatabase::get_template_versions()"); + static std::vector<std::string> dummy; + return dummy; +} + +std::string +CdlPackagesDatabaseBody::get_template_filename(std::string template_name, std::string version_name) const +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_template_filename"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + // Given the way templates are identified, the filename can be determined + // easily by concatenating a few strings. The only complication is that + // version_name may be an empty string, indicating that the most recent + // version should be used. + std::map<std::string,template_data>::const_iterator template_i = templates.find(template_name); + if (template_i == templates.end()) { + CYG_FAIL("Invalid template name passed to CdlPackagesDatabase::get_template_filename"); + CYG_REPORT_RETURN(); + return ""; + } + if ("" == version_name) { + CYG_ASSERTC(0 != template_i->second.versions.size()); + version_name = template_i->second.versions[0]; + } else { + std::vector<std::string>::const_iterator vsn_i = std::find(template_i->second.versions.begin(), + template_i->second.versions.end(), version_name); + if (vsn_i == template_i->second.versions.end()) { + CYG_FAIL("Invalid template version passed to CdlPackagesDatabase::get_template_filename"); + CYG_REPORT_RETURN(); + return ""; + } + } + + std::string result = component_repository + "/templates/" + template_name + "/" + version_name + ".ect"; + CYG_REPORT_RETURN(); + return result; +} + +// ---------------------------------------------------------------------------- +// The descriptions now live in an eCos savefile, i.e. a Tcl script, so +// extracting them can be relatively expensive and needs to happen on +// a just-in-time basis. + +const std::string +CdlPackagesDatabaseBody::get_template_description(std::string template_name, std::string version_name) +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_template_description"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + // Is this a known template? + std::map<std::string, struct template_data>::iterator template_i = templates.find(template_name); + if (template_i == templates.end()) { + CYG_FAIL("Invalid template name passed to CdlPackagesDatabase::get_template_description"); + CYG_REPORT_RETURN(); + return ""; + } + + // Is it a known version of the template? + if ("" == version_name) { + CYG_ASSERTC(0 != template_i->second.versions.size()); + version_name = template_i->second.versions[0]; + } else { + if (std::find(template_i->second.versions.begin(), template_i->second.versions.end(), version_name) == + template_i->second.versions.end()) { + + CYG_FAIL("Invalid template version passed to CdlPackagesDatabase::get_template_description"); + CYG_REPORT_RETURN(); + return ""; + } + } + + // We have a valid template and version. Has the version file in + // question been read in yet? + std::map<std::string, struct template_version_data>::iterator version_i; + version_i = template_i->second.version_details.find(version_name); + if (version_i != template_i->second.version_details.end()) { + CYG_REPORT_RETURN(); + return version_i->second.description; + } + + std::string filename = this->get_template_filename(template_name, version_name); + if ("" == filename) { + CYG_REPORT_RETURN(); + return ""; + } + extract_template_details(filename, template_i->second.version_details[version_name].description, + template_i->second.version_details[version_name].packages); + CYG_REPORT_RETURN(); + return template_i->second.version_details[version_name].description; +} + +// ---------------------------------------------------------------------------- +// Similarly extracting package information needs to happen on a +// just-in-time basis. +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_template_packages(std::string template_name, std::string version_name) +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_template_packages"); + CYG_REPORT_FUNCARG1XV(this); + CYG_PRECONDITION_THISC(); + + static std::vector<std::string> dummy; + + // Is this a known template? + std::map<std::string, struct template_data>::iterator template_i = templates.find(template_name); + if (template_i == templates.end()) { + CYG_FAIL("Invalid template name passed to CdlPackagesDatabase::get_template_packages"); + CYG_REPORT_RETURN(); + return dummy; + } + + // Is it a known version of the template? + if ("" == version_name) { + CYG_ASSERTC(0 != template_i->second.versions.size()); + version_name = template_i->second.versions[0]; + } else { + if (std::find(template_i->second.versions.begin(), template_i->second.versions.end(), version_name) == + template_i->second.versions.end()) { + + CYG_FAIL("Invalid template version passed to CdlPackagesDatabase::get_packages"); + CYG_REPORT_RETURN(); + return dummy; + } + } + + // We have a valid template and version. Has the version file in + // question been read in yet? + std::map<std::string, struct template_version_data>::iterator version_i; + version_i = template_i->second.version_details.find(version_name); + if (version_i != template_i->second.version_details.end()) { + CYG_REPORT_RETURN(); + return version_i->second.packages; + } + + std::string filename = this->get_template_filename(template_name, version_name); + if ("" == filename) { + CYG_REPORT_RETURN(); + return dummy; + } + extract_template_details(filename, template_i->second.version_details[version_name].description, + template_i->second.version_details[version_name].packages); + CYG_REPORT_RETURN(); + return template_i->second.version_details[version_name].packages; +} + +// ---------------------------------------------------------------------------- +// Extracting the description and package information involves running +// the script through a Tcl interpreter extended with the appropriate +// commands. Most of the savefile information is irrelevant and is handled +// by extract_ignore(). The commands of interest are cdl_configuration and +// its sub-commands description and package. + +static int +extract_ignore(CdlInterpreter interp, int argc, char** argv) +{ + return TCL_OK; +} + +static int +extract_cdl_configuration(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("extract_cdl_configuration", "result %d"); + CYG_REPORT_FUNCARG2XV(interp, argc); + CYG_PRECONDITION_CLASSC(interp); + + int result = TCL_OK; + + // usage: cdl_configuration <name> <body> + if (3 != argc) { + interp->set_result("Invalid cdl_configuration command in template, expecting two arguments"); + result = TCL_ERROR; + } else { + // Ignore the first argument for now. + std::string tmp; + result = interp->eval(argv[2], tmp); + + // After processing the cdl_configuration command the description and + // package information should be known. There is no point in processing + // the rest of the file. + if (TCL_OK == result) { + interp->set_result("OK"); + result = TCL_ERROR; + } + } + + CYG_REPORT_RETVAL(result); + return result; +} + +static int +extract_cdl_description(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("extract_cdl_description", "result %d"); + CYG_REPORT_FUNCARG2XV(interp, argc); + CYG_PRECONDITION_CLASSC(interp); + + int result = TCL_OK; + + // usage: package <name> + if (2 != argc) { + interp->set_result("Invalid description command in template, expecting just one argument"); + result = TCL_ERROR; + } else { + ClientData client_data = interp->get_assoc_data(template_description_key); + CYG_ASSERTC(0 != client_data); + std::string* result_ptr = static_cast<std::string*>(client_data); + *result_ptr = argv[1]; + } + + CYG_REPORT_RETVAL(result); + return result; +} + +static int +extract_cdl_package(CdlInterpreter interp, int argc, char** argv) +{ + CYG_REPORT_FUNCNAMETYPE("extract_cdl_package", "result %d"); + CYG_REPORT_FUNCARG2XV(interp, argc); + CYG_PRECONDITION_CLASSC(interp); + + int result = TCL_OK; + + // usage: package <name> <version> + if (2 > argc) { + interp->set_result("Invalid package command in template, expecting two arguments"); + result = TCL_ERROR; + } else { + ClientData client_data = interp->get_assoc_data(template_packages_key); + CYG_ASSERTC(0 != client_data); + std::vector<std::string>* result_ptr = static_cast<std::vector<std::string>*>(client_data); + result_ptr->push_back(argv[1]); + } + CYG_REPORT_RETVAL(result); + return result; +} + + +void +CdlPackagesDatabaseBody::extract_template_details(std::string filename, std::string& description, + std::vector<std::string>& packages) +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::extract_template_description"); + + CdlInterpreter interp = CdlInterpreterBody::make(); + interp->set_assoc_data(template_description_key, static_cast<ClientData>(&description)); + interp->set_assoc_data(template_packages_key, static_cast<ClientData>(&packages)); + static CdlInterpreterCommandEntry extract_commands[] = + { + CdlInterpreterCommandEntry("cdl_savefile_version", &extract_ignore ), + CdlInterpreterCommandEntry("cdl_savefile_command", &extract_ignore ), + CdlInterpreterCommandEntry("cdl_configuration", &extract_cdl_configuration ), + CdlInterpreterCommandEntry("hardware", &extract_ignore ), + CdlInterpreterCommandEntry("template", &extract_ignore ), + CdlInterpreterCommandEntry("description", &extract_cdl_description ), + CdlInterpreterCommandEntry("package", &extract_cdl_package ), + CdlInterpreterCommandEntry("unknown", &extract_ignore ), + CdlInterpreterCommandEntry("", 0 ) + }; + std::vector<CdlInterpreterCommandEntry> new_commands; + for (int i = 0; 0 != extract_commands[i].command; i++) { + new_commands.push_back(extract_commands[i]); + } + interp->push_commands(new_commands); + + std::string tmp; + int result = interp->eval_file(filename, tmp); + // Special escape mechanism, see extract_cdl_configuration() above + if ((TCL_ERROR == result) && ("OK" == tmp)) { + result = TCL_OK; + } +#if 0 + if (TCL_OK != result) { + // No obvious way of recovering just yet + } +#endif + delete interp; + + CYG_REPORT_RETURN(); +} + +//}}} +//{{{ CdlPackagesDatabase:: get_valid_cflags() + +// ---------------------------------------------------------------------------- + +const std::vector<std::string>& +CdlPackagesDatabaseBody::get_valid_cflags() +{ + CYG_REPORT_FUNCNAME("CdlPackagesDatabase::get_valid_compiler_flags"); + + static std::vector<std::string> result_vec; + static const char* valid_flags[] = { + "ARCHFLAGS", "CARCHFLAGS", "CXXARCHFLAGS", "LDARCHFLAGS", + "ERRFLAGS", "CERRFLAGS", "CXXERRFLAGS", "LDERRFLAGS", + "LANGFLAGS", "CLANGFLAGS", "CXXLANGFLAGS", "LDLANGFLAGS", + "DBGFLAGS", "CDBGFLAGS", "CXXDBGFLAGS", "LDDBGFLAGS", + "EXTRAFLAGS", "CEXTRAFLAGS", "CXXEXTRAFLAGS", "LDEXTRAFLAGS", + 0 + }; + + if (0 == result_vec.size()) { + for (int i = 0; 0 != valid_flags[i]; i++) { + result_vec.push_back(valid_flags[i]); + } + } + CYG_REPORT_RETURN(); + return result_vec; +} + +//}}}
