source: CMT/HEAD/source/cmt_project.cxx @ 551

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

See C.L. 436

  • Property svn:eol-style set to native
File size: 81.0 KB
Line 
1
2//-----------------------------------------------------------
3// Copyright Christian Arnault LAL-Orsay CNRS
4// arnault@lal.in2p3.fr
5// Modified by garonne@lal.in2p3.fr
6// See the complete license in cmt_license.txt "http://www.cecill.info".
7//-----------------------------------------------------------
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <ctype.h>
13
14#include "cmt_project.h"
15#include "cmt_database.h"
16#include "cmt_system.h"
17#include "cmt_awk.h"
18#include "cmt_syntax.h"
19#include "cmt_tag.h"
20#include "cmt_error.h"
21#include "cmt_log.h"
22
23class ProjectReader : public Awk
24{
25public:
26
27  ProjectReader ()
28  {
29  }
30 
31  const cmt_string& get_project_name () const
32  {
33    return (m_project);
34  }
35 
36  void filter (const cmt_string& line)
37  {
38    CmtSystem::cmt_string_vector words;
39    CmtSystem::split (line, " \t", words);
40    if (words[0] == "project")
41      {
42        m_project = words[1];
43      }
44  }
45 
46private:
47  cmt_string m_project;
48};
49
50class ProjectPatcher : public Awk
51{
52public:
53
54  ProjectPatcher (const cmt_string& p) : m_project (p)
55  {
56  }
57
58  void commit ()
59  {
60    m_output.write (Project::get_project_file_name ());
61  }
62
63  void filter (const cmt_string& line)
64  {
65    CmtSystem::cmt_string_vector words;
66    CmtSystem::split (line, " \t", words);
67    if (words[0] == "project")
68      {
69        m_output += "project ";
70        m_output += m_project;
71      }
72    else
73      {
74        m_output += line;
75      }
76
77    m_output += "\n";
78  }
79 
80private:
81  cmt_string m_output;
82  const cmt_string& m_project;
83};
84
85IProjectFactory& ProjectFactory::instance ()
86{
87  static ProjectFactory me;
88 
89  return (me);
90}
91
92void ProjectFactory::reset ()
93{
94  Project::clear_all ();
95}
96
97static bool get_release_from_path (const CmtSystem::cmt_string_vector& items, 
98                                   const cmt_string& path, 
99                                   const cmt_string& name, 
100                                   cmt_string& real_name, 
101                                   cmt_string& release)
102{
103  bool result = false;
104
105  release = "";
106  real_name = "";
107
108  cmt_string p = path;
109
110  if ((items.size () == 0) && (name == ""))
111    {
112      // There is no CMTPROJECTPATH and no expected project name.
113      // We have no way to find a project structure
114      // So we only expect a 2-level structure.
115
116      CmtSystem::basename (p, release);
117      CmtSystem::dirname (p, p);
118      CmtSystem::basename (p, real_name);
119     
120      return (false);
121    }
122
123  for (;;)
124    {
125      if (p == "")
126        {
127          // Protection: we found no matching project name
128          // and path was outside any CMTPROJECTPATH
129
130          p = path;
131
132          CmtSystem::basename (p, release);
133          CmtSystem::dirname (p, p);
134          CmtSystem::basename (p, real_name);
135
136          return (false);
137        }
138
139      cmt_string n;
140
141      CmtSystem::basename (p, n);
142      CmtSystem::dirname (p, p);
143
144      if (n == name)
145        {
146          real_name = name;
147          result = true;
148          break;
149        }
150
151      CmtSystem::basename (p, real_name);
152
153      for (int i = 0; i < items.size (); i++)
154        {
155          const cmt_string& item = items[i];
156          if (p == item)
157            {
158              // We have reached an item of CMTPROJECTPATH, no need to continue
159              return (false);
160            }
161        }
162
163      if (release == "")
164        {
165          release = n;
166        }
167      else
168        {
169          cmt_string r;
170
171          r = n;
172          r += CmtSystem::file_separator ();
173          r += release;
174          release = r;
175        }
176    }
177
178  //cerr << "$CMT> GRFP> path=" << path << " name=" << name << " rel=" << release << endl;
179
180  return (result);
181}
182 
183
184/*
185  Every new CMTPATH entry becomes associated with a dedicated PROJECT
186  This function will understand this new entry to CMTPATH and understand it:
187  - it can correspond to an existing project (ie already declared)
188  - it's a new project
189  - then it tries to read and parse its project file
190*/
191Project* ProjectFactory::create_project (const cmt_string& specified_name,
192                                         const cmt_string& path,
193                                         const cmt_string& source,
194                                         Project* parent)
195{
196  cmt_string compressed_path = path;
197  CmtSystem::compress_path (compressed_path);
198  bool specify_name = (specified_name != "");
199
200  if (Cmt::get_debug ())
201    {
202      cout << "Creating project " << path << " with parent " << ((parent==0)? "0" : parent->get_name ()) << endl;
203      Project::show_all ();
204    }
205
206  cmt_string sep;
207  sep = CmtSystem::path_separator ();
208
209  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH"); 
210  CmtSystem::cmt_string_vector items;
211  CmtSystem::split (cmtprojectpath, sep, items);
212
213  cmt_string here = CmtSystem::pwd ();
214  if (!CmtSystem::cd (compressed_path)) return (0);
215  cmt_string pwd = CmtSystem::pwd ();
216
217  static Project::ProjectVector& Projects = Project::projects ();
218
219  int i;
220 
221  for (i = 0; i < Projects.size (); i++)
222    {
223      Project& p = Projects[i];
224     
225      if ((p.get_cmtpath () == compressed_path) ||
226          (p.get_cmtpath_pwd () == pwd) ||
227          (specify_name && (p.get_name () == specified_name)))
228        {
229          cmt_string r;
230          cmt_string n;
231
232          get_release_from_path (items, compressed_path, p.get_name (), n, r);
233
234          if (r != p.get_release ())
235            {
236              CmtMessage::warning ("Project " + p.get_name ()
237                                   + " requested with conflicting releases "
238                                   + p.get_release () + " and " + r
239                                   + ", latter (in " + compressed_path + ") ignored");
240              /*
241              CmtMessage::error ("Project " + p.get_name ()
242                                   + " requested with conflicting releases "
243                                   + p.get_release () + " and " + r);
244              */
245              /*
246              if (!Cmt::get_quiet ())
247                {
248                  cerr << "#CMT> Project " << p.get_name ()
249                       << " requested with conflicting releases " << p.get_release () << " and " << r << endl;
250                }
251              */
252              //CmtError::set (CmtError::project_release_conflict, p.get_name ());
253            }
254 
255          bool updated (false);
256          if (parent != 0)
257            {
258              if (!p.has_parent (parent) || !parent->has_child (&p))
259                {
260              p.add_parent (parent);
261              parent->add_child (&p);
262
263              // Since p is a new parent, we should propagate the settings UP.
264
265              parent->update_strategies_from_children ();
266              updated = true;
267                }
268
269            }
270
271          CmtSystem::cd (here);
272          if (updated) Project::order_all ();
273          return (&p);
274        }
275    }
276
277
278  Project* project = 0;
279  Project* cmt = 0;
280 
281  bool is_current = false;
282 
283  cmt_string name = specified_name;
284  cmt_string project_name;
285  cmt_string release;
286
287  //
288  // Figure out if this is the current project
289  //
290  //  if (here.find (pwd) == 0) is_current = true;
291
292  // In case there are symlinks
293
294  //  cmt_string here_real, pwd_real;
295  //cerr << "realpath_: create_project" << endl;
296  /*
297  if (CmtSystem::realpath_ (here, here_real) && CmtSystem::realpath_ (pwd, pwd_real))
298    {
299      if (here_real.find (pwd_real) == 0) is_current = true;
300    }
301  */
302  cmt_string pwd_real;
303  if (!CmtSystem::realpath_ (pwd, pwd_real))
304    {
305      CmtError::set (CmtError::file_access_error, "Cannot compute real path `" +
306                     pwd + "'");
307      CmtError::print ();
308      return 0;
309      //      if (Cmt::get_current_dir_real ().find (pwd_real) == 0) is_current = true;
310    }
311
312  cmt_string text;
313
314  /*
315    Now Figure out the project name from the project file
316    or does not specify the project name
317  */
318  bool has_project_file = false;
319
320  if (CmtSystem::cd ("cmt") && CmtSystem::test_file (Project::get_project_file_name ()))
321    {
322      has_project_file = true;
323      text.read (Project::get_project_file_name ());
324
325      ProjectReader reader;
326
327      reader.run (text);
328
329      project_name = reader.get_project_name ();
330    }
331
332  enum
333    {
334      without_project_file   = 0x01,
335      with_project_file      = 0x02,
336      without_project_name   = 0x04,
337      with_project_name      = 0x08,
338      without_specified_name = 0x10,
339      with_specified_name    = 0x20,
340      names_mismatch         = 0x40,
341      names_match            = 0x80
342    };
343
344  int status = ((has_project_file) ? with_project_file : without_project_file) |
345    ((has_project_file && (project_name != "")) ? with_project_name : without_project_name) |
346    ((specify_name) ? with_specified_name : without_specified_name) |
347    ((specify_name && has_project_file && (project_name == specified_name)) ? names_match : names_mismatch);
348
349  if (source == "default path")
350    {
351      name = "CMT";
352    }
353  else
354    {
355      cmt_string n;
356         
357      switch (status)
358        {
359        case with_project_file | without_project_name | without_specified_name | names_mismatch:
360
361          // The project is neither specified from the caller nor from the project file
362
363          /*
364            if (!Cmt::get_quiet ())
365            {
366            cerr << "#CMT> Warning: project name unspecified in project file." << endl;
367            }
368          */
369     
370          get_release_from_path (items, compressed_path, "", name, release);
371
372          break;
373         
374        case with_project_file | without_project_name | with_specified_name | names_mismatch:
375         
376          // The name is only specified from the caller
377          // find this specified name in the path
378         
379          if (get_release_from_path (items, compressed_path, specified_name, name, release))
380            {
381              // The specified name has been found from the path.
382              // We believe in the release spec.
383            }
384          else
385            {
386              // The specified name is not in the path.
387              /*
388                if (!Cmt::get_quiet ())
389                {
390                cerr << "#CMT> Warning: specified project name "
391                << specified_name
392                << " from the caller does not match path." << endl;
393                }
394              */
395              name = specified_name;
396            }
397         
398          break;
399         
400        case with_project_file | with_project_name | with_specified_name | names_match:
401         
402          // We have a double specification: from the caller and from the project file.
403          // And both specifications are consistent. 
404         
405          if (get_release_from_path (items, compressed_path, specified_name, name, release))
406            {
407              // The specified name has been found from the path.
408              // We believe in the release spec.
409            }
410          else
411            {
412              // The specified name is not in the path.
413              /*
414                if (!Cmt::get_quiet ())
415                {
416                cerr << "#CMT> Warning: specified project name "
417                << specified_name
418                << " from project file and from caller does not match path." << endl;
419                }
420              */
421              name = specified_name;
422            }
423         
424          break;
425         
426        case with_project_file | with_project_name | with_specified_name | names_mismatch:
427         
428          // We have a double specification: from the caller and from the project file.
429          // Specifications are inconsistent!!
430         
431          /*
432            if (!Cmt::get_quiet ())
433            {
434            cerr << "#CMT> Warning: specified project name "
435            << specified_name
436            << " inconsistent with name "
437            << project_name
438            << " from project file." << endl;
439            }
440          */
441         
442          if (get_release_from_path (items, compressed_path, specified_name, n, release))
443            {
444              // name from caller wins.
445            }
446          else if (get_release_from_path (items, compressed_path, project_name, name, release))
447            {
448              // name from project file wins.
449            }
450          else
451            {
452              // The specified name is not in the path.
453             
454              CmtMessage::warning ("none of specified project names "
455                                   + specified_name + " from graph and "
456                                   + project_name + " from project file match path.");
457              /*
458              if (!Cmt::get_quiet ())
459                {
460                  cerr << "#CMT> Warning: none of specified project names "
461                       << specified_name
462                       << " from graph and "
463                       << project_name
464                       << " from project file match path." << endl;
465                }
466              */
467
468              name = specified_name;
469            }
470         
471          break;
472         
473        case with_project_file | with_project_name | without_specified_name | names_mismatch:
474         
475          // Project name is specified in the project file but not from the caller.
476         
477          if (get_release_from_path (items, compressed_path, project_name, name, release))
478            {
479              // The specified name has been found from the path.
480              // We believe in the release spec.
481
482            }
483          else
484            {
485              // The specified name is not in the path.
486
487              /*
488                if (!Cmt::get_quiet ())
489                {
490                cerr << "#CMT> Warning: specified project name "
491                << project_name
492                << " from project file does not match path." << endl;
493                }
494              */
495
496              name = project_name;
497            }
498         
499          break;
500         
501        case without_project_file | without_project_name | without_specified_name | names_mismatch:
502         
503          // The project is not specified from the caller and there is no project file
504          // This corresponds to the backward compatibility
505          // For the moment, assume /name/release/ structure where release is one level only
506         
507          /*
508            if (!Cmt::get_quiet ())
509            {
510            cerr << "#CMT> Warning: project name is not specified "
511            << " (no project file)." << endl;
512            }
513          */
514         
515          CmtSystem::basename (compressed_path, release);
516          CmtSystem::dirname (compressed_path, name);
517          CmtSystem::basename (name, name);
518
519          if (name == "")
520            {
521              name = release;
522              release = "";
523            }
524         
525          break;
526         
527        case without_project_file | without_project_name | with_specified_name | names_mismatch:
528         
529          // The name is only specified from the caller
530          // find this specified name in the path
531         
532          if (get_release_from_path (items, compressed_path, specified_name, name, release))
533            {
534              // The specified name has been found from the path.
535              // We believe in the release spec.
536            }
537          else
538            {
539              // The specified name is not in the path.
540              /*
541                if (!Cmt::get_quiet ())
542                {
543                cerr << "#CMT> Warning: specified project name "
544                << specified_name
545                << " from project graph does not match path." << endl;
546                }
547              */
548              name = specified_name;
549            }
550         
551          break;
552        }
553    }
554
555  if (name == "")
556    {
557      name = "Project";
558    }
559
560  project = Project::add (name, release);
561     
562  if (parent != 0)
563    {
564      project->add_parent (parent);
565      parent->add_child (project);
566
567      // Since project is a new child, we should propagate the settings UP.
568
569      parent->update_strategies_from_children ();
570    }
571  /*
572  else if ((name != "CMTUSERCONTEXT") && (name != "CMTHOME"))
573    //  else
574    {
575      // this project has no parent thus it should become the top project.
576      // Let's look for all projects without parent.
577      // they will become children of this project.
578
579      for (i = 0; i < Projects.size (); i++)
580        {
581          Project* p = &(Projects[i]);
582          const cmt_string& n = p->get_name ();
583          if (n == name) continue;
584          //      if (p->get_name () == name) continue;
585          if ((n == "CMTUSERCONTEXT") || (n == "CMTHOME")) continue;
586          if (!p->has_parents ())
587            {
588              project->add_child (p);
589              p->add_parent (project);
590            }
591        }
592
593      // Since project is a new parent, we should upgrade its settings
594
595      project->update_strategies_from_children ();
596    }
597  */
598  if (source == "default path")
599    {
600      cmt = project;
601      is_current = false;
602    }
603
604  project->set_cmtpath (compressed_path);
605  project->set_cmtpath_real (pwd_real);
606  project->set_cmtpath_pwd (pwd);
607  project->set_cmtpath_source (source);
608
609  //  project->set_is_current (is_current);
610  /*
611  if (is_current)
612    {
613      //      cerr << "current: " << project->get_name () << endl;
614      //
615      // The current project defines a tag with its name
616      //
617
618      Tag* tag;
619     
620      tag = Tag::add (project->get_name (), PriorityConfig, "PROJECT", 0);
621      tag->mark ();
622    }
623  */
624
625  //  Project::order_all ();
626
627  if (text != "")
628    {
629      // Last step is to parse the project file
630
631      if (Cmt::get_debug ())
632        {
633          cout << "About to parse project file [" << text << "]" << endl;
634        }
635
636      // First create the Project.m_use for the policy
637
638      Use* project_use = Use::create (project->get_cmtpath(), 
639                                      "package_policy_for_project_" + project->get_name(),                                       
640                                      project->get_release (), "", "");                                                         
641
642      project_use->done      = true;
643      project_use->discarded = false;
644      project_use->m_hidden  = true;
645      project_use->selected  = true;
646      project_use->m_located = true;
647      project_use->set_auto_imports(Off);
648      project_use->initial_scope = ScopePublic;     
649      project->set_use(project_use);
650     
651     
652      // add at the uses level ?????
653      /*static Use::UsePtrVector& uses = Use::get_ordered_uses ();
654        bool found = false;
655        int  size  = uses.size ();
656        cerr << "\n size:"<<size<< ":" << endl;     
657        for (int n = 0; n < size; n++)
658        {
659        Use* tuse = uses[n];
660        cerr << "\tpackage file [" << tuse->get_package_name() << "]" <<project_use->get_package_name()<< endl;                   
661        if (tuse->get_package_name()==project_use->get_package_name())
662        found=true;
663
664        }
665   
666        if (not found)
667        {
668        uses.push_back (project_use);
669        project_use->m_index = uses.size () - 1;
670        }
671      */
672
673      SyntaxParser::parse_project_file_text (text, 
674                                             Project::get_project_file_name (),
675                                             project);
676    }
677
678
679
680  CmtSystem::cd (here);
681  Project::order_all ();
682
683  return (project);
684}
685
686/*----------------------------------------------------------*/
687/*                                                          */
688/*  Operations on Projects                                  */
689/*                                                          */
690/*----------------------------------------------------------*/
691
692//----------------------------------------------------------
693bool Project::create (const cmt_string& name, 
694                      const cmt_string& release, 
695                      const cmt_string& path)
696{
697  cmt_string pwd = CmtSystem::pwd ();
698
699  if (CmtMessage::active (Error))
700    {
701  cerr << "------------------------------------------" << endl;
702  cerr << "Configuring environment for project " << name << " " << release << " (from " << pwd << ") ";
703
704  if (path != "")
705    {
706      cout << " in " << path;
707    }
708
709  cerr << endl;
710  cerr << "CMT version " << Cmt::get_cmt_version () << "." << endl;
711  cerr << "------------------------------------------" << endl;
712    }
713
714  if (path != "")
715    {
716      if (!CmtSystem::mkdir (path))
717        {
718          CmtMessage::error ("Cannot create the " + path + " directory");
719          //          cerr << "Cannot create the " << path << " directory" << endl;
720          return (false);
721        }
722
723      if (!CmtSystem::cd (path))
724        {
725          CmtMessage::error ("Cannot access the " + path + " directory");
726          //          cerr << "Cannot access the " << path << " directory" << endl;
727          return (false);
728        }
729    }
730
731  if (!CmtSystem::mkdir (name))
732    {
733      CmtMessage::error ("Cannot create the " + name + " directory");
734      //      cerr << "Cannot create the " << name << " directory" << endl;
735      return (false);
736    }
737
738  if (!CmtSystem::cd (name))
739    {
740      CmtMessage::error ("Cannot access the " + name + " directory");
741      //      cerr << "Cannot access the " << name << " directory" << endl;
742      return (false);
743    }
744
745  if (release != "")
746    {
747      if (!CmtSystem::mkdir (release))
748        {
749          CmtMessage::error ("Cannot create the " + release + " directory");
750          //      cerr << "Cannot create the " << release << " directory" << endl;
751          return (false);
752        }
753     
754      if (!CmtSystem::cd (release))
755        {
756          CmtMessage::error ("Cannot access the " + release + " directory");
757          //      cerr << "Cannot access the " << release << " directory" << endl;
758          return (false);
759        }
760    }
761
762  if (!CmtSystem::test_directory ("cmt"))
763    {
764      if (!CmtSystem::mkdir ("cmt"))
765        {
766          CmtMessage::error ("Cannot create the cmt directory");
767          //          cerr << "Cannot create the cmt directory" << endl;
768          return (false);
769        }
770      else
771        {
772          if (CmtMessage::active (Info))
773            cerr << "Installing the cmt directory" << endl;
774        }
775    }
776
777  CmtSystem::cd ("cmt");
778
779  if (!CmtSystem::test_file (get_project_file_name ()))
780    {
781      if (CmtMessage::active (Info))
782        cerr << "Creating a new project file" << endl;
783
784      ofstream f (get_project_file_name ());
785      if (f)
786        {
787          f << "project " << name << endl;
788          f << endl;
789          f.close ();
790        }
791      else
792        {
793          CmtMessage::error ("Cannot create the project file");
794          //          cerr << "Cannot create the project file" << endl;
795          return (false);
796        }
797    }
798  else
799    {
800      cmt_string text;
801      text.read (get_project_file_name ());
802
803      ProjectPatcher p (name);
804
805      p.run (text);
806      p.commit ();
807
808      if (CmtMessage::active (Info))
809        cerr << "project file already there" << endl;
810    }
811
812  return (true);
813}
814
815//----------------------------------------------------------
816Project* Project::find_by_name (const cmt_string& name)
817{
818  static ProjectVector& Projects = projects ();
819
820  for (int i = 0; i < Projects.size (); i++)
821    {
822      Project& p = Projects[i];
823      if (p.m_name == name) return (&p);
824     
825    }
826
827  return (0);
828}
829
830//----------------------------------------------------------
831Project* Project::find_by_cmtpath (const cmt_string& cmtpath)
832{
833  cmt_string compressed_path = cmtpath;
834  CmtSystem::compress_path (compressed_path);
835
836  static ProjectVector& Projects = projects ();
837
838  for (int i = 0; i < Projects.size (); i++)
839    {
840      Project& p = Projects[i];
841
842      if (p.m_cmtpath == compressed_path) return (&p);
843      if (p.m_cmtpath_real == compressed_path) return (&p);
844      if (p.m_cmtpath_pwd == compressed_path) return (&p);
845    }
846
847  return (0);
848}
849
850//----------------------------------------------------------
851Project* Project::get_current ()
852{
853  /*
854  cmt_string here = CmtSystem::pwd ();
855
856  // In case there are symlinks
857  cmt_string here_real;
858  CmtSystem::realpath_ (here, here_real);
859  */
860  static ProjectVector& Projects = projects ();
861
862  Project* result = 0;
863
864  for (int i = (Projects.size () - 1); i >= 0; i--)
865    {
866      Project& p = Projects[i];
867
868//       if (here.find (p.m_cmtpath_pwd) == 0)
869//      {
870//        result = &p;
871//      }
872
873//      if (here.find (p.m_cmtpath) == 0)
874      if (p.is_current ()) 
875        //      if (here_real.find (p.m_cmtpath_real) == 0)
876        {
877          result = &p;
878        }
879    }
880
881  return (result);
882}
883
884//----------------------------------------------------------
885Project* Project::add (const cmt_string& name,
886                       const cmt_string& release)
887{
888  static ProjectVector& Projects = projects ();
889
890  {
891    Project* project;
892
893    project = find_by_name (name);
894    if (project != 0) 
895      {
896        //      if (!Cmt::get_quiet ())
897        //        {
898            if (release != project->get_release ())
899              {
900                if (CmtMessage::active (Verbose))
901                  CmtMessage::error ("Project " + name
902                                     + " requested with conflicting releases "
903                                     + project->get_release () + " and " + release);
904                //              cerr << "#CMT> Project " << name << " requested with conflicting releases " << project->get_release () << " and " << release << endl;
905                CmtError::set (CmtError::project_release_conflict, name);
906              }
907            //    }
908
909        // Project objects are recreated here to follow the hierarchy
910        // This duplication is needed for properly applying the strategies
911        Project& p = Projects.add ();
912
913        p.set_name (name);
914        p.set_release (release);
915        p.configure ();
916
917        return (&p);
918
919        //return (project);
920      }
921  }
922
923  Project& project = Projects.add ();
924  project.clear ();
925  project.set_name (name);
926  project.set_release (release);
927  project.configure ();
928
929  return (&project);
930}
931
932//----------------------------------------------------------
933Project::ProjectVector& Project::projects ()
934{
935  static Database& db = Database::instance ();
936  static ProjectVector& Projects = db.projects ();
937
938  return (Projects);
939}
940
941//----------------------------------------------------------
942Project::ProjectPtrVector& Project::ordered_projects ()
943{
944  static Database& db = Database::instance ();
945  static ProjectPtrVector& Projects = db.ordered_projects ();
946
947  return (Projects);
948}
949
950//----------------------------------------------------------
951void Project::order_all ()
952//Project::ProjectPtrVector Project::ordered_projects ()
953{
954  ProjectPtrVector OrderedProjects;
955  //  static ProjectPtrVector OrderedProjects;
956  static Project::ProjectPtrVector& orderedProjects = Project::ordered_projects ();
957
958  static Project::ProjectVector& Projects = Project::projects ();
959  const int size = Projects.size ();
960 
961  int offset (0);
962  int iuser (-1);
963  int ihome (-1);
964  for (int i = 0; i < 2; i++)
965    {
966      if (offset < size)
967        {
968          const cmt_string& name = Projects[offset].get_name ();
969          if (name == "CMTUSERCONTEXT")
970            {
971              iuser = offset;
972              ++offset;
973            }
974          else if (name == "CMTHOME")
975            {
976              ihome = offset;
977              ++offset;
978            }
979          else
980            break;
981        }
982    }
983
984  OrderedProjects.resize (size);
985
986  Use& use = Use::current();
987  cmt_string current_path (Cmt::get_current_dir ());
988  if (use.located ())
989    {
990      current_path = use.real_path;
991      CmtMessage::verbose ("Using current use real_path `" + current_path + "'");
992    }
993
994  cmt_string current_path_real;
995  if (!CmtSystem::realpath_ (current_path, current_path_real))
996    {
997      CmtError::set (CmtError::file_access_error, "Cannot compute real path `" +
998                     current_path + "'");
999      CmtError::print ();
1000      return;
1001      //CmtMessage::error ("Cannot compute real path `" + Use::current().real_path + "'");
1002    }
1003
1004  Project* p_cur (0);
1005  for (int i = 0; i < size; i++)
1006    {
1007      Project& p = Projects[i];
1008      if (i >= offset)
1009        p.m_order = -1;
1010      else
1011        p.m_order = -2;
1012      p.m_visits = 0;
1013      //
1014      // The current project specification
1015      //
1016      if (current_path_real.find (p.get_cmtpath_real ()) == 0)
1017        {
1018          p_cur = &p;
1019          if (p.is_current ()) continue;
1020
1021          p.set_is_current (true);
1022          //
1023          // The current project defines a tag with its name
1024          //
1025         
1026          Tag* tag;
1027         
1028          tag = Tag::add (p.get_name (), PriorityConfig, "PROJECT", 0);
1029          tag->mark ();
1030        }
1031      else if (p.is_current ())
1032        {
1033          //
1034          // Unset the tag with its name - TODO
1035          //
1036          p.set_is_current (false);
1037        }
1038    }
1039
1040  if (size == offset)
1041    {
1042      for (int i = 0; i < offset; i++)
1043        {
1044          Project* p = &(Projects[i]);
1045          OrderedProjects[i] = p;
1046        }
1047      /*
1048      if (2 == offset)
1049        {
1050          OrderedProjects[0]->add_child (OrderedProjects[1]);
1051          OrderedProjects[1]->add_parent (OrderedProjects[0]);
1052          OrderedProjects[0]->update_strategies_from_children ();
1053        }
1054      */
1055      for (int i = OrderedProjects.size () - 2; i >= 0; i--)
1056        {
1057          if (!OrderedProjects[i]->has_parents () &&
1058              OrderedProjects[i]->get_children_size () == 0)
1059            {
1060              OrderedProjects[i]->add_child (OrderedProjects[i + 1]);
1061              OrderedProjects[i]->update_strategies_from_children ();
1062              OrderedProjects[i]->erase_child (OrderedProjects[i + 1]);
1063            }
1064        }
1065
1066      orderedProjects = OrderedProjects;
1067      //      return OrderedProjects;
1068      return;
1069    }
1070
1071  Project* p (p_cur);
1072  //  Project* p = get_current ();
1073
1074  //  cerr << "get_current: " << p << " offset: " << offset << endl;
1075  /*
1076  if (p == 0)
1077    {
1078      p = &(Projects[offset]);
1079      //      p = &(Projects[0]);
1080    }
1081  */
1082  //  cerr << "p: " << p << " offset: " << offset << " name: " << p->get_name () << endl;
1083
1084  int order (-1);
1085  /*
1086  if ((p->get_name () != "CMTUSERCONTEXT") && (p->get_name () != "CMTHOME"))
1087    {
1088      ProjectPtrVector projs;
1089      p->m_order = ++order;
1090      //      p->m_visits++;
1091      projs.push_back (p);
1092     
1093      visit (offset, order, projs);
1094      //  visit (order, projs);
1095    }
1096  //  cerr << "order: " << order << endl;
1097  //  int unordered = size - offset - (order + 1);
1098  */
1099  ProjectPtrVector projs;
1100
1101  if (p != 0 && (p->get_name () != "CMTUSERCONTEXT") && (p->get_name () != "CMTHOME"))
1102    {
1103      p->m_order = ++order;
1104      projs.push_back (p);
1105    }
1106
1107  if (p == 0 ||
1108      (!p->has_parents () && p->get_children_size () == 0)
1109      // comes from CMTPATH entry
1110      )
1111    {
1112      for (int i = offset; i < size; i++)
1113        {
1114          Project* q = &(Projects[i]);
1115          if (q != p && !q->has_parents ())
1116            {
1117              q->m_order = ++order;
1118              projs.push_back (q);
1119            }
1120        }
1121    }
1122
1123  visit (offset, order, projs);
1124
1125  int beg (0);
1126  if  (-1 != iuser)
1127    {
1128      OrderedProjects[0] = &(Projects[iuser]);
1129      //      cerr << "OrderedProjects[0]: " << (OrderedProjects[0])->get_name () << endl;
1130      ++beg;
1131    }
1132
1133  int noorder (0);
1134  for (int i = offset; i < size; i++)
1135    //  for (int i = 0; i < size; i++)
1136    {
1137      Project* p = &(Projects[i]);
1138      int j = p->m_order;
1139      if (-1 == j)
1140        {
1141          OrderedProjects[beg + order + 1 + noorder++] = p;
1142          //      cerr << "no: OrderedProjects[" << beg + order + noorder << "]: " << (OrderedProjects[beg + order + noorder])->get_name () << endl;
1143          //      OrderedProjects[order + 1 + noorder++] = p;
1144          /*
1145          if (CmtMessage::active (Verbose))
1146            CmtMessage::warning ("Not ordered project " + p->get_name () +
1147                                 " in path " + p->get_cmtpath_pwd () +
1148                                 " from " + p->get_cmtpath_source ());
1149          continue;
1150          */
1151        }
1152      else if (-2 != j)
1153        {
1154          OrderedProjects[beg + j] = p;
1155        }
1156      /*
1157      else if  (-2 == j)
1158        {
1159        }
1160      else
1161        {
1162          OrderedProjects[beg + j] = p;
1163      //      OrderedProjects[j] = p;
1164          //      cerr << "OrderedProjects[" << beg + j << "]: " << (OrderedProjects[beg + j])->get_name () << endl;
1165        }
1166      */
1167    }
1168
1169  if (p != 0)
1170    {
1171      for (int i = 0; i < noorder; i++)
1172        OrderedProjects.pop_back ();
1173    }
1174  if  (-1 != ihome)
1175    {
1176      OrderedProjects[OrderedProjects.size () - 1] = &(Projects[ihome]);
1177    }
1178  /*
1179  if (p)
1180    {
1181      if  (-1 != ihome)
1182        {
1183          OrderedProjects[beg + order + 1] = &(Projects[ihome]);
1184        }
1185      for (int i = 0; i < noorder; i++)
1186        OrderedProjects.pop_back ();
1187    }
1188  else
1189    {
1190      if  (-1 != ihome)
1191        {
1192          OrderedProjects[size - 1] = &(Projects[ihome]);
1193        }
1194    }
1195  */
1196      /*
1197  if  (-1 != iuser)
1198    {
1199      OrderedProjects[0]->add_child (OrderedProjects[1]);
1200      OrderedProjects[1]->add_parent (OrderedProjects[0]);
1201      OrderedProjects[0]->update_strategies_from_children ();
1202    }
1203      */
1204
1205//   if  (-1 != ihome)
1206//     {
1207      /*
1208      cerr << "beg: " << beg << " order: " << order << endl;
1209      cerr << "noorder: " << noorder << " size - offset: " << size - offset << endl;
1210      */
1211      /*
1212      if (noorder != size - offset)
1213        {  // the last ordered project
1214          OrderedProjects[beg + order]->add_child (OrderedProjects[size - 1]);
1215          OrderedProjects[size - 1]->add_parent (OrderedProjects[beg + order]);
1216          OrderedProjects[beg + order]->update_strategies_from_children ();
1217        }
1218      else
1219        {
1220          OrderedProjects[size - 2]->add_child (OrderedProjects[size - 1]);
1221          OrderedProjects[size - 1]->add_parent (OrderedProjects[size - 2]);
1222          OrderedProjects[size - 2]->update_strategies_from_children ();
1223        }
1224      */
1225//     }
1226
1227  for (int i = OrderedProjects.size () - 2; i >= 0; i--)
1228    {
1229      if (!OrderedProjects[i]->has_parents () &&
1230          OrderedProjects[i]->get_children_size () == 0)
1231        {
1232          OrderedProjects[i]->add_child (OrderedProjects[i + 1]);
1233          OrderedProjects[i]->update_strategies_from_children ();
1234          OrderedProjects[i]->erase_child (OrderedProjects[i + 1]);
1235        }
1236    }
1237
1238  orderedProjects = OrderedProjects;
1239  //  return OrderedProjects;
1240  return;
1241}
1242
1243/*----------------------------------------------------------*/
1244void Project::clear_all ()
1245{
1246  static ProjectVector& Projects = projects ();
1247
1248  for (int i = 0; i < Projects.size (); i++)
1249    {
1250      Project& project = Projects[i];
1251      project.clear ();
1252    }
1253
1254  Projects.clear ();
1255}
1256
1257/*----------------------------------------------------------*/
1258void Project::show_all (PrintMode mode)
1259//void Project::show_all ()
1260{
1261  static const Project::ProjectPtrVector& Ordered = Project::ordered_projects ();
1262  static Project::ProjectVector& Projects = Project::projects ();
1263 
1264  for (int i = 0; i < Projects.size (); i++)
1265    {
1266      Project& p = Projects[i];
1267      p.m_visited = false;
1268    }
1269
1270  switch (mode)
1271    {
1272    case Xml :
1273      Cmt::print_xml_prolog ("projects");
1274      cout << "<projects>";
1275      break;
1276    }
1277
1278  for (int i = 0; i < Ordered.size (); i++)
1279    Ordered[i]->show (mode);
1280  //    Ordered[i]->show ();
1281
1282  for (int i = 0; i < Projects.size (); i++)
1283    Projects[i].show (mode);
1284  //    Projects[i].show ();
1285
1286  switch (mode)
1287    {
1288    case Xml :
1289      cout << "</projects>" << endl;
1290      break;
1291    }
1292  /*
1293  Project* p = get_current ();
1294
1295  if (p == 0)
1296    {
1297      if (Ordered.size () == 0) return;
1298
1299      p = Ordered[0];
1300    }
1301  */
1302  //  p->show ();
1303}
1304
1305/*----------------------------------------------------------*/
1306void Project::show_container (const cmt_string& path)
1307//void Project::show_container ()
1308{
1309  Project* p (0);
1310  if (path == "")
1311    {
1312      p = get_current ();
1313    }
1314  else
1315    {
1316      p = find_by_cmtpath (find_in_cmt_paths (path));
1317    } 
1318
1319  if (p == 0)
1320    {
1321      cmt_string msg ("No project found for path "
1322                      + (path != "" ? path : (Use::current()).real_path)
1323                      );
1324      CmtMessage::warning (msg);
1325      CmtError::set (CmtError::warning, msg);
1326      return;
1327    }
1328  Use* use = &(p->m_container);
1329  if (use->get_package_name () == "")
1330    {
1331      cmt_string msg ("No container specified for project " + p->get_name ()
1332                      + " (" + p->get_cmtpath () + ")");
1333      CmtMessage::warning (msg);
1334      CmtError::set (CmtError::warning, msg);
1335      return;
1336    }
1337 
1338  if (!use->located ())
1339    {
1340      CmtMessage::warning ("container " + use->get_info ()
1341                           + " not found");
1342      CmtError::set (CmtError::package_not_found, use->get_package_name ());
1343    }
1344  else
1345    {
1346      static const cmt_string empty;
1347      cmt_string p = use->real_path;
1348      if (use->path != "")
1349        {
1350          int pos = p.find_last_of (use->path);
1351          if (pos != cmt_string::npos)
1352            {
1353              p.erase (pos);
1354            }
1355        }
1356     
1357      cout << "container " << use->get_package_name ()
1358           << " " << use->version;
1359     
1360      if (CmtSystem::absolute_path (use->path))
1361        {
1362          if (!Cmt::get_quiet ()) 
1363            {
1364              cout << " (" << use->path << ")";
1365            }
1366        }
1367      else
1368        {
1369          cout << " " << use->path;
1370        }
1371     
1372      if (!Cmt::get_quiet ()) 
1373        {
1374          if (p != "") cout << " (" << p << ")";
1375          if (use->auto_imports == Off) cout << " (no_auto_imports)";
1376        }
1377     
1378      cout << endl;
1379    }
1380}
1381
1382/*----------------------------------------------------------*/
1383void Project::show_specified_strategies_for_all ()
1384{
1385  static ProjectVector& Projects = projects ();
1386
1387  for (int i = 0; i < Projects.size (); i++)
1388    {
1389      const Project& project = Projects[i];
1390      project.show_specified_strategies ();
1391    }
1392}
1393
1394/*----------------------------------------------------------*/
1395class VisitorForShowPaths : public IProjectVisitor
1396{
1397public:
1398  VisitorForShowPaths ()
1399  {
1400  }
1401
1402  void pre (Project* p)
1403  {
1404    const cmt_string& w = p->get_cmtpath_pwd ();
1405    const cmt_string& s = p->get_cmtpath_source ();
1406
1407    if (s == "default path") return;
1408
1409    if (CmtSystem::test_directory (w))
1410      {
1411        cout << "# Add path " << w << " from " << s << endl;
1412      }
1413  }
1414
1415  void in (Project* p)
1416  {
1417    const cmt_string& w = p->get_cmtpath_pwd ();
1418    const cmt_string& s = p->get_cmtpath_source ();
1419
1420    if (s == "default path") return;
1421
1422    if (CmtSystem::test_directory (w))
1423      {
1424        cout << "# Add path " << w << " from " << s << endl;
1425      }
1426  }
1427
1428  void in_again (Project* p)
1429  {
1430    const cmt_string& w = p->get_cmtpath_pwd ();
1431    const cmt_string& s = p->get_cmtpath_source ();
1432
1433    if (s == "default path") return;
1434
1435    if (CmtSystem::test_directory (w))
1436      {
1437        cout << "# Remove path " << w << " from " << s << endl;
1438        cout << "# Add path " << w << " from " << s << endl;
1439      }
1440  }
1441
1442  void post (Project* p)
1443  {
1444  }
1445};
1446
1447/*----------------------------------------------------------*/
1448void Project::show_paths (const CmtSystem::cmt_string_vector& arguments,
1449                          ostream& out)
1450//void Project::show_paths ()
1451{
1452  if (arguments.size () == 0 ||
1453      Cmt::get_action () != action_show_path)
1454    {
1455      const ProjectPtrVector& Ordered = Project::ordered_projects ();
1456      for (int i = 0; i < Ordered.size (); i++)
1457        {
1458          const Project* p = Ordered[i];
1459          const cmt_string& w = p->get_cmtpath_pwd ();
1460          const cmt_string& s = p->get_cmtpath_source ();
1461         
1462          if (s == "default path") continue;
1463         
1464          if (CmtSystem::test_directory (w))
1465            {
1466              out << "# Add path " << w << " from " << s << endl;
1467            }
1468        }
1469    }
1470  else if (arguments.size () == 1 && cmt_string (arguments[0]) == "-d")
1471    {
1472      const ProjectVector& Projects = projects ();
1473      for (int i = 0; i < Projects.size (); i++)
1474        {
1475          Project& p = Projects[i];
1476          const cmt_string& w = p.get_cmtpath_pwd ();
1477          const cmt_string& s = p.get_cmtpath_source ();
1478         
1479          if (s == "default path") continue;
1480         
1481          if (CmtSystem::test_directory (w))
1482            {
1483              out << "# Create path " << w << " from " << s << endl;
1484            }
1485        }
1486      /*
1487      VisitorForShowPaths visitor;
1488      start_visit (visitor);
1489      */
1490    }
1491  else
1492    CmtMessage::error ("show_paths: unexpected argument(s)");
1493}
1494
1495//----------------------------------------------------------
1496const cmt_string& Project::get_project_file_name ()
1497{
1498  static const cmt_string name = "project.cmt";
1499
1500  return (name);
1501}
1502
1503//----------------------------------------------------------
1504void Project::fill_selection (int depth, CmtSystem::cmt_string_vector& path_selections)
1505{
1506  static ProjectPtrVector& Ordered = Project::ordered_projects ();
1507  for (int i = 0; i < Ordered.size (); i++)
1508    {
1509      const Project* project = Ordered[i];
1510
1511      const cmt_string& p = project->get_cmtpath ();
1512      const cmt_string& pwd = project->get_cmtpath_pwd ();
1513      const cmt_string& p_real = project->get_cmtpath_real ();
1514      const cmt_string& src = project->get_cmtpath_source ();
1515      /*
1516  static ProjectVector& Projects = projects ();
1517
1518  for (int i = 0; i < Projects.size (); i++)
1519    {
1520      Project& project = Projects[i];
1521
1522      const cmt_string& p = project.get_cmtpath ();
1523      const cmt_string& pwd = project.get_cmtpath_pwd ();
1524      const cmt_string& p_real = project.get_cmtpath_real ();
1525      const cmt_string& src = project.get_cmtpath_source ();
1526      */
1527      if (src != "default path")
1528        {
1529          if (depth > 0)
1530            {
1531              cmt_string& s1 = path_selections.add ();
1532              s1 = p;
1533              if (pwd != p)
1534                {
1535                  cmt_string& s2 = path_selections.add ();
1536                  s2 = pwd;
1537                }
1538              if (p_real != p && p_real != pwd)
1539                {
1540                  cmt_string& s3 = path_selections.add ();
1541                  s3 = p_real;
1542                }
1543              if (src != "CMTHOME" && src != "CMTUSERCONTEXT")
1544                depth--;
1545
1546              if (depth == 0) break;
1547            }
1548        }
1549    }
1550}
1551
1552//----------------------------------------------------------
1553void Project::broadcast (IProjectAction& action)
1554{
1555  //  const ProjectPtrVector Projects = Project::ordered_projects ();
1556  static ProjectPtrVector& Projects = Project::ordered_projects ();
1557
1558  for (int i = 0; i < Projects.size (); i++)
1559    {
1560      const Project* project = Projects[i];
1561
1562      if (!action.run (*project)) break;
1563    }
1564  /*
1565  static ProjectVector& Projects = projects ();
1566
1567  for (int i = 0; i < Projects.size (); i++)
1568    {
1569      const Project& project = Projects[i];
1570
1571      if (!action.run (project)) break;
1572    }
1573  */
1574}
1575
1576//----------------------------------------------------------
1577void Project::reverse_broadcast (IProjectAction& action)
1578{
1579  //  const ProjectPtrVector Projects = Project::ordered_projects ();
1580  static ProjectPtrVector& Projects = Project::ordered_projects ();
1581
1582  for (int i = (Projects.size () - 1); i >= 0; i--)
1583    {
1584      const Project* project = Projects[i];
1585
1586      if (!action.run (*project)) break;
1587    }
1588  /*
1589  static ProjectVector& Projects = projects ();
1590
1591  for (int i = (Projects.size () - 1); i >= 0; i--)
1592    {
1593      const Project& project = Projects[i];
1594
1595      if (!action.run (project)) break;
1596    }
1597  */
1598}
1599
1600//----------------------------------------------------------
1601void Project::scan_paths (PathScanner& scanner, PathScanner::actor& a)
1602{
1603  static ProjectVector& Projects = projects ();
1604
1605  int i;
1606
1607  for (i = 0; i < Projects.size (); i++)
1608    {
1609      Project& p  = Projects[i];
1610      p.m_visited = false;
1611    }
1612
1613  for (i = 0; i < Projects.size (); i++)
1614    {
1615      const Project& project = Projects[i];
1616       
1617      const cmt_string& p = project.m_cmtpath;
1618      scanner.scan_path (p, a);
1619    }
1620}
1621
1622//----------------------------------------------------------
1623void Project::scan_paths_for_package (PathScanner& scanner, const cmt_string& name)
1624{
1625  static ProjectVector& Projects = projects ();
1626
1627  bool found (false);
1628  for (int i = 0; i < Projects.size (); i++)
1629    {
1630      const Project& project = Projects[i];
1631
1632      const cmt_string& p = project.m_cmtpath;
1633      if (scanner.scan_package (p, name))
1634        found = true;
1635    }
1636
1637  if (!found)
1638    CmtError::set (CmtError::package_not_found, name);
1639}
1640
1641//----------------------------------------------------------
1642cmt_string Project::find_in_cmt_paths (const cmt_string& path)
1643{
1644  const cmt_string pwd = CmtSystem::pwd ();
1645
1646  // In case there are symlinks
1647  cmt_string path_real;
1648  //cerr << "realpath_: find_in_cmt_paths" << endl;
1649  CmtSystem::realpath_ (path, path_real);
1650
1651  static ProjectVector& Projects = projects ();
1652
1653  for (int i = 0; i < Projects.size (); i++)
1654    {
1655      const Project& project = Projects[i];
1656
1657      const cmt_string& p = project.m_cmtpath;
1658      const cmt_string& p_real = project.m_cmtpath_real;
1659      const cmt_string& w = project.m_cmtpath_pwd;
1660      const cmt_string& s = project.m_cmtpath_source;
1661
1662      if (s == "default path") continue;
1663
1664      if (CmtSystem::test_directory (p))
1665        {
1666//        if (path.find (p) != cmt_string::npos)
1667//          {
1668//            return (p);
1669//          }
1670
1671          if (path_real.find (p_real) != cmt_string::npos)
1672            {
1673              return (p);
1674            }
1675
1676          // To become the current area, a path must correspond to the current package
1677          if (path.find (w) != cmt_string::npos)
1678            {
1679              return (p);
1680            }
1681        }
1682
1683      if (p == w) continue;
1684
1685      if (CmtSystem::test_directory (w))
1686        {
1687          if (path.find (w) != cmt_string::npos)
1688            {
1689              return (w);
1690            }
1691        }
1692    }
1693
1694  return ("");
1695}
1696
1697//----------------------------------------------------------
1698void Project::visit (IProjectVisitor& visitor)
1699{
1700  if (m_visited) return;
1701  m_visited = true;
1702
1703  int i;
1704
1705  for (i = 0; i < get_children_size (); i++)
1706    {
1707      Project* child = get_child (i);
1708
1709      if (child->visited ()) continue;
1710
1711      visitor.in (child);
1712    }
1713
1714  for (i = 0; i < m_children.size (); i++)
1715    {
1716      Project* child = m_children[i];
1717      child->visit (visitor);
1718    }
1719}
1720
1721//----------------------------------------------------------
1722void Project::visit (IProjectVisitor& visitor, ProjectPtrVector& projects)
1723{
1724  int size = projects.size ();
1725  if (0 == size) return;
1726
1727  ProjectPtrVector children;
1728  for (int j = 0; j < size; j++)
1729    {
1730      Project* p = projects[j];
1731      if (20 == p->m_visits)
1732        continue;
1733      for (int i = 0; i < p->get_children_size (); i++)
1734        {
1735          Project* child = p->get_child (i);
1736          if (0 == child->m_visits)       
1737            visitor.in (child);
1738          else
1739            visitor.in_again (child);
1740          child->m_visits++;
1741          children.push_back (child);
1742        }
1743    }
1744
1745  visit (visitor, children);
1746}
1747
1748//----------------------------------------------------------
1749/**
1750 *  Visit the projects tree and order the projects.
1751 *  Order is the projects upon which the project depends directly,
1752 *  then the direct dependencies of the of the first dependency, of the second
1753 *  dependency and so on. That is first left to right, then downwards.
1754 *  @param offset the offset from which to use all the projects
1755 *  @param order the order of the last project visited
1756 *  @param projs vector of projects to visit and order
1757 */
1758void Project::visit (const int offset, int& order, ProjectPtrVector& projs)
1759{
1760  int size = projs.size ();
1761  //  cerr << "visit: " << offset << " " << order << " " << size << endl;
1762  if (0 == size) return;
1763  static ProjectVector& all = Project::projects ();
1764  /*
1765  cerr << "@ visit: " << order;
1766  for (int j = 0; j < size; j++)
1767    {
1768      Project* p = projs[j];
1769      cerr << " " << p->get_name ();
1770    }
1771  cerr << " @" << endl;
1772  */
1773  ProjectPtrVector children;
1774  for (int j = 0; j < size; j++)
1775    {
1776      Project* p = projs[j];
1777      p->m_visits++;
1778      // Avoid looping in case of circular project dependencies
1779      if (500 <= p->m_visits)
1780        //      if (100 <= p->m_visits)
1781        continue;
1782      for (int i = 0; i < p->get_children_size (); i++)
1783        {
1784          Project* child = p->get_child (i);
1785          const int chorder = child->m_order;
1786          const int porder = p->m_order;
1787          /*
1788          cerr << ">>> " << p->get_name () << " child: " << i << endl;
1789          cerr << child->get_name () << " in: " << chorder << endl;
1790          */
1791          if (-2 == chorder)
1792            continue;
1793          else if (-1 == chorder)
1794            { // not ordered yet, i.e. visited for the first time
1795              child->m_order = ++order;
1796            }
1797          else if (child->is_current ())
1798            //    else if (0 == chorder)
1799            { // the project we started with, i. e. the current project:
1800              //     o circular dependency
1801              //     o do want to keep it first no matter what
1802              if (CmtMessage::active (Verbose))
1803                CmtMessage::warning ("Circular dependency on project: "
1804                                     + child->get_name ()
1805                                     + " " + child->get_release ()
1806                                     + " " + child->get_cmtpath ());
1807            }
1808          else if ((0 <= chorder) && (chorder < porder))
1809            //    else if ((0 < chorder) && (chorder < porder))
1810            { // ordered already, want to put it after the parent in the order
1811              for (int k = offset; k < all.size (); k++)
1812                {
1813                  Project& q = all[k];
1814                  if (&q == child)
1815                    {// the child we are putting after the parent in the order
1816                      q.m_order = porder;
1817                      //              cerr << "Moved back: " << q.get_name () << " order: " << q.m_order << endl;
1818                    }
1819                  else if ((chorder < q.m_order) && (q.m_order <= porder))
1820                    q.m_order--;
1821                }
1822            }
1823          //  cerr << child->get_name () << " out: " << child->m_order << endl;
1824          //      child->m_visits++;
1825          bool unknown (true);
1826          for (int j = 0; j < children.size (); j++)
1827            {
1828              if (children[j] == child)
1829                {
1830                  unknown = false;
1831                  break;
1832                }
1833            }
1834          if (unknown)
1835            {
1836              children.push_back (child);
1837            }
1838        }
1839    }
1840
1841  visit (offset, order, children);
1842}
1843
1844//----------------------------------------------------------
1845void Project::start_visit (IProjectVisitor& visitor)
1846{
1847  static Project::ProjectVector& Projects = Project::projects ();
1848 
1849  for (int i = 0; i < Projects.size (); i++)
1850    {
1851      Project& p = Projects[i];
1852      p.m_visited = false;
1853      p.m_visits = 0;
1854    }
1855
1856  Project* p = get_current ();
1857
1858  if (p == 0)
1859    {
1860      if (Projects.size () == 0) return;
1861
1862      p = &(Projects[0]);
1863    }
1864
1865  //  visitor.pre (p);
1866  //p->visit (visitor);
1867  //  visitor.post (p);
1868  visitor.in (p);
1869  p->m_visits++;
1870  ProjectPtrVector projs;
1871  projs.push_back (p);
1872  visit (visitor, projs);
1873}
1874
1875//----------------------------------------------------------
1876class VisitorForFillCMTPATH : public IProjectVisitor
1877{
1878public:
1879  VisitorForFillCMTPATH (cmt_string& buffer) : m_buffer (buffer)
1880  {
1881    buffer = "path CMTPATH \"\" \n";
1882  }
1883
1884  void pre (Project* p)
1885  {
1886    const cmt_string& w = p->get_cmtpath_pwd ();
1887    const cmt_string& s = p->get_cmtpath_source ();
1888
1889    if (s == "default path") return;
1890
1891    if (CmtSystem::test_directory (w))
1892      {
1893        m_buffer += "path_append CMTPATH \"";
1894        m_buffer += w;
1895        m_buffer += "\" \n";
1896      }
1897  }
1898
1899  void in (Project* p)
1900  {
1901    const cmt_string& w = p->get_cmtpath_pwd ();
1902    const cmt_string& s = p->get_cmtpath_source ();
1903
1904    if (s == "default path") return;
1905
1906    if (CmtSystem::test_directory (w))
1907      {
1908        m_buffer += "path_append CMTPATH \"";
1909        m_buffer += w;
1910        m_buffer += "\" \n";
1911      }
1912  }
1913
1914  void in_again (Project* p)
1915  {
1916    const cmt_string& w = p->get_cmtpath_pwd ();
1917    const cmt_string& s = p->get_cmtpath_source ();
1918
1919    if (s == "default path") return;
1920
1921    if (CmtSystem::test_directory (w))
1922      {
1923        m_buffer += "path_remove CMTPATH \"";
1924        m_buffer += w;
1925        m_buffer += "\" \n";
1926        m_buffer += "path_append CMTPATH \"";
1927        m_buffer += w;
1928        m_buffer += "\" \n";
1929      }
1930  }
1931
1932  void post (Project* p)
1933  {
1934    //cerr << "Buffer = " << m_buffer << endl;
1935  }
1936
1937private:
1938  cmt_string& m_buffer;
1939
1940};
1941
1942//----------------------------------------------------------
1943void Project::fill_cmtpaths (cmt_string& buffer)
1944{
1945  /*
1946    Try to re-create all CMTPATH items from project definitions.
1947    The goal is to generate CMTPATH even if this EV was not pre-set
1948    which is the case when CMTPROJECTPATH is only used
1949  */
1950
1951  /*
1952  VisitorForFillCMTPATH visitor (buffer);
1953
1954  start_visit (visitor);
1955  */
1956  const ProjectPtrVector& Ordered = Project::ordered_projects ();
1957
1958  buffer = "path CMTPATH \"\" \n";
1959  for (int i = 0; i < Ordered.size (); i++)
1960    {
1961      const Project* p = Ordered[i];
1962      const cmt_string& w = p->get_cmtpath_pwd ();
1963      const cmt_string& s = p->get_cmtpath_source ();
1964     
1965      if (s == "default path") continue;
1966     
1967      if (CmtSystem::test_directory (w))
1968        {
1969          buffer += "path_append CMTPATH \"";
1970          buffer += w;
1971          buffer += "\" \n";
1972        }
1973    }
1974}
1975
1976//----------------------------------------------------------
1977Project::Project () : m_name (""), m_author("")
1978{
1979  clear ();
1980}
1981
1982//----------------------------------------------------------
1983const cmt_string& Project::get_name () const
1984{
1985  return (m_name);
1986}
1987
1988//----------------------------------------------------------
1989const cmt_string& Project::get_release () const
1990{
1991  return (m_release);
1992}
1993
1994//----------------------------------------------------------
1995const cmt_string& Project::get_container_name () const
1996{
1997  return (m_container_name);
1998}
1999
2000//----------------------------------------------------------
2001const cmt_string& Project::get_container_version () const
2002{
2003  return (m_container_version);
2004}
2005
2006//----------------------------------------------------------
2007const cmt_string& Project::get_container_path () const
2008{
2009  return (m_container_path);
2010}
2011
2012//----------------------------------------------------------
2013const Use& Project::get_container () const
2014{
2015  return (m_container);
2016}
2017
2018//----------------------------------------------------------
2019const cmt_string& Project::get_cmtpath () const
2020{
2021  return (m_cmtpath);
2022}
2023
2024//----------------------------------------------------------
2025const cmt_string& Project::get_cmtpath_real () const
2026{
2027  return (m_cmtpath_real);
2028}
2029
2030//----------------------------------------------------------
2031const cmt_string& Project::get_cmtpath_pwd () const
2032{
2033  return (m_cmtpath_pwd);
2034}
2035
2036//----------------------------------------------------------
2037const cmt_string& Project::get_cmtpath_source () const
2038{
2039  return (m_cmtpath_source);
2040}
2041
2042//----------------------------------------------------------
2043int Project::get_children_size () const
2044{
2045  return (m_children.size ());
2046}
2047
2048//----------------------------------------------------------
2049Project* Project::get_child (int index) const
2050{
2051  if (index < 0) return (0);
2052  if (index >= m_children.size ()) return (0);
2053  return (m_children[index]);
2054}
2055
2056//----------------------------------------------------------
2057bool Project::visited () const
2058{
2059  return (m_visited);
2060}
2061
2062//----------------------------------------------------------
2063void Project::set_name (const cmt_string& name)
2064{
2065  m_name = name;
2066}
2067
2068//----------------------------------------------------------
2069void Project::set_release (const cmt_string& release)
2070{
2071  m_release = release;
2072}
2073
2074//----------------------------------------------------------
2075void Project::set_container_name (const cmt_string& name)
2076{
2077  m_container_name = name;
2078}
2079
2080//----------------------------------------------------------
2081void Project::set_container_version (const cmt_string& container_version)
2082{
2083  m_container_version = container_version;
2084}
2085
2086//----------------------------------------------------------
2087void Project::set_container_path (const cmt_string& container_path)
2088{
2089  m_container_path = container_path;
2090}
2091
2092//----------------------------------------------------------
2093void Project::set_cmtpath (const cmt_string& path)
2094{
2095  m_cmtpath = path;
2096}
2097
2098//----------------------------------------------------------
2099void Project::set_cmtpath_real (const cmt_string& path)
2100{
2101  m_cmtpath_real = path;
2102}
2103
2104//----------------------------------------------------------
2105void Project::set_cmtpath_pwd (const cmt_string& path)
2106{
2107  m_cmtpath_pwd = path;
2108}
2109
2110//----------------------------------------------------------
2111void Project::set_cmtpath_source (const cmt_string& source)
2112{
2113  m_cmtpath_source = source;
2114}
2115
2116//----------------------------------------------------------
2117void Project::set_is_current (bool is_current)
2118{
2119  m_is_current = is_current;
2120}
2121
2122//----------------------------------------------------------
2123bool Project::is_current () const
2124{
2125  return m_is_current;
2126}
2127
2128//----------------------------------------------------------
2129void Project::clear ()
2130{
2131  m_name    = "";
2132  m_release = "";
2133  m_cmtpath = "";
2134  m_cmtpath_real = "";
2135  m_cmtpath_pwd    = "";
2136  m_cmtpath_source = "";
2137  m_use            = 0;
2138
2139  m_parents.clear ();
2140  m_children.clear ();
2141
2142  m_configured = false;
2143
2144  m_strategies.clear ();
2145  m_is_current = false;
2146}
2147
2148//----------------------------------------------------------
2149bool Project::has_parents () const
2150{
2151  return ((m_parents.size () > 0));
2152}
2153
2154//----------------------------------------------------------
2155bool Project::has_parent (Project* p) const
2156{
2157  if (p == 0) return (false);
2158  if (p == this) return (false);
2159
2160  const cmt_string& name = p->get_name ();
2161
2162  int i;
2163
2164  for (i = 0; i < m_parents.size (); i++)
2165    {
2166      const Project* parent = m_parents[i];
2167      if (parent == 0) continue;
2168
2169      if (parent->get_name () == name)
2170        {
2171          // registered as a parent
2172          return (true);
2173        }
2174
2175      if (parent->has_parent (p))
2176        {
2177          // recurse
2178          return (true);
2179        }
2180    }
2181
2182  return (false);
2183}
2184
2185//----------------------------------------------------------
2186bool Project::has_child (Project* p) const
2187{
2188  if (p == 0) return (false);
2189  if (p == this) return (false);
2190
2191  const cmt_string& name = p->get_name ();
2192
2193  int i;
2194
2195  for (i = 0; i < m_children.size (); i++)
2196    {
2197      const Project* child = m_children[i];
2198      if (child == 0) continue;
2199
2200      if (child->get_name () == name)
2201        {
2202          // registered as a child
2203          return (true);
2204        }
2205
2206      if (child->has_child (p))
2207        {
2208          // recurse
2209          return (true);
2210        }
2211    }
2212
2213  return (false);
2214}
2215
2216//----------------------------------------------------------
2217void Project::add_parent (Project* p)
2218{
2219  if (p == 0) return;
2220  if (p == this) return;
2221
2222  //cerr << "Adding parent " << p->get_name () << " to " << m_name << endl;
2223
2224  if (has_child (p)) return;
2225  if (has_parent (p)) return;
2226
2227  m_parents.push_back (p);
2228}
2229
2230//----------------------------------------------------------
2231void Project::add_child (Project* p)
2232{
2233  if (p == 0) return;
2234  if (p == this) return;
2235
2236  if (has_child (p)) return;
2237  if (has_parent (p)) return;
2238
2239  m_children.push_back (p);
2240}
2241
2242//----------------------------------------------------------
2243void Project::erase_child (Project* p)
2244{
2245  if (p == 0) return;
2246  if (p == this) return;
2247
2248  if (!has_child (p)) return;
2249
2250  const cmt_string& name = p->get_name ();
2251
2252  for (int i = 0; i < m_children.size (); i++)
2253    {
2254      const Project* child = m_children[i];
2255      if (child == 0) continue;
2256
2257      if (child->get_name () == name)
2258        {
2259          // registered as a child
2260          m_children.erase (i);
2261          break;
2262        }
2263    }
2264}
2265
2266//----------------------------------------------------------
2267void Project::configure ()
2268{
2269  if (m_configured) return;
2270  m_configured = true;
2271
2272  set_default_strategy ("SetupConfig");
2273  set_default_strategy ("SetupRoot");
2274  set_default_strategy ("SetupCleanup");
2275  set_default_strategy ("SetupScripts");
2276  set_default_strategy ("BuildPrototypes");
2277  set_default_strategy ("InstallArea");
2278  set_default_strategy ("VersionDirectory");
2279}
2280
2281/**---------------------------------------------------------
2282   A container statement is met in the project file
2283*/
2284void Project::container_action (const CmtSystem::cmt_string_vector& words)
2285//void Project::container_action (const cmt_string& name, const cmt_string& version)
2286{
2287  //
2288  // complete syntax : "container <package> <version> <path>" 
2289  // minimal syntax  : "container <package>"
2290  //
2291  //  o if <version> is omitted then take any version available
2292  //  o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
2293  //
2294  //  o the notation "v*" is preferred to omission (particularly since
2295  //    omission does not permit <path>)
2296  //
2297  Use* use = &m_container;
2298  use->~Use ();
2299  if (words.size () < 2) return;
2300
2301  CmtSystem::cmt_string_vector ewords;
2302  for (int i = 1; i < words.size (); i++)
2303    {
2304      const cmt_string& w = words[i];
2305      cmt_string ew = w;
2306
2307      Symbol::expand (ew);
2308      if (ew != w)
2309        {
2310          CmtSystem::cmt_string_vector ws;
2311          CmtSystem::split (ew, " ", ws);
2312
2313          for (int j = 0; j < ws.size (); ++j)
2314            {
2315              ewords.push_back (ws[j]);
2316            }
2317        }
2318      else
2319        {
2320          ewords.push_back (w);
2321        }
2322    }
2323
2324  cmt_string name, version, path;
2325  if (ewords.size () > 0) name = ewords[0];
2326  if (ewords.size () > 1) version = ewords[1];
2327  if (ewords.size () > 2) path = ewords[2];
2328
2329  if (name != "")
2330    {
2331      use->set (name, version, path);
2332      use->get_package ()->remove_use (use);
2333      CmtSystem::cd (m_cmtpath_pwd);
2334      if (use->move_to ("", true) &&
2335          !CmtSystem::absolute_path (use->real_path))
2336        {
2337          use->change_path (m_cmtpath_pwd);
2338        }
2339      CmtSystem::cd (m_cmtpath_pwd + CmtSystem::file_separator () + "cmt");
2340    }
2341
2342  set_container_name (name);
2343  set_container_version (version);
2344  set_container_path (path);
2345}
2346
2347/**---------------------------------------------------------
2348   A use statement is met in the project file
2349*/
2350void Project::use_action (const cmt_string& name, const cmt_string& release)
2351{
2352  if (Cmt::get_debug ())
2353    {
2354      cout << "Use action " << name << " " << release << endl;
2355    }
2356
2357  // A project with its release is specified
2358  //
2359  // Is this project already visible?
2360  // If not: look for it
2361  //   + get CMTPROJECTPATH
2362  //   + search from all entries of CMTPROJECTPATH : p(i)/<name>/<release>
2363  //   + when found, this should become a new CMTPATH entry
2364  //   +             the new project is then parsed ... etc...
2365
2366  // First test it wilcard is used
2367  int v = -1;
2368  int r = -1;
2369  int p = -1;
2370  cmt_string new_release = release;
2371  CmtSystem::is_version_directory (new_release, v, r, p); 
2372  bool use_has_wild_card = (v == -1) || (r == -1) || (p == -1);
2373  if (use_has_wild_card)
2374    {
2375      cmt_string selected_release = "";
2376
2377      if (select_release(name, new_release,selected_release))
2378        {
2379          // cerr <<"selected_release: "<<selected_release<<endl;   
2380          new_release = selected_release;
2381        }         
2382    }
2383
2384  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2385  cmt_string sep;
2386  sep = CmtSystem::path_separator ();
2387
2388  CmtSystem::cmt_string_vector items;
2389  CmtSystem::split (cmtprojectpath, sep, items);
2390
2391  bool found = false;
2392
2393  for (int i = 0; i < items.size (); i++)
2394    {
2395      const cmt_string& item = items[i];
2396      cmt_string p = item;
2397      p += CmtSystem::file_separator ();
2398      p += name;
2399      if (new_release != "")
2400        {
2401          p += CmtSystem::file_separator ();
2402          p += new_release;
2403        }
2404
2405      if (CmtSystem::test_directory (p))
2406        {
2407          //cerr << "Project directory " << p << " exists " << endl;
2408
2409          found = true;
2410
2411          IProjectFactory& factory = ProjectFactory::instance ();
2412
2413          factory.create_project (name, p, "ProjectPath", this);
2414
2415          break;
2416        }
2417    }
2418
2419  if (!found)
2420    {
2421      Project* p = Project::find_by_name (name);
2422
2423      if (p != 0)
2424        {
2425          found = true;
2426          p->add_parent (this);
2427          add_child (p);
2428
2429          update_strategies_from_children ();
2430        }
2431    }
2432   
2433  if (!found && (cmtprojectpath != ""))
2434    {
2435      CmtMessage::warning ("Project " + name + " " + release + " requested by " + m_name + " not found in CMTPROJECTPATH");
2436      //      cerr << "#CMT> Project " << name << " " << release << " requested by " << m_name << " not found in CMTPROJECTPATH" << endl;
2437    }
2438}
2439
2440//---------------------------------------------------------
2441bool Project::select_release(const cmt_string& name, const cmt_string& release, cmt_string& result)
2442{
2443  cmt_string selected_release = "";
2444
2445  int v = -1;
2446  int r = -1;
2447  int p = -1;
2448  CmtSystem::is_version_directory (release, v, r, p); 
2449
2450  int selected_v = -1;
2451  int selected_r = -1;
2452  int selected_p = -1;
2453  CmtSystem::cmt_string_vector releases = get_project_releases(name);
2454  for (int j = 0; j < releases.size (); j++)
2455    {
2456      int new_v = -1;
2457      int new_r = -1;
2458      int new_p = -1;
2459      CmtSystem::is_version_directory (releases[j], new_v, new_r, new_p);
2460      if (v == -1)
2461        {
2462          if (selected_v < new_v)
2463            {
2464              selected_v = new_v;
2465              selected_r = -1;
2466              selected_p = -1;
2467              selected_release = releases[j];
2468            }
2469          else if (selected_v == new_v)
2470            {
2471              // We compare the r
2472              if (selected_r < new_r)
2473                {
2474                  selected_r = new_r;
2475                  selected_p = -1;
2476                  selected_release = releases[j];                               
2477                }
2478              else if (selected_r == new_r)
2479                {
2480                  // We compare the p
2481                  if (selected_p < new_p)
2482                    {
2483                      selected_p = new_p;
2484                      selected_release = releases[j];                               
2485                    }
2486                  // else if ? not possible                                                           
2487                }                               
2488            }
2489        }
2490      else if (r == -1)
2491        {
2492          if (v == new_v)
2493            {
2494              // We compare the r                                                     
2495              if (selected_r < new_r)
2496                {
2497                  selected_r = new_r;
2498                  selected_p = -1;
2499                  selected_release = releases[j];                               
2500                }
2501              else if (selected_r == new_r)
2502                { 
2503                  // We compare the p
2504                  if (selected_p < new_p)
2505                    {
2506                      selected_p = new_p;
2507                      selected_release = releases[j];                               
2508                    }
2509                  // else if ? not possible
2510                }
2511            }
2512        }
2513      else if (p == -1)
2514        {
2515          if ((v == new_v) && (r == new_r))
2516            { 
2517              // We compare the p
2518              if (selected_p < new_p)
2519                {
2520                  selected_p = new_p;
2521                  selected_release = releases[j];                               
2522                }
2523              // else if ? not possible
2524            }       
2525        }       
2526
2527      //cerr << "v:" << new_v << ", r:" << new_r << ", p:" << new_p << endl;             
2528      //cerr << "req v:" << v << ", req r:" << r << ", req p:" << p << endl;       
2529
2530    }
2531
2532  // cerr << "selected release: " << selected_release << endl; 
2533
2534  if (selected_release == "") return false;
2535
2536  result = selected_release;   
2537
2538  return (true);
2539}
2540
2541//---------------------------------------------------------
2542const CmtSystem::cmt_string_vector Project::get_project_releases (const cmt_string& name) const
2543{
2544  CmtSystem::cmt_string_vector releases;
2545  cmt_string cmtprojectpath = Symbol::get_env_value ("CMTPROJECTPATH");
2546
2547  static cmt_string sep = CmtSystem::path_separator ();
2548
2549  CmtSystem::cmt_string_vector items;
2550  CmtSystem::split (cmtprojectpath, sep, items);   
2551
2552  for (int i = 0; i < items.size (); i++)
2553    {
2554      const cmt_string& item = items[i];
2555      cmt_string p = item;
2556      p += CmtSystem::file_separator ();
2557      p += name;
2558
2559      if (CmtSystem::test_directory (p))
2560        { 
2561          CmtSystem::cmt_string_vector directories;
2562          CmtSystem::scan_dir (p, directories);
2563
2564          for (int j = 0; j < directories.size (); j++)
2565            {
2566              if  (CmtSystem::test_directory(directories[j]))
2567                {
2568                  cmt_string release;
2569                  CmtSystem:: basename(directories[j], release);
2570
2571                  if (CmtSystem::is_version_directory(release))
2572                    {                             
2573                      cmt_string& name_entry = releases.add ();
2574                      name_entry = release; 
2575                    }             
2576                }                           
2577            }                           
2578        }
2579    }
2580  return (releases);
2581}
2582
2583//----------------------------------------------------------
2584Project& Project::operator = (const Project& other)
2585{
2586  m_name = other.m_name;
2587  m_cmtpath = other.m_cmtpath;
2588  m_cmtpath_real = other.m_cmtpath_real;
2589  m_cmtpath_pwd = other.m_cmtpath_pwd;
2590  m_cmtpath_source = other.m_cmtpath_source;
2591
2592  return (*this);
2593}
2594
2595//----------------------------------------------------------
2596bool Project::operator == (const cmt_string& name) const
2597{
2598  return ((m_name == name));
2599}
2600
2601//----------------------------------------------------------
2602bool Project::operator != (const cmt_string& name) const
2603{
2604  return ((m_name != name));
2605}
2606
2607//----------------------------------------------------------
2608void Project::show (PrintMode mode)
2609//void Project::show ()
2610{
2611  if (m_visited) return;
2612  m_visited = true;
2613
2614  static int level = 0;
2615
2616  //  bool is_current = false;
2617
2618  //  cmt_string here = CmtSystem::pwd ();
2619  // In case there are symlinks
2620  /*
2621  cmt_string here_real;
2622  CmtSystem::realpath_ (CmtSystem::pwd (), here_real);
2623
2624  //  if (here.find (m_cmtpath) == 0)
2625  if (here_real.find (m_cmtpath_real) == 0)
2626    {
2627      if (m_cmtpath_source != "default path")
2628        {
2629          is_current = true;
2630        }
2631    }
2632  */
2633  switch (mode)
2634    {
2635    case Xml :
2636      cout << "<project" << (m_is_current ? " current=\"yes\"" : "") << ">";
2637      //      if (m_order >= 0)
2638      cout << "<order>" << m_order << "</order>";
2639      cout << "<name>" << m_name << "</name><version>" << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << "</version><cmtpath>" << m_cmtpath << "</cmtpath>";
2640      break;
2641    default :
2642  for (int tab = 0; tab < level; tab++) cout << "  ";
2643  cout << m_name << " " << (m_name != "CMTUSERCONTEXT" && m_name != "CMTHOME" ? m_release : "v0") << " (in " << m_cmtpath << ")";
2644  //  cout << m_name << " " << m_release << " (in " << m_cmtpath << ")";
2645
2646  if (m_is_current) cout << " (current)";
2647  //  if (is_current) cout << " (current)";
2648      break;
2649    }
2650
2651  int i;
2652
2653  switch (mode)
2654    {
2655    case Xml :
2656      cout << "<clients>";
2657      break;
2658    }
2659  for (i = 0; i < m_parents.size (); i++)
2660    {
2661      Project* p = m_parents[i];
2662      if (p == 0) continue;
2663      switch (mode)
2664        {
2665        case Xml :
2666          //      cout << "<name>" << p->get_name () << "</name>";
2667          cout << "<project" << (p->is_current () ? " current=\"yes\"" : "") << ">";
2668          //  if (p->m_order >= 0)
2669          cout << "<order>" << p->m_order << "</order>";
2670          cout << "<name>" << p->get_name () << "</name><version>" << (p->get_name () != "CMTUSERCONTEXT" && p->get_name () != "CMTHOME" ? p->get_release () : "v0") << "</version><cmtpath>" << p->get_cmtpath () << "</cmtpath>";
2671          cout << "</project>";
2672          break;
2673        default :
2674      cout << " P=" << p->get_name ();
2675          break;
2676        }
2677    }
2678  switch (mode)
2679    {
2680    case Xml :
2681      cout << "</clients>";
2682      break;
2683    }
2684
2685  switch (mode)
2686    {
2687    case Xml :
2688      cout << "<uses>";
2689      break;
2690    }
2691  for (i = 0; i < m_children.size (); i++)
2692    {
2693      Project* p = m_children[i];
2694      if (p == 0) continue;
2695      switch (mode)
2696        {
2697        case Xml :
2698          //      cout << "<name>" << p->get_name () << "</name>";
2699          cout << "<project" << (p->is_current () ? " current=\"yes\"" : "") << ">";
2700          //      if (p->m_order >= 0)
2701          cout << "<order>" << p->m_order << "</order>";
2702          cout << "<name>" << p->get_name () << "</name><version>" << (p->get_name () != "CMTUSERCONTEXT" && p->get_name () != "CMTHOME" ? p->get_release () : "v0") << "</version><cmtpath>" << p->get_cmtpath () << "</cmtpath>";
2703          cout << "</project>";
2704          break;
2705        default :
2706      cout << " C=" << p->get_name ();
2707          break;
2708        }
2709    }
2710  switch (mode)
2711    {
2712    case Xml :
2713      cout << "</uses>";
2714      cout << "</project>";
2715      break;
2716    default :
2717  cout << endl;
2718      break;
2719    }
2720
2721
2722/*
2723  if (m_visited) return;
2724
2725  m_visited = true;
2726*/
2727
2728  for (i = 0; i < m_children.size (); i++)
2729    {
2730      Project* p = m_children[i];
2731      if (p == 0) continue;
2732      level++;
2733      p->show (mode);
2734      //      p->show ();
2735      level--;
2736    }
2737}
2738
2739
2740//----------------------------------------------------------
2741void Project::show_specified_strategies () const
2742{
2743  int i;
2744
2745  for (i = 0; i < m_strategies.size (); i++)
2746    {
2747      const Strategy& s = m_strategies[i];
2748      if (s.m_specified)
2749        {
2750          const StrategyDef* def = s.m_definition;
2751 
2752          cout << "# Project " << m_name
2753               << " sets " << def->m_keyword
2754               << " strategy to " << ((s.m_value) ? def->m_on_value : def->m_off_value);
2755
2756          if (s.m_context != "")
2757            {
2758              cout << " (from package " << s.m_context << ")";
2759            }
2760
2761          cout << endl;
2762        }
2763    }
2764}
2765
2766//----------------------------------------------------------
2767bool Project::has_strategy (const StrategyDef* definition) const
2768{
2769  int i;
2770
2771  for (i = 0; i < m_strategies.size (); i++)
2772    {
2773      const Strategy& s = m_strategies[i];
2774      if (s.m_definition == definition)
2775        {
2776          return (true);
2777        }
2778    }
2779
2780  return (false);
2781}
2782
2783//----------------------------------------------------------
2784bool Project::get_strategy (const cmt_string& name) const
2785{
2786  static StrategyMgr& mgr = StrategyMgr::instance ();
2787
2788  StrategyDef* def = mgr.find_strategy (name);
2789  if (def == 0)
2790    {
2791      CmtMessage::warning ("strategy " + name + " undefined");
2792      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2793      return (false);
2794    }
2795
2796  return (get_strategy (def));
2797}
2798
2799//----------------------------------------------------------
2800bool Project::is_specified (const StrategyDef* definition) const
2801{
2802  int i;
2803
2804  for (i = 0; i < m_strategies.size (); i++)
2805    {
2806      Strategy& s = m_strategies[i];
2807      if (s.m_definition == definition)
2808        {
2809          // This strategy is applied in this project
2810          return (s.m_specified);
2811        }
2812    }
2813
2814  // This strategy is not applied in this project
2815  return (false);
2816}
2817
2818//----------------------------------------------------------
2819bool Project::get_strategy (const StrategyDef* def) const
2820{
2821  int i;
2822
2823  for (i = 0; i < m_strategies.size (); i++)
2824    {
2825      Strategy& s = m_strategies[i];
2826      if (s.m_definition == def)
2827        {
2828          // This strategy is applied in this project
2829          if (s.m_specified)
2830            {
2831              return (s.m_specified_value);
2832            }
2833          return (s.m_value);
2834        }
2835    }
2836
2837  // This strategy is not applied in this project
2838  return (def->m_default_value);
2839}
2840
2841//----------------------------------------------------------
2842void Project::set_default_strategy (const cmt_string& name)
2843{
2844  static StrategyMgr& mgr = StrategyMgr::instance ();
2845
2846  StrategyDef* def = mgr.find_strategy (name);
2847  if (def == 0)
2848    {
2849      CmtMessage::warning ("strategy " + name + " undefined");
2850      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2851      return;
2852    }
2853
2854  update_strategy (def, def->m_default_value);
2855}
2856
2857
2858//----------------------------------------------------------
2859void Project::set_strategy (const cmt_string& name, const cmt_string& value, const cmt_string& context)
2860{
2861  static StrategyMgr& mgr = StrategyMgr::instance ();
2862
2863  StrategyDef* def = mgr.find_strategy (name);
2864  if (def == 0)
2865    {
2866      CmtMessage::warning ("strategy " + name + " undefined");
2867      //      cerr << "#CMT> strategy " << name << " undefined" << endl;
2868      return;
2869    }
2870
2871  bool b_value = false;
2872
2873  if (value == def->m_on_value)
2874    {
2875      b_value = true;
2876    }
2877  else if (value == def->m_off_value)
2878    {
2879      b_value = false;
2880    }
2881  else
2882    {
2883      CmtMessage::warning ("requested strategy value " + value + " undefined in strategy " + name);
2884      //      cerr << "#CMT> requested strategy value " << value << " undefined in strategy " << name << endl;
2885      return;
2886    }
2887
2888  set_strategy (def, b_value, context);
2889}
2890
2891//----------------------------------------------------------
2892void Project::set_strategy (StrategyDef* definition, bool b_value, const cmt_string& context)
2893{
2894  bool need_strategy = true;
2895
2896  int i;
2897
2898  for (i = 0; i < m_strategies.size (); i++)
2899    {
2900      Strategy& s = m_strategies[i];
2901      if (s.m_definition == definition)
2902        {
2903          // This strategy is already applied in this project. Let's change it's value
2904          s.set (definition, b_value, get_name ());
2905          if (context != "")
2906            {
2907              if (s.m_context != "") s.m_context += " ";
2908              s.m_context += context;
2909            }
2910          need_strategy = false;
2911          break;
2912        }
2913    }
2914
2915  if (need_strategy)
2916    {
2917      // This strategy is not yet applied in this project.
2918
2919      Strategy& s = m_strategies.add ();
2920      s.clear ();
2921      s.set (definition, b_value, get_name ());
2922      s.m_context = context;
2923    }
2924 
2925  for (i = 0; i < m_parents.size (); i++)
2926    {
2927      Project* project = m_parents[i];
2928
2929      project->update_strategy (definition, b_value);
2930    }
2931}
2932
2933/**----------------------------------------------------------
2934   The strategy value is changed because of indirect influences
2935   - default strategy at initialization time
2936   - change in the children
2937   - change in the children list
2938
2939   (This is not a specification : see the set_strategy method)
2940*/
2941void Project::update_strategy (StrategyDef* definition, bool b_value)
2942{
2943  bool need_strategy = true;
2944  bool specified = false;
2945
2946  int i;
2947
2948  for (i = 0; i < m_strategies.size (); i++)
2949    {
2950      Strategy& s = m_strategies[i];
2951      if (s.m_definition == definition)
2952        {
2953          need_strategy = false;
2954
2955          if (!s.m_specified)
2956            {
2957              // This strategy is already applied in this project. Let's change it's value
2958              s.update (definition, b_value, get_name ());
2959            }
2960          else
2961            {
2962              specified = true;
2963            }
2964          break;
2965        }
2966    }
2967
2968  if (need_strategy)
2969    {
2970      // This strategy is not yet applied in this project.
2971
2972      Strategy& s = m_strategies.add ();
2973      s.clear ();
2974      s.update (definition, b_value, get_name ());
2975    }
2976
2977  if (!specified)
2978    {
2979      for (i = 0; i < m_parents.size (); i++)
2980        {
2981          Project* project = m_parents[i];
2982
2983          project->update_strategy (definition, b_value);
2984        }
2985    }
2986}
2987
2988/**----------------------------------------------------------
2989   At least one of the children has changed this strategy
2990   Or the list of children has changed.
2991   We need to update the strategy value accordingly
2992   This will not change the specified value for this strategy
2993*/
2994void Project::update_strategy_from_children (StrategyDef* definition)
2995{
2996  // If this strategy is specified we don't care what happens from the children
2997
2998  //cerr << "Updating strategy " << definition->m_name << " from children for project " << m_name << endl;
2999
3000  int i;
3001
3002  for (i = 0; i < m_strategies.size (); i++)
3003    {
3004      Strategy& s = m_strategies[i];
3005      if (s.m_definition == definition)
3006        {
3007          // This strategy is applied in this project.
3008
3009          if (s.m_specified)
3010            {
3011              // There will be no impact since the strategy is specified
3012
3013              //cerr << "This strategy is specified in this project" << endl;
3014              return;
3015            }
3016
3017          break;
3018        }
3019    }
3020
3021  // The strategy is not specified locally so we will now figure out
3022  // which strategy has to be considered from the mixture of specifications
3023  // from all children.
3024
3025  // Algorithm:
3026  // - We consider children by pairs
3027  // - a child that specifies its strategy wins over a child that does not
3028  // - when the two children have the same level of priority we consider the priority value
3029
3030  Project* selected = 0;
3031  bool selected_is_specified = false;
3032  bool selected_value = definition->m_default_value;
3033
3034  for (i = 0; i < m_children.size (); i++)
3035    {
3036      Project* p = m_children[i];
3037
3038      //cerr << "Checking strategy for child " << p->get_name () << endl;
3039
3040      bool is_specified = p->is_specified (definition);
3041      bool value = p->get_strategy (definition);
3042
3043      if (selected == 0)
3044        {
3045          selected = p;
3046          selected_is_specified = is_specified;
3047          selected_value = value;
3048          continue;
3049        }
3050
3051      if (is_specified == selected_is_specified)
3052        {
3053          if (selected_value != value)
3054            {
3055              // same level of priority but different values -> we must decide
3056              bool priority_value = definition->m_priority_value;
3057              if (value == priority_value)
3058                {
3059                  selected = p;
3060                  selected_is_specified = is_specified;
3061                  selected_value = value;
3062                }
3063            }
3064        }
3065      else
3066        {
3067          if (is_specified)
3068            {
3069              selected = p;
3070              selected_is_specified = is_specified;
3071              selected_value = value;
3072            }
3073        }
3074    }
3075
3076  update_strategy (definition, selected_value); 
3077}
3078
3079/**----------------------------------------------------------
3080   At least one of the children has changed its strategies
3081   Or the list of children has changed.
3082   We need to update the strategy values accordingly
3083   This will not change the specified values
3084*/
3085void Project::update_strategies_from_children ()
3086{
3087  StrategyDef::StrategyDefs& defs = StrategyMgr::get_definitions ();
3088
3089  //cerr << "Updating strategies from children for project " << m_name << endl;
3090
3091  int i;
3092
3093  for (i = 0; i < defs.size (); i++)
3094    {
3095      StrategyDef* def = defs[i];
3096     
3097      update_strategy_from_children (def);
3098    }
3099
3100  for (i = 0; i < m_parents.size (); i++)
3101    {
3102      Project* p = m_parents[i];
3103      p->update_strategies_from_children ();
3104    }
3105}
3106
3107/**----------------------------------------------------------
3108   The StrategyMgr singleton
3109*/
3110StrategyMgr& StrategyMgr::instance ()
3111{
3112  static StrategyMgr me;
3113  return (me);
3114}
3115
3116/**----------------------------------------------------------
3117   The StrategyMgr constructor
3118   Here are primarily constructed all strategy definitions
3119*/
3120StrategyMgr::StrategyMgr ()
3121{
3122  m_defs.clear ();
3123
3124  StrategyDef* s;
3125
3126  s = new StrategyDef;
3127  s->m_keyword = "build";
3128  s->m_name = "BuildPrototypes";
3129  s->m_on_value = "prototypes";
3130  s->m_off_value = "no_prototypes";
3131  s->m_default_value = true;
3132  s->m_priority_value = false;
3133
3134  m_defs.push_back (s);
3135
3136  s = new StrategyDef;
3137  s->m_keyword = "build";
3138  s->m_name = "InstallArea";
3139  s->m_on_value = "with_installarea";
3140  s->m_off_value = "without_installarea";
3141  s->m_default_value = false;
3142  s->m_priority_value = true;
3143
3144  m_defs.push_back (s);
3145
3146  s = new StrategyDef;
3147  s->m_keyword = "setup";
3148  s->m_name = "SetupConfig";
3149  s->m_on_value = "config";
3150  s->m_off_value = "no_config";
3151  s->m_default_value = true;
3152  s->m_priority_value = false;
3153
3154  m_defs.push_back (s);
3155
3156  s = new StrategyDef;
3157  s->m_keyword = "setup";
3158  s->m_name = "SetupRoot";
3159  s->m_on_value = "root";
3160  s->m_off_value = "no_root";
3161  s->m_default_value = true;
3162  s->m_priority_value = false;
3163
3164  m_defs.push_back (s);
3165
3166  s = new StrategyDef;
3167  s->m_keyword = "setup";
3168  s->m_name = "SetupCleanup";
3169  s->m_on_value = "cleanup";
3170  s->m_off_value = "no_cleanup";
3171  s->m_default_value = true;
3172  s->m_priority_value = false;
3173
3174  m_defs.push_back (s);
3175
3176  s = new StrategyDef;
3177  s->m_keyword = "setup";
3178  s->m_name = "SetupScripts";
3179  s->m_on_value = "scripts";
3180  s->m_off_value = "no_scripts";
3181  s->m_default_value = true;
3182  s->m_priority_value = false;
3183
3184  m_defs.push_back (s);
3185
3186  s = new StrategyDef;
3187  s->m_keyword = "structure";
3188  s->m_name = "VersionDirectory";
3189  s->m_on_value = "with_version_directory";
3190  s->m_off_value = "without_version_directory";
3191  if (Cmt::get_current_structuring_style () != without_version_directory)
3192    {
3193      s->m_default_value = true;
3194      s->m_priority_value = false;
3195    }
3196  else
3197    {
3198      s->m_default_value = false;
3199      s->m_priority_value = true;
3200    }
3201
3202  m_defs.push_back (s);
3203}
3204
3205/**----------------------------------------------------------
3206   Find a strategy definition by its name
3207*/
3208StrategyDef* StrategyMgr::find_strategy (const cmt_string& name)
3209{
3210  static StrategyMgr& me = instance ();
3211
3212  int i;
3213
3214  for (i = 0; i < me.m_defs.size (); i++)
3215    {
3216      StrategyDef* def = me.m_defs[i];
3217      if (def->m_name == name)
3218        {
3219          return (def);
3220        }
3221    }
3222
3223  return (0);
3224}
3225
3226/**----------------------------------------------------------
3227   Retreive the default value defined for a given strategy
3228*/
3229bool StrategyMgr::get_default_strategy (const cmt_string& name)
3230{
3231  StrategyDef* def = find_strategy (name);
3232  if (def == 0) return (false);
3233  return (def->m_default_value);
3234}
3235
3236/**----------------------------------------------------------
3237   Retreive the priority value defined for a given strategy
3238   This value is used when two children of a project request two conflicting strategy values
3239*/
3240bool StrategyMgr::get_priority_strategy (const cmt_string& name)
3241{
3242  StrategyDef* def = find_strategy (name);
3243  if (def == 0) return (false);
3244  return (def->m_priority_value);
3245}
3246
3247/**----------------------------------------------------------
3248   Return the vector of all existing strategy definitions
3249*/
3250StrategyDef::StrategyDefs& StrategyMgr::get_definitions ()
3251{
3252  static StrategyMgr& me = instance ();
3253
3254  return (me.m_defs);
3255}
3256
3257//-----------------------------------------------------------
3258Strategy::Strategy ()
3259{
3260  clear ();
3261}
3262
3263//-----------------------------------------------------------
3264void Strategy::clear ()
3265{
3266  m_definition = 0;
3267  m_specified = false;
3268  m_specified_value = false;
3269  m_value = false;
3270  m_on_tag = 0;
3271  m_off_tag = 0;
3272}
3273
3274/**----------------------------------------------------------
3275   Specify a new value for this strategy.
3276   This only happens when a strategy statement is met in a project file or in a requirements file.
3277*/
3278void Strategy::set (StrategyDef* definition, bool value, const cmt_string& project_name)
3279{
3280  //cerr << "Setting strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3281
3282  m_definition = definition;
3283  m_specified = true;
3284  m_specified_value = value;
3285
3286  update (definition, value, project_name);
3287}
3288
3289/**----------------------------------------------------------
3290   Change the effective value for this strategy.
3291   This has no impact on to the specified value.
3292   This will adapt the tag settings
3293*/
3294void Strategy::update (StrategyDef* definition, bool value, const cmt_string& project_name)
3295{
3296  //cerr << "Updating strategy " << definition->m_name << " for project " << project_name << " to " << value << endl;
3297
3298  m_value = value;
3299  m_definition = definition;
3300
3301  cmt_string to_tag_name = project_name;
3302  cmt_string to_untag_name = project_name;
3303
3304  to_tag_name += "_";
3305  to_untag_name += "_";
3306
3307  if (m_value)
3308    {
3309      to_tag_name += m_definition->m_on_value;
3310      to_untag_name += m_definition->m_off_value;
3311    }
3312  else
3313    {
3314      to_tag_name += m_definition->m_off_value;
3315      to_untag_name += m_definition->m_on_value;
3316    }
3317
3318  m_on_tag = Tag::find (to_tag_name);
3319  m_off_tag = Tag::find (to_untag_name);
3320
3321  if (m_on_tag == 0 || m_off_tag == 0)
3322    {
3323      m_on_tag = Tag::add (to_tag_name, PriorityConfig, "PROJECT", 0);
3324      m_off_tag = Tag::add (to_untag_name, PriorityConfig, "PROJECT", 0);
3325
3326      m_on_tag->add_tag_exclude (m_off_tag);
3327      m_off_tag->add_tag_exclude (m_on_tag);
3328    }
3329
3330  m_off_tag->unmark ();
3331  m_on_tag->mark ();
3332}
3333
3334//-----------------------------------------------------------
3335const cmt_string& StrategyDef::get_default_value () const
3336{
3337  if (m_default_value)
3338    {
3339      return (m_on_value);
3340    }
3341  else
3342    {
3343      return (m_off_value);
3344    }
3345}
3346
3347//-----------------------------------------------------------
3348void Project::set_author (const cmt_string& name)
3349{
3350  // cerr << "set_author" << name << endl;     
3351  this->m_author = name;
3352}
3353
3354//-----------------------------------------------------------
3355const cmt_string& Project::get_author () const
3356{
3357  return (m_author);
3358}
3359
3360//-----------------------------------------------------------
3361void Project::project_author_action (const CmtSystem::cmt_string_vector& words)
3362{
3363  if (m_author != "") m_author += "\n";
3364
3365  for (int i = 1; i < words.size (); i++)
3366    {
3367      const cmt_string& w = words[i];
3368     
3369      if (i > 1) m_author += " ";
3370      m_author += w; 
3371    }
3372}
3373
3374//-----------------------------------------------------------
3375Use*  Project::get_use () const
3376{
3377  return m_use;   
3378} 
3379
3380//-----------------------------------------------------------
3381void  Project::set_use (Use* use)
3382{ 
3383  this->m_use = use;
3384}
3385
3386//-----------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.