//----------------------------------------------------------- // Copyright Christian Arnault LAL-Orsay CNRS // arnault@lal.in2p3.fr // See the complete license in cmt_license.txt "http://www.cecill.info". //----------------------------------------------------------- #include #include #include #include #include "cmt_use.h" #include "cmt_symbol.h" #include "cmt_system.h" #include "cmt_database.h" //------------------------------------------------------------- class SetBuilder : public ValueBuilder { public: const cmt_string build (const Symbol& symbol, const cmt_string& tag_name = ""); const cmt_string clean (const Symbol& symbol, const cmt_string& tag_name = "") { static const cmt_string empty = ""; return (empty); } }; //------------------------------------------------------------- //------------------------------------------------------------- class PathBuilder : public ValueBuilder { public: const cmt_string build (const Symbol& symbol, const cmt_string& tag_name = ""); const cmt_string clean (const Symbol& symbol, const cmt_string& tag_name = ""); }; //------------------------------------------------------------- //------------------------------------------------------------- class MacroBuilder : public ValueBuilder { public: const cmt_string build (const Symbol& symbol, const cmt_string& tag_name = ""); const cmt_string clean (const Symbol& symbol, const cmt_string& tag_name = "") { static const cmt_string empty = ""; return (empty); } }; //------------------------------------------------------------- //------------------------------------------------------------- class ScriptBuilder : public ValueBuilder { public: const cmt_string build (const Symbol& symbol, const cmt_string& tag_name = ""); const cmt_string clean (const Symbol& symbol, const cmt_string& tag_name = "") { static const cmt_string empty = ""; return (empty); } }; //------------------------------------------------------------- //------------------------------------------------------------- class ActionBuilder : public ValueBuilder { public: const cmt_string build (const Symbol& symbol, const cmt_string& tag_name = ""); const cmt_string clean (const Symbol& symbol, const cmt_string& tag_name = "") { static const cmt_string empty = ""; return (empty); } }; //------------------------------------------------------------- //------------------------------------------------------------- class symbol_marker { public: symbol_marker () { ptr = cmt_string::npos; pattern = 0; intro = 0; } symbol_marker (int a_ptr, char a_pattern, int a_intro) { ptr = a_ptr; pattern = a_pattern; intro = a_intro; } symbol_marker (const symbol_marker& other) { ptr = other.ptr; pattern = other.pattern; intro = other.intro; } void set (int a_ptr, char a_pattern, int a_intro) { ptr = a_ptr; pattern = a_pattern; intro = a_intro; } static symbol_marker& get_lowest (symbol_marker markers[], int count) { static symbol_marker result; int real_count = 0; int i; // Check that at least one marker has result for (i = 0; i < count; i++) { if (markers[i].ptr != cmt_string::npos) real_count++; } if (real_count == 0) return (result); // since we've passed the previous test, // at least one entry is not npos. // Now discards other npos by moving them to the end for (i = 0; i < count;) { if (markers[i].ptr == cmt_string::npos) { markers[i] = markers[count-1]; count--; if (count == 0) break; } else { i++; } } if (count == 0) return (result); // now all entries in [0, count-1] are not npos // let's sort the lowest one in [0] for (i = 1; i < count;) { if (markers[0].ptr > markers[i].ptr) { symbol_marker temp = markers[0]; markers[0] = markers[i]; markers[i] = temp; i = 1; } else { i++; } } return (markers[0]); } int ptr; char pattern; int intro; }; //------------------------------------------------------------- /** Attempt to substitute all occurrences of ${} $() %% [on Windows only] by the specified value in the given text. This is for one symbol only */ static void resolve_value (cmt_string& text, const cmt_string& symbol_name, const cmt_string& value) { static cmt_string pattern; pattern = "${"; pattern += symbol_name; pattern += "}"; text.replace_all (pattern, value); pattern = "$("; pattern += symbol_name; pattern += ")"; text.replace_all (pattern, value); #ifdef WIN32 pattern = "%"; pattern += symbol_name; pattern += "%"; text.replace_all (pattern, value); #endif } /** Attempt to substitute into the specified text all occurrences of ${xxx} $(xxx) `xxx` %xxx% [on Windows only] by the appropriate value: for `xxx` : xxx is considered as a shell command. Value is the result of its execution for other patterns: if xxx is a symbol name, its value is substituted to the pattern otherwise, xxx is tried as an environment variable ===> In all cases, the pattern is filtered away. */ static void resolve_value (cmt_string& text) { //static cmt_regexp reg ("[$%`]"); //if (!reg.match (text)) return; cmt_string pattern; cmt_string symbol_name; char end_pattern; int start = 0; for (;;) { int begin; int end; symbol_marker markers[4]; int num = 0; markers[num].set (text.find (start, "$("), ')', 2); num++; markers[num].set (text.find (start, "${"), '}', 2); num++; markers[num].set (text.find (start, "`"), '`', 1); num++; #ifdef WIN32 markers[num].set (text.find (start, "%"), '%', 1); num++; #endif // Find the first matching pattern symbol_marker& marker = symbol_marker::get_lowest (markers, num); begin = marker.ptr; if (begin == cmt_string::npos) break; end_pattern = marker.pattern; start = begin + marker.intro; end = text.find (start, end_pattern); if (end == cmt_string::npos) { // The pattern is a fake one (no ending!) start++; continue; } // This should never happen... if (end < begin) break; // Extract the complete pattern text.substr (begin, end - begin + 1, pattern); // Then only the symbol name text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name); if (text[begin] == '`') { cmt_string command = symbol_name; resolve_value (command); // The value is a shell command that first needs // to be applied. The output of the command is then substituted cmt_string result; Symbol::all_set (); CmtSystem::execute (command, result); int pos; pos = result.find ('\n'); if (pos != cmt_string::npos) result.erase (pos); pos = result.find ('\r'); if (pos != cmt_string::npos) result.erase (pos); if (Cmt::get_debug ()) { cout << " Executing [" << command << "] to expand a symbol value =>[" << result << "]" << endl; } text.replace_all (pattern, result); // The substitution will restart from the same place // allowing for recursive replacements start = begin; } else { Symbol* symbol = Symbol::find (symbol_name); if (symbol != 0) { // Symbol found cmt_string value = symbol->resolve_macro_value (); text.replace_all (pattern, value); // The substitution will restart from the same place // allowing for recursive replacements start = begin; } else { // Symbol not found. Look for env. variable cmt_string value = CmtSystem::getenv (symbol_name); // When the env. variable is not defined, the replacement is empty // thus all $(xxx) ${xxx} %xxx% patterns are always filtered away. text.replace_all (pattern, value); // The substitution will restart from the same place // allowing for recursive replacements start = begin; } } } } /** Attempt to substitute all occurrences of ${xxx} $(xxx) `xxx` %xxx% [on Windows only] by the appropriate value: for `xxx` : xxx is considered as a shell command. Value is the result of its execution for other patterns: if xxx is a macro name, its value is substituted to the pattern if xxx is a set or a path, it is kept in place (after fixing the pattern according to the OS style) otherwise it is simply kept in place */ static void resolve_value_for_macros (cmt_string& text) { cmt_string pattern; cmt_string symbol_name; char end_pattern; int start = 0; for (;;) { // // Try and substitute all ${xxx} $(xxx) or %xxx% patterns // using symbol values, only when the symbol is a macro. // int begin; int end; symbol_marker markers[4]; int num = 0; markers[num].set (text.find (start, "$("), ')', 2); num++; markers[num].set (text.find (start, "${"), '}', 2); num++; #ifdef WIN32 markers[num].set (text.find (start, "%"), '%', 1); num++; #endif markers[num].set (text.find (start, "`"), '`', 1); num++; // Find the first of three patterns symbol_marker& marker = symbol_marker::get_lowest (markers, num); begin = marker.ptr; if (begin == cmt_string::npos) break; end_pattern = marker.pattern; start = begin + marker.intro; end = text.find (start, end_pattern); if (end == cmt_string::npos) { // The pattern is a fake one (no ending!) start++; continue; } // This should never happen... if (end < begin) break; // Extract the complete pattern text.substr (begin, end - begin + 1, pattern); // Then only the macro name text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name); if (text[begin] == '`') { cmt_string command = symbol_name; resolve_value (command); // The macro value is a shell command that first needs // to be applied. The output of the command is substituted cmt_string result; Symbol::all_set (); CmtSystem::execute (command, result); int pos; pos = result.find ('\n'); if (pos != cmt_string::npos) result.erase (pos); pos = result.find ('\r'); if (pos != cmt_string::npos) result.erase (pos); if (Cmt::get_debug ()) { cout << " Executing [" << command << "] to expand a macro value =>[" << result << "]" << endl; } text.replace_all (pattern, result); // The substitution will restart from the same place // allowing for recursive replacements start = begin; } else { Symbol* macro = Symbol::find (symbol_name); if ((macro != 0) && (macro->type == Symbol::SymbolMacro)) { // Macro found cmt_string value = macro->resolve_macro_value (); text.replace_all (pattern, value); // The substitution will restart from the same place // allowing for recursive replacements start = begin; } else if ((macro == 0) || ((macro->type == Symbol::SymbolSet) || (macro->type == Symbol::SymbolPath))) { // Set found // ensure that the delimiters will match the OS dependent // delimiters. cmt_string pattern_close = marker.pattern; if (pattern_close != CmtSystem::ev_close ()) { cmt_string new_pattern; new_pattern = CmtSystem::ev_open (); new_pattern += symbol_name; new_pattern += CmtSystem::ev_close (); text.replace (pattern, new_pattern); } start = end + 1; } else { start = end + 1; } } } } /** This function suppress all OS delimiters ie ${ } or % % and replaces them by the pure macro delimiters $( ) `xxx` pattern is replaced by the result of the execution of the command */ static void suppress_OS_delimiters (cmt_string& text) { cmt_string pattern; cmt_string symbol_name; char end_pattern; int start = 0; for (;;) { int begin; int end; symbol_marker markers[3]; int num = 0; markers[num].set (text.find (start, "${"), '}', 2); num++; markers[num].set (text.find (start, "`"), '`', 1); num++; #ifdef WIN32 markers[num].set (text.find (start, "%"), '%', 1); num++; #endif // Find the first of three patterns symbol_marker& marker = symbol_marker::get_lowest (markers, num); begin = marker.ptr; if (begin == cmt_string::npos) break; end_pattern = marker.pattern; start = begin + marker.intro; end = text.find (start, end_pattern); if (end == cmt_string::npos) { // The pattern is a fake one (no ending!) start++; continue; } // This should never happen... if (end < begin) break; // Extract the complete pattern text.substr (begin, end - begin + 1, pattern); // Then only the macro name text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name); if (text[begin] == '`') { cmt_string command = symbol_name; resolve_value (command); // The macro value is a shell command that first needs // to be applied. The output of the command is substituted cmt_string result; Symbol::all_set (); CmtSystem::execute (command, result); int pos; pos = result.find ('\n'); if (pos != cmt_string::npos) result.erase (pos); pos = result.find ('\r'); if (pos != cmt_string::npos) result.erase (pos); if (Cmt::get_debug ()) { cout << " Executing [" << command << "] to expand a macro value =>[" << result << "]" << endl; } text.replace_all (pattern, result); // The substitution will restart from the same place // allowing for recursive replacements start = begin; } else { cmt_string new_pattern; new_pattern = "$("; new_pattern += symbol_name; new_pattern += ")"; text.replace (pattern, new_pattern); start = begin; } } } //------------------------------------------------------------- /* */ /* Operations on SymbolValues */ /* */ //------------------------------------------------------------- //------------------------------------------------------------- SymbolValue::SymbolValue () { tag = 0; } //------------------------------------------------------------- SymbolValue::~SymbolValue () { tag = 0; } //------------------------------------------------------------- /* */ /* Operations on Symbols */ /* */ //------------------------------------------------------------- //------------------------------------------------------------- Symbol* Symbol::create (const cmt_string& name, CommandType command, Use* use) { static SetBuilder Set; static PathBuilder Path; static MacroBuilder Macro; static ScriptBuilder Script; static ActionBuilder Action; static SymbolVector& Symbols = symbols (); static SymbolMap& SymbolMap = symbol_map (); SymbolType type = SymbolUndefined; switch (command) { case CommandSet: case CommandSetAppend: case CommandSetPrepend: case CommandSetRemove: case CommandSetRemoveRegexp: type = SymbolSet; break; case CommandPath: case CommandPathAppend: case CommandPathPrepend: case CommandPathRemove: case CommandPathRemoveRegexp: type = SymbolPath; break; case CommandMacro: case CommandMacroAppend: case CommandMacroPrepend: case CommandMacroRemove: case CommandMacroRemoveRegexp: case CommandMacroRemoveAll: case CommandMacroRemoveAllRegexp: type = SymbolMacro; break; case CommandAction: type = SymbolAction; break; case CommandAlias: type = SymbolAlias; break; case CommandSetupScript: type = SymbolSetupScript; break; case CommandCleanupScript: type = SymbolCleanupScript; break; } { Symbol* symbol; symbol = find (name); if (symbol != 0) { if (symbol->type != type) { ActionType action = Cmt::get_action (); if ((!Cmt::get_quiet ()) && (action != action_build_tag_makefile)) { cmt_string s1; cmt_string s2; switch (symbol->type) { case SymbolSet: s1 = "set"; break; case SymbolPath: s1 = "path"; break; case SymbolMacro: s1 = "macro"; break; case SymbolSetupScript: s1 = "setup_script"; break; case SymbolCleanupScript: s1 = "cleanup_script"; break; case SymbolAction: s1 = "action"; break; case SymbolAlias: s1 = "alias"; break; } switch (type) { case SymbolSet: s2 = "set"; break; case SymbolPath: s2 = "path"; break; case SymbolMacro: s2 = "macro"; break; case SymbolSetupScript: s2 = "setup_script"; break; case SymbolCleanupScript: s2 = "cleanup_script"; break; case SymbolAction: s2 = "action"; break; case SymbolAlias: s2 = "alias"; break; } cerr << "#CMT> Warning: Symbol " << name << " inconsistently redeclared from " << s1 << " to " << s2; if (use != 0) cerr << " in package " << use->get_package_name (); cerr << endl; } } return (symbol); } } Symbol& symbol = Symbols.add (); SymbolMap.add (name, symbol); symbol.name = name; symbol.scope = use->get_current_scope (); symbol.type = type; symbol.value_lists.clear (); switch (type) { case SymbolSet: symbol.builder = &Set; break; case SymbolPath: symbol.builder = &Path; break; case SymbolAlias: symbol.builder = &Set; break; case SymbolMacro: symbol.builder = &Macro; break; case SymbolSetupScript: case SymbolCleanupScript: symbol.builder = &Script; break; case SymbolAction: symbol.builder = &Action; break; } symbol.selected_value = -1; return (&symbol); } //------------------------------------------------------------- Symbol* Symbol::find (const cmt_string& name) { static SymbolMap& SymbolMap = symbol_map (); Symbol* result = 0; result = SymbolMap.find (name); return (result); } //------------------------------------------------------------- int Symbol::symbol_number () { static SymbolVector& Symbols = symbols (); return (Symbols.size ()); } //------------------------------------------------------------- Symbol::SymbolVector& Symbol::symbols () { static Database& db = Database::instance (); static SymbolVector& Symbols = db.symbols (); return (Symbols); } //------------------------------------------------------------- Symbol::SymbolMap& Symbol::symbol_map () { static Database& db = Database::instance (); static SymbolMap& SymbolMap = db.symbol_map (); return (SymbolMap); } //------------------------------------------------------------- Symbol& Symbol::symbol (int index) { static SymbolVector& Symbols = symbols (); return (Symbols[index]); } //------------------------------------------------------------- void Symbol::action (const CmtSystem::cmt_string_vector& words, CommandType command_type, Use* use) { int number; Symbol* symbol; Tag* tag; if (words.size () < 1) return; cmt_string name = words[1]; if ((command_type == CommandSetupScript) || (command_type == CommandCleanupScript)) { cmt_string full_name; Symbol::expand (name); if (name != "") { if (CmtSystem::absolute_path (name)) { full_name = name; } else { #ifdef WIN32 full_name = "%"; #else full_name = "${"; #endif full_name += use->prefix; full_name += "ROOT"; #ifdef WIN32 full_name += "%"; #else full_name += "}"; #endif full_name += CmtSystem::file_separator (); if (use->style == cmt_style) full_name += "cmt"; else if (use->style == no_version_style) full_name += "cmt"; else full_name += "mgr"; full_name += CmtSystem::file_separator (); full_name += name; } symbol = create (full_name, command_type, use); symbol->add_value_to_list (command_type, use, Tag::get_default (), full_name); } } else { if (words.size () < 2) return; const cmt_string& default_value = words[2]; if (Cmt::get_debug ()) { cout << "Symbol::action> name:" << name << " access:" << Cmt::get_current_access () << " scope:" << use->get_current_scope () << endl; } if (Cmt::get_current_access () == UserMode) { if (name == "constituents") return; if (name == "constituentscclean") return; if (use->get_current_scope () == ScopePrivate) return; } symbol = create (name, command_type, use); /* Parse the default value. */ symbol->add_value_to_list (command_type, use, Tag::get_default (), default_value); /* Then parse all specific values ... */ number = 3; while (number < (words.size () - 1)) { cmt_string tag_name = words[number]; const cmt_string& value = words[number + 1]; expand (tag_name); if (Cmt::get_debug ()) { cout << "Symbol::action> tag_name=" << tag_name << endl; } tag = Tag::find (tag_name); if (tag == 0) { tag = Tag::add (tag_name, PriorityUserTag, "use", use); } symbol->add_value_to_list (command_type, use, tag, value); number += 2; } if (name == "CMTPATH") { Cmt::configure_cmt_path (use); } else if (name == "CMTSITE") { Cmt::configure_site_tag (use); } else if (name == "CMTCONFIG") { //cerr << "redefining CMTCONFIG" << endl; Cmt::configure_tags (use); } else if (name == "CMTHOME") { Cmt::configure_home (use); } else if (name == "CMTUSERCONTEXT") { Cmt::configure_user_context (use); } else if (name.find ("_native_version") != cmt_string::npos) { cmt_string n = use->get_package_name (); n += "_native_version"; if (name == n) { use->set_native_version (true); } } } } //------------------------------------------------------------- int Symbol::is_selected (const cmt_string& name) { Symbol* symbol; int number; int value_number; symbol = find (name); if (symbol == 0) return (0); if (symbol->value_lists.size () == 0) return (0); for (number = 0; number < symbol->value_lists.size (); number++) { const SymbolValueList& value_list = symbol->value_lists[number]; if (value_list.discarded) continue; if ((value_list.command_type == CommandMacro) || (value_list.command_type == CommandSet) || (value_list.command_type == CommandSetAppend) || (value_list.command_type == CommandSetPrepend) || (value_list.command_type == CommandSetRemove) || (value_list.command_type == CommandSetRemoveRegexp) || (value_list.command_type == CommandAlias) || (value_list.command_type == CommandAction)) { for (value_number = 0; value_number < value_list.values.size (); value_number++) { Tag* tag; SymbolValue& value = value_list.values[value_number]; tag = value.tag; if ((tag == 0) || (tag == Tag::get_default ()) || (tag->is_selected () != 0)) { return (1); } } } } return (0); } //------------------------------------------------------------- Symbol::Symbol () { name = ""; } //------------------------------------------------------------- Symbol::~Symbol () { } /** * Characterizes if a value is provided as the reference to itself. */ bool Symbol::value_is_reflexive (const cmt_string& text) const { bool result = false; int text_length = text.size (); if (text_length == (name.size () + 3)) { static cmt_string temp; if (text[0] == '$') { if (text[1] == '(') { temp = "$("; temp += name; temp += ")"; if (text == temp) { result = true; } } else if (text[1] == '{') { temp = "${"; temp += name; temp += "}"; if (text == temp) { result = true; } } } } else if (text_length == (name.size () + 2)) { static cmt_string temp; temp = "%"; temp += name; temp += "%"; if (text == temp) { result = true; } } return (result); } //------------------------------------------------------------- void Symbol::add_value_to_list (CommandType command_type, Use* use, Tag* tag, const cmt_string& text) { SymbolValueList* value_list = 0; bool is_reflexive = false; // // First pickup the most recent value_list // if (value_lists.size () > 0) value_list = &(value_lists.back ()); // // Create a new value list is we switch to another use or // if we switch to a new command_type (eg. switching from // macro to macro_append). // if ((value_list == 0) || (use != value_list->use) || (command_type != value_list->command_type) || (tag == Tag::get_default ())) { value_list = &(value_lists.add ()); value_list->use = use; value_list->command_type = command_type; value_list->values.clear (); value_list->discarded = false; value_list->is_reflexive = false; } /* else { value_list = &(value_lists[value_lists.size () - 1]); } */ is_reflexive = value_list->is_reflexive; // // If the command_type is command_macro or command_set, // this is considered as a full re-set of this symbol // In this case, we have to discard all previous values // // However, we'd like to exclude from this logic the cases where // the value is **exactly* // // $() // ${} // %% // // which would then mean that we do not reset the value but rather // override it. // // // Inside this value_list, we add this new tag-value pair. // if ((command_type == CommandMacro) || (command_type == CommandSet) || (command_type == CommandPath) || (command_type == CommandAction)) { // // Check whether we have to hide previous settings by this new definition // (of course this is only useful if there WERE previous settings) // if ((value_lists.size () >= 1) && (!is_reflexive)) { if (value_is_reflexive (text)) { value_list->is_reflexive = true; is_reflexive = true; } else { //cout << "...discarding old values for symbol " << name << " text=[" << text << "]" << endl; for (int i = 0; i < (value_lists.size () - 1); i++) { SymbolValueList& vl = value_lists[i]; if ((vl.use != 0) && (vl.use->discarded)) { //vl.discarded = true; } } } } } SymbolValue& value = value_list->values.add (); value.tag = tag; value.text = text; value.selected = 0; } /** Compute the current value of all environment variables and set them to the shell */ void Symbol::all_set () { static bool done = false; if (Cmt::get_debug ()) { cout << "Symbol::all_set> done" << done << endl; } if (done) return; done = true; static SymbolVector& Symbols = symbols (); static CmtSystem::cmt_string_vector envs; envs.clear (); int number; if (Symbols.size () == 0) { //running = false; return; } cmt_string value; for (number = 0; number < Symbol::symbol_number (); number++) { Symbol& symbol = Symbol::symbol (number); if (symbol.type != SymbolSet) continue; value = symbol.build_macro_value (); if (value != "") { cmt_string& temp = envs.add (); temp = symbol.name; temp += '='; temp += value; } } for (number = 0; number < Symbol::symbol_number (); number++) { Symbol& symbol = Symbol::symbol (number); if ((symbol.type != SymbolPath)) continue; value = symbol.build_macro_value (); if (value != "") { cmt_string& temp = envs.add (); temp = symbol.name; temp += '='; temp += value; } } for (number = 0; number < envs.size (); number++) { cmt_string& env = envs[number]; Symbol::expand (env); #ifdef WIN32 env.replace_all ("/", "\\"); #endif if (Cmt::get_debug ()) { cout << "Symbol::all_set> " << env << endl; } CmtSystem::putenv (env); } //running = false; } //------------------------------------------------------------- void Symbol::all_print (PrintMode mode) { static SymbolVector& Symbols = symbols (); int number; if (Symbols.size () == 0) return; for (number = 0; number < Symbol::symbol_number (); number++) { Symbol& symbol = Symbol::symbol (number); if ((symbol.type == SymbolSet) || (symbol.type == SymbolAlias) || (symbol.type == SymbolSetupScript)) { if (symbol.print (mode)) { if (mode == Bat) { cout << endl; } else { //cout << "; "; cout << endl; } } } } for (number = 0; number < Symbol::symbol_number (); number++) { Symbol& symbol = Symbol::symbol (number); if ((symbol.type != SymbolPath)) continue; if (symbol.print (mode)) { if (mode == Bat) { cout << endl; } else { //cout << "; "; cout << endl; } } } } //------------------------------------------------------------- void Symbol::all_print_clean (PrintMode mode) { static SymbolVector& Symbols = symbols (); int number; if (Symbols.size () == 0) return; for (number = Symbols.size () - 1; number >= 0; number--) { Symbol& symbol = Symbols[number]; if ((symbol.type == SymbolSet) || (symbol.type == SymbolAlias) || (symbol.type == SymbolCleanupScript)) { if (symbol.print_clean (mode)) { cout << endl; } } } for (number = Symbols.size () - 1; number >= 0; number--) { Symbol& symbol = Symbols[number]; if ((symbol.type != SymbolPath)) continue; if (symbol.print_clean (mode)) { cout << endl; } } } //------------------------------------------------------------- int Symbol::print_clean (PrintMode mode) { int result = 0; static cmt_string temp; if (name == "CMTCONFIG") return (0); switch (type) { case SymbolSet : switch (mode) { case Csh : cout << "unsetenv " << name; result = 1; break; case Sh : cout << "unset " << name; result = 1; break; case Bat : cout << "set " << name << "="; result = 1; break; } break; case SymbolAlias : switch (mode) { case Csh : cout << "unalias " << name; result = 1; break; case Sh : cout << "unset " << name; result = 1; break; } break; case SymbolPath : temp = clean_macro_value (); switch (mode) { case Csh : if (temp == "") { cout << "unsetenv " << name; } else { cout << "setenv " << name << " " << temp; } result = 1; break; case Sh : cout << name << "=" << temp << "; export " << name; result = 1; break; case Bat : cout << "set " << name << "=" << temp; result = 1; break; } break; case SymbolCleanupScript : switch (mode) { case Csh : cout << "if ( -f " << name << ".csh ) then" << endl; cout << " source " << name << ".csh" << endl; cout << "endif" << endl; result = 1; break; case Sh : cout << "if test -f " << name << ".sh; then" << endl; cout << " . " << name << ".sh" << endl; cout << "fi" << endl; result = 1; break; case Bat : cout << "call " << name; result = 1; break; } break; } return (result); } //------------------------------------------------------------- int Symbol::print (PrintMode mode) { int result = 0; cmt_string temp; temp = build_macro_value (); bool empty = (temp.size () == 0) ? true : false; switch (type) { case SymbolSet : case SymbolPath : switch (mode) { case Csh : if (empty) cout << "unsetenv " << name; else cout << "setenv " << name << " \"" << temp << "\""; result = 1; break; case Sh : if (empty) cout << "unset " << name; else cout << name << "=\"" << temp << "\"; export " << name; result = 1; break; case Bat : temp.replace_all ("/", "\\"); cout << "set " << name << "=" << temp; result = 1; break; } break; case SymbolAlias : switch (mode) { case Csh : cout << "alias " << name << " \"" << temp << "\""; result = 1; break; case Sh : cout << "alias " << name << "=\"" << temp << "\"; export " << name; result = 1; break; case Bat : cout << "set " << name << "=" << temp; result = 1; break; } break; default : break; } if (temp != "") { switch (type) { case SymbolSetupScript : switch (mode) { case Csh : cout << "if ( -f " << name << ".csh ) then" << endl; cout << " source " << name << ".csh" << endl; cout << "endif" << endl; result = 1; break; case Sh : cout << "if test -f " << name << ".sh; then" << endl; cout << " . " << name << ".sh" << endl; cout << "fi" << endl; result = 1; break; case Bat : cout << "call " << name; result = 1; break; } break; default: break; } } return (result); } //------------------------------------------------------------- cmt_string Symbol::build_macro_value () const { cmt_string temp; temp = builder->build (*this); return (temp); } //------------------------------------------------------------- cmt_string Symbol::clean_macro_value () const { cmt_string temp; temp = builder->clean (*this); return (temp); } /** Attempt to substitute into the symbol value all occurrences of ${xxx} $(xxx) `xxx` %xxx% [on Windows only] by the appropriate value: for `xxx` : xxx is considered as a shell command. Value is the result of its execution for other patterns: if xxx is a symbol name, its value is substituted to the pattern otherwise, xxx is tried as an environment variable ===> In all cases, the pattern is filtered away. */ cmt_string Symbol::resolve_macro_value (const cmt_string& tag_name) { cmt_string temp = builder->build (*this, tag_name); resolve_value (temp); return (temp); } //------------------------------------------------------------- void Symbol::show_macro (PrintMode mode) { if (Cmt::get_debug ()) { cout << "Symbol::show_macro> " << name << endl; } ActionType action = Cmt::get_action (); cmt_string value = build_macro_value (); if ((!Cmt::get_quiet ()) && (action != action_build_tag_makefile) && (action != action_show_macros) && (action != action_show_actions) && (action != action_show_sets)) { cout << "#" << endl; cout << "# Selection : " << endl; } if (value.size () > 0) { if ((action == action_show_macro) || (action == action_show_macros) || (action == action_show_sets) || (action == action_show_set) || (action == action_show_actions) || (action == action_show_action) || (action == action_build_tag_makefile) || (action == action_load) || (!Cmt::get_quiet ())) { if (mode == Make) { cout << name << "="; } else { cout << name << "='"; } } if ((action == action_show_macro_value) || (action == action_show_set_value) || (action == action_show_action_value)) { expand (value); } else if (action == action_build_tag_makefile) { /* Unfortunately, the %xxx% pattern has to be kept on Unix. Therefore we cannot force all patterns to become $(xxx) This was useful on Windows so as to only keep $(xxx) */ #ifdef WIN32 suppress_OS_delimiters (value); #endif } cout << value; if ((action == action_show_macro) || (action == action_show_macros) || (action == action_show_sets) || (action == action_show_set) || (action == action_show_actions) || (action == action_show_action) || (action == action_build_tag_makefile) || (action == action_load) || (!Cmt::get_quiet ())) { if (mode != Make) { cout << "'"; } #ifdef WIN32 else { cout << " "; } #endif } cout << endl; } } //------------------------------------------------------------- void Symbol::clear_all () { static SymbolVector& Symbols = symbols (); static SymbolMap& SymbolMap = symbol_map (); SymbolMap.clear (); Symbols.clear (); } //------------------------------------------------------------- void Symbol::expand (cmt_string& text) { static cmt_regexp reg ("[$%`]"); if (!reg.match (text)) return; resolve_value (text); } //------------------------------------------------------------- const cmt_string SetBuilder::build (const Symbol& symbol, const cmt_string& /*tag_name*/) { // Control of recursivity static int level = 0; int show_it = 0; cmt_string temp; cmt_string previous_temp; cmt_string new_value; static const cmt_string empty; ActionType action = Cmt::get_action (); if (action == action_show_set) { if (symbol.name == Cmt::get_current_target ()) { // Should not display on recursive calls if (level == 0) show_it = 1; } } level++; temp = ""; bool first_definition = true; bool defined = false; for (int i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if ((value_list.use != 0) && (value_list.use->discarded)) continue; const int selected = value_list.select_first (); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; if (show_it) { value_list.show (symbol, value, first_definition); } if (value_list.discarded) continue; // // One should accumulate values if it refers to // itself. // new_value = value.text; resolve_value_for_macros (new_value); switch (value_list.command_type) { case CommandSet : if (!value_list.is_reflexive || !symbol.value_is_reflexive (value.text)) { resolve_value (new_value, symbol.name, temp); temp = new_value; } else if (temp == "") { temp = CmtSystem::getenv (symbol.name); } if (!defined) { defined = true; } else { if ((!Cmt::get_quiet ()) && ((action == action_show_macro) || (action == action_show_set) || (action == action_show_action) || (action == action_show_macros) || (action == action_show_sets) || (action == action_show_actions))) { cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden"; if (value_list.use != 0) { cerr << " in package " << value_list.use->get_package_name (); } cerr << endl; } } break; case CommandSetAppend : if (new_value != "") { temp += new_value; } break; case CommandSetPrepend : if (new_value != "") { previous_temp = temp; temp = new_value; temp += previous_temp; } break; case CommandSetRemove : if (new_value != "") { temp.replace_all (new_value, empty); } break; case CommandSetRemoveRegexp : if (new_value != "") { cmt_regexp e (new_value); cmt_regexp::iterator it; for (;;) { it = e.begin (temp); if (it == e.end ()) break; temp.erase (it._pos, it._length); } } break; case CommandAlias : resolve_value (new_value, symbol.name, temp); temp = new_value; break; } } level--; return (temp); } static bool find_path_entry (const cmt_string& paths, const cmt_string& value) { static const cmt_string path_separator = CmtSystem::path_separator (); static const cmt_string double_path_separator = path_separator + path_separator; cmt_string complete_paths; complete_paths = path_separator; complete_paths += paths; complete_paths += path_separator; complete_paths.replace_all (double_path_separator, path_separator); cmt_string complete_value; complete_value = path_separator; complete_value += value; complete_value += path_separator; if (complete_paths.find (complete_value) == cmt_string::npos) return (false); else return (true); } //------------------------------------------------------------- const cmt_string PathBuilder::build (const Symbol& symbol, const cmt_string& /*tag_name*/) { // Control of recursivity static int level = 0; int show_it = 0; cmt_string temp; cmt_string previous_temp; cmt_string new_value; static const cmt_string empty; static cmt_string path_separator = CmtSystem::path_separator (); ActionType action = Cmt::get_action (); if (action == action_show_set) { if (symbol.name == Cmt::get_current_target ()) { // Should not display on recursive calls if (level == 0) show_it = 1; } } level++; temp = CmtSystem::getenv (symbol.name); bool first_definition = true; bool defined = false; for (int i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if ((value_list.use != 0) && (value_list.use->discarded)) continue; const int selected = value_list.select_first (); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; if (show_it) { value_list.show (symbol, value, first_definition); } if (value_list.discarded) continue; new_value = value.text; //resolve_value (new_value); resolve_value_for_macros (new_value); switch (value_list.command_type) { case CommandPath : if (!value_list.is_reflexive || !symbol.value_is_reflexive (value.text)) { resolve_value (new_value, symbol.name, temp); temp = new_value; if (!defined) { defined = true; } else { if ((!Cmt::get_quiet ()) && ((action == action_show_macro) || (action == action_show_set) || (action == action_show_action) || (action == action_show_macros) || (action == action_show_sets) || (action == action_show_actions))) { cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden"; if (value_list.use != 0) { cerr << " in package " << value_list.use->get_package_name (); } cerr << endl; } } } break; case CommandPathAppend : if (new_value != "") { if (!find_path_entry (temp, new_value)) { if (temp != "") temp += path_separator; temp += new_value; } } break; case CommandPathPrepend : if (new_value != "") { if (!find_path_entry (temp, new_value)) { previous_temp = temp; temp = new_value; if (previous_temp != "") temp += path_separator; temp += previous_temp; } } break; case CommandPathRemove : if (new_value != "") { CmtSystem::cmt_string_vector paths; CmtSystem::split (temp, path_separator, paths); for (int j = 0; j < paths.size (); ++j) { cmt_string& s = paths[j]; if (s.find (new_value) != cmt_string::npos) { s = ""; } } Cmt::vector_to_string (paths, path_separator, temp); temp.replace_all ("::", ":"); temp.replace_all (";;", ";"); } break; case CommandPathRemoveRegexp : if (new_value != "") { cmt_regexp e (new_value); CmtSystem::cmt_string_vector paths; CmtSystem::split (temp, path_separator, paths); for (int j = 0; j < paths.size (); ++j) { cmt_string& s = paths[j]; if (CmtSystem::getenv ("TESTPRR") != "") { cout << "PRR> s=[" << s << "]"; } if (e.match (s)) { s = ""; if (CmtSystem::getenv ("TESTPRR") != "") { cout << " match "; } } else { if (CmtSystem::getenv ("TESTPRR") != "") { cout << " no match "; } } if (CmtSystem::getenv ("TESTPRR") != "") { cout << endl; } } Cmt::vector_to_string (paths, path_separator, temp); temp.replace_all ("::", ":"); temp.replace_all (";;", ";"); } break; } } level--; return (temp); } //------------------------------------------------------------- const cmt_string PathBuilder::clean (const Symbol& symbol, const cmt_string& /*tag_name*/) { // Control of recursivity static int level = 0; cmt_string temp; cmt_string new_value; static const cmt_string empty; static cmt_string path_separator = CmtSystem::path_separator (); temp = CmtSystem::getenv (symbol.name); //cerr << "#####1 temp=" << temp << endl; for (int i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if (value_list.discarded) continue; if ((value_list.use != 0) && (value_list.use->discarded)) continue; const int selected = value_list.select_first (); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; new_value = value.text; //resolve_value (new_value); //cerr << "#####1 new_value=" << new_value << endl; resolve_value_for_macros (new_value); resolve_value (new_value); //cerr << "#####2 new_value=" << new_value << endl; switch (value_list.command_type) { case CommandPath : temp = ""; break; case CommandPathAppend : case CommandPathPrepend : case CommandPathRemove : if (new_value != "") { CmtSystem::cmt_string_vector paths; CmtSystem::split (temp, path_separator, paths); for (int j = 0; j < paths.size (); ++j) { cmt_string& s = paths[j]; if (s.find (new_value) != cmt_string::npos) { s = ""; } if (j > 0) { cmt_string& s2 = paths[j-1]; if (s2 == s) { s2 = ""; } } } Cmt::vector_to_string (paths, path_separator, temp); temp.replace_all ("::", ":"); temp.replace_all (";;", ";"); } break; case CommandPathRemoveRegexp : if (new_value != "") { cmt_regexp e (new_value); CmtSystem::cmt_string_vector paths; CmtSystem::split (temp, path_separator, paths); for (int j = 0; j < paths.size (); ++j) { cmt_string& s = paths[j]; if (e.match (s)) { s = ""; } if (j > 0) { cmt_string& s2 = paths[j-1]; if (s2 == s) { s2 = ""; } } } Cmt::vector_to_string (paths, path_separator, temp); temp.replace_all ("::", ":"); temp.replace_all (";;", ";"); } break; } } //cerr << "#####2 temp=" << temp << endl; return (temp); } //------------------------------------------------------------- const cmt_string MacroBuilder::build (const Symbol& symbol, const cmt_string& tag_name) { // Control of recursivity static int level = 0; cmt_string temp; cmt_string previous_temp; static const cmt_string empty; int show_it = 0; ActionType action = Cmt::get_action (); if (action == action_show_macro) { if (symbol.name == Cmt::get_current_target ()) { // Should not display on recursive calls if (level == 0) show_it = 1; } } level++; temp = ""; int i; bool first_definition = true; bool defined = false; for (i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if ((value_list.use != 0) && (value_list.use->discarded)) continue; if (value_list.command_type != CommandMacroPrepend) continue; const int selected = value_list.select_first (tag_name); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; if (show_it) { value_list.show (symbol, value, first_definition); } if (value_list.discarded) continue; previous_temp = temp; temp = value.text; temp += previous_temp; } previous_temp = temp; temp = ""; first_definition = true; for (i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if ((value_list.use != 0) && (value_list.use->discarded)) continue; if (value_list.command_type != CommandMacro) continue; const int selected = value_list.select_first (tag_name); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; if (show_it) { value_list.show (symbol, value, first_definition); } // WARNING: // Commented just for a test : should be uncommented after the test if (value_list.discarded) continue; if (!value_list.is_reflexive || !symbol.value_is_reflexive (value.text)) { temp = value.text; if (!defined) { defined = true; } else { /* if ((!Cmt::get_quiet ()) && ((action == action_show_macro) || (action == action_show_set) || (action == action_show_action) || (action == action_show_macros) || (action == action_show_sets) || (action == action_show_actions))) { cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden"; if (value_list.use != 0) { cerr << " in package " << value_list.use->get_package_name (); } cerr << endl; } */ } } } previous_temp += temp; temp = previous_temp; for (i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if ((value_list.use != 0) && (value_list.use->discarded)) continue; if (value_list.command_type != CommandMacroAppend) continue; const int selected = value_list.select_first (tag_name); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; if (show_it) { value_list.show (symbol, value, first_definition); } if (value_list.discarded) continue; temp += value.text; } for (i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if ((value_list.use != 0) && (value_list.use->discarded)) continue; if ((value_list.command_type != CommandMacroRemove) && (value_list.command_type != CommandMacroRemoveRegexp) && (value_list.command_type != CommandMacroRemoveAll) && (value_list.command_type != CommandMacroRemoveAllRegexp)) continue; const int selected = value_list.select_first (tag_name); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; if (show_it) { value_list.show (symbol, value, first_definition); } if (value_list.discarded) continue; switch (value_list.command_type) { case CommandMacroRemove : temp.replace (value.text, empty); break; case CommandMacroRemoveRegexp : if (value.text != "") { cmt_regexp e (value.text); cmt_regexp::iterator it; it = e.begin (temp); if (it != e.end ()) { temp.erase (it._pos, it._length); } } break; case CommandMacroRemoveAll : temp.replace_all (value.text, empty); break; case CommandMacroRemoveAllRegexp : if (value.text != "") { cmt_regexp e (value.text); cmt_regexp::iterator it; for (;;) { it = e.begin (temp); if (it != e.end ()) { temp.erase (it._pos, it._length); } else { break; } } } break; } } level--; return (temp); } //------------------------------------------------------------- const cmt_string ScriptBuilder::build (const Symbol& symbol, const cmt_string& tag_name) { // Control of recursivity static int level = 0; static const cmt_string empty = ""; if (symbol.value_lists.size () > 0) { const SymbolValueList& value_list = symbol.value_lists[0]; if (value_list.discarded) return (empty); if ((value_list.use != 0) && (value_list.use->discarded)) return (empty); } return (symbol.name); } //------------------------------------------------------------- const cmt_string ActionBuilder::build (const Symbol& symbol, const cmt_string& tag_name) { // Control of recursivity static int level = 0; cmt_string temp; cmt_string previous_temp; static const cmt_string empty; int show_it = 0; ActionType action = Cmt::get_action (); if (action == action_show_action) { if (symbol.name == Cmt::get_current_target ()) { // Should not display on recursive calls if (level == 0) show_it = 1; } } level++; int i; bool first_definition = true; bool defined = false; temp = ""; for (i = 0; i < symbol.value_lists.size (); i++) { const SymbolValueList& value_list = symbol.value_lists[i]; if ((value_list.use != 0) && (value_list.use->discarded)) continue; if (value_list.command_type != CommandAction) continue; const int selected = value_list.select_first (tag_name); if (selected < 0) continue; SymbolValue& value = value_list.values[selected]; if (show_it) { value_list.show (symbol, value, first_definition); } // WARNING: // Commented just for a test : should be uncommented after the test if (value_list.discarded) continue; if (!value_list.is_reflexive || !symbol.value_is_reflexive (value.text)) { temp = value.text; if (!defined) { defined = true; } else { if ((!Cmt::get_quiet ()) && ((action == action_show_macro) || (action == action_show_set) || (action == action_show_action) || (action == action_show_macros) || (action == action_show_sets) || (action == action_show_actions))) { cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden"; if (value_list.use != 0) { cerr << " in package " << value_list.use->get_package_name (); } cerr << endl; } } } } level--; return (temp); } //------------------------------------------------------------- int SymbolValueList::select_first (const cmt_string& tag_name) const { int priority = 0; int value_number; int selected = -1; Tag* the_tag = 0; if (tag_name != "") the_tag = Tag::find (tag_name); for (value_number = 0; value_number < values.size (); value_number++) { const SymbolValue& value = values[value_number]; const Tag* tag = value.tag; if (the_tag == 0) { if (!tag->is_selected ()) continue; } else { if (tag != the_tag) continue; selected = value_number; } // // Only the first value at a given priority is // selected (which implies the '>' test instead // of '>=') // if (tag->get_priority () > priority) { priority = tag->get_priority (); selected = value_number; } } return (selected); } //------------------------------------------------------------- int SymbolValueList::select_last () const { int priority = 0; int value_number; int selected = -1; for (value_number = 0; value_number < values.size (); value_number++) { SymbolValue& value = values[value_number]; const Tag* tag = value.tag; if (tag->is_selected ()) { // // The last value at a given priority is // selected (which implies the '>=' test instead // of '>') // if (tag->get_priority () >= priority) { priority = tag->get_priority (); selected = value_number; } } } return (selected); } //------------------------------------------------------------- void SymbolValueList::show (const Symbol& symbol, const SymbolValue& value, bool& first_definition) const { cmt_string discarded_text; cmt_string define_text; ActionType action = Cmt::get_action (); if (value.text == "") return; if (discarded) discarded_text = " (discarded by override)"; else discarded_text = ""; if (first_definition) define_text = "defines"; else define_text = "overrides"; cout << "# Package "; if (use != 0) { cout << use->get_package_name () << " " << use->version; } switch (command_type) { case CommandSet : cout << " " << define_text << " set " << symbol.name << " as "; first_definition = false; break; case CommandSetAppend : cout << " appends to set " << symbol.name << " : "; break; case CommandSetPrepend : cout << " prepends to set " << symbol.name << " : "; break; case CommandSetRemove : cout << " removes from set " << symbol.name << " : "; break; case CommandSetRemoveRegexp : cout << " removes RE from set " << symbol.name << " : "; break; case CommandAlias : cout << " " << define_text << " alias " << symbol.name << " as "; first_definition = false; break; case CommandPath : cout << " " << define_text << " path " << symbol.name << " as "; first_definition = false; break; case CommandPathAppend : cout << " appends to path " << symbol.name << " : "; break; case CommandPathPrepend : cout << " prepends to path " << symbol.name << " : "; break; case CommandPathRemove : cout << " removes from path " << symbol.name << " : "; break; case CommandPathRemoveRegexp : cout << " removes RE from path " << symbol.name << " : "; break; case CommandMacroPrepend : cout << " prepends to macro " << symbol.name << " : "; break; case CommandMacro : cout << " " << define_text << " macro " << symbol.name << " as "; break; case CommandMacroAppend : cout << " appends to macro " << symbol.name << " : "; break; case CommandMacroRemove : cout << " remove from macro " << symbol.name << " : "; break; case CommandMacroRemoveRegexp : cout << " remove RE from macro " << symbol.name << " : "; break; case CommandMacroRemoveAll : cout << " remove all from macro " << symbol.name << " : "; break; case CommandMacroRemoveAllRegexp : cout << " remove all RE from macro " << symbol.name << " : "; break; case CommandAction : cout << " " << define_text << " action " << symbol.name << " as "; first_definition = false; break; } cout << "'" << value.text << "'"; Tag* selected_tag = value.tag; if ((selected_tag == 0) || (selected_tag == Tag::get_default ())) { cout << " for default tag"; } else { cout << " for tag '" << selected_tag->get_name () << "'"; } cout << discarded_text << endl; }