source: CMT/v1r18p20050501/source/cmt_symbol.cxx @ 660

Last change on this file since 660 was 40, checked in by arnault, 19 years ago

Improve the security of the path lookup for path_append and path_prepend - See CL 268

  • Property svn:eol-style set to native
File size: 70.0 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
17//-------------------------------------------------------------
18class SetBuilder : public ValueBuilder
19{
20public:
21  const cmt_string build (const Symbol& symbol,
22                          const cmt_string& tag_name = "");
23  const cmt_string clean (const Symbol& symbol,
24                          const cmt_string& tag_name = "")
25      {
26        static const cmt_string empty = "";
27        return (empty);
28      }
29};
30//-------------------------------------------------------------
31
32//-------------------------------------------------------------
33class PathBuilder : public ValueBuilder
34{
35public:
36  const cmt_string build (const Symbol& symbol,
37                          const cmt_string& tag_name = "");
38  const cmt_string clean (const Symbol& symbol,
39                          const cmt_string& tag_name = "");
40};
41//-------------------------------------------------------------
42
43//-------------------------------------------------------------
44class MacroBuilder : public ValueBuilder
45{
46public:
47  const cmt_string build (const Symbol& symbol,
48                          const cmt_string& tag_name = "");
49  const cmt_string clean (const Symbol& symbol,
50                          const cmt_string& tag_name = "")
51      {
52        static const cmt_string empty = "";
53        return (empty);
54      }
55};
56//-------------------------------------------------------------
57
58//-------------------------------------------------------------
59class ScriptBuilder : public ValueBuilder
60{
61public:
62  const cmt_string build (const Symbol& symbol,
63                          const cmt_string& tag_name = "");
64  const cmt_string clean (const Symbol& symbol,
65                          const cmt_string& tag_name = "")
66      {
67        static const cmt_string empty = "";
68        return (empty);
69      }
70};
71//-------------------------------------------------------------
72
73//-------------------------------------------------------------
74class ActionBuilder : public ValueBuilder
75{
76public:
77  const cmt_string build (const Symbol& symbol,
78                          const cmt_string& tag_name = "");
79  const cmt_string clean (const Symbol& symbol,
80                          const cmt_string& tag_name = "")
81      {
82        static const cmt_string empty = "";
83        return (empty);
84      }
85};
86//-------------------------------------------------------------
87
88//-------------------------------------------------------------
89class symbol_marker
90{
91public:
92  symbol_marker ()
93  {
94    ptr = cmt_string::npos;
95    pattern = 0;
96    intro = 0;
97  }
98
99  symbol_marker (int a_ptr, char a_pattern, int a_intro)
100  {
101    ptr = a_ptr;
102    pattern = a_pattern;
103    intro = a_intro;
104  }
105
106  symbol_marker (const symbol_marker& other)
107  {
108    ptr = other.ptr;
109    pattern = other.pattern;
110    intro = other.intro;
111  }
112
113  void set (int a_ptr, char a_pattern, int a_intro)
114  {
115    ptr = a_ptr;
116    pattern = a_pattern;
117    intro = a_intro;
118  }
119
120  static symbol_marker& get_lowest (symbol_marker markers[], int count)
121  {
122    static symbol_marker result;
123    int real_count = 0;
124    int i;
125
126      // Check that at least one marker has result
127
128    for (i = 0; i < count; i++)
129      {
130        if (markers[i].ptr != cmt_string::npos) real_count++;
131      }
132
133    if (real_count == 0) return (result);
134
135    // since we've passed the previous test,
136    // at least one entry is not npos.
137    // Now discards other npos by moving them to the end
138   
139    for (i = 0; i < count;)
140      {
141        if (markers[i].ptr == cmt_string::npos)
142          {
143            markers[i] = markers[count-1];
144            count--;
145            if (count == 0) break;
146          }
147        else
148          {
149            i++;
150          }
151      }
152   
153    if (count == 0) return (result);
154   
155    // now all entries in [0, count-1] are not npos
156    // let's sort the lowest one in [0]
157   
158    for (i = 1; i < count;)
159      {
160        if (markers[0].ptr > markers[i].ptr)
161          {
162            symbol_marker temp = markers[0];
163            markers[0] = markers[i];
164            markers[i] = temp;
165            i = 1;
166          }
167        else
168          {
169            i++;
170          }
171      }
172   
173    return (markers[0]);
174  }
175
176  int ptr;
177  char pattern;
178  int intro;
179};
180//-------------------------------------------------------------
181
182/**
183
184   Attempt to substitute all occurrences of
185
186      ${<symbol_name>}
187      $(<symbol_name>)
188      %<symbol_name>%    [on Windows only]
189
190      by the specified value in the given text.
191
192    This is for one symbol only
193
194 */
195static void resolve_value (cmt_string& text,
196                           const cmt_string& symbol_name,
197                           const cmt_string& value)
198{
199  static cmt_string pattern;
200
201  pattern = "${";
202  pattern += symbol_name;
203  pattern += "}";
204
205  text.replace_all (pattern, value);
206
207  pattern = "$(";
208  pattern += symbol_name;
209  pattern += ")";
210
211  text.replace_all (pattern, value);
212
213#ifdef WIN32
214  pattern = "%";
215  pattern += symbol_name;
216  pattern += "%";
217
218  text.replace_all (pattern, value);
219#endif
220}
221
222/**
223
224   Attempt to substitute into the specified text all occurrences of
225
226      ${xxx}
227      $(xxx)
228      `xxx`
229      %xxx%    [on Windows only]
230
231      by the appropriate value:
232
233        for `xxx` :
234
235            xxx is considered as a shell command. Value is the result of its execution
236
237        for other patterns:
238
239            if xxx is a symbol name, its value is substituted to the pattern
240            otherwise, xxx is tried as an environment variable
241
242
243     ===> In all cases, the pattern is filtered away.
244
245
246 */
247static void resolve_value (cmt_string& text)
248{
249  //static cmt_regexp reg ("[$%`]");
250
251  //if (!reg.match (text)) return;
252
253  cmt_string pattern;
254  cmt_string symbol_name;
255  char end_pattern;
256
257  int start = 0;
258
259  for (;;)
260    {
261      int begin;
262      int end;
263
264      symbol_marker markers[4];
265      int num = 0;
266
267      markers[num].set (text.find (start, "$("), ')', 2); num++;
268      markers[num].set (text.find (start, "${"), '}', 2); num++;
269      markers[num].set (text.find (start, "`"), '`', 1); num++;
270
271#ifdef WIN32
272      markers[num].set (text.find (start, "%"), '%', 1); num++;
273#endif
274
275      // Find the first matching pattern
276
277      symbol_marker& marker = symbol_marker::get_lowest (markers, num);
278
279      begin = marker.ptr;
280
281      if (begin == cmt_string::npos) break;
282
283      end_pattern = marker.pattern;
284      start = begin + marker.intro;
285
286      end = text.find (start, end_pattern);
287      if (end == cmt_string::npos)
288        {
289          // The pattern is a fake one (no ending!)
290          start++;
291          continue;
292        }
293
294      // This should never happen...
295      if (end < begin) break;
296
297      // Extract the complete pattern
298      text.substr (begin, end - begin + 1, pattern);
299
300      // Then only the symbol name
301      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);
302
303      if (text[begin] == '`')
304        {
305          cmt_string command = symbol_name;
306          resolve_value (command);
307
308            // The value is a shell command that first needs
309            // to be applied. The output of the command is then substituted
310
311          cmt_string result;
312
313          Symbol::all_set ();
314          CmtSystem::execute (command, result);
315         
316          int pos;
317          pos = result.find ('\n');
318          if (pos != cmt_string::npos) result.erase (pos);
319          pos = result.find ('\r');
320          if (pos != cmt_string::npos) result.erase (pos);
321         
322          if (Cmt::get_debug ())
323            {
324              cout << "   Executing [" << command << "] to expand a symbol value =>[" 
325                   << result << "]" << endl;
326            }
327         
328          text.replace_all (pattern, result);
329
330          // The substitution will restart from the same place
331          // allowing for recursive replacements
332          start = begin;
333        }
334      else
335        {
336          Symbol* symbol = Symbol::find (symbol_name);
337          if (symbol != 0)
338            {
339                // Symbol found
340              cmt_string value = symbol->resolve_macro_value ();
341              text.replace_all (pattern, value);
342             
343                // The substitution will restart from the same place
344                // allowing for recursive replacements
345              start = begin;
346            }
347          else
348            {
349                // Symbol not found. Look for env. variable
350              cmt_string value = CmtSystem::getenv (symbol_name);
351             
352                // When the env. variable is not defined, the replacement is empty
353                // thus all $(xxx) ${xxx} %xxx% patterns are always filtered away.
354              text.replace_all (pattern, value);
355             
356                // The substitution will restart from the same place
357                // allowing for recursive replacements
358              start = begin;
359            }
360        }
361    }
362}
363
364/**
365
366   Attempt to substitute all occurrences of
367
368      ${xxx}
369      $(xxx)
370      `xxx`
371      %xxx%    [on Windows only]
372
373      by the appropriate value:
374
375        for `xxx` :
376
377            xxx is considered as a shell command. Value is the result of its execution
378
379        for other patterns:
380
381            if xxx is a macro name, its value is substituted to the pattern
382
383            if xxx is a set or a path, it is kept in place (after fixing the pattern
384            according to the OS style)
385
386            otherwise it is simply kept in place
387
388 */
389static void resolve_value_for_macros (cmt_string& text)
390{
391  cmt_string pattern;
392  cmt_string symbol_name;
393  char end_pattern;
394
395  int start = 0;
396
397  for (;;)
398    {
399      //
400      // Try and substitute all ${xxx} $(xxx) or %xxx% patterns
401      // using symbol values, only when the symbol is a macro.
402      //
403
404      int begin;
405      int end;
406
407      symbol_marker markers[4];
408      int num = 0;
409
410      markers[num].set (text.find (start, "$("), ')', 2); num++;
411      markers[num].set (text.find (start, "${"), '}', 2); num++;
412
413#ifdef WIN32
414      markers[num].set (text.find (start, "%"), '%', 1); num++;
415#endif
416
417      markers[num].set (text.find (start, "`"), '`', 1); num++;
418
419      // Find the first of three patterns
420
421      symbol_marker& marker = symbol_marker::get_lowest (markers, num);
422
423      begin = marker.ptr;
424
425      if (begin == cmt_string::npos) break;
426
427      end_pattern = marker.pattern;
428      start = begin + marker.intro;
429
430      end = text.find (start, end_pattern);
431      if (end == cmt_string::npos)
432        {
433          // The pattern is a fake one (no ending!)
434          start++;
435          continue;
436        }
437
438      // This should never happen...
439      if (end < begin) break;
440
441      // Extract the complete pattern
442      text.substr (begin, end - begin + 1, pattern);
443
444      // Then only the macro name
445      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);
446
447      if (text[begin] == '`')
448        {
449          cmt_string command = symbol_name;
450          resolve_value (command);
451
452            // The macro value is a shell command that first needs
453            // to be applied. The output of the command is substituted
454
455          cmt_string result;
456
457          Symbol::all_set ();
458          CmtSystem::execute (command, result);
459         
460          int pos;
461          pos = result.find ('\n');
462          if (pos != cmt_string::npos) result.erase (pos);
463          pos = result.find ('\r');
464          if (pos != cmt_string::npos) result.erase (pos);
465         
466          if (Cmt::get_debug ())
467            {
468              cout << "   Executing [" << command << "] to expand a macro value =>[" 
469                   << result << "]" << endl;
470            }
471         
472          text.replace_all (pattern, result);
473
474          // The substitution will restart from the same place
475          // allowing for recursive replacements
476          start = begin;
477        }
478      else
479        {
480          Symbol* macro = Symbol::find (symbol_name);
481          if ((macro != 0) && 
482              (macro->type == Symbol::SymbolMacro))
483            {
484                // Macro found
485              cmt_string value = macro->resolve_macro_value ();
486              text.replace_all (pattern, value);
487
488                // The substitution will restart from the same place
489                // allowing for recursive replacements
490              start = begin;
491            }
492          else if ((macro == 0) || 
493                   ((macro->type == Symbol::SymbolSet) || (macro->type == Symbol::SymbolPath)))
494            {
495                // Set found
496                // ensure that the delimiters will match the OS dependent
497                // delimiters.
498             
499              cmt_string pattern_close = marker.pattern;
500             
501              if (pattern_close != CmtSystem::ev_close ())
502                {
503                  cmt_string new_pattern;
504                 
505                  new_pattern = CmtSystem::ev_open ();
506                  new_pattern += symbol_name;
507                  new_pattern += CmtSystem::ev_close ();
508                 
509                  text.replace (pattern, new_pattern);
510                }
511             
512              start = end + 1;
513            }
514          else
515            {
516              start = end + 1;
517            }
518        }
519    }
520}
521
522/**
523
524   This function suppress all OS delimiters ie ${ } or % % and replaces them
525   by the pure macro delimiters $( )
526
527   `xxx` pattern is replaced by the result of the execution of the command
528
529 */
530static void suppress_OS_delimiters (cmt_string& text)
531{
532  cmt_string pattern;
533  cmt_string symbol_name;
534  char end_pattern;
535
536  int start = 0;
537
538  for (;;)
539    {
540      int begin;
541      int end;
542
543      symbol_marker markers[3];
544      int num = 0;
545
546      markers[num].set (text.find (start, "${"), '}', 2); num++;
547      markers[num].set (text.find (start, "`"), '`', 1); num++;
548
549#ifdef WIN32
550      markers[num].set (text.find (start, "%"), '%', 1); num++;
551#endif
552
553      // Find the first of three patterns
554
555      symbol_marker& marker = symbol_marker::get_lowest (markers, num);
556
557      begin = marker.ptr;
558
559      if (begin == cmt_string::npos) break;
560
561      end_pattern = marker.pattern;
562      start = begin + marker.intro;
563
564      end = text.find (start, end_pattern);
565      if (end == cmt_string::npos)
566        {
567          // The pattern is a fake one (no ending!)
568          start++;
569          continue;
570        }
571
572      // This should never happen...
573      if (end < begin) break;
574
575      // Extract the complete pattern
576      text.substr (begin, end - begin + 1, pattern);
577
578      // Then only the macro name
579      text.substr (begin + marker.intro, end - begin - marker.intro, symbol_name);
580
581      if (text[begin] == '`')
582        {
583          cmt_string command = symbol_name;
584          resolve_value (command);
585
586            // The macro value is a shell command that first needs
587            // to be applied. The output of the command is substituted
588
589          cmt_string result;
590
591          Symbol::all_set ();
592          CmtSystem::execute (command, result);
593         
594          int pos;
595          pos = result.find ('\n');
596          if (pos != cmt_string::npos) result.erase (pos);
597          pos = result.find ('\r');
598          if (pos != cmt_string::npos) result.erase (pos);
599         
600          if (Cmt::get_debug ())
601            {
602              cout << "   Executing [" << command << "] to expand a macro value =>[" 
603                   << result << "]" << endl;
604            }
605         
606          text.replace_all (pattern, result);
607
608          // The substitution will restart from the same place
609          // allowing for recursive replacements
610          start = begin;
611        }
612      else
613        {
614          cmt_string new_pattern;
615
616          new_pattern = "$(";
617          new_pattern += symbol_name;
618          new_pattern += ")";
619
620          text.replace (pattern, new_pattern);
621
622          start = begin;
623        }
624    }
625}
626
627//-------------------------------------------------------------
628/*                                                          */
629/*  Operations on SymbolValues                              */
630/*                                                          */
631//-------------------------------------------------------------
632
633//-------------------------------------------------------------
634SymbolValue::SymbolValue ()
635{
636  tag = 0;
637}
638
639//-------------------------------------------------------------
640SymbolValue::~SymbolValue ()
641{
642  tag = 0;
643}
644
645//-------------------------------------------------------------
646/*                                                          */
647/*  Operations on Symbols                                   */
648/*                                                          */
649//-------------------------------------------------------------
650
651//-------------------------------------------------------------
652Symbol* Symbol::create (const cmt_string& name,
653                        CommandType command,
654                        Use* use)
655{
656  static SetBuilder Set;
657  static PathBuilder Path;
658  static MacroBuilder Macro;
659  static ScriptBuilder Script;
660  static ActionBuilder Action;
661
662  static SymbolVector& Symbols = symbols ();
663  static SymbolMap& SymbolMap = symbol_map ();
664
665  SymbolType type = SymbolUndefined;
666
667  switch (command)
668    {
669    case CommandSet:
670    case CommandSetAppend:
671    case CommandSetPrepend:
672    case CommandSetRemove:
673    case CommandSetRemoveRegexp:
674      type = SymbolSet;
675      break;
676    case CommandPath:
677    case CommandPathAppend:
678    case CommandPathPrepend:
679    case CommandPathRemove:
680    case CommandPathRemoveRegexp:
681      type = SymbolPath;
682      break;
683    case CommandMacro:
684    case CommandMacroAppend:
685    case CommandMacroPrepend:
686    case CommandMacroRemove:
687    case CommandMacroRemoveRegexp:
688    case CommandMacroRemoveAll:
689    case CommandMacroRemoveAllRegexp:
690      type = SymbolMacro;
691      break;
692    case CommandAction:
693      type = SymbolAction;
694      break;
695    case CommandAlias:
696      type = SymbolAlias;
697      break;
698    case CommandSetupScript:
699      type = SymbolSetupScript;
700      break;
701    case CommandCleanupScript:
702      type = SymbolCleanupScript;
703      break;
704    }
705
706  {
707    Symbol* symbol;
708
709    symbol = find (name);
710    if (symbol != 0) 
711      {
712        if (symbol->type != type)
713          {
714            ActionType action = Cmt::get_action ();
715
716            if ((!Cmt::get_quiet ()) &&
717                (action != action_build_tag_makefile))
718              {
719                cmt_string s1;
720                cmt_string s2;
721
722                switch (symbol->type)
723                  {
724                  case SymbolSet:
725                    s1 = "set";
726                    break;
727                  case SymbolPath:
728                    s1 = "path";
729                    break;
730                  case SymbolMacro:
731                    s1 = "macro";
732                    break;
733                  case SymbolSetupScript:
734                    s1 = "setup_script";
735                    break;
736                  case SymbolCleanupScript:
737                    s1 = "cleanup_script";
738                    break;
739                  case SymbolAction:
740                    s1 = "action";
741                    break;
742                  case SymbolAlias:
743                    s1 = "alias";
744                    break;
745                  } 
746
747                switch (type)
748                  {
749                  case SymbolSet:
750                    s2 = "set";   
751                    break;
752                  case SymbolPath:
753                    s2 = "path";   
754                    break;
755                  case SymbolMacro:
756                    s2 = "macro";   
757                    break;
758                  case SymbolSetupScript:
759                    s2 = "setup_script"; 
760                    break;
761                  case SymbolCleanupScript:
762                    s2 = "cleanup_script"; 
763                    break;
764                  case SymbolAction:
765                    s2 = "action";
766                    break;
767                  case SymbolAlias:
768                    s2 = "alias";
769                    break;
770                  } 
771
772                cerr << "#CMT> Warning: Symbol " << name
773                     << " inconsistently redeclared from " << s1 << " to " << s2;
774                if (use != 0) cerr << " in package " << use->get_package_name ();
775                cerr << endl;
776              }
777          }
778
779        return (symbol);
780      }
781  }
782
783  Symbol& symbol = Symbols.add ();
784  SymbolMap.add (name, symbol);
785
786  symbol.name  = name;
787  symbol.scope = use->get_current_scope ();
788  symbol.type  = type;
789
790  symbol.value_lists.clear ();
791
792  switch (type)
793    {
794    case SymbolSet:
795      symbol.builder = &Set;
796      break;
797    case SymbolPath:
798      symbol.builder = &Path;
799      break;
800    case SymbolAlias:
801      symbol.builder = &Set;
802      break;
803    case SymbolMacro:
804      symbol.builder = &Macro;
805      break;
806    case SymbolSetupScript:
807    case SymbolCleanupScript:
808      symbol.builder = &Script;
809      break;
810    case SymbolAction:
811      symbol.builder = &Action;
812      break;
813    }
814
815  symbol.selected_value = -1;
816
817  return (&symbol);
818}
819
820//-------------------------------------------------------------
821Symbol* Symbol::find (const cmt_string& name)
822{
823  static SymbolMap& SymbolMap = symbol_map ();
824
825  Symbol* result = 0;
826
827  result = SymbolMap.find (name);
828
829  return (result);
830}
831
832//-------------------------------------------------------------
833int Symbol::symbol_number ()
834{
835  static SymbolVector& Symbols = symbols ();
836
837  return (Symbols.size ());
838}
839
840//-------------------------------------------------------------
841Symbol::SymbolVector& Symbol::symbols ()
842{
843  static Database& db = Database::instance ();
844  static SymbolVector& Symbols = db.symbols ();
845
846  return (Symbols);
847}
848
849//-------------------------------------------------------------
850Symbol::SymbolMap& Symbol::symbol_map ()
851{
852  static Database& db = Database::instance ();
853  static SymbolMap& SymbolMap = db.symbol_map ();
854
855  return (SymbolMap);
856}
857
858//-------------------------------------------------------------
859Symbol& Symbol::symbol (int index)
860{
861  static SymbolVector& Symbols = symbols ();
862
863  return (Symbols[index]);
864}
865
866//-------------------------------------------------------------
867void Symbol::action (const CmtSystem::cmt_string_vector& words,
868                     CommandType command_type,
869                     Use* use)
870{
871  int number;
872  Symbol* symbol;
873  Tag* tag;
874
875  if (words.size () < 1) return;
876  cmt_string name = words[1];
877
878  if ((command_type == CommandSetupScript) ||
879      (command_type == CommandCleanupScript))
880    {
881      cmt_string full_name;
882
883      Symbol::expand (name);
884
885      if (name != "")
886        {
887          if (CmtSystem::absolute_path (name)) 
888            {
889              full_name = name;
890            }
891          else
892            {
893#ifdef WIN32
894              full_name = "%";
895#else
896              full_name = "${";
897#endif
898              full_name += use->prefix;
899              full_name += "ROOT";
900#ifdef WIN32
901              full_name += "%";
902#else
903              full_name += "}";
904#endif
905              full_name += CmtSystem::file_separator ();
906              if (use->style == cmt_style) full_name += "cmt";
907              else if (use->style == no_version_style) full_name += "cmt";
908              else full_name += "mgr";
909              full_name += CmtSystem::file_separator ();
910              full_name += name;
911            }
912
913          symbol = create (full_name, command_type, use);
914          symbol->add_value_to_list (command_type, use,
915                                     Tag::get_default (), full_name);
916        }
917    }
918  else
919    {
920      if (words.size () < 2) return;
921      const cmt_string& default_value = words[2];
922
923      if (Cmt::get_debug ())
924        {
925          cout << "Symbol::action> name:" << name
926               << " access:" << Cmt::get_current_access () 
927               << " scope:" << use->get_current_scope () << endl;
928        }
929
930      if (Cmt::get_current_access () == UserMode)
931        {
932          if (name == "constituents") return;
933          if (name == "constituentscclean") return;
934
935          if (use->get_current_scope () == ScopePrivate) return;
936        }
937
938      symbol = create (name, command_type, use);
939
940      /*
941        Parse the default value.
942      */
943     
944      symbol->add_value_to_list (command_type, use,
945                                 Tag::get_default (), default_value);
946     
947      /*
948        Then parse all specific values
949       
950        <tag> <value>
951        ...
952      */
953     
954      number = 3;
955      while (number < (words.size () - 1))
956        {
957          cmt_string tag_name = words[number];
958          const cmt_string& value = words[number + 1];
959
960          expand (tag_name);
961
962          if (Cmt::get_debug ())
963            {
964              cout << "Symbol::action> tag_name=" << tag_name << endl;
965            }
966
967          tag = Tag::find (tag_name);
968          if (tag == 0)
969            {
970              tag = Tag::add (tag_name, PriorityUserTag, "use", use);
971            }
972
973          symbol->add_value_to_list (command_type, use, tag, value);
974         
975          number += 2;
976        }
977
978      if (name == "CMTPATH")
979        {
980          Cmt::configure_cmt_path (use);
981        }
982      else if (name == "CMTSITE")
983        {
984          Cmt::configure_site_tag (use);
985        }
986      else if (name == "CMTCONFIG")
987        {
988            //cerr << "redefining CMTCONFIG" << endl;
989          Cmt::configure_tags (use);
990        }
991      else if (name == "CMTHOME")
992        {
993          Cmt::configure_home (use);
994        }
995      else if (name == "CMTUSERCONTEXT")
996        {
997          Cmt::configure_user_context (use);
998        }
999      else if (name.find ("_native_version") != cmt_string::npos)
1000        {
1001          cmt_string n = use->get_package_name ();
1002          n += "_native_version";
1003
1004          if (name == n)
1005            {
1006              use->set_native_version (true);
1007            }
1008        }
1009    }
1010}
1011
1012//-------------------------------------------------------------
1013int Symbol::is_selected (const cmt_string& name)
1014{
1015  Symbol* symbol;
1016  int number;
1017  int value_number;
1018
1019  symbol = find (name);
1020  if (symbol == 0) return (0);
1021
1022  if (symbol->value_lists.size () == 0) return (0);
1023
1024  for (number = 0;
1025       number < symbol->value_lists.size ();
1026       number++)
1027    {
1028      const SymbolValueList& value_list = symbol->value_lists[number];
1029
1030      if (value_list.discarded) continue;
1031
1032      if ((value_list.command_type == CommandMacro) ||
1033          (value_list.command_type == CommandSet) ||
1034          (value_list.command_type == CommandSetAppend) ||
1035          (value_list.command_type == CommandSetPrepend) ||
1036          (value_list.command_type == CommandSetRemove) ||
1037          (value_list.command_type == CommandSetRemoveRegexp) ||
1038          (value_list.command_type == CommandAlias) ||
1039          (value_list.command_type == CommandAction))
1040        {
1041          for (value_number = 0;
1042               value_number < value_list.values.size ();
1043               value_number++)
1044            {
1045              Tag* tag;
1046
1047              SymbolValue& value = value_list.values[value_number];
1048
1049              tag = value.tag;
1050              if ((tag == 0) ||
1051                  (tag == Tag::get_default ()) ||
1052                  (tag->is_selected () != 0))
1053                {
1054                  return (1);
1055                }
1056            }
1057        }
1058    }
1059
1060  return (0);
1061}
1062
1063//-------------------------------------------------------------
1064Symbol::Symbol ()
1065{
1066  name = "";
1067}
1068
1069//-------------------------------------------------------------
1070Symbol::~Symbol ()
1071{
1072}
1073
1074/**
1075 *  Characterizes if a value is provided as the reference to itself.
1076 */
1077bool Symbol::value_is_reflexive (const cmt_string& text) const
1078{
1079  bool result = false;
1080  int text_length = text.size ();
1081
1082  if (text_length == (name.size () + 3))
1083    {
1084      static cmt_string temp;
1085             
1086      if (text[0] == '$')
1087        {
1088          if (text[1] == '(')
1089            {
1090              temp = "$(";
1091              temp += name;
1092              temp += ")";
1093             
1094              if (text == temp)
1095                {
1096                  result = true;
1097                }
1098            }
1099          else if (text[1] == '{')
1100            {
1101              temp = "${";
1102              temp += name;
1103              temp += "}";
1104             
1105              if (text == temp)
1106                {
1107                  result = true;
1108                }
1109            }
1110        }
1111    }
1112  else if (text_length == (name.size () + 2))
1113    {
1114      static cmt_string temp;
1115
1116      temp = "%";
1117      temp += name;
1118      temp += "%";
1119
1120      if (text == temp)
1121        {
1122          result = true;
1123        }
1124    }
1125
1126  return (result);
1127}
1128
1129//-------------------------------------------------------------
1130void Symbol::add_value_to_list (CommandType command_type,
1131                                Use* use,
1132                                Tag* tag,
1133                                const cmt_string& text)
1134{
1135  SymbolValueList* value_list = 0;
1136  bool is_reflexive = false;
1137
1138    //
1139    // First pickup the most recent value_list
1140    //
1141  if (value_lists.size () > 0) value_list = &(value_lists.back ());
1142
1143    //
1144    //  Create a new value list is we switch to another use or
1145    //  if we switch to a new command_type (eg. switching from
1146    //  macro to macro_append).
1147    //
1148  if ((value_list == 0) ||
1149      (use != value_list->use) ||
1150      (command_type != value_list->command_type) ||
1151      (tag == Tag::get_default ()))
1152    {
1153      value_list = &(value_lists.add ());
1154      value_list->use = use;
1155      value_list->command_type = command_type;
1156      value_list->values.clear ();
1157      value_list->discarded = false;
1158      value_list->is_reflexive = false;
1159    }
1160
1161/*
1162  else
1163    {
1164        value_list = &(value_lists[value_lists.size () - 1]);
1165    }
1166*/
1167
1168  is_reflexive = value_list->is_reflexive;
1169
1170    //
1171    //  If the command_type is command_macro or command_set,
1172    // this is considered as a full re-set of this symbol
1173    //   In this case, we have to discard all previous values
1174    //
1175    //  However, we'd like to exclude from this logic the cases where
1176    //  the value is **exactly*
1177    //
1178    //     $(<symbol>)
1179    //     ${<symbol>}
1180    //     %<symbol>%
1181    //
1182    //   which would then mean that we do not reset the value but rather
1183    //  override it.
1184    //
1185
1186    //
1187    // Inside this value_list, we add this new tag-value pair.
1188    //
1189
1190  if ((command_type == CommandMacro) ||
1191      (command_type == CommandSet) ||
1192      (command_type == CommandPath) ||
1193      (command_type == CommandAction))
1194    {
1195        //
1196        // Check whether we have to hide previous settings by this new definition
1197        //  (of course this is only useful if there WERE previous settings)
1198        //
1199      if ((value_lists.size () >= 1) && (!is_reflexive))
1200        {
1201          if (value_is_reflexive (text))
1202            {
1203              value_list->is_reflexive = true;
1204              is_reflexive = true;
1205            }
1206          else
1207            {
1208              //cout << "...discarding old values for symbol " << name << " text=[" << text << "]" << endl;
1209                 
1210              for (int i = 0; i < (value_lists.size () - 1); i++)
1211                {
1212                  SymbolValueList& vl = value_lists[i];
1213                 
1214                  if ((vl.use != 0) &&
1215                      (vl.use->discarded))
1216                    {
1217                      //vl.discarded = true;
1218                    }
1219                }
1220            }
1221        }
1222    }
1223
1224  SymbolValue& value = value_list->values.add ();
1225
1226  value.tag = tag;
1227  value.text = text;
1228  value.selected = 0;
1229}
1230
1231/**
1232   Compute the current value of all environment variables and set them to the
1233   shell
1234 */
1235void Symbol::all_set ()
1236{
1237  //cerr << "all_set" << endl;
1238
1239  if (Cmt::get_debug ())
1240    {
1241      cout << "Symbol::all_set> done" << Cmt::get_all_sets_done () << endl;
1242    }
1243
1244  if (Cmt::get_all_sets_done ()) return;
1245
1246  Cmt::set_all_sets_done ();
1247
1248  static SymbolVector& Symbols = symbols ();
1249
1250  static CmtSystem::cmt_string_vector envs;
1251
1252  envs.clear ();
1253
1254  int number;
1255
1256  if (Symbols.size () == 0) 
1257    {
1258        //running = false;
1259      return;
1260    }
1261
1262  cmt_string value;
1263
1264  for (number = 0; number < Symbol::symbol_number (); number++)
1265    {
1266      Symbol& symbol = Symbol::symbol (number);
1267
1268      if (symbol.type != SymbolSet) continue;
1269
1270      value = symbol.build_macro_value ();
1271      if (value != "")
1272        {
1273          cmt_string& temp = envs.add ();
1274
1275          temp = symbol.name;
1276          temp += '=';
1277          temp += value;
1278        }
1279    }
1280
1281  for (number = 0; number < Symbol::symbol_number (); number++)
1282    {
1283      Symbol& symbol = Symbol::symbol (number);
1284
1285      if ((symbol.type != SymbolPath)) continue;
1286
1287      value = symbol.build_macro_value ();
1288      if (value != "")
1289        {
1290          cmt_string& temp = envs.add ();
1291
1292          temp = symbol.name;
1293          temp += '=';
1294          temp += value;
1295        }
1296    }
1297
1298  for (number = 0; number < envs.size (); number++)
1299    {
1300      cmt_string& env = envs[number];
1301      Symbol::expand (env);
1302
1303#ifdef WIN32
1304      env.replace_all ("/", "\\");
1305#endif
1306
1307      if (Cmt::get_debug ())
1308        {
1309          cout << "Symbol::all_set> " << env << endl;
1310        }
1311      CmtSystem::putenv (env);
1312    }
1313
1314    //running = false;
1315}
1316
1317//-------------------------------------------------------------
1318void Symbol::all_print (PrintMode mode)
1319{
1320  static SymbolVector& Symbols = symbols ();
1321
1322  int number;
1323
1324  if (Symbols.size () == 0) return;
1325
1326  for (number = 0; number < Symbol::symbol_number (); number++)
1327    {
1328      Symbol& symbol = Symbol::symbol (number);
1329
1330      if ((symbol.type == SymbolSet) ||
1331          (symbol.type == SymbolAlias) ||
1332          (symbol.type == SymbolSetupScript))
1333        {
1334          if (symbol.print (mode))
1335            {
1336              if (mode == Bat)
1337                {
1338                  cout << endl;
1339                }
1340              else
1341                {
1342                  //cout << "; ";
1343                  cout << endl;
1344                }
1345            }
1346        }
1347    }
1348
1349  for (number = 0; number < Symbol::symbol_number (); number++)
1350    {
1351      Symbol& symbol = Symbol::symbol (number);
1352
1353      if ((symbol.type != SymbolPath)) continue;
1354
1355      if (symbol.print (mode))
1356        {
1357          if (mode == Bat)
1358            {
1359              cout << endl;
1360            }
1361          else
1362            {
1363              //cout << "; ";
1364              cout << endl;
1365            }
1366        }
1367    }
1368}
1369
1370//-------------------------------------------------------------
1371void Symbol::all_print_clean (PrintMode mode)
1372{
1373  static SymbolVector& Symbols = symbols ();
1374
1375  int number;
1376
1377  if (Symbols.size () == 0) return;
1378
1379  for (number = Symbols.size () - 1; number >= 0; number--)
1380    {
1381      Symbol& symbol = Symbols[number];
1382
1383      if ((symbol.type == SymbolSet) ||
1384          (symbol.type == SymbolAlias) ||
1385          (symbol.type == SymbolCleanupScript))
1386        {
1387          if (symbol.print_clean (mode))
1388            {
1389              cout << endl;
1390            }
1391        }
1392    }
1393
1394  for (number = Symbols.size () - 1; number >= 0; number--)
1395    {
1396      Symbol& symbol = Symbols[number];
1397
1398      if ((symbol.type != SymbolPath)) continue;
1399
1400      if (symbol.print_clean (mode))
1401        {
1402          cout << endl;
1403        }
1404    }
1405}
1406
1407//-------------------------------------------------------------
1408int Symbol::print_clean (PrintMode mode)
1409{
1410  int result = 0;
1411  static cmt_string temp;
1412
1413  if (name == "CMTCONFIG") return (0);
1414
1415  switch (type)
1416    {
1417    case SymbolSet :
1418      switch (mode)
1419        {
1420        case Csh :
1421          cout << "unsetenv " << name;
1422          result = 1;
1423          break;
1424        case Sh :
1425          cout << "unset " << name;
1426          result = 1;
1427          break;
1428        case Bat :
1429          cout << "set " << name << "=";
1430          result = 1;
1431          break;
1432        }
1433      break;
1434    case SymbolAlias :
1435      switch (mode)
1436        {
1437          case Csh :
1438            cout << "unalias " << name;
1439            result = 1;
1440            break;
1441          case Sh :
1442            cout << "unset " << name;
1443            result = 1;
1444            break;
1445        }
1446      break;
1447    case SymbolPath :
1448      temp = clean_macro_value ();
1449      switch (mode)
1450        {
1451        case Csh :
1452          if (temp == "")
1453            {
1454              cout << "unsetenv " << name;
1455            }
1456          else
1457            {
1458              cout << "setenv " << name << " " << temp;
1459            }
1460          result = 1;
1461          break;
1462        case Sh :
1463          cout << name << "=" << temp << "; export " << name;
1464          result = 1;
1465          break;
1466        case Bat :
1467          cout << "set " << name << "=" << temp;
1468          result = 1;
1469          break;
1470        }
1471      break;
1472    case SymbolCleanupScript :
1473      switch (mode)
1474        {
1475        case Csh :
1476          cout << "if ( -f " << name << ".csh ) then" << endl;
1477          cout << "  source " << name << ".csh" << endl;
1478          cout << "endif" << endl;
1479          result = 1;
1480          break;
1481        case Sh :
1482          cout << "if test -f " << name << ".sh; then" << endl;
1483          cout << "  . " << name << ".sh" << endl;
1484          cout << "fi" << endl;
1485          result = 1;
1486          break;
1487        case Bat :
1488          cout << "call " << name;
1489          result = 1;
1490          break;
1491        }
1492      break;
1493    }
1494
1495  return (result);
1496}
1497
1498//-------------------------------------------------------------
1499int Symbol::print (PrintMode mode)
1500{
1501  int result = 0;
1502  cmt_string temp;
1503
1504  temp = build_macro_value ();
1505
1506  bool empty = (temp.size () == 0) ? true : false;
1507
1508  switch (type)
1509    {
1510      case SymbolSet :
1511      case SymbolPath :
1512        switch (mode)
1513          {
1514            case Csh :
1515              if (empty) cout << "unsetenv " << name;
1516              else cout << "setenv " << name << " \"" << temp << "\"";
1517
1518              result = 1;
1519              break;
1520            case Sh :
1521              if (empty) cout << "unset " << name;
1522              else cout << name << "=\"" << temp << "\"; export " << name;
1523
1524              result = 1;
1525              break;
1526            case Bat :
1527              temp.replace_all ("/", "\\");
1528              cout << "set " << name << "=" << temp;
1529              result = 1;
1530              break;
1531          }
1532        break;
1533      case SymbolAlias :
1534        switch (mode)
1535          {
1536            case Csh :
1537              cout << "alias " << name <<
1538                  " \"" << temp << "\"";
1539              result = 1;
1540              break;
1541            case Sh :
1542              cout << "alias " << name <<
1543                  "=\"" << temp << "\"";
1544              result = 1;
1545              break;
1546            case Bat :
1547              cout << "set " << name <<
1548                  "=" << temp;
1549              result = 1;
1550              break;
1551          }
1552        break;
1553      default :
1554        break;
1555    }
1556
1557  if (temp != "")
1558    {
1559      switch (type)
1560        {
1561          case SymbolSetupScript :
1562            switch (mode)
1563              {
1564                case Csh :
1565                  cout << "if ( -f " << name << ".csh ) then" << endl;
1566                  cout << "  source " << name << ".csh" << endl;
1567                  cout << "endif" << endl;
1568                  result = 1;
1569                  break;
1570                case Sh :
1571                  cout << "if test -f " << name << ".sh; then" << endl;
1572                  cout << "  . " << name << ".sh" << endl;
1573                  cout << "fi" << endl;
1574                  result = 1;
1575                  break;
1576                case Bat :
1577                  cout << "call " << name;
1578                  result = 1;
1579                  break;
1580              }
1581            break;
1582          default:
1583            break;
1584        }
1585    }
1586
1587  return (result);
1588}
1589
1590//-------------------------------------------------------------
1591cmt_string Symbol::build_macro_value (bool display_it) const
1592{
1593  cmt_string temp;
1594
1595  if (display_it)
1596    {
1597      temp = builder->build_and_display (*this);
1598    }
1599  else
1600    {
1601      temp = builder->build (*this);
1602    }
1603
1604  return (temp);
1605}
1606
1607//-------------------------------------------------------------
1608cmt_string Symbol::clean_macro_value () const
1609{
1610  cmt_string temp;
1611
1612  temp = builder->clean (*this);
1613
1614  return (temp);
1615}
1616
1617/**
1618
1619   Attempt to substitute into the symbol value all occurrences of
1620
1621      ${xxx}
1622      $(xxx)
1623      `xxx`
1624      %xxx%    [on Windows only]
1625
1626      by the appropriate value:
1627
1628        for `xxx` :
1629
1630            xxx is considered as a shell command. Value is the result of its execution
1631
1632        for other patterns:
1633
1634            if xxx is a symbol name, its value is substituted to the pattern
1635            otherwise, xxx is tried as an environment variable
1636
1637
1638     ===> In all cases, the pattern is filtered away.
1639
1640  */
1641cmt_string Symbol::resolve_macro_value (const cmt_string& tag_name)
1642{
1643  cmt_string temp = builder->build (*this, tag_name);
1644
1645  resolve_value (temp);
1646
1647  return (temp);
1648}
1649
1650//-------------------------------------------------------------
1651void Symbol::show_macro (PrintMode mode)
1652{
1653  if (Cmt::get_debug ())
1654    {
1655      cout << "Symbol::show_macro> " << name << endl;
1656    }
1657
1658  ActionType action = Cmt::get_action ();
1659
1660  cmt_string value = build_macro_value (true);
1661
1662  if ((!Cmt::get_quiet ()) &&
1663      (action != action_build_tag_makefile) &&
1664      (action != action_show_macros) &&
1665      (action != action_show_actions) &&
1666      (action != action_show_sets))
1667    {
1668      cout << "#" << endl;
1669      cout << "# Selection : " << endl;
1670    }
1671
1672  if (value.size () > 0)
1673    {
1674      if ((action == action_show_macro) ||
1675          (action == action_show_macros) ||
1676          (action == action_show_sets) ||
1677          (action == action_show_set) ||
1678          (action == action_show_actions) ||
1679          (action == action_show_action) ||
1680          (action == action_build_tag_makefile) ||
1681          (action == action_load) ||
1682          (!Cmt::get_quiet ()))
1683        {
1684          if (mode == Make)
1685            {
1686              cout << name << "=";
1687            }
1688          else
1689            {
1690              cout << name << "='";
1691            }
1692        }
1693
1694      if ((action == action_show_macro_value) ||
1695          (action == action_show_set_value) ||
1696          (action == action_show_action_value))
1697        {
1698          expand (value);
1699        }
1700      else if (action == action_build_tag_makefile)
1701        {
1702            /*
1703               Unfortunately, the %xxx% pattern has to be kept on Unix. Therefore
1704               we cannot force all patterns to become $(xxx)
1705
1706               This was useful on Windows so as to only keep $(xxx)
1707             */
1708#ifdef WIN32
1709          suppress_OS_delimiters (value);
1710#endif
1711        }
1712
1713      cout << value;
1714
1715      if ((action == action_show_macro) ||
1716          (action == action_show_macros) ||
1717          (action == action_show_sets) ||
1718          (action == action_show_set) ||
1719          (action == action_show_actions) ||
1720          (action == action_show_action) ||
1721          (action == action_build_tag_makefile) ||
1722          (action == action_load) ||
1723          (!Cmt::get_quiet ()))
1724        {
1725          if (mode != Make)
1726            {
1727              cout << "'";
1728            }
1729#ifdef WIN32
1730          else
1731            {
1732              cout << " ";
1733            }
1734#endif
1735        }
1736
1737      cout << endl;
1738    }
1739}
1740
1741//-------------------------------------------------------------
1742void Symbol::clear_all ()
1743{
1744  static SymbolVector& Symbols = symbols ();
1745  static SymbolMap& SymbolMap = symbol_map ();
1746
1747  SymbolMap.clear ();
1748  Symbols.clear ();
1749}
1750
1751//-------------------------------------------------------------
1752void Symbol::expand (cmt_string& text)
1753{
1754  static cmt_regexp reg ("[$%`]");
1755
1756  if (!reg.match (text)) return;
1757
1758  resolve_value (text);
1759}
1760
1761//-------------------------------------------------------------
1762ValueBuilder::ValueBuilder ()
1763{
1764  m_display_it = false;
1765}
1766
1767//-------------------------------------------------------------
1768const cmt_string ValueBuilder::build_and_display (const Symbol& symbol)
1769{
1770  cmt_string temp;
1771
1772  m_display_it = true;
1773  temp = build (symbol);
1774  m_display_it = false;
1775
1776  return (temp);
1777}
1778
1779//-------------------------------------------------------------
1780const cmt_string SetBuilder::build (const Symbol& symbol,
1781                                    const cmt_string& /*tag_name*/)
1782{
1783    // Control of recursivity
1784  static int level = 0;
1785
1786  bool show_it = false;
1787
1788  cmt_string temp;
1789  cmt_string previous_temp;
1790  cmt_string new_value;
1791  static const cmt_string empty;
1792
1793  ActionType action = Cmt::get_action ();
1794
1795  if (action == action_show_set)
1796    {
1797      if (symbol.name == Cmt::get_current_target ())
1798        {
1799             // Should not display on recursive calls
1800          if (level == 0) show_it = m_display_it;
1801        }
1802    }
1803
1804  level++;
1805
1806  temp = "";
1807
1808  bool first_definition = true;
1809  bool defined = false;
1810
1811  for (int i = 0; i < symbol.value_lists.size (); i++)
1812    {
1813      const SymbolValueList& value_list = symbol.value_lists[i];
1814
1815      if ((value_list.use != 0) &&
1816          (value_list.use->discarded)) continue;
1817
1818      const int selected = value_list.select_first ();
1819
1820      if (selected < 0) continue;
1821
1822      SymbolValue& value = value_list.values[selected];
1823
1824      if (show_it)
1825        {
1826          value_list.show (symbol, value, first_definition);
1827        }
1828     
1829      if (value_list.discarded) continue;
1830
1831        //
1832        // One should accumulate values if it refers to
1833        // itself.
1834        //
1835     
1836      new_value = value.text;
1837     
1838      resolve_value_for_macros (new_value);
1839     
1840      switch (value_list.command_type)
1841        {
1842          case CommandSet :
1843
1844            if (!value_list.is_reflexive || 
1845                !symbol.value_is_reflexive (value.text))
1846              {
1847                resolve_value (new_value, symbol.name, temp);
1848                temp = new_value;
1849              }
1850            else if (temp == "")
1851              {
1852                temp = CmtSystem::getenv (symbol.name);
1853              }
1854
1855            if (!defined)
1856              {
1857                defined = true;
1858              }
1859            else
1860              {
1861                if ((!Cmt::get_quiet ()) &&
1862                    ((action == action_show_macro) ||
1863                     (action == action_show_set) ||
1864                     (action == action_show_action) ||
1865                     (action == action_show_macros) ||
1866                     (action == action_show_sets) ||
1867                     (action == action_show_actions)))
1868                  {
1869                    cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden";
1870
1871                    if (value_list.use != 0)
1872                      {
1873                        cerr << " in package " << value_list.use->get_package_name ();
1874                      }
1875
1876                    cerr << endl;
1877                  }
1878              }
1879
1880            break;
1881          case CommandSetAppend :
1882           
1883            if (new_value != "")
1884              {
1885                temp += new_value;
1886              }
1887           
1888            break;
1889          case CommandSetPrepend :
1890           
1891            if (new_value != "")
1892              {
1893                previous_temp = temp;
1894                temp = new_value;
1895                temp += previous_temp;
1896              }
1897           
1898            break;
1899          case CommandSetRemove :
1900           
1901            if (new_value != "")
1902              {
1903                temp.replace_all (new_value, empty);
1904              }
1905           
1906            break;
1907          case CommandSetRemoveRegexp :
1908           
1909            if (new_value != "")
1910              {
1911                cmt_regexp e (new_value);
1912                cmt_regexp::iterator it;
1913
1914                for (;;)
1915                  {
1916                    it = e.begin (temp);
1917                    if (it == e.end ()) break;
1918
1919                    temp.erase (it._pos, it._length);
1920                  }
1921              }
1922           
1923            break;
1924          case CommandAlias :
1925           
1926            resolve_value (new_value, symbol.name, temp);
1927            temp = new_value;
1928           
1929            break;
1930        }
1931    }
1932
1933  level--;
1934
1935  return (temp);
1936}
1937
1938static bool find_path_entry (const cmt_string& paths, const cmt_string& value)
1939{
1940  static const cmt_string path_separator = CmtSystem::path_separator ();
1941
1942  cmt_string here = CmtSystem::pwd ();
1943  cmt_string rvalue = value;
1944
1945  if (CmtSystem::cd (value))
1946    {
1947      rvalue = CmtSystem::pwd ();
1948    }
1949  else
1950    {
1951      CmtSystem::compress_path (rvalue);
1952    }
1953
1954  CmtSystem::cmt_string_vector items;
1955  CmtSystem::split (paths, path_separator, items);
1956
1957  bool found = false;
1958
1959  for (int i = 0; i < items.size (); i++)
1960    {
1961      const cmt_string& item = items[i];
1962      cmt_string ritem = item;
1963      if (CmtSystem::cd (item))
1964        {
1965          ritem = CmtSystem::pwd ();
1966        }
1967      else
1968        {
1969          CmtSystem::compress_path (ritem);
1970        }
1971
1972      if (ritem == rvalue)
1973        {
1974          found = true;
1975          break;
1976        }
1977    }
1978
1979  CmtSystem::cd (here);
1980  return (found);
1981}
1982
1983//-------------------------------------------------------------
1984const cmt_string PathBuilder::build (const Symbol& symbol,
1985                                     const cmt_string& /*tag_name*/)
1986{
1987    // Control of recursivity
1988  static int level = 0;
1989
1990  bool show_it = false;
1991
1992  cmt_string temp;
1993  cmt_string previous_temp;
1994  cmt_string new_value;
1995  static const cmt_string empty;
1996
1997  static cmt_string path_separator = CmtSystem::path_separator ();
1998
1999  ActionType action = Cmt::get_action ();
2000
2001  if (action == action_show_set)
2002    {
2003      if (symbol.name == Cmt::get_current_target ())
2004        {
2005            // Should not display on recursive calls
2006          if (level == 0) show_it = m_display_it;
2007        }
2008    }
2009
2010  level++;
2011
2012  temp = CmtSystem::getenv (symbol.name);
2013
2014  bool first_definition = true;
2015  bool defined = false;
2016
2017  for (int i = 0; i < symbol.value_lists.size (); i++)
2018    {
2019      const SymbolValueList& value_list = symbol.value_lists[i];
2020
2021      if ((value_list.use != 0) &&
2022          (value_list.use->discarded)) continue;
2023
2024      const int selected = value_list.select_first ();
2025     
2026      if (selected < 0) continue;
2027 
2028      SymbolValue& value = value_list.values[selected];
2029         
2030      if (show_it)
2031        {
2032          value_list.show (symbol, value, first_definition);
2033        }
2034         
2035      if (value_list.discarded) continue;
2036
2037      new_value = value.text;
2038         
2039          //resolve_value (new_value);
2040      resolve_value_for_macros (new_value);
2041         
2042      switch (value_list.command_type)
2043        {
2044          case CommandPath :
2045           
2046            if (!value_list.is_reflexive || 
2047                !symbol.value_is_reflexive (value.text))
2048              {
2049                resolve_value (new_value, symbol.name, temp);
2050                temp = new_value;
2051
2052                if (!defined)
2053                  {
2054                    defined = true;
2055                  }
2056                else
2057                  {
2058                    if ((!Cmt::get_quiet ()) &&
2059                        ((action == action_show_macro) ||
2060                         (action == action_show_set) ||
2061                         (action == action_show_action) ||
2062                         (action == action_show_macros) ||
2063                         (action == action_show_sets) ||
2064                         (action == action_show_actions)))
2065                      {
2066                        cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden";
2067                       
2068                        if (value_list.use != 0)
2069                          {
2070                            cerr << " in package " << value_list.use->get_package_name ();
2071                          }
2072                       
2073                        cerr << endl;
2074                      }
2075                  }
2076              }
2077
2078            break;
2079          case CommandPathAppend :
2080             
2081            if (new_value != "")
2082              {
2083                if (!find_path_entry (temp, new_value))
2084                  {
2085                    if (temp != "") temp += path_separator;
2086                     
2087                    temp += new_value;
2088                  }
2089              }
2090                 
2091            break;
2092          case CommandPathPrepend :
2093             
2094            if (new_value != "")
2095              {
2096                if (!find_path_entry (temp, new_value))
2097                  {
2098                    previous_temp = temp;
2099                    temp = new_value;
2100                    if (previous_temp != "") temp += path_separator;
2101                    temp += previous_temp;
2102                  }
2103              }
2104                 
2105            break;
2106          case CommandPathRemove :
2107             
2108            if (new_value != "")
2109              {
2110                CmtSystem::cmt_string_vector paths;
2111                 
2112                CmtSystem::split (temp, path_separator, paths);
2113                 
2114                for (int j = 0; j < paths.size (); ++j)
2115                  {
2116                    cmt_string& s = paths[j];
2117                     
2118                    if (s.find (new_value) != cmt_string::npos)
2119                      {
2120                        s = "";
2121                      }
2122                  }
2123
2124                Cmt::vector_to_string (paths, path_separator, temp);
2125                temp.replace_all ("::", ":");
2126                temp.replace_all (";;", ";");
2127              }
2128             
2129            break;
2130          case CommandPathRemoveRegexp :
2131
2132            if (new_value != "")
2133              {
2134                cmt_regexp e (new_value);
2135
2136                CmtSystem::cmt_string_vector paths;
2137                 
2138                CmtSystem::split (temp, path_separator, paths);
2139                 
2140                for (int j = 0; j < paths.size (); ++j)
2141                  {
2142                    cmt_string& s = paths[j];
2143
2144                    if (CmtSystem::getenv ("TESTPRR") != "")
2145                      {
2146                        cout << "PRR> s=[" << s << "]";
2147                      }
2148
2149                    if (e.match (s))
2150                      {
2151                        s = "";
2152
2153                        if (CmtSystem::getenv ("TESTPRR") != "")
2154                          {
2155                            cout << " match ";
2156                          }
2157                      }
2158                    else
2159                      {
2160                        if (CmtSystem::getenv ("TESTPRR") != "")
2161                          {
2162                            cout << " no match ";
2163                          }
2164                      }
2165
2166                    if (CmtSystem::getenv ("TESTPRR") != "")
2167                      {
2168                        cout << endl;
2169                      }
2170                  }
2171
2172                Cmt::vector_to_string (paths, path_separator, temp);
2173                temp.replace_all ("::", ":");
2174                temp.replace_all (";;", ";");
2175              }
2176             
2177            break;
2178        }
2179
2180    }
2181
2182  level--;
2183 
2184  return (temp);
2185}
2186
2187//-------------------------------------------------------------
2188const cmt_string PathBuilder::clean (const Symbol& symbol,
2189                                     const cmt_string& /*tag_name*/)
2190{
2191    // Control of recursivity
2192  static int level = 0;
2193
2194  cmt_string temp;
2195  cmt_string new_value;
2196  static const cmt_string empty;
2197
2198  static cmt_string path_separator = CmtSystem::path_separator ();
2199
2200  temp = CmtSystem::getenv (symbol.name);
2201
2202    //cerr << "#####1 temp=" << temp << endl;
2203
2204  for (int i = 0; i < symbol.value_lists.size (); i++)
2205    {
2206      const SymbolValueList& value_list = symbol.value_lists[i];
2207
2208      if (value_list.discarded) continue;
2209
2210      if ((value_list.use != 0) &&
2211          (value_list.use->discarded)) continue;
2212
2213      const int selected = value_list.select_first ();
2214     
2215      if (selected < 0) continue;
2216 
2217      SymbolValue& value = value_list.values[selected];
2218         
2219      new_value = value.text;
2220         
2221          //resolve_value (new_value);
2222
2223        //cerr << "#####1 new_value=" << new_value << endl;
2224
2225      resolve_value_for_macros (new_value);
2226      resolve_value (new_value);
2227         
2228        //cerr << "#####2 new_value=" << new_value << endl;
2229
2230      switch (value_list.command_type)
2231        {
2232          case CommandPath :
2233           
2234            temp = "";
2235           
2236            break;
2237          case CommandPathAppend :
2238          case CommandPathPrepend :
2239          case CommandPathRemove :
2240
2241            if (new_value != "")
2242              {
2243                CmtSystem::cmt_string_vector paths;
2244                 
2245                CmtSystem::split (temp, path_separator, paths);
2246                 
2247                for (int j = 0; j < paths.size (); ++j)
2248                  {
2249                    cmt_string& s = paths[j];
2250                     
2251                    if (s.find (new_value) != cmt_string::npos)
2252                      {
2253                        s = "";
2254                      }
2255
2256                    if (j > 0)
2257                      {
2258                        cmt_string& s2 = paths[j-1];
2259                        if (s2 == s)
2260                          {
2261                            s2 = "";
2262                          }
2263                      }
2264                  }
2265
2266                Cmt::vector_to_string (paths, path_separator, temp);
2267                temp.replace_all ("::", ":");
2268                temp.replace_all (";;", ";");
2269              }
2270             
2271            break;
2272          case CommandPathRemoveRegexp :
2273
2274            if (new_value != "")
2275              {
2276                cmt_regexp e (new_value);
2277
2278                CmtSystem::cmt_string_vector paths;
2279                 
2280                CmtSystem::split (temp, path_separator, paths);
2281                 
2282                for (int j = 0; j < paths.size (); ++j)
2283                  {
2284                    cmt_string& s = paths[j];
2285                     
2286                    if (e.match (s))
2287                      {
2288                        s = "";
2289                      }
2290
2291                    if (j > 0)
2292                      {
2293                        cmt_string& s2 = paths[j-1];
2294                        if (s2 == s)
2295                          {
2296                            s2 = "";
2297                          }
2298                      }
2299                  }
2300
2301                Cmt::vector_to_string (paths, path_separator, temp);
2302                temp.replace_all ("::", ":");
2303                temp.replace_all (";;", ";");
2304              }
2305             
2306            break;
2307        }
2308    }
2309
2310    //cerr << "#####2 temp=" << temp << endl;
2311 
2312  return (temp);
2313}
2314
2315//-------------------------------------------------------------
2316const cmt_string MacroBuilder::build (const Symbol& symbol,
2317                                      const cmt_string& tag_name)
2318{
2319    // Control of recursivity
2320  static int level = 0;
2321
2322  cmt_string temp;
2323  cmt_string previous_temp;
2324  static const cmt_string empty;
2325  bool show_it = false;
2326
2327  ActionType action = Cmt::get_action ();
2328
2329  if (action == action_show_macro)
2330    {
2331      if (symbol.name == Cmt::get_current_target ())
2332        {
2333             // Should not display on recursive calls
2334          if (level == 0) show_it = m_display_it;
2335        }
2336    }
2337
2338  level++;
2339
2340  temp = "";
2341
2342  int i;
2343
2344  bool first_definition = true;
2345  bool defined = false;
2346
2347  for (i = 0; i < symbol.value_lists.size (); i++)
2348    {
2349      const SymbolValueList& value_list = symbol.value_lists[i];
2350
2351      if ((value_list.use != 0) &&
2352          (value_list.use->discarded)) continue;
2353
2354      if (value_list.command_type != CommandMacroPrepend) continue;
2355
2356      const int selected = value_list.select_first (tag_name);
2357
2358      if (selected < 0) continue;
2359
2360      SymbolValue& value = value_list.values[selected];
2361
2362      if (show_it)
2363        {
2364          value_list.show (symbol, value, first_definition);
2365        }
2366
2367      if (value_list.discarded) continue;
2368
2369      previous_temp = temp;
2370      temp = value.text;
2371      temp += previous_temp;
2372    }
2373
2374  previous_temp = temp;
2375  temp = "";
2376
2377  first_definition = true;
2378
2379  for (i = 0; i < symbol.value_lists.size (); i++)
2380    {
2381      const SymbolValueList& value_list = symbol.value_lists[i];
2382
2383      if ((value_list.use != 0) &&
2384          (value_list.use->discarded)) continue;
2385
2386      if (value_list.command_type != CommandMacro) continue;
2387
2388      const int selected = value_list.select_first (tag_name);
2389
2390      if (selected < 0) continue;
2391
2392      SymbolValue& value = value_list.values[selected];
2393
2394      if (show_it)
2395        {
2396          value_list.show (symbol, value, first_definition);
2397        }
2398
2399      // WARNING:
2400      // Commented just for a test : should be uncommented after the test
2401      if (value_list.discarded) continue;
2402     
2403      if (!value_list.is_reflexive || 
2404          !symbol.value_is_reflexive (value.text))
2405        {
2406          temp = value.text;
2407
2408          if (!defined)
2409            {
2410              defined = true;
2411            }
2412          else
2413            {
2414              /*
2415              if ((!Cmt::get_quiet ()) &&
2416                  ((action == action_show_macro) ||
2417                   (action == action_show_set) ||
2418                   (action == action_show_action) ||
2419                   (action == action_show_macros) ||
2420                   (action == action_show_sets) ||
2421                   (action == action_show_actions)))
2422                {
2423                  cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden";
2424                 
2425                  if (value_list.use != 0)
2426                    {
2427                      cerr << " in package " << value_list.use->get_package_name ();
2428                    }
2429
2430                  cerr << endl;
2431                }
2432              */
2433            }
2434        }
2435    }
2436
2437  previous_temp += temp;
2438  temp = previous_temp;
2439
2440  for (i = 0; i < symbol.value_lists.size (); i++)
2441    {
2442      const SymbolValueList& value_list = symbol.value_lists[i];
2443
2444      if ((value_list.use != 0) &&
2445          (value_list.use->discarded)) continue;
2446
2447      if (value_list.command_type != CommandMacroAppend) continue;
2448
2449      const int selected = value_list.select_first (tag_name);
2450
2451      if (selected < 0) continue;
2452
2453      SymbolValue& value = value_list.values[selected];
2454
2455      if (show_it)
2456        {
2457          value_list.show (symbol, value, first_definition);
2458        }
2459
2460      if (value_list.discarded) continue;
2461
2462      temp += value.text;
2463    }
2464
2465  for (i = 0; i < symbol.value_lists.size (); i++)
2466    {
2467      const SymbolValueList& value_list = symbol.value_lists[i];
2468
2469      if ((value_list.use != 0) &&
2470          (value_list.use->discarded)) continue;
2471
2472      if ((value_list.command_type != CommandMacroRemove) &&
2473          (value_list.command_type != CommandMacroRemoveRegexp) &&
2474          (value_list.command_type != CommandMacroRemoveAll) &&
2475          (value_list.command_type != CommandMacroRemoveAllRegexp)) continue;
2476
2477      const int selected = value_list.select_first (tag_name);
2478
2479      if (selected < 0) continue;
2480
2481      SymbolValue& value = value_list.values[selected];
2482
2483      if (show_it)
2484        {
2485          value_list.show (symbol, value, first_definition);
2486        }
2487
2488      if (value_list.discarded) continue;
2489
2490      switch (value_list.command_type)
2491        {
2492          case CommandMacroRemove :
2493            temp.replace (value.text, empty);
2494            break;
2495          case CommandMacroRemoveRegexp :
2496            if (value.text != "")
2497              {
2498                cmt_regexp e (value.text);
2499                cmt_regexp::iterator it;
2500
2501                it = e.begin (temp);
2502                if (it != e.end ())
2503                  {
2504                    temp.erase (it._pos, it._length);
2505                  }
2506              }
2507            break;
2508          case CommandMacroRemoveAll :
2509            temp.replace_all (value.text, empty);
2510            break;
2511          case CommandMacroRemoveAllRegexp :
2512            if (value.text != "")
2513              {
2514                cmt_regexp e (value.text);
2515                cmt_regexp::iterator it;
2516
2517                for (;;)
2518                  {
2519                    it = e.begin (temp);
2520                    if (it != e.end ())
2521                      {
2522                        temp.erase (it._pos, it._length);
2523                      }
2524                    else
2525                      {
2526                        break;
2527                      }
2528                  }
2529              }
2530            break;
2531        }
2532    }
2533
2534  level--;
2535
2536  return (temp);
2537}
2538
2539//-------------------------------------------------------------
2540const cmt_string ScriptBuilder::build (const Symbol& symbol,
2541                                       const cmt_string& tag_name)
2542{
2543    // Control of recursivity
2544  static int level = 0;
2545
2546  static const cmt_string empty = "";
2547
2548  if (symbol.value_lists.size () > 0)
2549    {
2550      const SymbolValueList& value_list = symbol.value_lists[0];
2551
2552      if (value_list.discarded) return (empty);
2553
2554      if ((value_list.use != 0) &&
2555          (value_list.use->discarded)) return (empty);
2556    }
2557
2558  return (symbol.name);
2559}
2560
2561//-------------------------------------------------------------
2562const cmt_string ActionBuilder::build (const Symbol& symbol,
2563                                       const cmt_string& tag_name)
2564{
2565    // Control of recursivity
2566  static int level = 0;
2567
2568  cmt_string temp;
2569  cmt_string previous_temp;
2570  static const cmt_string empty;
2571  bool show_it = false;
2572
2573  ActionType action = Cmt::get_action ();
2574
2575  if (action == action_show_action)
2576    {
2577      if (symbol.name == Cmt::get_current_target ())
2578        {
2579             // Should not display on recursive calls
2580          if (level == 0) show_it = m_display_it;
2581        }
2582    }
2583
2584  level++;
2585
2586  int i;
2587
2588  bool first_definition = true;
2589  bool defined = false;
2590
2591  temp = "";
2592
2593  for (i = 0; i < symbol.value_lists.size (); i++)
2594    {
2595      const SymbolValueList& value_list = symbol.value_lists[i];
2596
2597      if ((value_list.use != 0) &&
2598          (value_list.use->discarded)) continue;
2599
2600      if (value_list.command_type != CommandAction) continue;
2601
2602      const int selected = value_list.select_first (tag_name);
2603
2604      if (selected < 0) continue;
2605
2606      SymbolValue& value = value_list.values[selected];
2607
2608      if (show_it)
2609        {
2610          value_list.show (symbol, value, first_definition);
2611        }
2612
2613      // WARNING:
2614      // Commented just for a test : should be uncommented after the test
2615      if (value_list.discarded) continue;
2616     
2617      if (!value_list.is_reflexive || 
2618          !symbol.value_is_reflexive (value.text))
2619        {
2620          temp = value.text;
2621
2622          if (!defined)
2623            {
2624              defined = true;
2625            }
2626          else
2627            {
2628              if ((!Cmt::get_quiet ()) &&
2629                  ((action == action_show_macro) ||
2630                   (action == action_show_set) ||
2631                   (action == action_show_action) ||
2632                   (action == action_show_macros) ||
2633                   (action == action_show_sets) ||
2634                   (action == action_show_actions)))
2635                {
2636                  cerr << "#CMT> Warning: Symbol " << symbol.name << " overridden";
2637                 
2638                  if (value_list.use != 0)
2639                    {
2640                      cerr << " in package " << value_list.use->get_package_name ();
2641                    }
2642
2643                  cerr << endl;
2644                }
2645            }
2646        }
2647    }
2648
2649  level--;
2650
2651  return (temp);
2652}
2653
2654//-------------------------------------------------------------
2655int SymbolValueList::select_first (const cmt_string& tag_name) const
2656{
2657  int priority = 0;
2658  int value_number;
2659  int selected = -1;
2660
2661  Tag* the_tag = 0;
2662
2663  if (tag_name != "") the_tag = Tag::find (tag_name);
2664
2665  for (value_number = 0;
2666       value_number < values.size ();
2667       value_number++)
2668    {
2669      const SymbolValue& value = values[value_number];
2670
2671      const Tag* tag = value.tag;
2672
2673      if (the_tag == 0)
2674        {
2675          if (!tag->is_selected ()) continue;
2676        }
2677      else
2678        {
2679          if (tag != the_tag) continue;
2680          selected = value_number;
2681        }
2682
2683      //
2684      // Only the first value at a given priority is
2685      // selected (which implies the '>' test instead
2686      // of '>=')
2687      //
2688
2689      if (tag->get_priority () > priority)
2690        {
2691          priority = tag->get_priority ();
2692          selected = value_number;
2693        }
2694    }
2695
2696  return (selected);
2697}
2698
2699//-------------------------------------------------------------
2700int SymbolValueList::select_last () const
2701{
2702  int priority = 0;
2703  int value_number;
2704  int selected = -1;
2705
2706  for (value_number = 0;
2707       value_number < values.size ();
2708       value_number++)
2709    {
2710      SymbolValue& value = values[value_number];
2711
2712      const Tag* tag = value.tag;
2713
2714      if (tag->is_selected ())
2715        {
2716          //
2717          // The last value at a given priority is
2718          // selected (which implies the '>=' test instead
2719          // of '>')
2720          //
2721
2722          if (tag->get_priority () >= priority)
2723            {
2724              priority = tag->get_priority ();
2725              selected = value_number;
2726            }
2727        }
2728    }
2729
2730  return (selected);
2731}
2732
2733//-------------------------------------------------------------
2734void SymbolValueList::show (const Symbol& symbol, 
2735                            const SymbolValue& value, 
2736                            bool& first_definition) const
2737{
2738  cmt_string discarded_text;
2739  cmt_string define_text;
2740  ActionType action = Cmt::get_action ();
2741
2742  if (value.text == "") return;
2743
2744  if (discarded) discarded_text = " (discarded by override)";
2745  else discarded_text = "";
2746
2747  if (first_definition) define_text = "defines";
2748  else define_text = "overrides";
2749
2750  cout << "# Package ";
2751  if (use != 0)
2752    {
2753      cout << use->get_package_name () << " " << use->version;
2754    }
2755
2756  switch (command_type)
2757    {
2758      case CommandSet :
2759        cout << " " << define_text << " set " << symbol.name << " as ";
2760        first_definition = false;
2761        break;
2762      case CommandSetAppend :
2763        cout << " appends to set " << symbol.name << " : ";
2764        break;
2765      case CommandSetPrepend :
2766        cout << " prepends to set " << symbol.name << " : ";
2767        break;
2768      case CommandSetRemove :
2769        cout << " removes from set " << symbol.name << " : ";
2770        break;
2771      case CommandSetRemoveRegexp :
2772        cout << " removes RE from set " << symbol.name << " : ";
2773        break;
2774      case CommandAlias :
2775        cout << " " << define_text << " alias " << symbol.name << " as ";
2776        first_definition = false;
2777        break;
2778      case CommandPath :
2779        cout << " " << define_text << " path " << symbol.name << " as ";
2780        first_definition = false;
2781        break;
2782      case CommandPathAppend :
2783        cout << " appends to path " << symbol.name << " : ";
2784        break;
2785      case CommandPathPrepend :
2786        cout << " prepends to path " << symbol.name << " : ";
2787        break;
2788      case CommandPathRemove :
2789        cout << " removes from path " << symbol.name << " : ";
2790        break;
2791      case CommandPathRemoveRegexp :
2792        cout << " removes RE from path " << symbol.name << " : ";
2793        break;
2794      case CommandMacroPrepend :
2795        cout << " prepends to macro " << symbol.name << " : ";
2796        break;
2797      case CommandMacro :
2798        cout << " " << define_text << " macro " << symbol.name << " as ";
2799        break;
2800      case CommandMacroAppend :
2801        cout << " appends to macro " << symbol.name << " : ";
2802        break;
2803      case CommandMacroRemove :
2804        cout << " remove from macro " << symbol.name << " : ";
2805        break;
2806      case CommandMacroRemoveRegexp :
2807        cout << " remove RE from macro " << symbol.name << " : ";
2808        break;
2809      case CommandMacroRemoveAll :
2810        cout << " remove all from macro " << symbol.name << " : ";
2811        break;
2812      case CommandMacroRemoveAllRegexp :
2813        cout << " remove all RE from macro " << symbol.name << " : ";
2814        break;
2815      case CommandAction :
2816        cout << " " << define_text << " action " << symbol.name << " as ";
2817        first_definition = false;
2818        break;
2819    }
2820
2821  cout << "'" << value.text << "'";
2822         
2823  Tag* selected_tag = value.tag;
2824         
2825  if ((selected_tag == 0) ||
2826      (selected_tag == Tag::get_default ()))
2827    {
2828      cout << " for default tag";
2829    }
2830  else
2831    {
2832      cout << " for tag '" << selected_tag->get_name () << "'";
2833    }
2834 
2835  cout << discarded_text << endl;
2836}
2837
2838//-------------------------------------------------------------
2839bool Symbol::check_tag_used (Tag* tag)
2840{
2841  if (tag == 0) return (false);
2842
2843  static SymbolVector& Symbols = symbols ();
2844
2845  if (Symbols.size () == 0) 
2846    {
2847      return (false);
2848    }
2849
2850  for (int number = 0; number < Symbol::symbol_number (); number++)
2851    {
2852      Symbol& symbol = Symbol::symbol (number);
2853
2854      for (int i = 0; i < symbol.value_lists.size (); i++)
2855        {
2856          const SymbolValueList& value_list = symbol.value_lists[i];
2857
2858          for (int j = 0; j < value_list.values.size (); j++)
2859            {
2860              const SymbolValue& value = value_list.values[j];
2861              Tag* t = value.tag;
2862
2863              if (t != 0)
2864                {
2865                  if (t->use_operand (tag)) return (true);
2866                }
2867            }
2868        }
2869    }
2870
2871  return (false);
2872}
2873
Note: See TracBrowser for help on using the repository browser.