source: CMT/v1r25p20130606/source/cmt_symbol.cxx

Last change on this file was 637, checked in by rybkin, 11 years ago

merge -r 618:627 HEAD

  • Property svn:eol-style set to native
File size: 89.1 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// See the complete license in cmt_license.txt "http://www.cecill.info".
5//-----------------------------------------------------------
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <ctype.h>
11
12#include "cmt_use.h"
13#include "cmt_symbol.h"
14#include "cmt_system.h"
15#include "cmt_database.h"
16#include "cmt_log.h"
17
18// Global inhibitor of any display
19bool Symbol::m_inhibit_display = false;
20
21//-------------------------------------------------------------
22class SetBuilder : public ValueBuilder
23{
24public:
25  const cmt_string build (const Symbol& symbol,
26                          const cmt_string& tag_name = "");
27  const cmt_string clean (const Symbol& symbol,
28                          const cmt_string& tag_name = "")
29      {
30        static const cmt_string empty = "";
31        return (empty);
32      }
33};
34//-------------------------------------------------------------
35
36//-------------------------------------------------------------
37class PathBuilder : public ValueBuilder
38{
39public:
40  const cmt_string build (const Symbol& symbol,
41                          const cmt_string& tag_name = "");
42  const cmt_string clean (const Symbol& symbol,
43                          const cmt_string& tag_name = "");
44};
45//-------------------------------------------------------------
46
47//-------------------------------------------------------------
48class MacroBuilder : public ValueBuilder
49{
50public:
51  const cmt_string build (const Symbol& symbol,
52                          const cmt_string& tag_name = "");
53  const cmt_string clean (const Symbol& symbol,
54                          const cmt_string& tag_name = "")
55      {
56        static const cmt_string empty = "";
57        return (empty);
58      }
59};
60//-------------------------------------------------------------
61
62//-------------------------------------------------------------
63class ScriptBuilder : public ValueBuilder
64{
65public:
66  const cmt_string build (const Symbol& symbol,
67                          const cmt_string& tag_name = "");
68  const cmt_string clean (const Symbol& symbol,
69                          const cmt_string& tag_name = "")
70      {
71        static const cmt_string empty = "";
72        return (empty);
73      }
74};
75//-------------------------------------------------------------
76
77//-------------------------------------------------------------
78class ActionBuilder : public ValueBuilder
79{
80public:
81  const cmt_string build (const Symbol& symbol,
82                          const cmt_string& tag_name = "");
83  const cmt_string clean (const Symbol& symbol,
84                          const cmt_string& tag_name = "")
85      {
86        static const cmt_string empty = "";
87        return (empty);
88      }
89};
90//-------------------------------------------------------------
91
92//-------------------------------------------------------------
93class symbol_marker
94{
95public:
96  symbol_marker ()
97  {
98    ptr = cmt_string::npos;
99    pattern = 0;
100    intro = 0;
101  }
102
103  symbol_marker (int a_ptr, char a_pattern, int a_intro)
104  {
105    ptr = a_ptr;
106    pattern = a_pattern;
107    intro = a_intro;
108  }
109
110  symbol_marker (const symbol_marker& other)
111  {
112    ptr = other.ptr;
113    pattern = other.pattern;
114    intro = other.intro;
115  }
116
117  void set (int a_ptr, char a_pattern, int a_intro)
118  {
119    ptr = a_ptr;
120    pattern = a_pattern;
121    intro = a_intro;
122  }
123
124  static symbol_marker& get_lowest (symbol_marker markers[], int count)
125  {
126    static symbol_marker result;
127    int real_count = 0;
128    int i;
129
130      // Check that at least one marker has result
131
132    for (i = 0; i < count; i++)
133      {
134        if (markers[i].ptr != cmt_string::npos) real_count++;
135      }
136
137    if (real_count == 0) return (result);
138
139    // since we've passed the previous test,
140    // at least one entry is not npos.
141    // Now discards other npos by moving them to the end
142   
143    for (i = 0; i < count;)
144      {
145        if (markers[i].ptr == cmt_string::npos)
146          {
147            markers[i] = markers[count-1];
148            count--;
149            if (count == 0) break;
150          }
151        else
152          {
153            i++;
154          }
155      }
156   
157    if (count == 0) return (result);
158   
159    // now all entries in [0, count-1] are not npos
160    // let's sort the lowest one in [0]
161   
162    for (i = 1; i < count;)
163      {
164        if (markers[0].ptr > markers[i].ptr)
165          {
166            symbol_marker temp = markers[0];
167            markers[0] = markers[i];
168            markers[i] = temp;
169            i = 1;
170          }
171        else
172          {
173            i++;
174          }
175      }
176   
177    return (markers[0]);
178  }
179
180  int ptr;
181  char pattern;
182  int intro;
183};
184//-------------------------------------------------------------
185
186/**
187
188   Attempt to substitute all occurrences of
189
190      ${<symbol_name>}
191      $(<symbol_name>)
192      %<symbol_name>%    [on Windows only]
193
194      by the specified value in the given text.
195
196    This is for one symbol only
197
198 */
199static void resolve_value (cmt_string& text,
200                           const cmt_string& symbol_name,
201                           const cmt_string& value)
202{
203  static cmt_string pattern;
204
205  pattern = "${";
206  pattern += symbol_name;
207  pattern += "}";
208
209  text.replace_all (pattern, value);
210
211  pattern = "$(";
212  pattern += symbol_name;
213  pattern += ")";
214
215  text.replace_all (pattern, value);
216
217#ifdef WIN32
218  pattern = "%";
219  pattern += symbol_name;
220  pattern += "%";
221
222  text.replace_all (pattern, value);
223#endif
224}
225/**
226 * similar to processing
227 * `shell' function of GNU Make does
228 *  on command output
229 */
230static void process_cmd_output (cmt_string& text)
231{
232  //cerr << "process_cmd_output (begin): [" << text << "]" << endl;
233  // remove trailing (carriage-return and) newline(s)
234  int nl = text.size ();
235  while (nl > 0 && text[nl - 1] == '\n')
236    {
237      nl--;
238      if (nl > 0 && text[nl - 1] == '\r')
239        nl--;
240    }
241  if (nl != text.size ())
242    text.erase (nl);
243
244  // convert each newline (or carriage-return / newline pair) to a single space
245  text.replace_all ("\r\n", " ");
246  text.replace_all ("\n", " ");
247  //cerr << "process_cmd_output (end): [" << text << "]" << endl;
248}
249
250/**
251
252   Attempt to substitute into the specified text all occurrences of
253
254      ${xxx}
255      $(xxx)
256      `xxx`
257      %xxx%    [on Windows only]
258
259      by the appropriate value:
260
261        for `xxx` :
262
263            xxx is considered as a shell command. Value is the result of its execution
264
265        for other patterns:
266
267            if xxx is a symbol name, its value is substituted to the pattern
268            otherwise, xxx is tried as an environment variable
269
270
271     ===> In all cases, the pattern is filtered away.
272
273
274 */
275static void resolve_value (cmt_string& text)
276{
277  //static cmt_regexp reg ("[$%`]");
278
279  //if (!reg.match (text)) return;
280
281  cmt_string pattern;
282  cmt_string symbol_name;
283  char end_pattern;
284
285  int start = 0;
286
287  for (;;)
288    {
289      int begin;
290      int end;
291
292      symbol_marker markers[4];
293      int num = 0;
294
295      markers[num].set (text.find (start, "$("), ')', 2); num++;
296      markers[num].set (text.find (start, "${"), '}', 2); num++;
297      markers[num].set (text.find (start, "`"), '`', 1); num++;
298
299#ifdef WIN32
300      markers[num].set (text.find (start, "%"), '%', 1); num++;
301#endif
302
303      // Find the first matching pattern
304
305      symbol_marker& marker = symbol_marker::get_lowest (markers, num);
306
307      begin = marker.ptr;
308
309      if (begin == cmt_string::npos) break;
310
311      end_pattern = marker.pattern;
312      start = begin + marker.intro;
313
314      end = text.find (start, end_pattern);
315      if (end == cmt_string::npos)
316        {
317          // The pattern is a fake one (no ending!)
318          start++;
319          continue;
320        }
321
322      // This should never happen...
323      if (end < begin) break;
324
325      // Extract the complete pattern
326      text.substr (begin, end - begin + 1, pattern);
327
328      // Then only the symbol name
329      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);
330
331      if (text[begin] == '`')
332        {
333          cmt_string command = symbol_name;
334          resolve_value (command);
335
336            // The value is a shell command that first needs
337            // to be applied. The output of the command is then substituted
338
339          cmt_string result;
340
341          Symbol::all_set ();
342          CmtSystem::execute (command, result);
343         
344          /*
345          int pos;
346          pos = result.find ('\n');
347          if (pos != cmt_string::npos) result.erase (pos);
348          pos = result.find ('\r');
349          if (pos != cmt_string::npos) result.erase (pos);
350          */         
351          process_cmd_output (result);
352
353          if (Cmt::get_debug ())
354            {
355              cout << "resolve_value: Executing [" << command << "] to expand a symbol value =>[" 
356                   << result << "]" << endl;
357            }
358         
359          text.replace_all (pattern, result);
360
361          // The substitution will restart from the same place
362          // allowing for recursive replacements
363          start = begin;
364        }
365      else
366        {
367          Symbol* symbol = Symbol::find (symbol_name);
368          if (symbol != 0)
369            {
370                // Symbol found
371              cmt_string value = symbol->resolve_macro_value ();
372              text.replace_all (pattern, value);
373             
374                // The substitution will restart from the same place
375                // allowing for recursive replacements
376              start = begin;
377            }
378          else
379            {
380                // Symbol not found. Look for env. variable
381              cmt_string value = CmtSystem::getenv (symbol_name);
382             
383                // When the env. variable is not defined, the replacement is empty
384                // thus all $(xxx) ${xxx} %xxx% patterns are always filtered away.
385              text.replace_all (pattern, value);
386             
387                // The substitution will restart from the same place
388                // allowing for recursive replacements
389              start = begin;
390            }
391        }
392    }
393}
394
395/**
396
397   Attempt to substitute all occurrences of
398
399      ${xxx}
400      $(xxx)
401      `xxx`
402      %xxx%    [on Windows only]
403
404      by the appropriate value:
405
406        for `xxx` :
407
408            xxx is considered as a shell command. Value is the result of its execution
409
410        for other patterns:
411
412            if xxx is a macro name, its value is substituted to the pattern
413
414            if xxx is a set or a path, it is kept in place (after fixing the pattern
415            according to the OS style)
416
417            otherwise it is simply kept in place
418
419 */
420static void resolve_value_for_macros (cmt_string& text)
421{
422  cmt_string pattern;
423  cmt_string symbol_name;
424  char end_pattern;
425
426  int start = 0;
427
428  for (;;)
429    {
430      //
431      // Try and substitute all ${xxx} $(xxx) or %xxx% patterns
432      // using symbol values, only when the symbol is a macro.
433      //
434
435      int begin;
436      int end;
437
438      symbol_marker markers[4];
439      int num = 0;
440
441      markers[num].set (text.find (start, "$("), ')', 2); num++;
442      markers[num].set (text.find (start, "${"), '}', 2); num++;
443
444#ifdef WIN32
445      markers[num].set (text.find (start, "%"), '%', 1); num++;
446#endif
447
448      markers[num].set (text.find (start, "`"), '`', 1); num++;
449
450      // Find the first of three patterns
451
452      symbol_marker& marker = symbol_marker::get_lowest (markers, num);
453
454      begin = marker.ptr;
455
456      if (begin == cmt_string::npos) break;
457
458      end_pattern = marker.pattern;
459      start = begin + marker.intro;
460
461      end = text.find (start, end_pattern);
462      if (end == cmt_string::npos)
463        {
464          // The pattern is a fake one (no ending!)
465          start++;
466          continue;
467        }
468
469      // This should never happen...
470      if (end < begin) break;
471
472      // Extract the complete pattern
473      text.substr (begin, end - begin + 1, pattern);
474
475      // Then only the macro name
476      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);
477
478      if (text[begin] == '`')
479        {
480          cmt_string command = symbol_name;
481          resolve_value (command);
482
483            // The macro value is a shell command that first needs
484            // to be applied. The output of the command is substituted
485
486          cmt_string result;
487
488          Symbol::all_set ();
489          CmtSystem::execute (command, result);
490         
491          /*
492          int pos;
493          pos = result.find ('\n');
494          if (pos != cmt_string::npos) result.erase (pos);
495          pos = result.find ('\r');
496          if (pos != cmt_string::npos) result.erase (pos);
497          */
498          process_cmd_output (result);
499         
500          if (Cmt::get_debug ())
501            {
502              cout << "   Executing [" << command << "] to expand a macro value =>[" 
503                   << result << "]" << endl;
504            }
505         
506          text.replace_all (pattern, result);
507
508          // The substitution will restart from the same place
509          // allowing for recursive replacements
510          start = begin;
511        }
512      else
513        {
514          Symbol* macro = Symbol::find (symbol_name);
515          if ((macro != 0) && 
516              (macro->type == Symbol::SymbolMacro))
517            {
518                // Macro found
519              cmt_string value = macro->resolve_macro_value ();
520              text.replace_all (pattern, value);
521
522                // The substitution will restart from the same place
523                // allowing for recursive replacements
524              start = begin;
525            }
526          else if ((macro == 0) || 
527                   ((macro->type == Symbol::SymbolSet) || (macro->type == Symbol::SymbolPath)))
528            {
529                // Set found
530                // ensure that the delimiters will match the OS dependent
531                // delimiters.
532             
533              cmt_string pattern_close = marker.pattern;
534             
535              if (pattern_close != CmtSystem::ev_close ())
536                {
537                  cmt_string new_pattern;
538                 
539                  new_pattern = CmtSystem::ev_open ();
540                  new_pattern += symbol_name;
541                  new_pattern += CmtSystem::ev_close ();
542                 
543                  text.replace (pattern, new_pattern);
544                }
545             
546              start = end + 1;
547            }
548          else
549            {
550              start = end + 1;
551            }
552        }
553    }
554}
555
556/**
557
558   This function suppress all OS delimiters ie ${ } or % % and replaces them
559   by the pure macro delimiters $( )
560
561   `xxx` pattern is replaced by the result of the execution of the command
562
563 */
564static void suppress_OS_delimiters (cmt_string& text)
565{
566  cmt_string pattern;
567  cmt_string symbol_name;
568  char end_pattern;
569
570  int start = 0;
571
572  for (;;)
573    {
574      int begin;
575      int end;
576
577      symbol_marker markers[3];
578      int num = 0;
579
580      markers[num].set (text.find (start, "${"), '}', 2); num++;
581      markers[num].set (text.find (start, "`"), '`', 1); num++;
582
583#ifdef WIN32
584      markers[num].set (text.find (start, "%"), '%', 1); num++;
585#endif
586
587      // Find the first of three patterns
588
589      symbol_marker& marker = symbol_marker::get_lowest (markers, num);
590
591      begin = marker.ptr;
592
593      if (begin == cmt_string::npos) break;
594
595      end_pattern = marker.pattern;
596      start = begin + marker.intro;
597
598      end = text.find (start, end_pattern);
599      if (end == cmt_string::npos)
600        {
601          // The pattern is a fake one (no ending!)
602          start++;
603          continue;
604        }
605
606      // This should never happen...
607      if (end < begin) break;
608
609      // Extract the complete pattern
610      text.substr (begin, end - begin + 1, pattern);
611
612      // Then only the macro name
613      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);
614
615      if (text[begin] == '`')
616        {
617          cmt_string command = symbol_name;
618          resolve_value (command);
619
620            // The macro value is a shell command that first needs
621            // to be applied. The output of the command is substituted
622
623          cmt_string result;
624
625          Symbol::all_set ();
626          CmtSystem::execute (command, result);
627         
628          /*
629          int pos;
630          pos = result.find ('\n');
631          if (pos != cmt_string::npos) result.erase (pos);
632          pos = result.find ('\r');
633          if (pos != cmt_string::npos) result.erase (pos);
634          */         
635          process_cmd_output (result);
636         
637          if (Cmt::get_debug ())
638            {
639              cout << "   Executing [" << command << "] to expand a macro value =>[" 
640                   << result << "]" << endl;
641            }
642         
643          text.replace_all (pattern, result);
644
645          // The substitution will restart from the same place
646          // allowing for recursive replacements
647          start = begin;
648        }
649      else
650        {
651          cmt_string new_pattern;
652
653          new_pattern = "$(";
654          new_pattern += symbol_name;
655          new_pattern += ")";
656
657          text.replace (pattern, new_pattern);
658
659          start = begin;
660        }
661    }
662}
663
664//-------------------------------------------------------------
665/*                                                          */
666/*  Operations on SymbolValues                              */
667/*                                                          */
668//-------------------------------------------------------------
669
670//-------------------------------------------------------------
671SymbolValue::SymbolValue ()
672{
673  tag = 0;
674}
675
676//-------------------------------------------------------------
677SymbolValue::~SymbolValue ()
678{
679  tag = 0;
680}
681
682//-------------------------------------------------------------
683/*                                                          */
684/*  Operations on Symbols                                   */
685/*                                                          */
686//-------------------------------------------------------------
687
688//-------------------------------------------------------------
689Symbol* Symbol::create (const cmt_string& name,
690                        CommandType command,
691                        Use* use)
692{
693  static SetBuilder Set;
694  static PathBuilder Path;
695  static MacroBuilder Macro;
696  static ScriptBuilder Script;
697  static ActionBuilder Action;
698
699  static SymbolVector& Symbols = symbols ();
700  static SymbolMap& SymbolMap = symbol_map ();
701
702  SymbolType type = SymbolUndefined;
703
704  switch (command)
705    {
706    case CommandSet:
707    case CommandSetAppend:
708    case CommandSetPrepend:
709    case CommandSetRemove:
710    case CommandSetRemoveRegexp:
711      type = SymbolSet;
712      break;
713    case CommandPath:
714    case CommandPathAppend:
715    case CommandPathPrepend:
716    case CommandPathRemove:
717    case CommandPathRemoveRegexp:
718      type = SymbolPath;
719      break;
720    case CommandMacro:
721    case CommandMacroAppend:
722    case CommandMacroPrepend:
723    case CommandMacroRemove:
724    case CommandMacroRemoveRegexp:
725    case CommandMacroRemoveAll:
726    case CommandMacroRemoveAllRegexp:
727      type = SymbolMacro;
728      break;
729    case CommandAction:
730      type = SymbolAction;
731      break;
732    case CommandAlias:
733      type = SymbolAlias;
734      break;
735    case CommandSetupScript:
736      type = SymbolSetupScript;
737      break;
738    case CommandCleanupScript:
739      type = SymbolCleanupScript;
740      break;
741    }
742
743  {
744    Symbol* symbol;
745
746    symbol = find (name);
747    if (symbol != 0) 
748      {
749        if (symbol->type != type)
750          {
751            ActionType action = Cmt::get_action ();
752
753            if ((!Cmt::get_quiet ()) &&
754                (action != action_build_constituents_config) &&
755                (action != action_build_constituent_config))
756              {
757                cmt_string s1;
758                cmt_string s2;
759
760                switch (symbol->type)
761                  {
762                  case SymbolSet:
763                    s1 = "set";
764                    break;
765                  case SymbolPath:
766                    s1 = "path";
767                    break;
768                  case SymbolMacro:
769                    s1 = "macro";
770                    break;
771                  case SymbolSetupScript:
772                    s1 = "setup_script";
773                    break;
774                  case SymbolCleanupScript:
775                    s1 = "cleanup_script";
776                    break;
777                  case SymbolAction:
778                    s1 = "action";
779                    break;
780                  case SymbolAlias:
781                    s1 = "alias";
782                    break;
783                  } 
784
785                switch (type)
786                  {
787                  case SymbolSet:
788                    s2 = "set";   
789                    break;
790                  case SymbolPath:
791                    s2 = "path";   
792                    break;
793                  case SymbolMacro:
794                    s2 = "macro";   
795                    break;
796                  case SymbolSetupScript:
797                    s2 = "setup_script"; 
798                    break;
799                  case SymbolCleanupScript:
800                    s2 = "cleanup_script"; 
801                    break;
802                  case SymbolAction:
803                    s2 = "action";
804                    break;
805                  case SymbolAlias:
806                    s2 = "alias";
807                    break;
808                  } 
809                // <PACKAGE>ROOT macro is defined in
810                // Use::fill_standard_macros <- SyntaxParser::parse_requirements
811                // "cmt -requirements setup" may generate <PACKAGE>ROOT set
812                // hence, warning
813                // Symbol <PACKAGE>ROOT inconsistently redeclared from macro to set in package <package>
814                // below, we suppress the warning for current package
815                if (use != &(Use::current()) ||
816                    (Use::current().prefix + "ROOT") != name ||
817                    symbol->type != SymbolMacro ||
818                    type != SymbolSet)
819                  CmtMessage::warning ("Symbol " + name
820                                       + " inconsistently redeclared from " + s1
821                                       + " to " + s2
822                                       + ( (use != 0) ?
823                                           " in package " + use->get_package_name () :
824                                           "" )
825                                       );
826                /*
827                cerr << "#CMT> Warning: Symbol " << name
828                     << " inconsistently redeclared from " << s1 << " to " << s2;
829                if (use != 0) cerr << " in package " << use->get_package_name ();
830                cerr << endl;
831                */
832              }
833          }
834
835        return (symbol);
836      }
837  }
838
839  Symbol& symbol = Symbols.add ();
840  SymbolMap.add (name, symbol);
841
842  symbol.name  = name;
843  symbol.scope = use->get_current_scope ();
844  symbol.type  = type;
845
846  symbol.value_lists.clear ();
847
848  switch (type)
849    {
850    case SymbolSet:
851      symbol.builder = &Set;
852      break;
853    case SymbolPath:
854      symbol.builder = &Path;
855      break;
856    case SymbolAlias:
857      symbol.builder = &Set;
858      break;
859    case SymbolMacro:
860      symbol.builder = &Macro;
861      break;
862    case SymbolSetupScript:
863    case SymbolCleanupScript:
864      symbol.builder = &Script;
865      break;
866    case SymbolAction:
867      symbol.builder = &Action;
868      break;
869    }
870
871  symbol.selected_value = -1;
872  symbol.printed = false;
873
874  return (&symbol);
875}
876
877//-------------------------------------------------------------
878Symbol* Symbol::find (const cmt_string& name)
879{
880  static SymbolMap& SymbolMap = symbol_map ();
881
882  Symbol* result = 0;
883
884  result = SymbolMap.find (name);
885
886  return (result);
887}
888
889//-------------------------------------------------------------
890int Symbol::symbol_number ()
891{
892  static SymbolVector& Symbols = symbols ();
893
894  return (Symbols.size ());
895}
896
897//-------------------------------------------------------------
898Symbol::SymbolVector& Symbol::symbols ()
899{
900  static Database& db = Database::instance ();
901  static SymbolVector& Symbols = db.symbols ();
902
903  return (Symbols);
904}
905
906//-------------------------------------------------------------
907Symbol::SymbolMap& Symbol::symbol_map ()
908{
909  static Database& db = Database::instance ();
910  static SymbolMap& SymbolMap = db.symbol_map ();
911
912  return (SymbolMap);
913}
914
915/**
916   Filter out faulty items of a path-like symbol value
917 */
918void Symbol::filter_path_value (const cmt_string& name, cmt_string& text)
919{
920
921  CmtSystem::cmt_string_vector paths;
922  CmtSystem::cmt_string_vector normalyzed_paths;   
923                 
924  CmtSystem::split (text, CmtSystem::path_separator (), paths);
925                 
926  for (int j = 0; j < paths.size (); ++j)
927    {
928      cmt_string& t = paths[j];
929
930            /*
931        if (!CmtSystem::test_directory (t))
932              if (Cmt::get_warnings ())
933              {
934                  cerr << "#CMT> Warning: Wrong path item " << t << " in " << name << endl;
935              }
936            */
937           
938      int exist = 0; 
939      for (int i = 0; i < j; ++i)
940      {
941          cmt_string& u = paths[i];
942          if (u == t)
943            {
944              exist = 1;
945              break;
946            }
947      }           
948      if (exist==0)
949      {
950          cmt_string& s = normalyzed_paths.add ();
951          s = t;
952          if (CmtMessage::active (Verbose))
953            if (!CmtSystem::test_directory (t))
954              {
955                CmtMessage::warning ("Non-existent directory " + t + " in " + name);
956              }
957      }
958    }
959   
960  Cmt::vector_to_string (normalyzed_paths, CmtSystem::path_separator (), text);
961
962  for (;;)
963    {
964      int sz = text.size ();
965
966      if (sz == 0) break;
967
968      if ((text[0] == ';') || (text[0] == ':'))
969        {
970          text.erase (0, 1);
971        }
972      else if ((text[sz-1] == ';') || (text[sz-1] == ':'))
973        {
974          text.erase (sz-1, 1);
975        }
976      else
977        {
978          break;
979        }
980    }
981
982  text.replace_all ("::", ":");
983  text.replace_all (";;", ";");
984}
985
986
987//-------------------------------------------------------------
988Symbol& Symbol::symbol (int index)
989{
990  static SymbolVector& Symbols = symbols ();
991
992  return (Symbols[index]);
993}
994
995//-------------------------------------------------------------
996void Symbol::action (const CmtSystem::cmt_string_vector& words,
997                     CommandType command_type,
998                     Use* use)
999{
1000  int number;
1001  Symbol* symbol;
1002  Tag* tag;
1003
1004  if (words.size () < 1) return;
1005  cmt_string name = words[1];
1006
1007  if ((command_type == CommandSetupScript) ||
1008      (command_type == CommandCleanupScript))
1009    {
1010      cmt_string full_name;
1011
1012      Symbol::expand (name);
1013
1014      if (name != "")
1015        {
1016          if (CmtSystem::absolute_path (name)) 
1017            {
1018              full_name = name;
1019            }
1020          else
1021            {
1022              if (use->get_strategy ("SetupRoot") &&
1023                  use->get_package_name () != "cmt_standalone")
1024                {
1025#ifdef WIN32
1026              full_name = "%";
1027#else
1028              full_name = "${";
1029#endif
1030              full_name += CmtSystem::mangle (use->prefix);
1031              full_name += "ROOT";
1032#ifdef WIN32
1033              full_name += "%";
1034#else
1035              full_name += "}";
1036#endif
1037                }
1038              else
1039                {
1040              full_name = use->get_full_path ();
1041                }
1042              if (use->style == cmt_style)
1043                {
1044                  full_name += CmtSystem::file_separator ();
1045                  full_name += "cmt";
1046                }
1047              else if (use->style == mgr_style)
1048                {
1049                  full_name += CmtSystem::file_separator ();
1050                  full_name += "mgr";
1051                }
1052              //              else if (use->style == no_version_style) full_name += "cmt";
1053              //              else full_name += "mgr";
1054              full_name += CmtSystem::file_separator ();
1055              full_name += name;
1056            }
1057
1058          symbol = create (full_name, command_type, use);
1059          symbol->add_value_to_list (command_type, use,
1060                                     Tag::get_default (), full_name);
1061        }
1062    }
1063  else
1064    {
1065      if (words.size () < 2) return;
1066      const cmt_string& default_value = words[2];
1067
1068      Cmt::reset_all_sets_done ();
1069
1070      if (Cmt::get_debug ())
1071        {
1072          cout << "Symbol::action> name:" << name
1073               << " access:" << Cmt::get_current_access () 
1074               << " scope:" << use->get_current_scope () << endl;
1075        }
1076
1077      if (Cmt::get_current_access () == UserMode)
1078        {
1079          /*
1080            The following statements mean that some symbols are
1081            always private.
1082            This list is hardcoded. This should be replaced by a
1083            database of "private" symbols.
1084           */
1085          if (name == "constituents") return;
1086          if (name == "constituentscclean") return;
1087
1088          if (use->get_current_scope () == ScopePrivate) return;
1089        }
1090
1091      symbol = create (name, command_type, use);
1092
1093      /*
1094        Parse the default value.
1095      */
1096     
1097      symbol->add_value_to_list (command_type, use,
1098                                 Tag::get_default (), default_value);
1099     
1100      /*
1101        Then parse all specific values
1102       
1103        <tag> <value>
1104        ...
1105      */
1106     
1107      number = 3;
1108      while (number < (words.size () - 1))
1109        {
1110          cmt_string tag_name = words[number];
1111          const cmt_string& value = words[number + 1];
1112
1113          expand (tag_name);
1114
1115          if (Cmt::get_debug ())
1116            {
1117              cout << "Symbol::action> tag_name=" << tag_name << endl;
1118            }
1119
1120          tag = Tag::find (tag_name);
1121          if (tag == 0)
1122            {
1123              tag = Tag::add (tag_name, PriorityUserTag, "use", use);
1124            }
1125
1126          symbol->add_value_to_list (command_type, use, tag, value);
1127         
1128          number += 2;
1129        }
1130
1131      if (name == "CMTPATH")
1132        {
1133          Cmt::configure_cmt_path (use);
1134        }
1135      else if (name == "CMTPROJECTPATH")
1136        {
1137          Cmt::configure_cmt_path (use);
1138        }
1139      else if (name == "CMTSITE")
1140        {
1141          Cmt::configure_site_tag (use);
1142        }
1143      else if (name == "CMTCONFIG")
1144        {
1145            //cerr << "redefining CMTCONFIG" << endl;
1146          Cmt::configure_tags (use);
1147        }
1148      else if (name == "CMTHOME")
1149        {
1150          Cmt::configure_home (use);
1151        }
1152      else if (name == "CMTUSERCONTEXT")
1153        {
1154          Cmt::configure_user_context (use);
1155        }
1156      else if (name.find ("_native_version") != cmt_string::npos)
1157        {
1158          cmt_string n = use->get_package_name ();
1159          n += "_native_version";
1160
1161          if (name == n)
1162            {
1163              use->set_native_version (true);
1164            }
1165        }
1166    }
1167}
1168
1169//-------------------------------------------------------------
1170int Symbol::is_selected (const cmt_string& name)
1171{
1172  Symbol* symbol;
1173  int number;
1174  int value_number;
1175
1176  symbol = find (name);
1177  if (symbol == 0) return (0);
1178
1179  if (symbol->value_lists.size () == 0) return (0);
1180
1181  for (number = 0;
1182       number < symbol->value_lists.size ();
1183       number++)
1184    {
1185      const SymbolValueList& value_list = symbol->value_lists[number];
1186
1187      if (value_list.discarded) continue;
1188
1189      if ((value_list.command_type == CommandMacro) ||
1190          (value_list.command_type == CommandSet) ||
1191          (value_list.command_type == CommandSetAppend) ||
1192          (value_list.command_type == CommandSetPrepend) ||
1193          (value_list.command_type == CommandSetRemove) ||
1194          (value_list.command_type == CommandSetRemoveRegexp) ||
1195          (value_list.command_type == CommandAlias) ||
1196          (value_list.command_type == CommandAction))
1197        {
1198          for (value_number = 0;
1199               value_number < value_list.values.size ();
1200               value_number++)
1201            {
1202              Tag* tag;
1203
1204              SymbolValue& value = value_list.values[value_number];
1205
1206              tag = value.tag;
1207              if ((tag == 0) ||
1208                  (tag == Tag::get_default ()) ||
1209                  (tag->is_selected () != 0))
1210                {
1211                  return (1);
1212                }
1213            }
1214        }
1215    }
1216
1217  return (0);
1218}
1219
1220//-------------------------------------------------------------
1221Symbol::Symbol ()
1222{
1223  name = "";
1224}
1225
1226//-------------------------------------------------------------
1227Symbol::~Symbol ()
1228{
1229}
1230
1231/**
1232 *  Characterizes if a value is provided as the reference to itself.
1233 */
1234bool Symbol::value_is_reflexive (const cmt_string& text) const
1235{
1236  bool result = false;
1237  int text_length = text.size ();
1238
1239  if (text_length == (name.size () + 3))
1240    {
1241      static cmt_string temp;
1242             
1243      if (text[0] == '$')
1244        {
1245          if (text[1] == '(')
1246            {
1247              temp = "$(";
1248              temp += name;
1249              temp += ")";
1250             
1251              if (text == temp)
1252                {
1253                  result = true;
1254                }
1255            }
1256          else if (text[1] == '{')
1257            {
1258              temp = "${";
1259              temp += name;
1260              temp += "}";
1261             
1262              if (text == temp)
1263                {
1264                  result = true;
1265                }
1266            }
1267        }
1268    }
1269  else if (text_length == (name.size () + 2))
1270    {
1271      static cmt_string temp;
1272
1273      temp = "%";
1274      temp += name;
1275      temp += "%";
1276
1277      if (text == temp)
1278        {
1279          result = true;
1280        }
1281    }
1282
1283  return (result);
1284}
1285
1286//-------------------------------------------------------------
1287void Symbol::add_value_to_list (CommandType command_type,
1288                                Use* use,
1289                                Tag* tag,
1290                                const cmt_string& text)
1291{
1292  SymbolValueList* value_list = 0;
1293  bool is_reflexive = false;
1294
1295    //
1296    // First pickup the most recent value_list
1297    //
1298  if (value_lists.size () > 0) value_list = &(value_lists.back ());
1299
1300    //
1301    //  Create a new value list is we switch to another use or
1302    //  if we switch to a new command_type (eg. switching from
1303    //  macro to macro_append).
1304    //
1305  if ((value_list == 0) ||
1306      (use != value_list->use) ||
1307      (command_type != value_list->command_type) ||
1308      (tag == Tag::get_default ()))
1309    {
1310      value_list = &(value_lists.add ());
1311      value_list->use = use;
1312      value_list->command_type = command_type;
1313      value_list->values.clear ();
1314      value_list->discarded = false;
1315      value_list->is_reflexive = false;
1316    }
1317
1318/*
1319  else
1320    {
1321        value_list = &(value_lists[value_lists.size () - 1]);
1322    }
1323*/
1324
1325  is_reflexive = value_list->is_reflexive;
1326
1327    //
1328    //  If the command_type is command_macro or command_set,
1329    // this is considered as a full re-set of this symbol
1330    //   In this case, we have to discard all previous values
1331    //
1332    //  However, we'd like to exclude from this logic the cases where
1333    //  the value is **exactly*
1334    //
1335    //     $(<symbol>)
1336    //     ${<symbol>}
1337    //     %<symbol>%
1338    //
1339    //   which would then mean that we do not reset the value but rather
1340    //  override it.
1341    //
1342
1343    //
1344    // Inside this value_list, we add this new tag-value pair.
1345    //
1346
1347  if ((command_type == CommandMacro) ||
1348      (command_type == CommandSet) ||
1349      (command_type == CommandPath) ||
1350      (command_type == CommandAction))
1351    {
1352        //
1353        // Check whether we have to hide previous settings by this new definition
1354        //  (of course this is only useful if there WERE previous settings)
1355        //
1356      if ((value_lists.size () >= 1) && (!is_reflexive))
1357        {
1358          if (value_is_reflexive (text))
1359            {
1360              value_list->is_reflexive = true;
1361              is_reflexive = true;
1362            }
1363          else
1364            {
1365              //cerr << "...discarding old values for symbol " << name << " text=[" << text << "]" << endl;
1366                 
1367              for (int i = 0; i < (value_lists.size () - 1); i++)
1368                {
1369                  SymbolValueList& vl = value_lists[i];
1370                 
1371                  if ((vl.use != 0) &&
1372                      (vl.use->discarded))
1373                    {
1374                      //vl.discarded = true;
1375                    }
1376                }
1377            }
1378        }
1379    }
1380
1381  SymbolValue& value = value_list->values.add ();
1382
1383  value.tag = tag;
1384  value.text = text;
1385  value.selected = 0;
1386}
1387
1388/**
1389   Compute the current value of all environment variables and set them to the
1390   shell
1391 */
1392void Symbol::all_set ()
1393{
1394  //cerr << "all_set" << endl;
1395
1396  static bool running = false;
1397
1398
1399  if (Cmt::get_debug ())
1400    {
1401      cout << "\nSymbol::all_set> done=" << running << endl;
1402    }
1403
1404  if (Cmt::get_all_sets_done ()) return;
1405
1406  if (running) return;
1407
1408  running = true;
1409  Cmt::set_all_sets_done ();
1410
1411  static SymbolVector& Symbols = symbols ();
1412  Use::UsePtrVector& Uses = Use::get_ordered_uses ();
1413
1414  int number;
1415
1416  if (Symbols.size () == 0) 
1417    {
1418      running = false;
1419      return;
1420    }
1421
1422  cmt_string value;
1423
1424  for (number = 0; number < Symbol::symbol_number (); number++)
1425    {
1426      Symbol& symbol = Symbol::symbol (number);
1427
1428      if (symbol.type != SymbolSet) continue;
1429
1430      value = symbol.build_macro_value ();
1431      if (value != "")
1432        {
1433          Symbol::expand (value);
1434
1435          CmtSystem::putenv (symbol.name, value);
1436        }
1437    }
1438
1439  cmt_string cmtconfig = CmtSystem::get_cmt_config ();
1440
1441  if (Uses.size () > 0)
1442    {
1443      int number;
1444
1445      for (number = 0; number < Uses.size (); number++)
1446        {
1447          Use& use = *(Uses[number]);
1448
1449          if (use.discarded) continue;
1450
1451          if (use.get_package_name () == "cmt_standalone") continue;
1452
1453          if (use.get_strategy ("SetupConfig"))
1454            {
1455              cmt_string temp;
1456
1457              temp = use.prefix;
1458              temp += "CONFIG";
1459
1460              CmtSystem::putenv (temp, cmtconfig);
1461            }
1462
1463          if (use.get_strategy ("SetupRoot"))
1464            {
1465              cmt_string temp;
1466
1467              temp = use.prefix;
1468              temp += "ROOT";
1469
1470              CmtSystem::putenv (temp, use.get_full_path ());
1471            }
1472        }
1473    }
1474
1475  {
1476    Use& use = Use::current ();
1477
1478    if (use.get_package_name () != "cmt_standalone")
1479      {
1480        if (use.get_strategy ("SetupConfig"))
1481          {
1482            cmt_string temp;
1483
1484            temp = use.prefix;
1485            temp += "CONFIG";
1486
1487            CmtSystem::putenv (temp, cmtconfig);
1488          }
1489       
1490        if (use.get_strategy ("SetupRoot"))
1491          {
1492            cmt_string temp;
1493
1494            temp = use.prefix;
1495            temp += "ROOT";
1496
1497            CmtSystem::putenv (temp, use.get_full_path ());
1498          }
1499      }
1500  }
1501
1502  for (number = 0; number < Symbol::symbol_number (); number++)
1503    {
1504      Symbol& symbol = Symbol::symbol (number);
1505
1506      if ((symbol.type != SymbolPath)) continue;
1507
1508      value = symbol.build_macro_value ();
1509      if (value != "")
1510        {
1511          Symbol::expand (value);
1512          filter_path_value (symbol.name, value);
1513
1514#ifdef WIN32
1515          value.replace_all ("/", "\\");
1516#endif
1517
1518          if (Cmt::get_debug ())
1519            {
1520              cerr << "Symbol::all_set-2> " << symbol.name << " = " << value << endl;
1521            }
1522
1523          CmtSystem::putenv (symbol.name, value);
1524        }
1525    }
1526
1527  running = false;
1528}
1529
1530//-------------------------------------------------------------
1531void Symbol::all_print (PrintMode mode)
1532{
1533  static SymbolVector& Symbols = symbols ();
1534
1535  int number;
1536
1537  if (Symbols.size () == 0) return;
1538
1539  switch (mode)
1540    {
1541    case Requirements :
1542      for (number = 0; number < Symbol::symbol_number (); number++)
1543        {
1544          Symbol& symbol = Symbol::symbol (number);
1545
1546          if ((symbol.type == SymbolSet) ||
1547              (symbol.type == SymbolAlias) ||
1548              (symbol.type == SymbolSetupScript) ||
1549              (symbol.type == SymbolPath) ||
1550              (symbol.type == SymbolMacro))
1551            {
1552              if (symbol.print_macro (mode))
1553                {
1554                  //              cout << endl;
1555                }
1556            }
1557        }
1558      break;
1559    default :
1560      for (number = 0; number < Symbol::symbol_number (); number++)
1561        {
1562          Symbol& symbol = Symbol::symbol (number);
1563         
1564          if ((symbol.type == SymbolSet) ||
1565              (symbol.type == SymbolAlias) ||
1566              (symbol.type == SymbolSetupScript) ||
1567              (symbol.type == SymbolPath))
1568            {
1569              if (symbol.print (mode))
1570                {
1571                  if (mode == Bat)
1572                    {
1573                      cout << endl;
1574                    }
1575                  else if (mode == Xml)
1576                    {
1577                      //                      cout << endl;
1578                    }
1579                  else
1580                    {
1581                      cout << endl;
1582                    }
1583                }
1584            }
1585        }
1586      break;
1587    }
1588}
1589
1590//-------------------------------------------------------------
1591void Symbol::check_all_paths ()
1592{
1593  static SymbolVector& Symbols = symbols ();
1594
1595  int number;
1596
1597  if (Symbols.size () == 0) return;
1598
1599  for (number = 0; number < Symbol::symbol_number (); number++)
1600    {
1601      Symbol& symbol = Symbol::symbol (number);
1602
1603      if (symbol.type == SymbolPath)
1604        {
1605          cmt_string temp;
1606
1607          temp = symbol.build_macro_value ();
1608          expand (temp);
1609
1610          Symbol::filter_path_value (symbol.name, temp);
1611        }
1612    }
1613}
1614
1615//-------------------------------------------------------------
1616void Symbol::all_print_clean (PrintMode mode)
1617{
1618  static SymbolVector& Symbols = symbols ();
1619
1620  int number;
1621
1622  if (Symbols.size () == 0) return;
1623
1624  for (number = Symbols.size () - 1; number >= 0; number--)
1625    {
1626      Symbol& symbol = Symbols[number];
1627
1628      if ((symbol.type == SymbolSet) ||
1629          (symbol.type == SymbolAlias) ||
1630          (symbol.type == SymbolCleanupScript))
1631        {
1632          if (symbol.print_clean (mode))
1633            {
1634              cout << endl;
1635            }
1636        }
1637    }
1638
1639  for (number = Symbols.size () - 1; number >= 0; number--)
1640    {
1641      Symbol& symbol = Symbols[number];
1642
1643      if ((symbol.type != SymbolPath)) continue;
1644
1645      if (symbol.print_clean (mode))
1646        {
1647          cout << endl;
1648        }
1649    }
1650}
1651
1652//-------------------------------------------------------------
1653int Symbol::print_clean (PrintMode mode)
1654{
1655  int result = 0;
1656  static cmt_string temp;
1657
1658  if (name == "CMTCONFIG") return (0);
1659
1660  cmt_string _name;
1661  switch (type)
1662    {
1663    case SymbolSet :
1664    case SymbolPath :
1665      if (0 != CmtSystem::mangle (name, _name))
1666        CmtMessage::info ("Replace " + name + " with " + _name);
1667      break;
1668    }
1669
1670  switch (type)
1671    {
1672    case SymbolSet :
1673      switch (mode)
1674        {
1675        case Csh :
1676          cout << "unsetenv " << _name;
1677          result = 1;
1678          break;
1679        case Sh :
1680          cout << "[ -z ${" << _name << "+CMT} ] || unset " << _name;
1681          //          cout << "unset " << _name;
1682          result = 1;
1683          break;
1684        case Bat :
1685          cout << "set " << _name << "=";
1686          result = 1;
1687          break;
1688        }
1689      break;
1690    case SymbolAlias :
1691      switch (mode)
1692        {
1693          case Csh :
1694            cout << "unalias " << name;
1695            result = 1;
1696            break;
1697          case Sh :
1698            cout << "[ -z ${" << name << "+CMT} ] || unset " << name;
1699          //            cout << "unset " << name;
1700            result = 1;
1701            break;
1702        }
1703      break;
1704    case SymbolPath :
1705      temp = clean_macro_value ();
1706      switch (mode)
1707        {
1708        case Csh :
1709          if (temp == "")
1710            {
1711              cout << "unsetenv " << _name;
1712            }
1713          else
1714            {
1715              cout << "setenv " << _name << " " << CmtSystem::quote (temp, " \t");
1716            }
1717          result = 1;
1718          break;
1719        case Sh :
1720          cout << _name << "=" << CmtSystem::quote (temp, " \t") << "; export " << _name;
1721          result = 1;
1722          break;
1723        case Bat :
1724          cout << "set " << _name << "=" << CmtSystem::quote (temp, " \t");
1725          result = 1;
1726          break;
1727        }
1728      break;
1729    case SymbolCleanupScript :
1730      switch (mode)
1731        {
1732        case Csh :
1733          cout << "if ( -f " << CmtSystem::quote (name, " \t") << ".csh ) then" << endl;
1734          cout << "  source " << CmtSystem::quote (name, " \t") << ".csh" << endl;
1735          cout <<
1736            "if ( $status != 0 ) then\n"
1737            "    set cmtcleanupstatus=1\n"
1738            "endif\n";
1739          cout << "endif" << endl;
1740          result = 1;
1741          break;
1742        case Sh :
1743          cout << "if test -f " << CmtSystem::quote (name, " \t") << ".sh; then" << endl;
1744          cout << "  . " << CmtSystem::quote (name, " \t") << ".sh" << endl;
1745          cout <<
1746            "if test $? != 0; then\n"
1747            "    cmtcleanupstatus=1\n"
1748            "fi\n";
1749          cout << "fi" << endl;
1750          result = 1;
1751          break;
1752        case Bat :
1753          cout << "call " << CmtSystem::quote (name, " \t");
1754          result = 1;
1755          break;
1756        }
1757      break;
1758    }
1759
1760  return (result);
1761}
1762
1763//-------------------------------------------------------------
1764int Symbol::print (PrintMode mode)
1765{
1766  int result = 0;
1767
1768  cmt_string temp = build_macro_value ();
1769  bool empty = (temp.size () == 0) ? true : false;
1770
1771  if (type == SymbolPath)
1772    {
1773      expand (temp);
1774      Symbol::filter_path_value (name, temp);
1775    }
1776
1777  cmt_string _name;
1778  switch (type)
1779    {
1780      case SymbolSet :
1781      case SymbolPath :
1782        if (0 != CmtSystem::mangle (name, _name))
1783          CmtMessage::info ("Replace " + name + " with " + _name);
1784        switch (mode)
1785          {
1786            case Csh :
1787              if (empty) cout << "unsetenv " << _name;
1788              else cout << "setenv " << _name << " \"" << temp << "\"";
1789              //else cout << "setenv " << name << " " << CmtSystem::quote (temp, " \t");
1790
1791              result = 1;
1792              break;
1793            case Sh :
1794              if (empty) cout << "[ -z ${" << _name << "+CMT} ] || unset " << _name;
1795              //              if (empty) cout << "unset " << _name;
1796              else cout << _name << "=\"" << temp << "\"; export " << _name;
1797              //else cout << name << "=" << CmtSystem::quote (temp, " \t") << "; export " << name;
1798
1799              result = 1;
1800              break;
1801            case Bat :
1802              temp.replace_all ("/", "\\");
1803              cout << "set " << _name << "=" << CmtSystem::quote (temp, " \t");
1804              //cout << "set " << name << "=" << temp;
1805              result = 1;
1806              break;
1807            case Xml :
1808              cout << "<variable><name>" << _name << "</name>"
1809                   << "<value>" << temp << "</value></variable>";
1810              result = 1;
1811              break;
1812          }
1813        break;
1814      case SymbolAlias :
1815        switch (mode)
1816          {
1817            case Csh :
1818              cout << "alias " << name <<
1819                " \"" << temp << "\"";
1820              //CmtSystem::quote (temp, " \t");
1821              result = 1;
1822              break;
1823            case Sh :
1824              cout << "alias " << name <<
1825                "=\"" << temp << "\"";
1826              //"=" << CmtSystem::quote (temp, " \t");
1827              result = 1;
1828              break;
1829            case Bat :
1830              cout << "set " << name <<
1831                "=" << CmtSystem::quote (temp, " \t");
1832              //"=" << temp;
1833              result = 1;
1834              break;
1835            case Xml :
1836              cout << "<alias><name>" << name << "</name>"
1837                   << "<value>" << temp << "</value></alias>";
1838              result = 1;
1839              break;
1840          }
1841        break;
1842      default :
1843        break;
1844    }
1845
1846  if (temp != "")
1847    {
1848      switch (type)
1849        {
1850          case SymbolSetupScript :
1851            switch (mode)
1852              {
1853                case Csh :
1854                  cout << "if ( -f " << CmtSystem::quote (name, " \t") << ".csh ) then" << endl;
1855                  cout << "  source " << CmtSystem::quote (name, " \t") << ".csh" << endl;
1856                  cout <<
1857                    "if ( $status != 0 ) then\n"
1858                    "    set cmtsetupstatus=1\n"
1859                    "endif\n";
1860                  cout << "endif" << endl;
1861                  result = 1;
1862                  break;
1863                case Sh :
1864                  cout << "if test -f " << CmtSystem::quote (name, " \t") << ".sh; then" << endl;
1865                  cout << "  . " << CmtSystem::quote (name, " \t") << ".sh" << endl;
1866                  cout <<
1867                    "if test $? != 0; then\n"
1868                    "    cmtsetupstatus=1\n"
1869                    "fi\n";
1870                  cout << "fi" << endl;
1871                  result = 1;
1872                  break;
1873                case Bat :
1874                  cout << "call " << CmtSystem::quote (name, " \t");
1875                  result = 1;
1876                  break;
1877                case Xml :
1878                  cout << "<script>" << name << "</script>";
1879                  result = 1;
1880                  break;
1881              }
1882            break;
1883          default:
1884            break;
1885        }
1886    }
1887
1888  return (result);
1889}
1890
1891//-------------------------------------------------------------
1892cmt_string Symbol::build_macro_value (bool display_it) const
1893{
1894  cmt_string temp;
1895
1896  if (display_it)
1897    {
1898      temp = builder->build_and_display (*this);
1899    }
1900  else
1901    {
1902      temp = builder->build (*this);
1903    }
1904
1905  return (temp);
1906}
1907
1908//-------------------------------------------------------------
1909int Symbol::print_macro (PrintMode mode, ostream& out) const
1910{
1911  if (mode != Requirements || printed) return 0;
1912  return builder->print (*this, out);
1913}
1914
1915//-------------------------------------------------------------
1916cmt_string Symbol::clean_macro_value () const
1917{
1918  cmt_string temp;
1919
1920  temp = builder->clean (*this);
1921
1922  return (temp);
1923}
1924
1925/**
1926
1927   Attempt to substitute into the symbol value all occurrences of
1928
1929      ${xxx}
1930      $(xxx)
1931      `xxx`
1932      %xxx%    [on Windows only]
1933
1934      by the appropriate value:
1935
1936        for `xxx` :
1937
1938            xxx is considered as a shell command. Value is the result of its execution
1939
1940        for other patterns:
1941
1942            if xxx is a symbol name, its value is substituted to the pattern
1943            otherwise, xxx is tried as an environment variable
1944
1945
1946     ===> In all cases, the pattern is filtered away.
1947
1948  */
1949cmt_string Symbol::resolve_macro_value (const cmt_string& tag_name) const
1950{
1951  cmt_string temp = builder->build (*this, tag_name);
1952
1953  resolve_value (temp);
1954
1955  return (temp);
1956}
1957
1958//-------------------------------------------------------------
1959void Symbol::show_macro (PrintMode mode, ostream& out)
1960//void Symbol::show_macro (PrintMode mode)
1961{
1962  if (Cmt::get_debug ())
1963    {
1964      cout << "Symbol::show_macro> " << name << endl;
1965    }
1966
1967  ActionType action = Cmt::get_action ();
1968
1969  cmt_string value = build_macro_value (true);
1970
1971  if ((!Cmt::get_quiet ()) &&
1972      (action != action_build_tag_makefile) &&
1973      (action != action_build_constituents_config) &&
1974      (action != action_build_constituent_config) &&
1975      (action != action_build_broadcast_config) &&
1976      (action != action_show_macros) &&
1977      (action != action_show_actions) &&
1978      (action != action_show_aliases) &&
1979      (action != action_show_sets))
1980    {
1981      out << "#" << endl;
1982      out << "# Selection : " << endl;
1983    }
1984
1985  if (value.size () > 0)
1986    {
1987      if ((action == action_show_macro) ||
1988          (action == action_show_macros) ||
1989          (action == action_show_sets) ||
1990          (action == action_show_set) ||
1991          (action == action_show_actions) ||
1992          (action == action_show_action) ||
1993          (action == action_show_alias) ||
1994          (action == action_show_aliases) ||
1995          (action == action_build_tag_makefile) ||
1996          (action == action_build_constituents_config) ||
1997          (action == action_build_constituent_config) ||
1998          (action == action_build_broadcast_config) ||
1999          (action == action_load) ||
2000          (!Cmt::get_quiet ()))
2001        {
2002          if (mode == Make)
2003            {
2004              out << name << "=";
2005            }
2006          else
2007            {
2008              out << name << "='";
2009            }
2010        }
2011
2012      if ((action == action_show_macro_value) ||
2013          (action == action_show_set_value) ||
2014          (action == action_show_action_value) ||
2015          (action == action_show_alias_value))
2016        {
2017          expand (value);
2018        }
2019      else if (action == action_build_tag_makefile ||
2020               action == action_build_constituents_config ||
2021               action == action_build_constituent_config ||
2022               action == action_build_broadcast_config)
2023        {
2024            /*
2025               Unfortunately, the %xxx% pattern has to be kept on Unix. Therefore
2026               we cannot force all patterns to become $(xxx)
2027
2028               This was useful on Windows so as to only keep $(xxx)
2029             */
2030#ifdef WIN32
2031          suppress_OS_delimiters (value);
2032#endif
2033        }
2034
2035      out << value;
2036
2037      if ((action == action_show_macro) ||
2038          (action == action_show_macros) ||
2039          (action == action_show_sets) ||
2040          (action == action_show_set) ||
2041          (action == action_show_actions) ||
2042          (action == action_show_action) ||
2043          (action == action_show_alias) ||
2044          (action == action_show_aliases) ||
2045          (action == action_build_tag_makefile) ||
2046          (action == action_build_constituents_config) ||
2047          (action == action_build_constituent_config) ||
2048          (action == action_build_broadcast_config) ||
2049          (action == action_load) ||
2050          (!Cmt::get_quiet ()))
2051        {
2052          if (mode != Make)
2053            {
2054              out << "'";
2055            }
2056#ifdef WIN32
2057          else
2058            {
2059              out << " ";
2060            }
2061#endif
2062        }
2063
2064      out << endl;
2065    }
2066}
2067
2068//-------------------------------------------------------------
2069void Symbol::clear_all ()
2070{
2071  static SymbolVector& Symbols = symbols ();
2072  static SymbolMap& SymbolMap = symbol_map ();
2073
2074  SymbolMap.clear ();
2075  Symbols.clear ();
2076}
2077
2078//-------------------------------------------------------------
2079void Symbol::expand (cmt_string& text)
2080{
2081  static cmt_regexp reg ("[$%`]");
2082
2083  if (!reg.match (text)) return;
2084
2085  resolve_value (text);
2086}
2087
2088//-------------------------------------------------------------
2089ValueBuilder::ValueBuilder ()
2090{
2091  m_display_it = false;
2092}
2093
2094//-------------------------------------------------------------
2095const cmt_string ValueBuilder::build_and_display (const Symbol& symbol)
2096{
2097  cmt_string temp;
2098
2099  m_display_it = true;
2100  temp = build (symbol);
2101  m_display_it = false;
2102
2103  return (temp);
2104}
2105
2106//-------------------------------------------------------------
2107int ValueBuilder::print (const Symbol& symbol, ostream& out)
2108{
2109  int result (0);
2110
2111  bool first_definition = true;
2112 
2113  for (int i = 0; i < symbol.value_lists.size (); i++)
2114    {
2115      const SymbolValueList& value_list = symbol.value_lists[i];
2116
2117      if ((value_list.use != 0) &&
2118          (value_list.use->discarded)) continue;
2119
2120      const int selected = value_list.select_first ();
2121
2122      if (selected < 0) continue;
2123
2124      SymbolValue& value = value_list.values[selected];
2125
2126      result += value_list.print (symbol, value, first_definition);
2127    }
2128
2129  return result;
2130}
2131
2132//-------------------------------------------------------------
2133const cmt_string SetBuilder::build (const Symbol& symbol,
2134                                    const cmt_string& /*tag_name*/)
2135{
2136    // Control of recursivity
2137  static int level = 0;
2138
2139  bool show_it = false;
2140
2141  cmt_string temp;
2142  cmt_string previous_temp;
2143  cmt_string new_value;
2144  static const cmt_string empty;
2145
2146  ActionType action = Cmt::get_action ();
2147
2148  if (action == action_show_set)
2149    {
2150      if (symbol.name == Cmt::get_current_target ())
2151        {
2152             // Should not display on recursive calls
2153          if (level == 0) show_it = m_display_it;
2154        }
2155    }
2156
2157  level++;
2158
2159  temp = "";
2160
2161  bool first_definition = true;
2162
2163  for (int i = 0; i < symbol.value_lists.size (); i++)
2164    {
2165      const SymbolValueList& value_list = symbol.value_lists[i];
2166
2167      if ((value_list.use != 0) &&
2168          (value_list.use->discarded)) continue;
2169
2170      const int selected = value_list.select_first ();
2171
2172      if (selected < 0) continue;
2173
2174      SymbolValue& value = value_list.values[selected];
2175
2176      if (show_it && !Symbol::get_inhibit_display())
2177        {
2178          value_list.show (symbol, value, first_definition);
2179        }
2180     
2181      if (value_list.discarded) continue;
2182
2183        //
2184        // One should accumulate values if it refers to
2185        // itself.
2186        //
2187     
2188      new_value = value.text;
2189     
2190      resolve_value_for_macros (new_value);
2191     
2192      switch (value_list.command_type)
2193        {
2194          case CommandSet :
2195
2196            if (!value_list.is_reflexive || 
2197                !symbol.value_is_reflexive (value.text))
2198              {
2199                resolve_value (new_value, symbol.name, temp);
2200                temp = new_value;
2201              }
2202            else if (temp == "")
2203              {
2204                temp = CmtSystem::getenv (symbol.name);
2205              }
2206
2207            break;
2208          case CommandSetAppend :
2209           
2210            if (new_value != "")
2211              {
2212                temp += new_value;
2213              }
2214           
2215            break;
2216          case CommandSetPrepend :
2217           
2218            if (new_value != "")
2219              {
2220                previous_temp = temp;
2221                temp = new_value;
2222                temp += previous_temp;
2223              }
2224           
2225            break;
2226          case CommandSetRemove :
2227           
2228            if (new_value != "")
2229              {
2230                temp.replace_all (new_value, empty);
2231              }
2232           
2233            break;
2234          case CommandSetRemoveRegexp :
2235           
2236            if (new_value != "")
2237              {
2238                cmt_regexp e (new_value);
2239                cmt_regexp::iterator it;
2240
2241                for (;;)
2242                  {
2243                    it = e.begin (temp);
2244                    if (it == e.end ()) break;
2245
2246                    temp.erase (it._pos, it._length);
2247                  }
2248              }
2249           
2250            break;
2251          case CommandAlias :
2252           
2253            resolve_value (new_value, symbol.name, temp);
2254            temp = new_value;
2255           
2256            break;
2257        }
2258    }
2259
2260  level--;
2261
2262  return (temp);
2263}
2264
2265static bool find_path_entry (const CmtSystem::cmt_string_vector& items, const cmt_string& value)
2266{
2267  static const cmt_string path_separator = CmtSystem::path_separator ();
2268  static cmt_vmap <cmt_string, cmt_string> realpaths;
2269
2270  if (value.size () == 0) return true;
2271
2272  cmt_string rvalue;
2273  const cmt_string * prvalue;
2274
2275  if (!(prvalue = realpaths.find (value)))
2276    {
2277      if (!CmtSystem::realpath_ (value, rvalue))
2278        {
2279          rvalue = value;
2280          CmtSystem::compress_path (rvalue);
2281        }
2282      prvalue = &rvalue;
2283      realpaths.add (value, rvalue);
2284      //      cerr << "realpaths.add: " << value << " , " << rvalue << endl;
2285    }
2286
2287  //  CmtSystem::cmt_string_vector items;
2288  //  CmtSystem::split (paths, path_separator, items);
2289
2290  bool found = false;
2291
2292  for (int i = 0; i < items.size (); i++)
2293    {
2294      const cmt_string& item = items[i];
2295      if (item.size () == 0) continue;
2296      cmt_string ritem;
2297      const cmt_string * pritem;
2298
2299      if (!(pritem = realpaths.find (item)))
2300        {
2301          if (!CmtSystem::realpath_ (item, ritem))
2302            {
2303              ritem = item;
2304              CmtSystem::compress_path (ritem);
2305            }
2306          pritem = &ritem;
2307          realpaths.add (item, ritem);
2308          //  cerr << "realpaths.add: " << item << " , " << ritem << endl;
2309        }
2310      if (*pritem == *prvalue)
2311        {
2312          found = true;
2313          break;
2314        }
2315    }
2316
2317  return (found);
2318}
2319
2320static bool find_path_entry (const cmt_string& paths, const cmt_string& value)
2321{
2322  static const cmt_string path_separator = CmtSystem::path_separator ();
2323  static cmt_vmap <cmt_string, cmt_string> realpaths;
2324
2325  cmt_string rvalue;
2326  const cmt_string * prvalue;
2327
2328  if (!(prvalue = realpaths.find (value)))
2329    {
2330      if (!CmtSystem::realpath_ (value, rvalue))
2331        {
2332          rvalue = value;
2333          CmtSystem::compress_path (rvalue);
2334        }
2335      prvalue = &rvalue;
2336      realpaths.add (value, rvalue);
2337      //      cerr << "realpaths.add: " << value << " , " << rvalue << endl;
2338    }
2339
2340  CmtSystem::cmt_string_vector items;
2341  CmtSystem::split (paths, path_separator, items);
2342
2343  bool found = false;
2344
2345  for (int i = 0; i < items.size (); i++)
2346    {
2347      const cmt_string& item = items[i];
2348      cmt_string ritem;
2349      const cmt_string * pritem;
2350
2351      if (!(pritem = realpaths.find (item)))
2352        {
2353          if (!CmtSystem::realpath_ (item, ritem))
2354            {
2355              ritem = item;
2356              CmtSystem::compress_path (ritem);
2357            }
2358          pritem = &ritem;
2359          realpaths.add (item, ritem);
2360          //  cerr << "realpaths.add: " << item << " , " << ritem << endl;
2361        }
2362      if (*pritem == *prvalue)
2363        {
2364          found = true;
2365          break;
2366        }
2367    }
2368
2369  return (found);
2370}
2371
2372//-------------------------------------------------------------
2373const cmt_string PathBuilder::build (const Symbol& symbol,
2374                                     const cmt_string& /*tag_name*/)
2375{
2376    // Control of recursivity
2377  static int level = 0;
2378
2379  bool show_it = false;
2380
2381  cmt_string temp;
2382  CmtSystem::cmt_string_vector temp_vector;
2383  //  cmt_string previous_temp;
2384  CmtSystem::cmt_string_vector new_value_vector;
2385  cmt_string new_value;
2386  static const cmt_string empty;
2387
2388  static cmt_string path_separator = CmtSystem::path_separator ();
2389
2390  ActionType action = Cmt::get_action ();
2391
2392  if (action == action_show_set)
2393    {
2394      if (symbol.name == Cmt::get_current_target ())
2395        {
2396            // Should not display on recursive calls
2397          if (level == 0) show_it = m_display_it;
2398        }
2399    }
2400
2401  level++;
2402
2403  CmtSystem::split (CmtSystem::getenv (symbol.name), path_separator, temp_vector);
2404  //temp = CmtSystem::getenv (symbol.name);
2405
2406  bool first_definition = true;
2407
2408  for (int i = 0; i < symbol.value_lists.size (); i++)
2409    {
2410      const SymbolValueList& value_list = symbol.value_lists[i];
2411
2412      if ((value_list.use != 0) &&
2413          (value_list.use->discarded)) continue;
2414
2415      const int selected = value_list.select_first ();
2416     
2417      if (selected < 0) continue;
2418 
2419      SymbolValue& value = value_list.values[selected];
2420         
2421      if (show_it && !Symbol::get_inhibit_display())
2422        {
2423          value_list.show (symbol, value, first_definition);
2424        }
2425         
2426      if (value_list.discarded) continue;
2427
2428      new_value = value.text;
2429         
2430          //resolve_value (new_value);
2431      resolve_value_for_macros (new_value);
2432         
2433      switch (value_list.command_type)
2434        {
2435          case CommandPath :
2436           
2437            if (!value_list.is_reflexive || 
2438                !symbol.value_is_reflexive (value.text))
2439              {
2440                Cmt::vector_to_string (temp_vector, path_separator, temp);
2441                resolve_value (new_value, symbol.name, temp);
2442                CmtSystem::split (new_value, path_separator, temp_vector);
2443                //temp = new_value;
2444              }
2445
2446            break;
2447          case CommandPathAppend :
2448             
2449            if (new_value != "")
2450              {
2451                CmtSystem::split (new_value, path_separator, new_value_vector);
2452                for (int i = 0; i < new_value_vector.size (); i++)
2453                  if (!find_path_entry (temp_vector, new_value_vector[i]))
2454                    //if (!find_path_entry (temp, new_value))
2455                    {
2456                      temp_vector.push_back (new_value_vector[i]);
2457                      /*
2458                        if (temp != "") temp += path_separator;
2459                       
2460                        temp += new_value;
2461                      */
2462                    }
2463              }
2464                 
2465            break;
2466          case CommandPathPrepend :
2467             
2468            if (new_value != "")
2469              {
2470                CmtSystem::split (new_value, path_separator, new_value_vector);
2471                int n (new_value_vector.size ());
2472                temp_vector.resize (temp_vector.size () + n);
2473                for (int i = temp_vector.size () - 1; i > n - 1; i--)
2474                  temp_vector [i] = temp_vector [i - n];
2475                for (int i = 0; i < new_value_vector.size (); i++)
2476                  if (!find_path_entry (temp_vector, new_value_vector[i]))
2477                    //if (!find_path_entry (temp, new_value))
2478                    {
2479                      temp_vector [i] = new_value_vector[i];
2480                      /*
2481                        previous_temp = temp;
2482                        temp = new_value;
2483                        if (previous_temp != "") temp += path_separator;
2484                        temp += previous_temp;
2485                      */
2486                    }
2487                  else
2488                    temp_vector [i] = "";
2489              }
2490           
2491            break;
2492          case CommandPathRemove :
2493             
2494            if (new_value != "")
2495              {
2496                for (int j = 0; j < temp_vector.size (); ++j)
2497                  {
2498                    cmt_string& s = temp_vector[j];
2499                   
2500                    if (s.find (new_value) != cmt_string::npos)
2501                      {
2502                        s = "";
2503                      }
2504                  }
2505                /*
2506                CmtSystem::cmt_string_vector paths;
2507                 
2508                CmtSystem::split (temp, path_separator, paths);
2509                 
2510                for (int j = 0; j < paths.size (); ++j)
2511                  {
2512                    cmt_string& s = paths[j];
2513                     
2514                    if (s.find (new_value) != cmt_string::npos)
2515                      {
2516                        s = "";
2517                      }
2518                  }
2519
2520                Cmt::vector_to_string (paths, path_separator, temp);
2521                */
2522              }
2523             
2524            break;
2525          case CommandPathRemoveRegexp :
2526
2527            if (new_value != "")
2528              {
2529                cmt_regexp e (new_value);
2530
2531                for (int j = 0; j < temp_vector.size (); ++j)
2532                  {
2533                    cmt_string& s = temp_vector[j];
2534
2535                    if (Cmt::get_debug () &&
2536                        CmtSystem::getenv ("TESTPRR") != "")
2537                      {
2538                        cerr << "PRR> s=[" << s << "]";
2539                      }
2540
2541                    if (e.match (s))
2542                      {
2543                        s = "";
2544
2545                        if (Cmt::get_debug () &&
2546                            CmtSystem::getenv ("TESTPRR") != "")
2547                          {
2548                            cerr << " match ";
2549                          }
2550                      }
2551                    else
2552                      {
2553                        if (Cmt::get_debug () &&
2554                            CmtSystem::getenv ("TESTPRR") != "")
2555                          {
2556                            cerr << " no match ";
2557                          }
2558                      }
2559
2560                    if (Cmt::get_debug () &&
2561                        CmtSystem::getenv ("TESTPRR") != "")
2562                      {
2563                        cerr << endl;
2564                      }
2565                  }
2566
2567                /*
2568                CmtSystem::cmt_string_vector paths;
2569                 
2570                CmtSystem::split (temp, path_separator, paths);
2571                 
2572                for (int j = 0; j < paths.size (); ++j)
2573                  {
2574                    cmt_string& s = paths[j];
2575
2576                    if (CmtSystem::getenv ("TESTPRR") != "")
2577                      {
2578                        cerr << "PRR> s=[" << s << "]";
2579                      }
2580
2581                    if (e.match (s))
2582                      {
2583                        s = "";
2584
2585                        if (CmtSystem::getenv ("TESTPRR") != "")
2586                          {
2587                            cerr << " match ";
2588                          }
2589                      }
2590                    else
2591                      {
2592                        if (CmtSystem::getenv ("TESTPRR") != "")
2593                          {
2594                            cerr << " no match ";
2595                          }
2596                      }
2597
2598                    if (CmtSystem::getenv ("TESTPRR") != "")
2599                      {
2600                        cerr << endl;
2601                      }
2602                  }
2603
2604                Cmt::vector_to_string (paths, path_separator, temp);
2605                */
2606              }
2607             
2608            break;
2609        }
2610
2611    }
2612
2613  Cmt::vector_to_string (temp_vector, path_separator, temp);
2614
2615  level--;
2616
2617  for (;;)
2618    {
2619      int sz = temp.size ();
2620
2621      if (sz == 0) break;
2622
2623      if ((temp[0] == ';') || (temp[0] == ':'))
2624        {
2625          temp.erase (0, 1);
2626        }
2627      else if ((temp[sz-1] == ';') || (temp[sz-1] == ':'))
2628        {
2629          temp.erase (sz-1, 1);
2630        }
2631      else
2632        {
2633          break;
2634        }
2635    }
2636
2637  temp.replace_all ("::", ":");
2638  temp.replace_all (";;", ";");
2639 
2640  return (temp);
2641}
2642
2643//-------------------------------------------------------------
2644const cmt_string PathBuilder::clean (const Symbol& symbol,
2645                                     const cmt_string& /*tag_name*/)
2646{
2647    // Control of recursivity
2648  static int level = 0;
2649
2650  cmt_string temp;
2651  cmt_string new_value;
2652  static const cmt_string empty;
2653
2654  static cmt_string path_separator = CmtSystem::path_separator ();
2655
2656  temp = CmtSystem::getenv (symbol.name);
2657
2658    //cerr << "#####1 temp=" << temp << endl;
2659
2660  for (int i = 0; i < symbol.value_lists.size (); i++)
2661    {
2662      const SymbolValueList& value_list = symbol.value_lists[i];
2663
2664      if (value_list.discarded) continue;
2665
2666      if ((value_list.use != 0) &&
2667          (value_list.use->discarded)) continue;
2668
2669      const int selected = value_list.select_first ();
2670     
2671      if (selected < 0) continue;
2672 
2673      SymbolValue& value = value_list.values[selected];
2674         
2675      new_value = value.text;
2676         
2677          //resolve_value (new_value);
2678
2679        //cerr << "#####1 new_value=" << new_value << endl;
2680
2681      resolve_value_for_macros (new_value);
2682      resolve_value (new_value);
2683         
2684        //cerr << "#####2 new_value=" << new_value << endl;
2685
2686      switch (value_list.command_type)
2687        {
2688          case CommandPath :
2689           
2690            temp = "";
2691           
2692            break;
2693          case CommandPathAppend :
2694          case CommandPathPrepend :
2695          case CommandPathRemove :
2696
2697            if (new_value != "")
2698              {
2699                CmtSystem::cmt_string_vector paths;
2700                 
2701                CmtSystem::split (temp, path_separator, paths);
2702                 
2703                for (int j = 0; j < paths.size (); ++j)
2704                  {
2705                    cmt_string& s = paths[j];
2706                     
2707                    if (s.find (new_value) != cmt_string::npos)
2708                      {
2709                        s = "";
2710                      }
2711
2712                    if (j > 0)
2713                      {
2714                        cmt_string& s2 = paths[j-1];
2715                        if (s2 == s)
2716                          {
2717                            s2 = "";
2718                          }
2719                      }
2720                  }
2721
2722                Cmt::vector_to_string (paths, path_separator, temp);
2723                temp.replace_all ("::", ":");
2724                temp.replace_all (";;", ";");
2725              }
2726             
2727            break;
2728          case CommandPathRemoveRegexp :
2729
2730            if (new_value != "")
2731              {
2732                cmt_regexp e (new_value);
2733
2734                CmtSystem::cmt_string_vector paths;
2735                 
2736                CmtSystem::split (temp, path_separator, paths);
2737                 
2738                for (int j = 0; j < paths.size (); ++j)
2739                  {
2740                    cmt_string& s = paths[j];
2741                     
2742                    if (e.match (s))
2743                      {
2744                        s = "";
2745                      }
2746
2747                    if (j > 0)
2748                      {
2749                        cmt_string& s2 = paths[j-1];
2750                        if (s2 == s)
2751                          {
2752                            s2 = "";
2753                          }
2754                      }
2755                  }
2756
2757                Cmt::vector_to_string (paths, path_separator, temp);
2758                temp.replace_all ("::", ":");
2759                temp.replace_all (";;", ";");
2760              }
2761             
2762            break;
2763        }
2764    }
2765
2766    //cerr << "#####2 temp=" << temp << endl;
2767 
2768  return (temp);
2769}
2770
2771//-------------------------------------------------------------
2772const cmt_string MacroBuilder::build (const Symbol& symbol,
2773                                      const cmt_string& tag_name)
2774{
2775    // Control of recursivity
2776  static int level = 0;
2777
2778  cmt_string temp;
2779  cmt_string previous_temp;
2780  static const cmt_string empty;
2781  bool show_it = false;
2782
2783  ActionType action = Cmt::get_action ();
2784
2785  if (action == action_show_macro)
2786    {
2787      if (symbol.name == Cmt::get_current_target ())
2788        {
2789             // Should not display on recursive calls
2790          if (level == 0) show_it = m_display_it;
2791        }
2792    }
2793
2794  level++;
2795
2796  temp = "";
2797
2798  int i;
2799
2800  bool first_definition = true;
2801
2802  for (i = 0; i < symbol.value_lists.size (); i++)
2803    {
2804      const SymbolValueList& value_list = symbol.value_lists[i];
2805
2806      if ((value_list.use != 0) &&
2807          (value_list.use->discarded)) continue;
2808
2809      if (value_list.command_type != CommandMacroPrepend) continue;
2810
2811      const int selected = value_list.select_first (tag_name);
2812
2813      if (selected < 0) continue;
2814
2815      SymbolValue& value = value_list.values[selected];
2816
2817      if (show_it && !Symbol::get_inhibit_display())
2818        {
2819          value_list.show (symbol, value, first_definition);
2820        }
2821
2822      if (value_list.discarded) continue;
2823
2824      previous_temp = temp;
2825      temp = value.text;
2826      temp += previous_temp;
2827    }
2828
2829  previous_temp = temp;
2830  temp = "";
2831
2832  first_definition = true;
2833
2834  for (i = 0; i < symbol.value_lists.size (); i++)
2835    {
2836      const SymbolValueList& value_list = symbol.value_lists[i];
2837
2838      if ((value_list.use != 0) &&
2839          (value_list.use->discarded)) continue;
2840
2841      if (value_list.command_type != CommandMacro) continue;
2842
2843      const int selected = value_list.select_first (tag_name);
2844
2845      if (selected < 0) continue;
2846
2847      SymbolValue& value = value_list.values[selected];
2848
2849      if (show_it && !Symbol::get_inhibit_display())
2850        {
2851          value_list.show (symbol, value, first_definition);
2852        }
2853
2854      // WARNING:
2855      // Commented just for a test : should be uncommented after the test
2856      if (value_list.discarded) continue;
2857     
2858      if (!value_list.is_reflexive || 
2859          !symbol.value_is_reflexive (value.text))
2860        {
2861          temp = value.text;
2862        }
2863    }
2864
2865  previous_temp += temp;
2866  temp = previous_temp;
2867
2868  for (i = 0; i < symbol.value_lists.size (); i++)
2869    {
2870      const SymbolValueList& value_list = symbol.value_lists[i];
2871
2872      if ((value_list.use != 0) &&
2873          (value_list.use->discarded)) continue;
2874
2875      if (value_list.command_type != CommandMacroAppend) continue;
2876
2877      const int selected = value_list.select_first (tag_name);
2878
2879      if (selected < 0) continue;
2880
2881      SymbolValue& value = value_list.values[selected];
2882
2883      if (show_it && !Symbol::get_inhibit_display())
2884        {
2885          value_list.show (symbol, value, first_definition);
2886        }
2887
2888      if (value_list.discarded) continue;
2889
2890      temp += value.text;
2891    }
2892
2893  for (i = 0; i < symbol.value_lists.size (); i++)
2894    {
2895      const SymbolValueList& value_list = symbol.value_lists[i];
2896
2897      if ((value_list.use != 0) &&
2898          (value_list.use->discarded)) continue;
2899
2900      if ((value_list.command_type != CommandMacroRemove) &&
2901          (value_list.command_type != CommandMacroRemoveRegexp) &&
2902          (value_list.command_type != CommandMacroRemoveAll) &&
2903          (value_list.command_type != CommandMacroRemoveAllRegexp)) continue;
2904
2905      const int selected = value_list.select_first (tag_name);
2906
2907      if (selected < 0) continue;
2908
2909      SymbolValue& value = value_list.values[selected];
2910
2911      if (show_it && !Symbol::get_inhibit_display())
2912        {
2913          value_list.show (symbol, value, first_definition);
2914        }
2915
2916      if (value_list.discarded) continue;
2917
2918      switch (value_list.command_type)
2919        {
2920          case CommandMacroRemove :
2921            temp.replace (value.text, empty);
2922            break;
2923          case CommandMacroRemoveRegexp :
2924            if (value.text != "")
2925              {
2926                cmt_regexp e (value.text);
2927                cmt_regexp::iterator it;
2928
2929                it = e.begin (temp);
2930                if (it != e.end ())
2931                  {
2932                    temp.erase (it._pos, it._length);
2933                  }
2934              }
2935            break;
2936          case CommandMacroRemoveAll :
2937            temp.replace_all (value.text, empty);
2938            break;
2939          case CommandMacroRemoveAllRegexp :
2940            if (value.text != "")
2941              {
2942                cmt_regexp e (value.text);
2943                cmt_regexp::iterator it;
2944
2945                for (;;)
2946                  {
2947                    it = e.begin (temp);
2948                    if (it != e.end ())
2949                      {
2950                        temp.erase (it._pos, it._length);
2951                      }
2952                    else
2953                      {
2954                        break;
2955                      }
2956                  }
2957              }
2958            break;
2959        }
2960    }
2961
2962  level--;
2963
2964  return (temp);
2965}
2966
2967//-------------------------------------------------------------
2968const cmt_string ScriptBuilder::build (const Symbol& symbol,
2969                                       const cmt_string& tag_name)
2970{
2971    // Control of recursivity
2972  static int level = 0;
2973
2974  static const cmt_string empty = "";
2975
2976  if (symbol.value_lists.size () > 0)
2977    {
2978      const SymbolValueList& value_list = symbol.value_lists[0];
2979
2980      if (value_list.discarded) return (empty);
2981
2982      if ((value_list.use != 0) &&
2983          (value_list.use->discarded)) return (empty);
2984    }
2985
2986  return (symbol.name);
2987}
2988
2989//-------------------------------------------------------------
2990const cmt_string ActionBuilder::build (const Symbol& symbol,
2991                                       const cmt_string& tag_name)
2992{
2993    // Control of recursivity
2994  static int level = 0;
2995
2996  cmt_string temp;
2997  cmt_string previous_temp;
2998  static const cmt_string empty;
2999  bool show_it = false;
3000
3001  ActionType action = Cmt::get_action ();
3002
3003  if (action == action_show_action)
3004    {
3005      if (symbol.name == Cmt::get_current_target ())
3006        {
3007             // Should not display on recursive calls
3008          if (level == 0) show_it = m_display_it;
3009        }
3010    }
3011
3012  level++;
3013
3014  int i;
3015
3016  bool first_definition = true;
3017
3018  temp = "";
3019
3020  for (i = 0; i < symbol.value_lists.size (); i++)
3021    {
3022      const SymbolValueList& value_list = symbol.value_lists[i];
3023
3024      if ((value_list.use != 0) &&
3025          (value_list.use->discarded)) continue;
3026
3027      if (value_list.command_type != CommandAction) continue;
3028
3029      const int selected = value_list.select_first (tag_name);
3030
3031      if (selected < 0) continue;
3032
3033      SymbolValue& value = value_list.values[selected];
3034
3035      if (show_it && !Symbol::get_inhibit_display())
3036        {
3037          value_list.show (symbol, value, first_definition);
3038        }
3039
3040      // WARNING:
3041      // Commented just for a test : should be uncommented after the test
3042      if (value_list.discarded) continue;
3043     
3044      if (!value_list.is_reflexive || 
3045          !symbol.value_is_reflexive (value.text))
3046        {
3047          temp = value.text;
3048        }
3049    }
3050
3051  level--;
3052
3053  return (temp);
3054}
3055
3056//-------------------------------------------------------------
3057int SymbolValueList::select_first (const cmt_string& tag_name) const
3058{
3059  int priority = 0;
3060  int value_number;
3061  int selected = -1;
3062
3063  Tag* the_tag = 0;
3064
3065  if (tag_name != "") the_tag = Tag::find (tag_name);
3066
3067  for (value_number = 0;
3068       value_number < values.size ();
3069       value_number++)
3070    {
3071      const SymbolValue& value = values[value_number];
3072
3073      const Tag* tag = value.tag;
3074
3075      if (the_tag == 0)
3076        {
3077          if (!tag->is_selected ()) continue;
3078          selected = value_number;
3079          if (tag == Tag::get_default ())
3080            continue;
3081        }
3082      else
3083        {
3084          if (tag != the_tag) continue;
3085          selected = value_number;
3086        }
3087
3088      //
3089      // Only the value for the first alternative (i.e. non-default)
3090      // matching tag expression is
3091      // selected (which means the selection stops here)
3092      //
3093      break;
3094
3095      //
3096      // Only the first value at a given priority is
3097      // selected (which implies the '>' test instead
3098      // of '>=')
3099      //
3100      /*
3101      if (tag->get_priority () > priority)
3102        {
3103          priority = tag->get_priority ();
3104          selected = value_number;
3105        }
3106      */
3107    }
3108
3109  return (selected);
3110}
3111
3112//-------------------------------------------------------------
3113int SymbolValueList::select_last () const
3114{
3115  int priority = 0;
3116  int value_number;
3117  int selected = -1;
3118
3119  for (value_number = 0;
3120       value_number < values.size ();
3121       value_number++)
3122    {
3123      SymbolValue& value = values[value_number];
3124
3125      const Tag* tag = value.tag;
3126
3127      if (tag->is_selected ())
3128        {
3129          //
3130          // The last value at a given priority is
3131          // selected (which implies the '>=' test instead
3132          // of '>')
3133          //
3134
3135          if (tag->get_priority () >= priority)
3136            {
3137              priority = tag->get_priority ();
3138              selected = value_number;
3139            }
3140        }
3141    }
3142
3143  return (selected);
3144}
3145
3146//-------------------------------------------------------------
3147void SymbolValueList::show (const Symbol& symbol, 
3148                            const SymbolValue& value, 
3149                            bool& first_definition) const
3150{
3151  cmt_string discarded_text;
3152  cmt_string define_text;
3153  ActionType action = Cmt::get_action ();
3154
3155  switch (command_type)
3156    {
3157      //case CommandSet :
3158      case CommandSetAppend :
3159      case CommandSetPrepend :
3160      case CommandSetRemove :
3161      case CommandSetRemoveRegexp :
3162        //case CommandAlias :
3163        //case CommandPath :
3164      case CommandPathAppend :
3165      case CommandPathPrepend :
3166      case CommandPathRemove :
3167      case CommandPathRemoveRegexp :
3168      case CommandMacroPrepend :
3169        //case CommandMacro :
3170      case CommandMacroAppend :
3171      case CommandMacroRemove :
3172      case CommandMacroRemoveRegexp :
3173      case CommandMacroRemoveAll :
3174      case CommandMacroRemoveAllRegexp :
3175        //case CommandAction :
3176        if (value.text == "") return;
3177        break;
3178    }
3179
3180  if (discarded) discarded_text = " (discarded by override)";
3181  else discarded_text = "";
3182
3183  if (first_definition) define_text = "defines";
3184  else define_text = "overrides";
3185
3186  cout << "# Package ";
3187  if (use != 0)
3188    {
3189      cout << use->get_package_name () << " " << use->version;
3190    }
3191
3192  switch (command_type)
3193    {
3194      case CommandSet :
3195        cout << " " << define_text << " set " << symbol.name << " as ";
3196        first_definition = false;
3197        break;
3198      case CommandSetAppend :
3199        cout << " appends to set " << symbol.name << " : ";
3200        break;
3201      case CommandSetPrepend :
3202        cout << " prepends to set " << symbol.name << " : ";
3203        break;
3204      case CommandSetRemove :
3205        cout << " removes from set " << symbol.name << " : ";
3206        break;
3207      case CommandSetRemoveRegexp :
3208        cout << " removes RE from set " << symbol.name << " : ";
3209        break;
3210      case CommandAlias :
3211        cout << " " << define_text << " alias " << symbol.name << " as ";
3212        first_definition = false;
3213        break;
3214      case CommandPath :
3215        cout << " " << define_text << " path " << symbol.name << " as ";
3216        first_definition = false;
3217        break;
3218      case CommandPathAppend :
3219        cout << " appends to path " << symbol.name << " : ";
3220        break;
3221      case CommandPathPrepend :
3222        cout << " prepends to path " << symbol.name << " : ";
3223        break;
3224      case CommandPathRemove :
3225        cout << " removes from path " << symbol.name << " : ";
3226        break;
3227      case CommandPathRemoveRegexp :
3228        cout << " removes RE from path " << symbol.name << " : ";
3229        break;
3230      case CommandMacroPrepend :
3231        cout << " prepends to macro " << symbol.name << " : ";
3232        break;
3233      case CommandMacro :
3234        cout << " " << define_text << " macro " << symbol.name << " as ";
3235        break;
3236      case CommandMacroAppend :
3237        cout << " appends to macro " << symbol.name << " : ";
3238        break;
3239      case CommandMacroRemove :
3240        cout << " remove from macro " << symbol.name << " : ";
3241        break;
3242      case CommandMacroRemoveRegexp :
3243        cout << " remove RE from macro " << symbol.name << " : ";
3244        break;
3245      case CommandMacroRemoveAll :
3246        cout << " remove all from macro " << symbol.name << " : ";
3247        break;
3248      case CommandMacroRemoveAllRegexp :
3249        cout << " remove all RE from macro " << symbol.name << " : ";
3250        break;
3251      case CommandAction :
3252        cout << " " << define_text << " action " << symbol.name << " as ";
3253        first_definition = false;
3254        break;
3255    }
3256
3257  cout << "'" << value.text << "'";
3258         
3259  Tag* selected_tag = value.tag;
3260         
3261  if ((selected_tag == 0) ||
3262      (selected_tag == Tag::get_default ()))
3263    {
3264      cout << " for default tag";
3265    }
3266  else
3267    {
3268      cout << " for tag '" << selected_tag->get_name () << "'";
3269    }
3270 
3271  cout << discarded_text << endl;
3272}
3273
3274//-------------------------------------------------------------
3275int SymbolValueList::print (const Symbol& symbol, 
3276                            const SymbolValue& value, 
3277                            bool& first_definition) const
3278{
3279  int result (0);
3280
3281  //if (use->get_package_name () == "CMT") return result;
3282
3283  cmt_string discarded_text;
3284  cmt_string define_text;
3285  ActionType action = Cmt::get_action ();
3286
3287  switch (command_type)
3288    {
3289      //case CommandSet :
3290      case CommandSetAppend :
3291      case CommandSetPrepend :
3292      case CommandSetRemove :
3293      case CommandSetRemoveRegexp :
3294        //case CommandAlias :
3295        //case CommandPath :
3296      case CommandPathAppend :
3297      case CommandPathPrepend :
3298      case CommandPathRemove :
3299      case CommandPathRemoveRegexp :
3300      case CommandMacroPrepend :
3301        //case CommandMacro :
3302      case CommandMacroAppend :
3303      case CommandMacroRemove :
3304      case CommandMacroRemoveRegexp :
3305      case CommandMacroRemoveAll :
3306      case CommandMacroRemoveAllRegexp :
3307        //case CommandAction :
3308        if (value.text == "") return result;
3309        break;
3310    }
3311
3312  if (discarded) discarded_text = " (discarded by override)";
3313  else discarded_text = "";
3314
3315  if (first_definition) define_text = "defines";
3316  else define_text = "overrides";
3317
3318  if (CmtMessage::active (Verbose))
3319    cout << "# Package " << (use != 0 ? use->get_package_name () + " " + use->version : "");
3320  /*
3321  if (use != 0)
3322    {
3323      cout << use->get_package_name () << " " << use->version;
3324    }
3325  */
3326
3327  switch (command_type)
3328    {
3329      case CommandSet :
3330        if (CmtMessage::active (Verbose))
3331          cout << " " << define_text << " set " << symbol.name << " as " << endl;
3332        //        cout << " " << define_text << " set " << symbol.name << " as ";
3333        cout << "set " << symbol.name;
3334        first_definition = false;
3335        result = 1;
3336        break;
3337      case CommandSetAppend :
3338        if (CmtMessage::active (Verbose))
3339          cout << " appends to set " << symbol.name << " : " << endl;
3340        //        cout << " appends to set " << symbol.name << " : ";
3341        cout << "set_append " << symbol.name;
3342        result = 1;
3343        break;
3344      case CommandSetPrepend :
3345        if (CmtMessage::active (Verbose))
3346          cout << " prepends to set " << symbol.name << " : " << endl;
3347        //        cout << " prepends to set " << symbol.name << " : ";
3348        cout << "set_prepend " << symbol.name;
3349        result = 1;
3350        break;
3351      case CommandSetRemove :
3352        if (CmtMessage::active (Verbose))
3353          cout << " removes from set " << symbol.name << " : " << endl;
3354        //        cout << " removes from set " << symbol.name << " : ";
3355        cout << "set_remove " << symbol.name;
3356        result = 1;
3357        break;
3358      case CommandSetRemoveRegexp :
3359        if (CmtMessage::active (Verbose))
3360          cout << " removes RE from set " << symbol.name << " : " << endl;
3361        //        cout << " removes RE from set " << symbol.name << " : ";
3362        cout << "set_remove_regexp " << symbol.name;
3363        result = 1;
3364        break;
3365      case CommandAlias :
3366        if (CmtMessage::active (Verbose))
3367          cout << " " << define_text << " alias " << symbol.name << endl;
3368        //        cout << " " << define_text << " alias " << symbol.name << " as ";
3369        cout << "alias " << symbol.name;
3370        first_definition = false;
3371        result = 1;
3372        break;
3373      case CommandPath :
3374        if (CmtMessage::active (Verbose))
3375          cout << " " << define_text << " path " << symbol.name << endl;
3376        //        cout << " " << define_text << " path " << symbol.name << " as ";
3377        cout << "path " << symbol.name;
3378        first_definition = false;
3379        result = 1;
3380        break;
3381      case CommandPathAppend :
3382        if (CmtMessage::active (Verbose))
3383          cout << " appends to path " << symbol.name << endl;
3384        //        cout << " appends to path " << symbol.name << " : ";
3385        cout << "path_append " << symbol.name;
3386        result = 1;
3387        break;
3388      case CommandPathPrepend :
3389        if (CmtMessage::active (Verbose))
3390          cout << " prepends to path " << symbol.name << " : " << endl;
3391        //        cout << " prepends to path " << symbol.name << " : ";
3392        cout << "path_prepend " << symbol.name;
3393        result = 1;
3394        break;
3395      case CommandPathRemove :
3396        if (CmtMessage::active (Verbose))
3397          cout << " removes from path " << symbol.name << " : " << endl;
3398        //        cout << " removes from path " << symbol.name << " : ";
3399        cout << "path_remove " << symbol.name;
3400        result = 1;
3401        break;
3402      case CommandPathRemoveRegexp :
3403        if (CmtMessage::active (Verbose))
3404          cout << " removes RE from path " << symbol.name << " : " << endl;
3405        //        cout << " removes RE from path " << symbol.name << " : ";
3406        cout << "path_remove_regexp " << symbol.name;
3407        result = 1;
3408        break;
3409      case CommandMacro :
3410        if (CmtMessage::active (Verbose))
3411          cout << " " << define_text << " macro " << symbol.name << " as " << endl;
3412        //        cout << " " << define_text << " macro " << symbol.name << " as ";
3413        cout << "macro " << symbol.name;
3414        result = 1;
3415        break;
3416      case CommandMacroPrepend :
3417        if (CmtMessage::active (Verbose))
3418          cout << " prepends to macro " << symbol.name << " : " << endl;
3419        //        cout << " prepends to macro " << symbol.name << " : ";
3420        cout << "macro_prepend " << symbol.name;
3421        result = 1;
3422        break;
3423      case CommandMacroAppend :
3424        if (CmtMessage::active (Verbose))
3425          cout << " appends to macro " << symbol.name << " : " << endl;
3426        //        cout << " appends to macro " << symbol.name << " : ";
3427        cout << "macro_append " << symbol.name;
3428        result = 1;
3429        break;
3430      case CommandMacroRemove :
3431        if (CmtMessage::active (Verbose))
3432          cout << " remove from macro " << symbol.name << " : " << endl;
3433        //        cout << " remove from macro " << symbol.name << " : ";
3434        cout << "macro_remove " << symbol.name;
3435        result = 1;
3436        break;
3437      case CommandMacroRemoveRegexp :
3438        if (CmtMessage::active (Verbose))
3439          cout << " remove RE from macro " << symbol.name << " : " << endl;
3440        //        cout << " remove RE from macro " << symbol.name << " : ";
3441        cout << "macro_remove_regexp " << symbol.name;
3442        result = 1;
3443        break;
3444      case CommandMacroRemoveAll :
3445        if (CmtMessage::active (Verbose))
3446          cout << " remove all from macro " << symbol.name << " : " << endl;
3447        //        cout << " remove all from macro " << symbol.name << " : ";
3448        cout << "macro_remove_all " << symbol.name;
3449        result = 1;
3450        break;
3451      case CommandMacroRemoveAllRegexp :
3452        if (CmtMessage::active (Verbose))
3453          cout << " remove all RE from macro " << symbol.name << " : " << endl;
3454        //        cout << " remove all RE from macro " << symbol.name << " : ";
3455        cout << "macro_remove_all_regexp " << symbol.name;
3456        result = 1;
3457        break;
3458      case CommandSetupScript :
3459        if (CmtMessage::active (Verbose))
3460          cout << " " << define_text << " setup script " << symbol.name << endl;
3461        //       cout << " " << define_text << " action " << symbol.name << " as ";
3462        cout << "setup_script" /* << symbol.name */;
3463        first_definition = false;
3464        result = 1;
3465        break;
3466        /*
3467      case CommandAction :
3468        cout << " " << define_text << " action " << symbol.name << " as ";
3469        first_definition = false;
3470        break;
3471        */
3472    }
3473
3474  cout << " " << CmtSystem::quote (value.text, " \t");
3475  //  cout << "'" << value.text << "'";
3476         
3477  /*
3478  Tag* selected_tag = value.tag;
3479         
3480  if ((selected_tag == 0) ||
3481      (selected_tag == Tag::get_default ()))
3482    {
3483      cout << " for default tag";
3484    }
3485  else
3486    {
3487      cout << " for tag '" << selected_tag->get_name () << "'";
3488    }
3489  */
3490
3491  cout << endl;
3492  //  cout << discarded_text << endl;
3493  return result;
3494}
3495
3496//-------------------------------------------------------------
3497bool Symbol::check_tag_used (const Tag* tag)
3498{
3499  if (tag == 0) return (false);
3500
3501  static SymbolVector& Symbols = symbols ();
3502
3503  if (Symbols.size () == 0) 
3504    {
3505      return (false);
3506    }
3507
3508  for (int number = 0; number < Symbol::symbol_number (); number++)
3509    {
3510      Symbol& symbol = Symbol::symbol (number);
3511
3512      for (int i = 0; i < symbol.value_lists.size (); i++)
3513        {
3514          const SymbolValueList& value_list = symbol.value_lists[i];
3515
3516          for (int j = 0; j < value_list.values.size (); j++)
3517            {
3518              const SymbolValue& value = value_list.values[j];
3519              Tag* t = value.tag;
3520
3521              if (t != 0)
3522                {
3523                  if (t->use_operand (tag)) return (true);
3524                }
3525            }
3526        }
3527    }
3528
3529  return (false);
3530}
3531
3532//-------------------------------------------------------------
3533cmt_string Symbol::get_env_value (const cmt_string& name)
3534{
3535  cmt_string s;
3536
3537  Symbol* symbol = Symbol::find (name);
3538  if (symbol != 0)
3539    {
3540      m_inhibit_display = true;
3541
3542      s = symbol->build_macro_value ();
3543      Symbol::expand (s);
3544
3545      m_inhibit_display = false;
3546    }
3547  else
3548    {
3549      s = CmtSystem::getenv (name);
3550    }
3551
3552  return (s);
3553}
3554
3555bool Symbol::get_inhibit_display ()
3556{
3557  return (m_inhibit_display);
3558}
3559
Note: See TracBrowser for help on using the repository browser.