source: CMT/v1r22/source/cmt_symbol.cxx @ 597

Last change on this file since 597 was 550, checked in by rybkin, 14 years ago

See C.L. 435

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