source: CMT/HEAD/source/cmt_symbol.cxx @ 656

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

See C.L. 515

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