diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 237fa1059..4ac53a39a 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -27,20 +27,49 @@ #include "tlTimer.h" #include "tlEquivalenceClusters.h" #include "tlLog.h" +#include "tlEnv.h" #include -// verbose debug output -// TODO: make this a feature? -// #define PRINT_DEBUG_NETCOMPARE +namespace { -// verbose net graph output -// TODO: make this a feature? -// #define PRINT_DEBUG_NETGRAPH +struct GlobalCompareOptions +{ + GlobalCompareOptions () + { + m_is_initialized = false; + } -// Add this define for case insensitive compare -// (applies to circuits, device classes) -#define COMPARE_CASE_INSENSITIVE + void ensure_initialized () + { + if (! m_is_initialized) { + // $KLAYOUT_NETLIST_COMPARE_DEBUG_NETCOMPARE + debug_netcompare = tl::app_flag ("netlist-compare-debug-netcompare"); + // $KLAYOUT_NETLIST_COMPARE_DEBUG_NETGRAPH + debug_netgraph = tl::app_flag ("netlist-compare-debug-netgraph"); + // $KLAYOUT_NETLIST_COMPARE_CASE_SENSITIVE + compare_case_sensitive = tl::app_flag ("netlist-compare-case-sensitive"); + m_is_initialized = true; + } + } + + bool debug_netcompare; + bool debug_netgraph; + bool compare_case_sensitive; + +private: + bool m_is_initialized; +}; + +} + +static GlobalCompareOptions *options () +{ + // TODO: thread safe? + static GlobalCompareOptions s_options; + s_options.ensure_initialized (); + return &s_options; +} // A constant indicating a failed match const size_t failed_match = std::numeric_limits::max (); @@ -63,28 +92,25 @@ namespace db static int name_compare (const std::string &n1, const std::string &n2) { // TODO: unicode support? -#if defined(COMPARE_CASE_INSENSITIVE) + if (options ()->compare_case_sensitive) { + return strcmp (n1.c_str (), n2.c_str ()); + } else { #if defined(_WIN32) - return _stricmp (n1.c_str (), n2.c_str ()); + return _stricmp (n1.c_str (), n2.c_str ()); #else - return strcasecmp (n1.c_str (), n2.c_str ()); -#endif -#else - return strcmp (n1.c_str (), n2.c_str ()); + return strcasecmp (n1.c_str (), n2.c_str ()); #endif + } } -#if defined(COMPARE_CASE_INSENSITIVE) -static std::string normalize_name (const std::string &n) +static inline std::string normalize_name (const std::string &n) { - return tl::to_upper_case (n); + if (options ()->compare_case_sensitive) { + return n; + } else { + return tl::to_upper_case (n); + } } -#else -static inline const std::string &normalize_name (const std::string &n) -{ - return n; -} -#endif // -------------------------------------------------------------------------------------------------------------------- // DeviceCompare definition and implementation @@ -1515,11 +1541,12 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci for (std::vector::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { i->apply_net_index (m_net_index); } -#if defined(PRINT_DEBUG_NETGRAPH) - for (std::vector::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { - tl::info << i->to_string () << tl::noendl; + + if (options ()->debug_netgraph) { + for (std::vector::iterator i = m_nodes.begin (); i != m_nodes.end (); ++i) { + tl::info << i->to_string () << tl::noendl; + } } -#endif // create subcircuit virtual nodes @@ -1543,11 +1570,12 @@ NetGraph::build (const db::Circuit *c, DeviceCategorizer &device_categorizer, Ci for (std::map::iterator i = m_virtual_nodes.begin (); i != m_virtual_nodes.end (); ++i) { i->second.apply_net_index (m_net_index); } -#if defined(PRINT_DEBUG_NETGRAPH) - for (std::map::iterator i = m_virtual_nodes.begin (); i != m_virtual_nodes.end (); ++i) { - tl::info << i->second.to_string () << tl::noendl; + + if (options ()->debug_netgraph) { + for (std::map::iterator i = m_virtual_nodes.begin (); i != m_virtual_nodes.end (); ++i) { + tl::info << i->second.to_string () << tl::noendl; + } } -#endif } size_t @@ -1560,34 +1588,48 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr std::vector other_nodes; other_nodes.reserve (ee - e); -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "consider transitions:"; -#endif + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "considering transitions:"; + } + + bool first = true; for (NetGraphNode::edge_iterator i = e; i != ee; ++i) { if (i->second.first != net_index) { const NetGraphNode *nn = &node (i->second.first); -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "here: " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via"; - for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { - tl::info << indent(depth) << " " << t->to_string(); + if (options ()->debug_netcompare) { + if (first) { + tl::info << indent (depth) << " here: " << (node (net_index).net () ? node (net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; + first = false; + } + tl::info << indent (depth) << " " << (nn->net () ? nn->net ()->expanded_name ().c_str() : "(null)") << " via: " << tl::noendl; + for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { + tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl; + } + tl::info << ""; } -#endif nodes.push_back (nn); } } if (! nodes.empty ()) { // if non-ambiguous, non-assigned + first = true; + for (NetGraphNode::edge_iterator i = e_other; i != ee_other; ++i) { if (i->second.first != other_net_index) { const NetGraphNode *nn = &data->other->node (i->second.first); -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "there: " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via"; - for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { - tl::info << indent(depth) << " " << t->to_string(); + if (options ()->debug_netcompare) { + if (first) { + tl::info << indent (depth) << " there: " << (data->other->node (other_net_index).net () ? data->other->node (other_net_index).net ()->expanded_name ().c_str () : "(null)") << " ->"; + first = false; + } + tl::info << indent(depth) << " " << (nn->net() ? nn->net()->expanded_name().c_str() : "(null)") << " via: " << tl::noendl; + for (std::vector::const_iterator t = i->first.begin (); t != i->first.end(); ++t) { + tl::info << (t != i->first.begin () ? "; " : "") << t->to_string() << tl::noendl; + } + tl::info << ""; } -#endif other_nodes.push_back (nn); } } @@ -1604,9 +1646,9 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr if (tentative) { if (nodes.size () != other_nodes.size ()) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "! rejected branch."; -#endif + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; + } return failed_match; } @@ -1614,9 +1656,9 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr if (nodes.size () > 1 || other_nodes.size () > 1) { for (size_t i = 0; i < nodes.size (); ++i) { if (! (*nodes[i] == *other_nodes[i])) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "! rejected branch."; -#endif + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; + } return failed_match; } } @@ -1631,9 +1673,9 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr if (bt_count == failed_match) { if (tentative) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "! rejected branch."; -#endif + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected branch."; + } return bt_count; } } else { @@ -1642,11 +1684,11 @@ NetGraph::derive_node_identities_for_edges (NetGraphNode::edge_iterator e, NetGr } -#if defined(PRINT_DEBUG_NETCOMPARE) - if (! new_nodes) { - tl::info << indent(depth) << "! no updates."; + if (options ()->debug_netcompare) { + if (! new_nodes) { + tl::info << indent(depth) << "=> no updates."; + } } -#endif return new_nodes; } @@ -1671,13 +1713,13 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc size_t other_net_index = n->other_net_index (); NetGraphNode *n_other = & data->other->node (other_net_index); -#if defined(PRINT_DEBUG_NETCOMPARE) - if (! tentative) { - tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); - } else { - tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); + if (options ()->debug_netcompare) { + if (! tentative) { + tl::info << indent(depth) << "deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); + } else { + tl::info << indent(depth) << "tentatively deducing from pair: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name (); + } } -#endif size_t new_nodes = 0; @@ -1722,9 +1764,9 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc size_t bt_count = derive_node_identities_for_edges (e, ee, e_other, ee_other, net_index, other_net_index, depth, n_branch, tentative, with_ambiguous, data); if (bt_count == failed_match) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "! rejected pair."; -#endif + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected pair."; + } return bt_count; } else { new_nodes += bt_count; @@ -1733,9 +1775,9 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc } else if (tentative) { // in tentative mode an exact match is required: no having the same edges for a node disqualifies the node // as matching. -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "! rejected pair for missing edge."; -#endif + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected pair for missing edge."; + } return failed_match; } @@ -1758,9 +1800,9 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc NetGraphNode::edge_iterator e = n->find_edge (e_other->first); if (e == n->end ()) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent(depth) << "! rejected pair for missing edge."; -#endif + if (options ()->debug_netcompare) { + tl::info << indent(depth) << "=> rejected pair for missing edge."; + } return failed_match; } @@ -1770,11 +1812,11 @@ NetGraph::derive_node_identities (size_t net_index, size_t depth, size_t n_branc } -#if defined(PRINT_DEBUG_NETCOMPARE) - if (! tentative && new_nodes > 0) { - tl::info << indent(depth) << "finished pair deduction: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name () << " with " << new_nodes << " new pairs"; + if (options ()->debug_netcompare) { + if (! tentative && new_nodes > 0) { + tl::info << indent(depth) << "=> finished pair deduction: " << n->net ()->expanded_name () << " vs. " << n_other->net ()->expanded_name () << " with " << new_nodes << " new pairs"; + } } -#endif return new_nodes; } @@ -1855,17 +1897,18 @@ static bool net_names_are_different (const db::Net *a, const db::Net *b) size_t NetGraph::derive_node_identities_from_node_set (std::vector &nodes, std::vector &other_nodes, size_t depth, size_t n_branch, TentativeNodeMapping *tentative, bool with_ambiguous, CompareData *data) { -#if defined(PRINT_DEBUG_NETCOMPARE) - std::string indent_s = indent (depth); - indent_s += "*" + tl::to_string (n_branch) + " "; -#endif + std::string indent_s; + if (options ()->debug_netcompare) { + indent_s = indent (depth); + indent_s += "*" + tl::to_string (n_branch) + " "; + } size_t new_nodes = 0; if (depth > data->max_depth) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "max. depth exhausted (" << depth + 1 << ">" << data->max_depth << ")"; -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "max. depth exhausted (" << depth + 1 << ">" << data->max_depth << ")"; + } return failed_match; } @@ -1881,9 +1924,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother, other_ni); -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "deduced match (singular): " << nodes.front ()->net ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name (); -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "deduced match (singular): " << nodes.front ()->net ()->expanded_name () << " vs. " << other_nodes.front ()->net ()->expanded_name (); + } if (data->logger && ! tentative) { if (! (node (ni) == data->other->node (other_ni))) { // this is a mismatch but we continue, because that is the only candidate @@ -2030,9 +2073,9 @@ NetGraph::derive_node_identities_from_node_set (std::vector this favors net matching by name if (tentative && ! data->dont_consider_net_names && net_names_are_different ((*nr->n1)->net (), (*nr->n2)->net ())) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "rejecting pair as names are not identical: " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "rejecting pair as names are not identical: " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); + } return failed_match; } @@ -2044,9 +2087,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother, other_ni); -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "deduced match (singular): " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "deduced match (singular): " << (*nr->n1)->net ()->expanded_name () << " vs. " << (*nr->n2)->net ()->expanded_name (); + } if (data->logger && ! tentative) { if (! (node (ni) == data->other->node (other_ni))) { // this is a mismatch, but we continue with this @@ -2086,16 +2129,16 @@ NetGraph::derive_node_identities_from_node_set (std::vectornum * n_branch > data->max_n_branch) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "max. complexity exhausted (" << nr->num << "*" << n_branch << ">" << data->max_n_branch << ") - mismatch."; -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "max. complexity exhausted (" << nr->num << "*" << n_branch << ">" << data->max_n_branch << ") - mismatch."; + } return failed_match; } else { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "analyzing ambiguity group with " << nr->num << " members"; -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "analyzing ambiguity group with " << nr->num << " members"; + } // sort the ambiguity group such that net names match best @@ -2152,16 +2195,16 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother, other_ni); // try this candidate in tentative mode -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "trying in tentative mode: " << (*i1)->net ()->expanded_name () << " vs. " << (*i2)->net ()->expanded_name (); -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "trying in tentative mode: " << (*i1)->net ()->expanded_name () << " vs. " << (*i2)->net ()->expanded_name (); + } size_t bt_count = derive_node_identities (ni, depth + 1, nr->num * n_branch, &tn, with_ambiguous, data); if (bt_count != failed_match) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << indent_s << "match found"; -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "match found"; + } // we have a match ... if (any) { @@ -2185,9 +2228,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectordebug_netcompare) { + tl::info << indent_s << "mismatch."; + } // a mismatch - stop here. return failed_match; } @@ -2207,13 +2250,13 @@ NetGraph::derive_node_identities_from_node_set (std::vectorother, other_ni); -#if defined(PRINT_DEBUG_NETCOMPARE) - if (equivalent_other_nodes.has_attribute (p->second)) { - tl::info << indent_s << "deduced ambiguous match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name (); - } else { - tl::info << indent_s << "deduced match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name (); + if (options ()->debug_netcompare) { + if (equivalent_other_nodes.has_attribute (p->second)) { + tl::info << indent_s << "deduced ambiguous match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name (); + } else { + tl::info << indent_s << "deduced match: " << p->first->net ()->expanded_name () << " vs. " << p->second->net ()->expanded_name (); + } } -#endif if (data->logger) { bool ambiguous = equivalent_other_nodes.has_attribute (p->second); if (ambiguous) { @@ -2249,9 +2292,9 @@ NetGraph::derive_node_identities_from_node_set (std::vectornum << " members"; -#endif + if (options ()->debug_netcompare) { + tl::info << indent_s << "finished analysis of ambiguity group with " << nr->num << " members"; + } } @@ -2516,9 +2559,9 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const if (all_subcircuits_verified (ca, verified_circuits_a) && all_subcircuits_verified (cb, verified_circuits_b)) { -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << "treating circuit: " << ca->name () << " vs. " << cb->name (); -#endif + if (options ()->debug_netcompare) { + tl::info << "treating circuit: " << ca->name () << " vs. " << cb->name (); + } if (mp_logger) { mp_logger->begin_circuit (ca, cb); } @@ -2835,9 +2878,7 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, g2.identify (ni2, ni1); } -#if defined(PRINT_DEBUG_NETCOMPARE) int iter = 0; -#endif // two passes: one without ambiguities, the second one with @@ -2845,20 +2886,20 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, for (int pass = 0; pass < 2; ++pass) { -#if defined(PRINT_DEBUG_NETCOMPARE) - if (pass > 0) { - tl::info << "including ambiguous nodes now."; + if (options ()->debug_netcompare) { + if (pass > 0) { + tl::info << "including ambiguous nodes now."; + } } -#endif good = true; while (true) { -#if defined(PRINT_DEBUG_NETCOMPARE) ++iter; - tl::info << "new compare iteration #" << iter; - tl::info << "deducing from present nodes ..."; -#endif + if (options ()->debug_netcompare) { + tl::info << "new compare iteration #" << iter; + tl::info << "deducing from present nodes ..."; + } size_t new_identities = 0; @@ -2877,18 +2918,18 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, size_t ni = g1.derive_node_identities (i1 - g1.begin (), 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data); if (ni > 0 && ni != failed_match) { new_identities += ni; -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << ni << " new identities."; -#endif + if (options ()->debug_netcompare) { + tl::info << ni << " new identities."; + } } } } -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << "checking topological identity ..."; -#endif + if (options ()->debug_netcompare) { + tl::info << "checking topological identity ..."; + } // derive new identities through topology: first collect all nets with the same topological signature @@ -2934,9 +2975,9 @@ NetlistComparer::compare_circuits (const db::Circuit *c1, const db::Circuit *c2, size_t ni = g1.derive_node_identities_from_node_set (nodes, other_nodes, 0, 1, 0 /*not tentative*/, pass > 0 /*with ambiguities*/, &data); if (ni > 0 && ni != failed_match) { new_identities += ni; -#if defined(PRINT_DEBUG_NETCOMPARE) - tl::info << ni << " new identities."; -#endif + if (options ()->debug_netcompare) { + tl::info << ni << " new identities."; + } } if (new_identities == 0) { diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 0d5024e9f..4b8004b8c 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -1283,14 +1283,6 @@ ApplicationBase::get_config_names () const return names; } -bool -ApplicationBase::special_app_flag (const std::string &name) -{ - // TODO: some more elaborate scheme? - const char *env = getenv (("KLAYOUT_" + name).c_str ()); - return (env && *env); -} - // -------------------------------------------------------------------------------- // GuiApplication implementation diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h index 8ef31e2d5..5bd45fa6c 100644 --- a/src/lay/lay/layApplication.h +++ b/src/lay/lay/layApplication.h @@ -198,16 +198,6 @@ public: */ std::vector get_config_names () const; - /** - * @brief Gets a value indicating whether the give special application flag is set - * - * Special application flags are ways to introduce debug or flags for special - * use cases. Such flags have a name and currently are controlled externally by - * an environment variable called "KLAYOUT_x" where x is the name. If that - * variable is set and the value is non-empty, the flag is regarded set. - */ - bool special_app_flag (const std::string &name); - /** * @brief Return a reference to the Ruby interpreter */ diff --git a/src/lay/lay/laySystemPaths.cc b/src/lay/lay/laySystemPaths.cc index 719c41090..708f1ed45 100644 --- a/src/lay/lay/laySystemPaths.cc +++ b/src/lay/lay/laySystemPaths.cc @@ -24,6 +24,7 @@ #include "laySystemPaths.h" #include "tlFileUtils.h" #include "tlString.h" +#include "tlEnv.h" #include #include @@ -31,32 +32,17 @@ #ifdef _WIN32 # include -#elif __APPLE__ -# include -# include -#else -# include #endif -#include - namespace lay { std::string get_appdata_path () { -#ifdef _WIN32 - wchar_t *env = _wgetenv (L"KLAYOUT_HOME"); - if (env) { - return tl::to_string (QString ((const QChar *) env)); + if (tl::has_env ("KLAYOUT_HOME")) { + return tl::get_env ("KLAYOUT_HOME"); } -#else - char *env = getenv ("KLAYOUT_HOME"); - if (env) { - return (tl::system_to_string (env)); - } -#endif QDir appdata_dir = QDir::homePath (); QString appdata_folder; @@ -138,23 +124,14 @@ get_klayout_path () // generate the klayout path: the first component is always the appdata path klayout_path.push_back (get_appdata_path ()); -#ifdef _WIN32 - wchar_t *env = _wgetenv (L"KLAYOUT_PATH"); - if (env) { - split_path (tl::to_string (QString ((const QChar *) env)), klayout_path); + + std::string env = tl::get_env ("KLAYOUT_PATH"); + if (! env.empty ()) { + split_path (env, klayout_path); } else { get_other_system_paths (klayout_path); klayout_path.push_back (tl::get_inst_path ()); } -#else - char *env = getenv ("KLAYOUT_PATH"); - if (env) { - split_path (tl::system_to_string (env), klayout_path); - } else { - get_other_system_paths (klayout_path); - klayout_path.push_back (tl::get_inst_path ()); - } -#endif return klayout_path; @@ -164,23 +141,7 @@ get_klayout_path () std::string salt_mine_url () { - const std::string default_url ("http://sami.klayout.org/repository.xml"); - -#ifdef _WIN32 - wchar_t *env = _wgetenv (L"KLAYOUT_SALT_MINE"); - if (env) { - return tl::to_string (QString ((const QChar *) env)); - } else { - return default_url; - } -#else - char *env = getenv ("KLAYOUT_SALT_MINE"); - if (env) { - return (tl::system_to_string (env)); - } else { - return default_url; - } -#endif + return tl::get_env ("KLAYOUT_SALT_MINE", "http://sami.klayout.org/repository.xml"); } } diff --git a/src/plugins/tools/xor/lay_plugin/layXORToolDialog.cc b/src/plugins/tools/xor/lay_plugin/layXORToolDialog.cc index ccb55afed..e4597edce 100644 --- a/src/plugins/tools/xor/lay_plugin/layXORToolDialog.cc +++ b/src/plugins/tools/xor/lay_plugin/layXORToolDialog.cc @@ -35,6 +35,7 @@ #include "tlTimer.h" #include "tlProgress.h" #include "tlThreadedWorkers.h" +#include "tlEnv.h" #include "tlExceptions.h" #include "tlMath.h" #include "layCellView.h" @@ -1085,7 +1086,7 @@ XORToolDialog::run_xor () bool summarize = mp_ui->summarize_cb->isChecked (); // TODO: make this a user interface feature later - bool process_el = lay::ApplicationBase::instance ()->special_app_flag ("ALWAYS_DO_XOR"); + bool process_el = tl::app_flag ("always-do-xor"); int cv_index_a = mp_ui->layouta->current_cv_index (); int cv_index_b = mp_ui->layoutb->current_cv_index (); diff --git a/src/tl/tl/tl.pro b/src/tl/tl/tl.pro index c63c2ec55..7ab83679f 100644 --- a/src/tl/tl/tl.pro +++ b/src/tl/tl/tl.pro @@ -46,7 +46,8 @@ SOURCES = \ tlList.cc \ tlEquivalenceClusters.cc \ tlUniqueName.cc \ - tlRecipe.cc + tlRecipe.cc \ + tlEnv.cc HEADERS = \ tlAlgorithm.h \ @@ -103,7 +104,8 @@ HEADERS = \ tlEquivalenceClusters.h \ tlUniqueName.h \ tlRecipe.h \ - tlSelect.h + tlSelect.h \ + tlEnv.h equals(HAVE_CURL, "1") { diff --git a/src/tl/tl/tlEnv.cc b/src/tl/tl/tlEnv.cc new file mode 100644 index 000000000..9b3e03e89 --- /dev/null +++ b/src/tl/tl/tlEnv.cc @@ -0,0 +1,85 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "tlEnv.h" +#include "tlString.h" + +#include + +#ifdef _WIN32 +# include +#elif __APPLE__ +# include +# include +#else +# include +#endif + +namespace tl +{ + +std::string get_env (const std::string &name, const std::string &def_value) +{ +#ifdef _WIN32 + std::wstring wname = tl::to_wstring (name); + wchar_t *env = _wgetenv (wname.c_str ()); + if (env) { + return tl::to_string (QString ((const QChar *) env)); + } else { + return def_value; + } +#else + char *env = getenv (name.c_str ()); + if (env) { + return tl::system_to_string (env); + } else { + return def_value; + } +#endif +} + +bool has_env (const std::string &name) +{ +#ifdef _WIN32 + std::wstring wname = tl::to_wstring (name); + wchar_t *env = _wgetenv (wname.c_str ()); + return env != 0; +#else + char *env = getenv (name.c_str ()); + return env != 0; +#endif +} + +bool app_flag (const std::string &name) +{ + std::string env_name = std::string ("KLAYOUT_") + tl::replaced (tl::to_upper_case (name), "-", "_"); + + int v = 0; + std::string vs = get_env (env_name); + tl::Extractor ex (vs.c_str ()); + return ex.try_read (v) && v != 0; +} + +} // namespace tl + + diff --git a/src/tl/tl/tlEnv.h b/src/tl/tl/tlEnv.h new file mode 100644 index 000000000..898ec142c --- /dev/null +++ b/src/tl/tl/tlEnv.h @@ -0,0 +1,65 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_tlAppFlags +#define HDR_tlAppFlags + +#include "tlCommon.h" + +#include + +namespace tl +{ + +/** + * @brief Gets the value for the given environment variable + * + * If the environment variable is not set, the default value will be returned. + */ +std::string TL_PUBLIC get_env (const std::string &name, const std::string &def_value = std::string ()); + +/** + * @brief Gets the value if the given environment variable is set + */ +bool TL_PUBLIC has_env (const std::string &name); + +/** + * @brief Gets an application flag with the given name + * + * This feature is supposed to deliver special flags for debugging etc. + * By using a central access point for these settings, it will be easy to provide + * different implementations later. + * + * Currently, application flags are derived by checking whether a corresponding + * environment variable exists. Names like "a-b" are translated into "KLAYOUT_A_B" + * for the environment variable. + * + * If the corresponding variable exists and does not have a value of "0", true + * is returned from this function. + */ +bool TL_PUBLIC app_flag (const std::string &name); + +} + +#endif + diff --git a/src/tl/tl/tlExpression.cc b/src/tl/tl/tlExpression.cc index 1d26b061b..28cb07d69 100644 --- a/src/tl/tl/tlExpression.cc +++ b/src/tl/tl/tlExpression.cc @@ -26,6 +26,7 @@ #include "tlString.h" #include "tlGlobPattern.h" #include "tlFileUtils.h" +#include "tlEnv.h" #include #include @@ -35,7 +36,6 @@ #define _USE_MATH_DEFINES // for MSVC #include #include -#include #include // Suggestions for further functions: @@ -2800,9 +2800,9 @@ env_f (const ExpressionParserContext &context, tl::Variant &out, const std::vect throw EvalError (tl::to_string (tr ("'env' function expects exactly two arguments")), context); } - const char *env = getenv (vv [0].to_string ()); - if (env) { - out = env; + const char *vn = vv [0].to_string (); + if (tl::has_env (vn)) { + out = tl::get_env (vn); } else { out = tl::Variant (); } diff --git a/src/tl/tl/tlLog.cc b/src/tl/tl/tlLog.cc index 258e793a3..1ada55bf2 100644 --- a/src/tl/tl/tlLog.cc +++ b/src/tl/tl/tlLog.cc @@ -23,16 +23,12 @@ #include "tlLog.h" #include "tlString.h" +#include "tlEnv.h" #include #if !defined(_MSC_VER) # include #endif -#include - -#if defined(_WIN32) -# include -#endif namespace tl { @@ -42,21 +38,9 @@ namespace tl static int default_verbosity () { - const char *verbosity_str = 0; - -#if defined(_WIN32) - const wchar_t *verbosity_wstr = _wgetenv (L"KLAYOUT_VERBOSITY"); - std::string vs; - if (verbosity_wstr) { - vs = tl::to_string (std::wstring (verbosity_wstr)); - verbosity_str = vs.c_str (); - } -#else - verbosity_str = getenv ("KLAYOUT_VERBOSITY"); -#endif - int verbosity = 0; - if (verbosity_str) { + std::string verbosity_str = tl::get_env ("KLAYOUT_VERBOSITY"); + if (! verbosity_str.empty ()) { try { tl::from_string (verbosity_str, verbosity); } catch (...) { diff --git a/src/tl/tl/tlUnitTest.cc b/src/tl/tl/tlUnitTest.cc index 8a719b5fb..f0dd8c7e3 100644 --- a/src/tl/tl/tlUnitTest.cc +++ b/src/tl/tl/tlUnitTest.cc @@ -24,6 +24,7 @@ #include "tlFileUtils.h" #include "tlTimer.h" #include "tlStream.h" +#include "tlEnv.h" #include @@ -85,8 +86,8 @@ void set_debug_mode (bool f) std::string testsrc () { - const char *ts = getenv ("TESTSRC"); - if (! ts) { + std::string ts = tl::get_env ("TESTSRC"); + if (ts.empty ()) { throw tl::Exception ("TESTSRC undefined"); } return ts; @@ -104,8 +105,8 @@ std::string testsrc_private () std::string testtmp () { // Ensures the test temp directory is present - const char *tt = getenv ("TESTTMP"); - if (! tt) { + std::string tt = tl::get_env ("TESTTMP"); + if (tt.empty ()) { throw tl::Exception ("TESTTMP undefined"); } return tt; diff --git a/src/tl/unit_tests/tlExpression.cc b/src/tl/unit_tests/tlExpression.cc index 7bbb7dcc5..751a3e3a3 100644 --- a/src/tl/unit_tests/tlExpression.cc +++ b/src/tl/unit_tests/tlExpression.cc @@ -24,8 +24,8 @@ #include "tlExpression.h" #include "tlVariantUserClasses.h" #include "tlUnitTest.h" +#include "tlEnv.h" -#include #define _USE_MATH_DEFINES // for MSVC #include @@ -834,7 +834,7 @@ TEST(6) v = e.parse ("env('HJASK')").execute (); EXPECT_EQ (v.to_string (), std::string ("nil")); v = e.parse ("env('PATH')").execute (); - EXPECT_EQ (v.to_string (), std::string (getenv ("PATH"))); + EXPECT_EQ (v.to_string (), tl::get_env ("PATH")); v = e.parse ("absolute_path('./x.gds')").execute (); // EXPECT_EQ (v.to_string (), std::string ()); // not universal v = e.parse ("absolute_file_path('./x.gds')").execute ();