source: CMT/v1r12p20020606/src/cmt_use.cxx @ 1

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

Import all tags

File size: 66.7 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "cmt_use.h"
6#include "cmt_system.h"
7#include "cmt_symbol.h"
8#include "cmt_error.h"
9#include "cmt_database.h"
10
11/*
12 *   Design.
13 *
14 *   There is one central database of all Use objects. This in the Database using:
15 *       Database::instance().all_uses ();
16 *
17 *   There is also a list of selected Use pointers available from
18 *       Database::instance().uses ();
19 *
20 *   A new Use object is created when a new use statement requires it:
21 *     o if the specified version is specified for the first time
22 *     o if the specified path is specified for the first time
23 *
24 */
25
26class UseContext
27{
28public:
29
30  static UseContext& current ()
31  {
32    static UseContext me;
33
34    return (me);
35  }
36
37  UseContext ()
38  {
39    m_auto_imports = On;
40    m_scope = ScopePublic;
41  }
42
43  UseContext (const UseContext& other)
44  {
45    m_auto_imports = other.m_auto_imports;
46    m_scope = other.m_scope;
47  }
48
49  UseContext& operator = (const UseContext& other)
50  {
51    m_auto_imports = other.m_auto_imports;
52    m_scope = other.m_scope;
53
54    return (*this);
55  }
56
57  static void set_current (State auto_imports)
58  {
59    UseContext& c = current ();
60
61    c.m_auto_imports = auto_imports;
62  }
63
64  static void set_current (ScopeType scope)
65  {
66    UseContext& c = current ();
67
68    c.m_scope = scope;
69  }
70
71  static State get_current_auto_imports ()
72  {
73    UseContext& c = current ();
74
75    return (c.m_auto_imports);
76  }
77
78  static ScopeType get_current_scope ()
79  {
80    UseContext& c = current ();
81
82    return (c.m_scope);
83  }
84
85private:
86  State m_auto_imports;
87  ScopeType m_scope;
88};
89
90/**
91 *    Version selectors provide the mechanism for comparing two
92 *  Use objects and decide which one has to be kept WRT their version
93 *  id .
94 *    Each strategy is implemented as a separate class (which overrides
95 *  the operate method)
96 */
97class VersionSelector
98{
99public:
100  static VersionSelector& instance ();
101
102  virtual Use* operate (Use* ref_use, Use* new_use)
103  {
104    return (ref_use);
105  }
106};
107
108class BestFitSelector : public VersionSelector
109{
110public:
111  Use* operate (Use* ref_use, Use* new_use);
112};
113
114class BestFitNoCheckSelector : public VersionSelector
115{
116public:
117  Use* operate (Use* ref_use, Use* new_use);
118};
119
120class FirstChoiceSelector : public VersionSelector
121{
122public:
123  Use* operate (Use* ref_use, Use* new_use);
124};
125
126class LastChoiceSelector : public VersionSelector
127{
128public:
129  Use* operate (Use* ref_use, Use* new_use);
130};
131
132class KeepAllSelector : public VersionSelector
133{
134public:
135  Use* operate (Use* ref_use, Use* new_use);
136};
137//----------------------------------------------------------
138
139//----------------------------------------------------------
140//
141//  Operations on Use
142//
143//----------------------------------------------------------
144
145/**
146 *  Mark all clients of the current package.
147 */
148void Use::select_clients (const cmt_string& package,
149                          const cmt_string& version)
150{
151  static UsePtrVector& Uses = uses ();
152
153  int number;
154  Use* use = 0;
155
156  unselect_all ();
157  undiscard_all ();
158
159  for (number = Uses.size () - 1; number >= 0; number--)
160    {
161      use = Uses[number];
162      if (use == 0) continue;
163      if (use->is_selected ()) continue;
164      use->select ();
165      if (!use->is_client (package, version)) use->discard ();
166    }
167}
168
169//----------------------------------------------------------
170void Use::show_all (bool skip_discarded)
171{
172  show_all ("use ", skip_discarded);
173}
174
175//----------------------------------------------------------
176void Use::show_all (const cmt_string& prefix, bool skip_discarded)
177{
178  static UsePtrVector& Uses = uses ();
179
180  Use* use;
181  int number;
182
183  unselect_all ();
184
185  use = &(current ());
186  use->unselect ();
187  if (!Cmt::get_quiet ()) use->show_sub_uses (skip_discarded);
188
189  if (Uses.size () > 0)
190    {
191      if (!Cmt::get_quiet ())
192        {
193          cout << "#\n";
194          cout << "# Selection :\n";
195        }
196
197      //
198      //  First move the CMT package to the end of the use set.
199      //  (ie. used by everybody)
200      //
201      use = Use::find ("CMT");
202      Use::move (use);
203
204      for (number = Uses.size () - 1; number >= 0; number--)
205        {
206          use = Uses[number];
207
208          if (use->discarded) continue;
209
210          if (!use->located ())
211            {
212              if (!Cmt::get_quiet ())
213                {
214                  cout << "# package " << use->package <<
215                      " " << use->version << " " << use->path << 
216                      " not found" <<
217                      endl;
218                }
219              CmtError::set (CmtError::package_not_found, use->package);
220            }
221          else
222            {
223              static const cmt_string empty;
224              cmt_string p = use->real_path;
225              if (use->path != "")
226                {
227                  p.replace (use->path, empty);
228                }
229             
230              cout << prefix << use->package <<
231                  " " << use->version <<
232                  " " << use->path;
233
234              if (!Cmt::get_quiet ()) 
235                {
236                  if (p != "") cout << " (" << p << ")";
237                  if (use->auto_imports == Off) cout << " (no_auto_imports)";
238                }
239
240              cout << endl;
241            }
242        }
243
244      if (Cmt::get_cmt_home () != "")
245        {
246          cout << prefix << CmtSystem::get_home_package () <<
247              " " << Cmt::get_cmt_home () <<
248              endl;
249        }
250
251      if (Cmt::get_cmt_user_context () != "")
252        {
253          cout << prefix << CmtSystem::get_user_context_package () <<
254              " " << Cmt::get_cmt_user_context () <<
255              endl;
256        }
257    }
258}
259
260/**
261 *   This private class parses the use statement after macro expansion
262 *   This is a finite state machine.
263 *    It maintains the results of the parsing in terms of a package name,
264 *   a version, a path, and state variables (no_auto_imports)
265 */
266class use_action_iterator
267{
268public:
269
270  use_action_iterator ()
271      {
272        state = need_package;
273        auto_imports = Unspecified;
274      }
275
276  void set (const cmt_string& w)
277      {
278        if (w == "-auto_imports")
279          {
280            auto_imports = On;
281          }
282        else if (w == "-no_auto_imports")
283          {
284            auto_imports = Off;
285          }
286        else if (w == "|")
287          {
288            state = need_version_alias;
289          }
290        else
291          {
292            switch (state)
293              {
294                case need_package:
295                  package = w;
296                  state = need_version;
297                  break;
298                case need_version:
299                  version = w;
300                  state = need_path;
301                  break;
302                case need_path:
303                  path = w;
304                  state = finished;
305                  break;
306                case need_version_alias:
307                  version_alias = w;
308                  state = need_path_alias;
309                  break;
310                case need_path_alias:
311                  path_alias = w;
312                  state = finished;
313                  break;
314              }
315          }
316      }
317
318  bool ok ()
319      {
320        if (package == "") return (false);
321        if (CmtSystem::is_home_package (package, version)) return (false);
322        if (CmtSystem::is_user_context_package (package, version)) return (false);
323
324        return (true);
325      }
326
327  /**
328   *
329   *  Build or retreive the Use object corresponding to the parsed specification.
330   *
331   */
332  Use* get_use (Use* parent)
333      {
334        static Use::UsePtrVector& Uses = Use::uses ();
335
336        if (version == "") version = "*";
337
338        if (Cmt::get_debug ())
339          {
340            int i;
341
342            cout << "use::action1> current=" << parent->package <<
343                " package=" << package << " ";
344
345            for (i = 0; i < Uses.size (); i++)
346              {
347                Use* u = Uses[i];
348                cout << u->package << " ";
349              }
350            cout << endl;
351          }
352
353        const Use& cu = Use::current ();
354
355        /**
356         *   Do not continue the operations for private uses
357         *  accessed from an external context.
358         *
359         *   Exceptions should be considered for
360         *     - cmt broadcast
361         *     - cmt show uses
362         */
363
364        ActionType action = Cmt::get_action ();
365
366        if (Cmt::get_debug ())
367          {
368            cout << "before adding " << package <<"> auto_imports=" << auto_imports
369                 << " (current AI was " << UseContext::get_current_auto_imports () << ")" 
370                 << " (current scope was " << UseContext::get_current_scope () << ")" 
371                 << " (Cmt::scope=" << Cmt::get_scope () << ")"
372                 << " (parent=" << parent->package << ")"
373                 << endl;
374          }
375
376        bool hidden_by_scope = false;
377
378        if ((Cmt::get_scope () == ScopePrivate) || (UseContext::get_current_scope () == ScopePrivate))
379          {
380            hidden_by_scope = true;
381
382            // Do not hide immediate children of the current package.
383            if ((parent == 0) || (parent->package == cu.package)) hidden_by_scope = false;
384
385            // Do not hide in broadcast and show uses actions.
386            if ((action == action_broadcast) ||
387                (action == action_show_uses)) hidden_by_scope = false;
388          }
389
390        if (hidden_by_scope)
391          {
392            return (0);
393          }
394
395        // Here the version may contain wild cards
396
397        UseContext save = UseContext::current ();
398
399          /**
400           *  "auto_imports" is the state which is specified on the use statement
401           *  currently being parsed.
402           */
403        switch (auto_imports)
404          {
405            case Unspecified:
406
407                // unspecified => we forward the state saved in the current use context
408
409              UseContext::set_current (UseContext::get_current_auto_imports ());
410              break;
411            case Off:
412
413                // off => the context becomes constrained to be off
414
415              UseContext::set_current (Off);
416              break;
417            case On:
418
419                // on => if current context is off it is kept off
420                //       otherwise it is forced to on
421
422              if (UseContext::get_current_auto_imports () != Off)
423                {
424                  UseContext::set_current (On);
425                }
426              break;
427          }
428
429        if (hidden_by_scope)
430          {
431            UseContext::set_current (Cmt::get_scope ());
432          }
433
434        /// Now do create or retreive the Use object.
435        Use* new_use = Use::add (path, package, version, 
436                                 version_alias, path_alias, parent,
437                                 auto_imports);
438
439        if (new_use != 0)
440          {
441            if (Cmt::get_debug ())
442              {
443                cout << "after adding1 " << package << "> auto_imports=" << new_use->auto_imports << endl;
444              }
445
446            switch (new_use->auto_imports)
447              {
448                case Unspecified:
449                  new_use->auto_imports = UseContext::get_current_auto_imports ();
450                  break;
451                case On:
452                  break;
453                case Off:
454                  if (UseContext::get_current_auto_imports () == On)
455                    {
456                        /**
457                         *  Warning : this Use had been previously specified as -no_auto_imports
458                         *  Now this new specification tries to turn it to auto_imports.
459                         *  It will be required to propagate the change, according to the
460                         *  specifications:
461                         *
462                         *    for all sub_uses:
463                         *       if it is unspecified OR specified as auto_imports:
464                         *          turn it to auto_imports
465                         *
466                         */
467                      new_use->set_auto_imports (On);
468                    }
469                  break;
470              }
471
472
473            if (Cmt::get_debug ())
474              {
475                cout << "after adding2 " << package << "> auto_imports=" << new_use->auto_imports << endl;
476              }
477
478            UseContext& c = UseContext::current ();
479            c = save;
480
481            Use::reorder (new_use, parent);
482           
483            if (Cmt::get_debug ())
484              {
485                int i;
486               
487                cout << "use::action2> current=" << parent->package
488                     << " package=" << package << " ";
489
490                for (i = 0; i < Uses.size (); i++)
491                  {
492                    Use* u = Uses[i];
493                    cout << u->package << " ";
494                  }
495
496                cout << endl;
497              }
498          }
499
500        return (new_use);
501      }
502
503private:
504
505  enum
506  {
507    need_package,
508    need_version,
509    need_path,
510    need_version_alias,
511    need_path_alias,
512    finished
513  } state;
514 
515  State auto_imports;
516
517  cmt_string package;
518  cmt_string version;
519  cmt_string path;
520  cmt_string version_alias;
521  cmt_string path_alias;
522};
523
524//----------------------------------------------------------
525Use* Use::action (const CmtSystem::cmt_string_vector& words, Use* parent)
526{
527  Use* new_use;
528
529  //
530  // complete syntax : "use <package> <version> <path>"
531  // minimal syntax  : "use <package>"
532  //
533  //  o if <version> is omitted then take any version available
534  //  o <version> can be specified using "v*" or "v<n>r*" or "v<n>r<m>p*"
535  //
536  //  o the notation "v*" is preferred to omission (particularly since
537  //    omission does not permit <path>)
538  //
539  if (words.size () < 2) return (0);
540
541  use_action_iterator it;
542
543  for (int i = 1; i < words.size (); i++)
544    {
545      const cmt_string& w = words[i];
546      cmt_string ew = w;
547
548      Symbol::expand (ew);
549      if (ew != w)
550        {
551          CmtSystem::cmt_string_vector ws;
552
553          CmtSystem::split (ew, " ", ws);
554
555          for (int j = 0; j < ws.size (); ++j)
556            {
557              const cmt_string& ww = ws[j];
558              it.set (ww);
559            }
560        }
561      else
562        {
563          it.set (ew);
564        }
565    }
566
567  if (!it.ok ()) return (0);
568
569  static int level = 0;
570
571  level++;
572  new_use = it.get_use (parent);
573  level--;
574
575  return (new_use);
576}
577
578//----------------------------------------------------------
579void Use::author_action (const CmtSystem::cmt_string_vector& words)
580{
581  if (author != "") author += "\n";
582  for (int i = 1; i < words.size (); i++)
583    {
584      const cmt_string& w = words[i];
585     
586      if (i > 1) author += " ";
587      author += w;
588    }
589}
590
591//----------------------------------------------------------
592void Use::manager_action (const CmtSystem::cmt_string_vector& words)
593{
594  if (manager != "") manager += "\n";
595  for (int i = 1; i < words.size (); i++)
596    {
597      const cmt_string& w = words[i];
598     
599      if (i > 1) manager += " ";
600      manager += w;
601    }
602}
603
604//----------------------------------------------------------
605Use* Use::find (const cmt_string& package, 
606                const cmt_string& version, 
607                const cmt_string& path)
608{
609  static UsePtrVector& Uses = uses ();
610  static UseVector& AllUses = all_uses ();
611
612  int use_index;
613
614  if (AllUses.size () == 0) return (0);
615
616  for (use_index = 0; use_index < Uses.size (); use_index++)
617    {
618      Use& use = (*Uses[use_index]);
619
620      if (use.package == package)
621        {
622            // If the version argument is omitted then
623            // take the first registered version
624          if (version == "") return (&use);
625         
626            // Otherwise compare against specified_version and path
627            //if ((use.specified_version == version) &&
628            //  (use.specified_path == path)) return (&use);
629         
630            // what about comparing wild cards?
631
632          if (use.specified_version == version) return (&use);
633        }
634    }
635
636  return (0);
637}
638
639//----------------------------------------------------------
640int Use::find_index (const cmt_string& package, 
641                     const cmt_string& version, 
642                     const cmt_string& path)
643{
644  static UsePtrVector& Uses = uses ();
645  static UseVector& AllUses = all_uses ();
646
647  int use_index;
648
649  if (AllUses.size () == 0) return (-1);
650
651  for (use_index = 0; use_index < Uses.size (); use_index++)
652    {
653      Use& use = (*Uses[use_index]);
654
655      if (use.package == package)
656        {
657          // If the version argument is omitted then
658          // take the first registered version
659          if (version == "") return (use_index);
660         
661          // Otherwise compare against specified_version and path
662          //if ((use.specified_version == version) &&
663          //  (use.specified_path == path)) return (&use);
664         
665          // what about comparing wild cards?
666
667          if (use.specified_version == version) return (use_index);
668        }
669    }
670
671  return (-1);
672}
673
674/**
675 *   1) Given a Use object identified by its index in the uses() array,
676 *   2) Given a vector of states containing the auto_imports states of all Uses,
677 *
678 *     we want to switch to 'On' the auto_imports states of all
679 *     sub_uses of the argument that were Off.
680 *
681 */
682void Use::set_auto_imports_state (int use_index,
683                                  cmt_vector<bool>& auto_imports_states)
684{
685  // check if this is already done (recursivity ending)
686  if (auto_imports_states[use_index]) return;
687
688  Use::UsePtrVector& Uses = Use::uses ();
689  Use* use = Uses[use_index];
690
691  // Is this a mistake? we only have to deal with Use objects that were
692  // actually turned Off
693  if (use->auto_imports != Off) return;
694
695  /**
696   *  Here, use points to a Use object which had been declared as
697   *  no_auto_imports. But we need to switch it On. Therefore,
698   *
699   *    1) the state in auto_imports_states has to be set On
700   *    2) the operation has to be recursively propagated to all
701   *         sub_uses which also had no_auto_imports. (only to those)
702   * 
703   */
704 
705  auto_imports_states[use_index] = true;
706
707  for (int i = 0; i < use->sub_uses.size (); i++)
708    {
709      Use* u = use->sub_uses[i];
710
711      if (u->sub_use_auto_imports[i] == Off)
712        {
713          int j;
714         
715          // first find the index of this use.
716         
717          for (j = 0; j < Uses.size(); j++)
718            {
719              if (u == Uses[j]) break;
720            }
721         
722          set_auto_imports_state (j, auto_imports_states);
723        }
724    }
725}
726
727//----------------------------------------------------------
728//
729//  Move use to the end
730//
731//----------------------------------------------------------
732void Use::move (Use* use1)
733{
734  static UsePtrVector& Uses = uses ();
735
736  int use_index;
737  Use* use;
738  int found = 0;
739
740  if (Uses.size () == 0) return;
741  if (use1 == 0) return;
742
743  //
744  // On se positionne sur le pointeur.
745  //
746  for (use_index = 0; use_index < Uses.size (); use_index++)
747    {
748      use = Uses[use_index];
749
750      if (use == use1)
751        {
752          found = 1;
753          break;
754        }
755    }
756
757  if (!found) return;
758
759  //
760  // On deplace tous les pointeurs d'une case en arriere
761  //
762  for (use_index++;
763       use_index < Uses.size ();
764       use_index++)
765    {
766      Uses[use_index - 1] = Uses[use_index];
767    }
768
769  //
770  // use1 est donc replace en derniere position
771  //
772  {
773    Uses[Uses.size () - 1] = use1;
774  }
775}
776
777/**
778 *   Reorder use1 versus use2 in the UsePtrVector list, so that the order reflects the fact
779 *  that use2 makes use of use1.
780 *   The result should be that use1 appears before use2 in the list.
781 */
782void Use::reorder (Use* use1, Use* use2)
783{
784  static UsePtrVector& Uses = uses ();
785
786  int use_index;
787  int index1 = -1;
788  int index2 = -1;
789  Use* use;
790
791  if (Uses.size () == 0) return;
792  if (use1 == use2) return;
793
794  //
795  // First locate the two use objects into the Uses vector.
796  //   -> index1 and index 2
797  //
798  for (use_index = 0; use_index < Uses.size (); use_index++)
799    {
800      use = (Use*) Uses[use_index];
801
802      if (use == use1) index1 = use_index;
803      if (use == use2) index2 = use_index;
804    }
805
806  if (Cmt::get_debug ())
807    {
808      cout << "Use::reorder> 1=" << index1 << " 2=" << index2 << endl;
809    }
810
811  //
812  // Both objects must be installed in Uses before acting.
813  //
814  if (index1 == -1) return;
815  if (index2 == -1) return;
816
817  if (index2 < index1)
818    {
819      //
820      // 2 is already before 1 so job is finished
821      //
822      return;
823    }
824  else
825    {
826      //
827      // before : <a a a 1 b b b 2 c c c>
828      //                 ^       ^
829      //                 i1      i2
830      //
831      //  1) move "1 b b b" by one place to the right
832      // thus :   <a a a 1 1 b b b c c c>
833      //
834      //  2) move "2" to [i1]
835      //
836      // after  : <a a a 2 1 b b b c c c>
837      //
838
839      use = use2;
840
841      for (use_index = index2 - 1; use_index >= index1; use_index--)
842        {
843          Uses[use_index + 1] = Uses[use_index];
844        }
845
846      Uses[index1] = use;
847    }
848}
849
850//----------------------------------------------------------
851void Use::clear_all ()
852{
853  static UsePtrVector& Uses = uses ();
854  static UseVector& AllUses = all_uses ();
855
856  int use_index;
857
858  for (use_index = 0; use_index < AllUses.size (); use_index++)
859    {
860      Use& use = AllUses[use_index];
861      use.clear ();
862    }
863
864  Uses.clear ();
865  AllUses.clear ();
866}
867
868//----------------------------------------------------------
869void Use::unselect_all ()
870{
871  static UsePtrVector& Uses = uses ();
872
873  int use_index;
874
875  if (Uses.size () == 0) return;
876
877  for (use_index = 0; use_index < Uses.size (); use_index++)
878    {
879      Use* use = Uses[use_index];
880
881      if (use != 0)
882        {
883          use->unselect ();
884        }
885    }
886}
887
888//----------------------------------------------------------
889void Use::undiscard_all ()
890{
891  static UsePtrVector& Uses = uses ();
892
893  int use_index;
894
895  if (Uses.size () == 0) return;
896
897  for (use_index = 0; use_index < Uses.size (); use_index++)
898    {
899      Use* use = Uses[use_index];
900
901      if (use != 0)
902        {
903          use->undiscard ();
904        }
905    }
906}
907
908//----------------------------------------------------------
909void Use::fill_macro_all (cmt_string& buffer, const cmt_string& suffix)
910{
911  UsePtrVector& Uses = uses ();
912
913  buffer = "macro_append use_";
914  buffer += suffix;
915  buffer += " \" ";
916  (Use::current()).fill_macro (buffer, suffix);
917
918  for (int number = 0; number < Uses.size (); number++)
919    {
920      Use* use = Uses[number];
921     
922      if (use->package == "CMT") continue;
923      if (use->package == "methods") continue;
924      if (use->discarded) continue;
925      if (use->auto_imports == Off) continue;
926
927      use->fill_macro (buffer, suffix);
928    }
929 
930  buffer += "\"";
931}
932
933//----------------------------------------------------------
934Use::Use ()
935{
936  done = false;
937  discarded = false;
938  auto_imports = Unspecified;
939
940  clear ();
941}
942
943//----------------------------------------------------------
944Use::Use (const cmt_string& new_package,
945          const cmt_string& new_version,
946          const cmt_string& new_path)
947{
948  auto_imports = Unspecified;
949  m_located = false;
950  set (new_package, new_version, new_path);
951}
952
953//----------------------------------------------------------
954Use::~Use ()
955{
956  clear ();
957}
958
959//----------------------------------------------------------
960void Use::clear ()
961{
962  specified_path = "";
963  path      = "";
964  package   = "";
965  version   = "";
966  author    = "";
967  manager   = "";
968  real_path = "";
969
970  prefix    = "";
971  style     = mgr_style;
972  scope     = Cmt::get_scope ();
973  done      = false;
974  discarded = false;
975  selected  = false;
976  auto_imports = Unspecified;
977
978  includes.clear ();
979  include_path = "";
980  scripts.clear ();
981  apply_patterns.clear ();
982  ignore_patterns.clear ();
983
984  sub_uses.clear ();
985  sub_use_scopes.clear ();
986  sub_use_auto_imports.clear ();
987
988  alternate_versions.clear ();
989  alternate_paths.clear ();
990
991  version_alias = "";
992  path_alias    = "";
993
994  m_located = false;
995  m_has_native_version = false;
996}
997
998//----------------------------------------------------------
999void Use::set (const cmt_string& new_package,
1000               const cmt_string& new_version,
1001               const cmt_string& new_path,
1002               const cmt_string& new_version_alias,
1003               const cmt_string& new_path_alias)
1004{
1005  clear ();
1006
1007  package           = new_package;
1008  specified_path    = new_path;
1009  // specified_path.replace_all ("\\", "/");
1010
1011  specified_version = new_version;
1012  version           = new_version;
1013  path              = specified_path;
1014  Symbol::expand (path);
1015  real_path         = "";
1016  style             = mgr_style;
1017  scope             = Cmt::get_scope ();
1018  done              = false;
1019  discarded         = false;
1020  Cmt::build_prefix (new_package, prefix);
1021
1022  version_alias = new_version_alias;
1023  path_alias    = new_path_alias;
1024}
1025
1026//----------------------------------------------------------
1027void Use::change_path (const cmt_string& new_path)
1028{
1029  //
1030  // This methods changes real_path after an actual location
1031  // where this package/version has been found.
1032  //
1033
1034  real_path = "";
1035
1036  if (new_path != "")
1037    {
1038      if ((path.size () > 0) &&
1039          (!CmtSystem::absolute_path (path)))
1040        {
1041          real_path = new_path;
1042          real_path += CmtSystem::file_separator ();
1043          real_path += path;
1044        }
1045      else
1046        {
1047          real_path = new_path;
1048        }
1049      // real_path.replace_all ("\\", "/");
1050    }
1051 
1052  m_located = true;
1053}
1054
1055//----------------------------------------------------------
1056int Use::reach_package (const cmt_string& from_path)
1057{
1058  //cerr << "Use::reach_package> (" << package << " " << version << ")from " << from_path << endl;
1059
1060  //
1061  // We try to reach a package/version starting from from_path
1062  //
1063
1064  // check if from_path is at least real
1065  if ((from_path != "") && !CmtSystem::cd (from_path)) return (0);
1066
1067  // check in case from_path is a new search path
1068  if (from_path != real_path)
1069    {
1070      // Move to that prefix only if it is a relative path.
1071      if ((path.size () > 0) && (!CmtSystem::absolute_path (path)))
1072        {
1073          if (!CmtSystem::cd (path))
1074            {
1075              return (0);
1076            }
1077        }
1078    }
1079
1080  // Special treatment for CMTHOME package...
1081  if (package == CmtSystem::get_home_package ())
1082    {
1083      discarded = 1;
1084      if (!CmtSystem::test_file ("requirements"))
1085        {
1086          return (0);
1087        }
1088      else
1089        {
1090          return (1);
1091        }
1092    }
1093
1094  // Special treatment for CMTUSERCONTEXT package...
1095  if (package == CmtSystem::get_user_context_package ())
1096    {
1097      discarded = 1;
1098      if (!CmtSystem::test_file ("requirements"))
1099        {
1100          return (0);
1101        }
1102      else
1103        {
1104          return (1);
1105        }
1106    }
1107
1108  // Now from_path exists, try if the package exists there
1109  if (!CmtSystem::cd (package))
1110    {
1111      return (0);
1112    }
1113
1114  if (!CmtSystem::cd (version))
1115    {
1116      //
1117      // The specified version cannot be found per-se
1118      // There are alternate possibilities when it contains wild cards
1119      //
1120      if ((version == "") ||
1121          (version.find ("*") != cmt_string::npos))
1122        {
1123          static CmtSystem::cmt_string_vector versions;
1124          static cmt_string name;
1125
1126          name = ".";
1127          name += CmtSystem::file_separator ();
1128          if (version == "") name += "*";
1129          else name += version;
1130
1131          CmtSystem::scan_dir (name, versions);
1132         
1133          int i;
1134          bool found = false;
1135         
1136          for (i = 0; i < versions.size (); i++)
1137            {
1138              const cmt_string& vers = versions[i];
1139             
1140              if (Cmt::get_debug ())
1141                {
1142                  cout << "     ... version " << vers << " exists" << endl;
1143                }
1144
1145              CmtSystem::basename (vers, name);
1146             
1147              int v;
1148              int r;
1149              int p;
1150             
1151              if (CmtSystem::is_version_directory (name, v, r, p))
1152                {
1153                  /*
1154                    This check is not sufficient !! We need to check in addition
1155                    that the selected directory is really the start of a true CMT
1156                    package (ie with either /mgr/requirements or /cmt/requirements below)
1157                  */
1158
1159                  cmt_string req;
1160
1161                  req = name;
1162                  req += CmtSystem::file_separator ();
1163                  req += "mgr";
1164                  req += CmtSystem::file_separator ();
1165                  req += "requirements";
1166
1167                  if (!CmtSystem::test_file (req))
1168                    {
1169                      req = name;
1170                      req += CmtSystem::file_separator ();
1171                      req += "cmt";
1172                      req += CmtSystem::file_separator ();
1173                      req += "requirements";
1174
1175                      if (!CmtSystem::test_file (req)) continue;
1176                    }
1177
1178                  cmt_string& new_v = alternate_versions.add ();
1179                  new_v = name;
1180                  cmt_string& new_p = alternate_paths.add ();
1181                  new_p = from_path;
1182
1183                  found = true;
1184                }
1185            }
1186        }
1187
1188      if (Cmt::get_debug ())
1189        {
1190          cout << "  ... end of version scan" << endl;
1191        }
1192
1193        //
1194        //  We have now the list of possible alternate versions. However
1195        // we return that the expected package/version was not found (yet).
1196        //
1197
1198      return (0);
1199    }
1200
1201  //cerr << "  ... version " << version << " exists" << endl;
1202
1203  // Now we have met the exact specified version!
1204  if (!CmtSystem::test_file ("cmt/requirements"))
1205    {
1206      if (!CmtSystem::test_file ("mgr/requirements"))
1207        {
1208          return (0);
1209        }
1210      else
1211        {
1212          CmtSystem::cd ("mgr");
1213          style = mgr_style;
1214        }
1215    }
1216  else
1217    {
1218      CmtSystem::cd ("cmt");
1219      style = cmt_style;
1220    }
1221
1222  return (1);
1223}
1224
1225//----------------------------------------------------------
1226bool Use::move_to ()
1227{
1228  if (m_located)
1229    {
1230      //
1231      // The real path where this version/package can be found
1232      // has already been resolved. We thus first go there.
1233      //
1234
1235      if (Cmt::get_debug ())
1236        {
1237          cout << "move_to1> " << real_path << endl;
1238        }
1239
1240      reach_package (real_path);
1241
1242      return (true);
1243    }
1244
1245  cmt_string expanded_path = path;
1246
1247  //
1248  // Try here.
1249  //
1250  if (expanded_path == "")
1251    {
1252      if (reach_package (""))
1253        {
1254          if (Cmt::get_debug ())
1255            {
1256              cout << "move_to2> " << expanded_path << endl;
1257            }
1258
1259          change_path (expanded_path);
1260
1261          return (true);
1262        }
1263      else if (alternate_versions.size () > 0)
1264        {
1265          if (select_alternate ()) 
1266            {
1267              if (Cmt::get_debug ())
1268                {
1269                  cout << "move_to5> " << real_path << endl;
1270                }
1271             
1272              return (true);
1273            }
1274        }
1275    }
1276     
1277  //
1278  // If the path specified in this use is a true absolute path,
1279  // then we search the package from there first.
1280  //
1281  if (CmtSystem::absolute_path (expanded_path))
1282    {
1283      if (reach_package (expanded_path))
1284        {
1285          if (Cmt::get_debug ())
1286            {
1287              cout << "move_to3> " << expanded_path << endl;
1288            }
1289
1290          change_path (expanded_path);
1291
1292          return (true);
1293        }
1294      else if (alternate_versions.size () > 0)
1295        {
1296          if (select_alternate ()) 
1297            {
1298              if (Cmt::get_debug ())
1299                {
1300                  cout << "move_to5> " << real_path << endl;
1301                }
1302             
1303              return (true);
1304            }
1305        }
1306    }
1307     
1308  //
1309  // Second try is among the CMTPATHs
1310  //
1311     
1312  static const CmtSystem::cmt_string_vector& search_path = Cmt::get_cmt_path ();
1313  int path_index = 0;
1314     
1315  for (path_index = 0; path_index < search_path.size (); path_index++)
1316    {
1317      const cmt_string& next_path = search_path[path_index];
1318     
1319      alternate_versions.clear ();
1320      alternate_paths.clear ();
1321
1322      if (reach_package (next_path))
1323        {
1324          if (Cmt::get_debug ())
1325            {
1326              cout << "move_to4> " << next_path << endl;
1327            }
1328
1329          change_path (next_path);
1330
1331          return (true);
1332        }
1333      else if (alternate_versions.size () > 0)
1334        {
1335          if (select_alternate ()) 
1336            {
1337              if (Cmt::get_debug ())
1338                {
1339                  cout << "move_to5> " << real_path << endl;
1340                }
1341             
1342              return (true);
1343            }
1344        }
1345    }
1346 
1347
1348  return (false);
1349}
1350
1351//----------------------------------------------------------
1352bool Use::select_alternate ()
1353{
1354  int i;
1355
1356  int v0 = 0;
1357  int r0 = 0;
1358  int p0 = 0;
1359
1360  int v = 0;
1361  int r = 0;
1362  int p = 0;
1363
1364  int selected_index = -1;
1365
1366  for (i = 0; i < alternate_versions.size (); i++)
1367    {
1368      cmt_string& name = alternate_versions[i];
1369
1370        /*
1371      if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "")
1372        {
1373          cout << "select_alternate[" << this << "]> package " << package <<
1374              " sv=" << specified_version <<
1375              " v=" << version <<
1376              " av[" << i << "]=" << name << endl;
1377        }
1378        */
1379
1380      if (i == 0)
1381        {
1382          CmtSystem::is_version_directory (name, v0, r0, p0);
1383          selected_index = 0;
1384        }
1385      else
1386        {
1387          CmtSystem::is_version_directory (name, v, r, p);
1388
1389          if (v > v0)
1390            {
1391              selected_index = i;
1392              v0 = v;
1393              r0 = r;
1394              p0 = p;
1395            }
1396          else if (v == v0)
1397            {
1398              if (r > r0)
1399                {
1400                  selected_index = i;
1401                  r0 = r;
1402                  p0 = p;
1403                }
1404              else if (r == r0)
1405                {
1406                  if (p > p0)
1407                    {
1408                      selected_index = i;
1409                      p0 = p;
1410                    }
1411                }
1412            }
1413        }
1414    }
1415
1416  if (selected_index >= 0)
1417    {
1418      if (CmtSystem::cd (alternate_paths[selected_index]))
1419        {
1420          version = alternate_versions[selected_index];
1421          if (reach_package (alternate_paths[selected_index]))
1422            {
1423                /*
1424              if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "")
1425                {
1426                  cout << "select_alternate2> package " << package <<
1427                      " sv=" << specified_version <<
1428                      " v=" << version << endl;
1429                }
1430                */
1431
1432              if (Cmt::get_debug ())
1433                {
1434                  cout << "select_alternate> " << alternate_paths[selected_index] << endl;
1435                }
1436
1437              change_path (alternate_paths[selected_index]);
1438              return (true);
1439            }
1440        }
1441    }
1442
1443  return (false);
1444}
1445
1446//----------------------------------------------------------
1447bool Use::need_new (const cmt_string& path,
1448                    const cmt_string& package,
1449                    const cmt_string& version,
1450                    Use** old_use)
1451{
1452  bool has_wild_card = (version.find ("*") != cmt_string::npos);
1453
1454  static UsePtrVector& Uses = uses ();
1455  static UseVector& AllUses = all_uses ();
1456
1457  bool result = true;
1458  Use* found = 0;
1459
1460  int use_index;
1461
1462  if (old_use != 0) *old_use = 0;
1463  if (AllUses.size () == 0) return (true);
1464
1465  for (use_index = 0; use_index < Uses.size (); use_index++)
1466    {
1467      Use& use = (*Uses[use_index]);
1468
1469      if (use.package != package) continue;
1470
1471      found = &use;
1472
1473      /*
1474        cerr << "Use::need_new> (" << package
1475        << ") requested version=" << version
1476        << " vs existing=" << use->version
1477        << " (specified as " << use->specified_version
1478        << ")" << endl;
1479      */
1480
1481      bool use_has_wild_card = (use.specified_version.find ("*") != cmt_string::npos);
1482
1483      if (has_wild_card && !use_has_wild_card)
1484        {
1485          //cerr << "  ... requested wildcarded loses against existing explicit" << endl;
1486          result = false;
1487          break;
1488        }
1489
1490      if ((version == use.specified_version) &&
1491          (path == use.specified_path))
1492        {
1493          // exactly same version and path!
1494          result = false;
1495          break;
1496        }
1497
1498      // requested explicit wins against existing wildcarded
1499      // In any case when paths are different, consider the new one.
1500      // Now paths are identical (thus versions are different).
1501    }
1502
1503  if (old_use != 0) *old_use = found;
1504  return (result);
1505}
1506
1507//----------------------------------------------------------
1508//
1509//  Here the version which is provided here is the specified version.
1510// It may contain wild cards or it may be simply empty.
1511//
1512//----------------------------------------------------------
1513Use* Use::create (const cmt_string& path,
1514                  const cmt_string& package,
1515                  const cmt_string& version,
1516                  const cmt_string& version_alias,
1517                  const cmt_string& path_alias)
1518{
1519  static UseVector& AllUses = all_uses ();
1520
1521  // We first look in the database.
1522  for (int use_index = 0; use_index < AllUses.size (); use_index++)
1523    {
1524      Use& use = AllUses[use_index];
1525
1526      if (use.package == package)
1527        {
1528          if ((use.specified_version == version) && 
1529              (use.specified_path == path)) return (&use);
1530        }
1531    }
1532
1533  // We now really create a new Use entry.
1534
1535  Use& use_object = AllUses.add ();
1536  use_object.set (package, version, path, version_alias, path_alias);
1537
1538  return (&use_object);
1539}
1540
1541//----------------------------------------------------------
1542//  Add a use request into the database.
1543//
1544//  o If a use request already exist in the database,
1545//    check the version compatibility
1546//
1547//----------------------------------------------------------
1548Use* Use::add (const cmt_string& path,
1549               const cmt_string& package,
1550               const cmt_string& version,
1551               const cmt_string& version_alias,
1552               const cmt_string& path_alias,
1553               Use* context_use,
1554               State specified_auto_imports)
1555{
1556  static UsePtrVector& Uses = uses ();
1557
1558  bool do_need_new = false;
1559
1560  Use* old_use = 0;
1561  Use* use = 0;
1562
1563  do_need_new = need_new (path, package, version, &old_use);
1564
1565  /*
1566    if (old_use != 0)
1567    {
1568    cout << "add> old_use " << old_use->package <<
1569    " " << old_use->version <<
1570    " " << old_use->path <<
1571    endl;
1572    }
1573  */
1574
1575  if (do_need_new)
1576    {
1577      use = create (path, package, version, version_alias, path_alias);
1578    }
1579  else
1580    {
1581      // Since we don't need a new Use, it means that old_use exists !
1582      use = old_use;
1583      old_use = 0;
1584    }
1585
1586  if (package == CmtSystem::get_home_package ())
1587    {
1588      return (use);
1589    }
1590
1591  if (package == CmtSystem::get_user_context_package ())
1592    {
1593      return (use);
1594    }
1595
1596  cmt_string here = CmtSystem::pwd ();
1597
1598    //
1599    // Store the specified sub_uses. Some of them may become discarded
1600    // later on.
1601    //
1602  if (context_use != 0)
1603    {
1604      context_use->sub_uses.push_back (use);
1605      context_use->sub_use_scopes.push_back (Cmt::get_scope ());
1606      context_use->sub_use_auto_imports.push_back (specified_auto_imports);
1607
1608      if (Cmt::get_debug ())
1609        {
1610          cout << "Use::add context(" << context_use->package << ") "
1611               << "[u:" << package
1612               << " s:" << Cmt::get_scope ()
1613               << " ai:" << specified_auto_imports
1614               << "]" << endl;
1615        }
1616    }
1617
1618  /*
1619   *   Now we have a Use object. If it is a new one, we have to
1620   *    1) understand if it exists physically
1621   *    2) it is better than the old ones.
1622   *
1623   *   Here, we may have :
1624   *    1) old_use = 0
1625   *         there was no Use object before for this package
1626   *         the existing one is fine
1627   *
1628   *    2) old_use != 0
1629   *         we have created a new Use (which has to be validated)
1630   */
1631
1632  bool found = use->move_to ();
1633
1634  if (Cmt::get_debug ())
1635    {
1636      cout << "add> use " << use->package
1637           << " " << use->version
1638           << " " << use->path
1639           << " found=" << found
1640           << endl;
1641    }
1642     
1643  if (!found)
1644    {
1645      if (!Cmt::get_quiet ())
1646        {
1647          cerr << "#(Warning) package " << use->package <<
1648            " " << use->version << " " << use->path << 
1649            " not found" <<
1650            endl;
1651        }
1652
1653      CmtError::set (CmtError::package_not_found, use->package);
1654      use = 0;
1655    }
1656
1657  if ((old_use != 0) && (use != old_use))
1658    {
1659      /*
1660       *    There was another version of this Use. But a new one was created due to
1661       *   some criteria.
1662       *    New we are going to apply the version strategy to make the final selection.
1663       */
1664
1665      /*
1666        if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "")
1667        {
1668        cout << "select? [" << use << "] vs old_use[" << old_use << "] " << old_use->package <<
1669        " " << old_use->version <<
1670        " " << old_use->path <<
1671        endl;
1672        }
1673      */
1674
1675      if (!found)
1676        {
1677          /*
1678           *  This new Use does not correspond to any physical package.
1679           *  let's simply discard it
1680           */
1681
1682          if (use != 0) use->discard ();
1683          use = old_use;
1684          found = use->move_to ();
1685        }
1686      else
1687        {
1688            //
1689            //  This new version is different from the old one
1690            // thus we have to choose
1691            //
1692          VersionSelector& selector = VersionSelector::instance ();
1693          Use* selected_use = selector.operate (old_use, use);
1694
1695            //
1696            // Some situations managed by selector.operate happen
1697            // to fail discarding the rejected Use.
1698            //
1699          if (use != selected_use) 
1700            {
1701              use->discard ();
1702            }
1703         
1704          use = selected_use;
1705
1706          /*
1707           *   current directory is moved to the selected one
1708           */
1709          found = use->move_to ();
1710        }
1711    }
1712
1713    //
1714    // The following statement is no longer considered as useful.
1715    // It is commented. But we should clarify why it was really needed!
1716    //
1717    //use->undiscard ();
1718
1719  if (found)
1720    {
1721      bool registered = false;
1722      const Use& cu = Use::current ();
1723
1724      //
1725      // A pointer to this new object is also added or replaced.
1726      //
1727      if ((use != &cu) && (package == cu.package))
1728        {
1729            // This is a recursive call to the current package!!
1730          registered = true;
1731          use->done = true;
1732        }
1733      else
1734        {
1735          for (int i = 0; i < Uses.size(); i++)
1736            {
1737              Use* u = Uses[i];
1738             
1739              if (u->package == package)
1740                {
1741                  registered = true;
1742                  Uses[i] = use;
1743                  break;
1744                }
1745            }
1746        }
1747     
1748      if (!registered) Uses.push_back (use);
1749
1750      if (!use->done && Cmt::get_recursive ())
1751        {
1752          use->done = true;
1753
1754          /*
1755            if (CmtSystem::getenv ("CMTTESTUSEWILDCARDS") != "")
1756            {
1757            for (int use_index = 0; use_index < Uses.size (); use_index++)
1758            {
1759            Use* u = (Use*) Uses[use_index];
1760            cout << "  use[" << use_index << "] p=" << u->package <<
1761            " v=" << u->version <<
1762            " discarded=" << u->discarded <<
1763            " selected=" << u->selected <<
1764            endl;
1765            }
1766           
1767            cout << "parsing at " << CmtSystem::pwd () << endl;
1768            }
1769          */
1770         
1771          /**
1772             Get the previous set of effective use statements
1773             that might have been obtained in a previous build.
1774             This is stored in uses.log. Ignored if file does not exist.
1775          */
1776         
1777          //Cmt::parse_requirements ("uses.log", use);
1778         
1779          if (Cmt::get_debug ())
1780            {
1781              cout << "Parsing requirements file at " << CmtSystem::pwd () << endl;
1782            }
1783         
1784          Cmt::parse_requirements ("requirements", use);
1785        }
1786    }
1787
1788  CmtSystem::cd (here);
1789
1790  return (use);
1791}
1792
1793//----------------------------------------------------------
1794void Use::discard ()
1795{
1796  discarded = true;
1797}
1798
1799//----------------------------------------------------------
1800void Use::undiscard ()
1801{
1802  discarded = false;
1803}
1804
1805//----------------------------------------------------------
1806void Use::select ()
1807{
1808  selected = true;
1809}
1810
1811//----------------------------------------------------------
1812void Use::unselect ()
1813{
1814  selected = false;
1815}
1816
1817//----------------------------------------------------------
1818bool Use::is_selected ()
1819{
1820  return (selected);
1821}
1822
1823/**
1824 *    Check if the package makes use of the specified package/version
1825 *
1826 *    The seach only considers the first level of uses (thus it is
1827 *   NOT recursive)
1828 */
1829bool Use::is_client (const cmt_string& used_package,
1830                     const cmt_string& used_version)
1831{
1832  // A package is client of itself
1833  if ((package == used_package) &&
1834      (version == used_version)) return (true);
1835
1836  if (discarded) return (false);
1837
1838  int i;
1839
1840  for (i = 0; i < sub_uses.size (); i++)
1841    {
1842      Use* use = sub_uses[i];
1843      if (use == 0) continue;
1844
1845      if ((use->package == used_package) &&
1846          (use->version == used_version)) return (true);
1847
1848      /*
1849        if (use->is_client (used_package, used_version))
1850        {
1851        return (true);
1852        }
1853      */
1854    }
1855
1856  return (false);
1857}
1858
1859//----------------------------------------------------------
1860void Use::apply_global_patterns ()
1861{
1862  int i;
1863
1864  Pattern::PatternVector& vector = Pattern::patterns ();
1865
1866  for (i = 0; i < vector.size (); i++)
1867    {
1868      Pattern& p = vector[i];
1869
1870      if (p.global)
1871        {
1872          p.apply (this);
1873        }
1874    }
1875}
1876
1877//----------------------------------------------------------
1878void Use::set_include_path (const cmt_string& new_path)
1879{
1880  include_path = new_path;
1881}
1882
1883/**
1884 *   Compute the full real path of a found package.
1885 *   Takes the structuring style into account
1886 *
1887 *    Result is used to fill in the referenced string
1888 *    Result does NOT include the trailing file_separator
1889 */
1890void Use::get_full_path (cmt_string& s) const
1891{
1892  if (real_path == "") s = CmtSystem::pwd ();
1893  else s = real_path;
1894
1895  s += CmtSystem::file_separator ();
1896  s += package;
1897 
1898  s += CmtSystem::file_separator ();
1899  s += version;
1900}
1901
1902/**
1903 *   Compute the full real path of a found package.
1904 *   Takes the structuring style into account
1905 */
1906cmt_string Use::get_full_path () const
1907{
1908  cmt_string result;
1909
1910  get_full_path (result);
1911
1912  return (result);
1913}
1914
1915/**
1916 *   Considering a given path, try and reduce the part of it
1917 *  that corresponds to the full path of this package into its
1918 *  normal form ${<PACKAGE>ROOT}
1919 *   The argument is modified if the pattern is exactly found.
1920 */
1921void Use::reduce_path (cmt_string& s) const
1922{
1923  cmt_string pattern;
1924  get_full_path (pattern);
1925  pattern += CmtSystem::file_separator ();
1926 
1927  cmt_string replacement = "${";
1928  replacement += prefix;
1929  replacement += "ROOT}";
1930
1931  s.replace (pattern, replacement);
1932}
1933
1934//----------------------------------------------------------
1935void Use::fill_includes_macro (cmt_string& buffer) const
1936{
1937  if (include_path == "")
1938    {
1939      buffer += "$(ppcmd)\"$(";
1940      buffer += package;
1941      buffer += "_root)";
1942      buffer += CmtSystem::file_separator ();
1943      buffer += "src\" ";
1944    }
1945  else if (include_path != "none")
1946    {
1947      buffer += "$(ppcmd)\"";
1948      buffer += include_path;
1949      buffer += "\" ";
1950    }
1951 
1952  for (int i = 0; i < includes.size (); i++)
1953    {
1954      Include& incl = includes[i];
1955     
1956      buffer += "$(ppcmd)\"";
1957      buffer += incl.name;
1958      buffer += "\" ";
1959    }
1960}
1961
1962//----------------------------------------------------------
1963void Use::fill_macro (cmt_string& buffer, const cmt_string& suffix) const
1964{
1965  buffer += " $(";
1966  buffer += package;
1967  buffer += "_";
1968  buffer += suffix;
1969  buffer += ") ";
1970}
1971
1972/**
1973 *   This function tries to get the replacement of a Use when it has
1974 *  been discarded by a better match to version constraints.
1975 */
1976Use* Use::get_selected_version ()
1977{
1978  static Use::UsePtrVector& Uses = uses ();
1979
1980    //cout << "get_selected_version for package " << package << endl;
1981
1982  if (!discarded) return (this);
1983
1984  for (int i = 0; i < Uses.size (); i++)
1985    {
1986      Use* u = Uses[i];
1987      if (u == 0) continue;
1988      if (u->discarded) continue;
1989      if (u->package == package) 
1990        {
1991            //cout << "  got a version" << endl;
1992          return (u);
1993        }
1994    }
1995
1996  return (0);
1997}
1998
1999void Use::set_auto_imports (State new_state)
2000{
2001  if (Cmt::get_debug ())
2002    {
2003      cout << "Use::set_auto_imports>(" << package << ") " 
2004           << auto_imports << " -> " << new_state << endl;
2005    }
2006
2007  if (auto_imports == new_state) return;
2008 
2009  State old_state = auto_imports;
2010 
2011  auto_imports = new_state;
2012
2013    // We propagate only when we switch from Off to On
2014
2015  if ((old_state == Off) && (new_state == On))
2016    {
2017      cmt_string s;
2018      static const cmt_string state_text[] = {"Unspecified", "Off", "On"};
2019
2020      if (Cmt::get_debug ())
2021        {
2022          s = "Use::set_auto_imports>(";
2023          s += package;
2024          s += ") ";
2025
2026          cout << s << endl;
2027        }
2028
2029      for (int i = 0; i < sub_uses.size (); i++)
2030        {
2031          Use* u = sub_uses[i];
2032          State state = sub_use_auto_imports[i];
2033         
2034          if (Cmt::get_debug ())
2035            {
2036              s += " ";
2037              s += u->package;
2038              s += "(";
2039              s += state_text[state];
2040              s += ")";
2041            }
2042
2043          if (state == Unspecified)
2044            {
2045              u->set_auto_imports (On);
2046            }
2047        }
2048         
2049      if (Cmt::get_debug ())
2050        {
2051          cout << s << endl;
2052        }
2053    }
2054}
2055
2056void Use::set_native_version (bool state)
2057{
2058  m_has_native_version = state;
2059}
2060
2061bool Use::has_native_version () const
2062{
2063  return (m_has_native_version);
2064}
2065
2066//----------------------------------------------------------
2067bool Use::get_paths (Use* to, UsePtrVector& list)
2068{
2069  bool found = false;
2070  bool cycle = false;
2071
2072  static int level = 0;
2073  static UsePtrVector stack;
2074
2075  if (level == 0)
2076    {
2077      stack.clear ();
2078    }
2079 
2080  // Protect against cycles.
2081  for (int k = 0; k < stack.size (); k++)
2082    {
2083      Use* u = stack[k];
2084      if (u == this) 
2085        {
2086          if (Cmt::get_debug ())
2087            {
2088              cout << "Use::get_paths." << level << ">" << package << " cycle " << endl;
2089            }
2090
2091          return (false);
2092        }
2093    }
2094
2095  // Save this to the protection stack.
2096  if (stack.size () <= level)
2097    {
2098      stack.push_back (this);
2099    }
2100  else
2101    {
2102      stack[level] = this;
2103    }
2104
2105    // First figure out whether 'to' is used by 'this'.
2106
2107  if (Cmt::get_debug ())
2108    {
2109      cout << "Use::get_paths." << level << ">" << package << " to=" << to->package << " list[" << list.size () << "]" << endl;
2110    }
2111
2112  if (this == to)
2113    {
2114      found = true;
2115    }
2116  else
2117    {
2118      for (int n = 0; n < sub_uses.size (); n++)
2119        {
2120          Use* use = sub_uses[n];
2121
2122          if (use == 0) continue;
2123
2124          if (Cmt::get_debug ())
2125            {
2126              cout << "  Use::get_paths." << level << "> try1 sub=" << use->package << endl;
2127            }
2128
2129          if (use->discarded)
2130            {
2131              Use* u;
2132
2133              u = use->get_selected_version ();
2134              if (u == 0) continue;
2135
2136              use = u;
2137            }
2138
2139          cycle = false;
2140     
2141            // This use must not be already in the list (protection against cycles)
2142
2143          for (int m = 0; m < list.size (); m++)
2144            {
2145              Use* u = list[m];
2146              if (u == use)
2147                {
2148                  cycle = true;
2149                  break;
2150                }
2151            }
2152
2153          if (cycle) 
2154            {
2155              found = true;
2156              continue;
2157            }
2158
2159          if (Cmt::get_debug ())
2160            {
2161              cout << "  Use::get_paths." << level << "> try2 sub=" << use->package << endl;
2162            }
2163
2164          level++;
2165          bool r = use->get_paths (to, list);
2166          level--;
2167
2168          if (r)
2169            {
2170              found = true;
2171            }
2172        }
2173    }
2174
2175  if (found)
2176    {
2177      cycle = false;
2178
2179      for (int m = 0; m < list.size (); m++)
2180        {
2181          Use* u = list[m];
2182          if (u == this)
2183            {
2184              cycle = true;
2185              break;
2186            }
2187        }
2188
2189      if (!cycle)
2190        {
2191          if (Cmt::get_debug ())
2192            {
2193              cout << "Use::get_paths." << level << "> push " << package << endl;
2194            }
2195          list.push_back (this);
2196        }
2197    }
2198
2199  return (found); 
2200}
2201
2202//----------------------------------------------------------
2203bool Use::located () const
2204{
2205  return (m_located);
2206}
2207
2208//----------------------------------------------------------
2209void Use::show_sub_uses (bool skip_discarded)
2210{
2211  int n;
2212  Use* use;
2213  static int level = 0;
2214
2215  if (skip_discarded && discarded) return;
2216
2217  if (level > 0)
2218    {
2219      cout << "# ";
2220      for (n = 0; n < (level-1); n++) cout << "  ";
2221
2222      cout << "use " << package << " " << specified_version;
2223
2224      if (specified_path != "") cout << " " << specified_path;
2225
2226      if (version_alias != "")
2227        {
2228          cout << " | " << version_alias << " " << path_alias;
2229        }
2230
2231      if (scope == ScopeUnspecified) cout << " unspecified";
2232      else if (scope != ScopePublic) cout << " (private)";
2233      //else cout << " private";
2234
2235      if (auto_imports == Off) cout << " (no_auto_imports)";
2236
2237      if (m_has_native_version)
2238        {
2239          cmt_string n = package;
2240          n += "_native_version";
2241
2242          Symbol* s = Symbol::find (n);
2243          if (s != 0)
2244            {
2245              cmt_string value = s->resolve_macro_value ();
2246              cout << " (native_version=" << value << ")";
2247            }
2248        }
2249
2250      cout << endl;
2251    }
2252
2253  if (selected) return;
2254  selected = true;
2255
2256  level++;
2257  for (n = 0; n < sub_uses.size (); n++)
2258    {
2259      use = sub_uses[n];
2260      if (use == 0) continue;
2261
2262      ScopeType saved_scope = use->scope;
2263      State saved_state = use->auto_imports;
2264
2265      use->scope = sub_use_scopes[n];
2266      use->auto_imports = sub_use_auto_imports[n];
2267
2268      use->show_sub_uses (skip_discarded);
2269
2270      use->scope = saved_scope;
2271      use->auto_imports = saved_state;
2272    }
2273  level--;
2274}
2275
2276//----------------------------------------------------------
2277Use& Use::current ()
2278{
2279  static UseVector& AllUses = all_uses ();
2280  static Use* current_use = 0;
2281
2282  if ((current_use == 0) || (AllUses.size () == 0))
2283    {
2284      Use& use_object = AllUses.add ();
2285      current_use = &use_object;
2286    }
2287
2288  return (*current_use);
2289}
2290
2291//----------------------------------------------------------
2292const Use& Use::const_current ()
2293{
2294  const Use& use = Use::current ();
2295
2296  return (use);
2297}
2298
2299//----------------------------------------------------------
2300Use::UseVector& Use::all_uses ()
2301{
2302  static Database& db = Database::instance ();
2303  static UseVector& AllUses = db.all_uses ();
2304
2305  return (AllUses);
2306}
2307
2308//----------------------------------------------------------
2309Use::UsePtrVector& Use::uses ()
2310{
2311  static Database& db = Database::instance ();
2312  static UsePtrVector& Uses = db.uses ();
2313
2314  return (Uses);
2315}
2316
2317//----------------------------------------------------------
2318VersionSelector& VersionSelector::instance ()
2319{
2320  static BestFitSelector best_fit;
2321  static BestFitNoCheckSelector best_fit_no_check;
2322  static FirstChoiceSelector first_choice;
2323  static LastChoiceSelector last_choice;
2324  static KeepAllSelector keep_all;
2325
2326  switch (Cmt::get_current_strategy ())
2327    {
2328    case BestFit:
2329      return (best_fit);
2330    case BestFitNoCheck:
2331      return (best_fit_no_check);
2332    case FirstChoice:
2333      return (first_choice);
2334    case LastChoice:
2335      return (last_choice);
2336    case KeepAll:
2337      return (keep_all);
2338    default:
2339      return (best_fit);
2340    }
2341}
2342
2343//----------------------------------------------------------
2344//
2345//  Check if the specified version is better than the
2346//  current one.
2347//
2348//----------------------------------------------------------
2349Use* BestFitSelector::operate (Use* ref_use, Use* new_use)
2350{
2351  Use* selected = ref_use;
2352
2353  int old_v = -1;
2354  int old_r = -1;
2355  int old_p = -1;
2356  cmt_string old_pp;
2357
2358  int new_v = -1;
2359  int new_r = -1;
2360  int new_p = -1;
2361  cmt_string new_pp;
2362
2363  int alias_v = -1;
2364  int alias_r = -1;
2365  int alias_p = -1;
2366  cmt_string alias_pp;
2367
2368  enum { no_alias, new_has_alias, ref_has_alias } has_alias = no_alias;
2369
2370  CmtSystem::is_version_directory (ref_use->version, old_v, old_r, old_p);
2371  old_pp = ref_use->path;
2372
2373  CmtSystem::is_version_directory (new_use->version, new_v, new_r, new_p);
2374  new_pp = new_use->path;
2375
2376  if (new_use->version_alias != "")
2377    {
2378      has_alias = new_has_alias;
2379      CmtSystem::is_version_directory (new_use->version_alias, 
2380                                       alias_v, alias_r, alias_p);
2381      alias_pp = new_use->path_alias;
2382    }
2383  else if (ref_use->version_alias != "")
2384    {
2385      has_alias = ref_has_alias;
2386      CmtSystem::is_version_directory (ref_use->version_alias, 
2387                                       alias_v, alias_r, alias_p);
2388      alias_pp = ref_use->path_alias;
2389    }
2390
2391  ref_use->undiscard ();
2392  new_use->undiscard ();
2393
2394  if (new_v != old_v)
2395    {
2396      if (has_alias != no_alias)
2397        {
2398          if (has_alias == new_has_alias)
2399            {
2400              new_v = alias_v;
2401              new_r = alias_r;
2402              new_p = alias_p;
2403              new_pp = alias_pp;
2404            }
2405          else if (has_alias == ref_has_alias)
2406            {
2407              old_v = alias_v;
2408              old_r = alias_r;
2409              old_p = alias_p;
2410              old_pp = alias_pp;
2411            }
2412        }
2413    }
2414
2415  if (new_v != old_v)
2416    {
2417      if (!Cmt::get_quiet ())
2418        cout << "# Required version " << new_use->version <<
2419          " of package " << ref_use->package <<
2420          " incompatible with selected version " << ref_use->version <<
2421          endl;
2422
2423      CmtError::set (CmtError::version_conflict, "BestFitSelector::operate> ");
2424
2425      if (ref_use != new_use) new_use->discard ();
2426    }
2427  else if (new_r < old_r)
2428    {
2429      //
2430      // we plan to discard new_use, but if it was specified as explicit
2431      // and ref_use was wildcarded then new_use will win !!
2432      //
2433      // So then we'll have to understand where are the wild
2434      // cards... If they are on v or r, then we consider them.
2435      //
2436      //
2437
2438
2439      bool new_is_wildcarded = false;
2440      bool ref_is_wildcarded = false;
2441
2442      if (new_use->specified_version.find ("*") != cmt_string::npos)
2443        {
2444          int nv = -1;
2445          int nr = -1;
2446          int np = -1;
2447
2448          CmtSystem::is_version_directory (new_use->specified_version, nv, nr, np);
2449          if ((nv == -1) || (nr == -1)) new_is_wildcarded = true;
2450        }
2451
2452      if (ref_use->specified_version.find ("*") != cmt_string::npos)
2453        {
2454          int nv = -1;
2455          int nr = -1;
2456          int np = -1;
2457
2458          CmtSystem::is_version_directory (ref_use->specified_version, nv, nr, np);
2459          if ((nv == -1) || (nr == -1)) new_is_wildcarded = true;
2460        }
2461
2462      if (!ref_is_wildcarded && new_is_wildcarded)
2463        {
2464          if (ref_use != new_use) ref_use->discard ();
2465          selected = new_use;
2466          selected->done = false; // Will read the new requirements
2467        }
2468      else
2469        {
2470          if (!Cmt::get_quiet ())
2471            cout << "# keep release " << ref_use->version <<
2472              " of package " << ref_use->package <<
2473              " (ignore release " << new_use->version << ")" <<
2474              endl;
2475
2476          if (ref_use != new_use) new_use->discard ();
2477        }
2478    }
2479  else if (new_r > old_r)
2480    {
2481      if (!Cmt::get_quiet ())
2482        {
2483          cout << "# Select release " << new_use->version <<
2484            " of package " << ref_use->package <<
2485            " instead of existing " << ref_use->version <<
2486            endl;
2487        }
2488
2489      if (ref_use != new_use) ref_use->discard ();
2490      selected = new_use;
2491      selected->done = false; // Will read the new requirements
2492    }
2493  else if (new_p > old_p)
2494    {
2495      if (!Cmt::get_quiet ())
2496        {
2497          cout << "# Select patch " << new_use->version <<
2498            " of package " << ref_use->package <<
2499            " instead of existing " << ref_use->version <<
2500            endl;
2501        }
2502
2503      if (ref_use != new_use) ref_use->discard ();
2504      selected = new_use;
2505      selected->done = false; // Will read the new requirements
2506    }
2507  else if (new_pp != old_pp) // same version-r-p but from different path
2508    {
2509      if (ref_use != new_use) ref_use->discard ();
2510      selected = new_use;
2511      selected->done = false; // Will read the new requirements
2512    }
2513
2514  return (selected);
2515}
2516
2517//----------------------------------------------------------
2518//
2519//  Check if the specified version is better than the
2520//  current one. We don't check major ids incompatibilities
2521//
2522//----------------------------------------------------------
2523Use* BestFitNoCheckSelector::operate (Use* ref_use, Use* new_use)
2524{
2525  Use* selected = ref_use;
2526
2527  int old_v = -1;
2528  int old_r = -1;
2529  int old_p = -1;
2530  cmt_string old_pp;
2531
2532  int new_v = -1;
2533  int new_r = -1;
2534  int new_p = -1;
2535  cmt_string new_pp;
2536
2537  int alias_v = -1;
2538  int alias_r = -1;
2539  int alias_p = -1;
2540  cmt_string alias_pp;
2541
2542  enum { no_alias, new_has_alias, ref_has_alias } has_alias = no_alias;
2543
2544  CmtSystem::is_version_directory (ref_use->version, old_v, old_r, old_p);
2545  old_pp = ref_use->path;
2546
2547  CmtSystem::is_version_directory (new_use->version, new_v, new_r, new_p);
2548  new_pp = new_use->path;
2549
2550  if (new_use->version_alias != "")
2551    {
2552      has_alias = new_has_alias;
2553      CmtSystem::is_version_directory (new_use->version_alias, 
2554                                       alias_v, alias_r, alias_p);
2555      alias_pp = new_use->path_alias;
2556    }
2557  else if (ref_use->version_alias != "")
2558    {
2559      has_alias = ref_has_alias;
2560      CmtSystem::is_version_directory (ref_use->version_alias, 
2561                                       alias_v, alias_r, alias_p);
2562      alias_pp = ref_use->path_alias;
2563    }
2564
2565  ref_use->undiscard ();
2566  new_use->undiscard ();
2567
2568  if (new_v != old_v)
2569    {
2570      if (has_alias != no_alias)
2571        {
2572          if (has_alias == new_has_alias)
2573            {
2574              new_v = alias_v;
2575              new_r = alias_r;
2576              new_p = alias_p;
2577              new_pp = alias_pp;
2578            }
2579          else if (has_alias == ref_has_alias)
2580            {
2581              old_v = alias_v;
2582              old_r = alias_r;
2583              old_p = alias_p;
2584              old_pp = alias_pp;
2585            }
2586        }
2587    }
2588
2589  if (new_v < old_v)
2590    {
2591      if (!Cmt::get_quiet ())
2592        {
2593          cout << "# Keep version " << ref_use->version <<
2594            " of package " << ref_use->package <<
2595            " (ignore version " << new_use->version << ")" <<
2596            endl;
2597        }
2598
2599      if (ref_use != new_use) new_use->discard ();
2600    }
2601  else if (new_v > old_v)
2602    {
2603      if (!Cmt::get_quiet ())
2604        {
2605          cout << "# Select version " << new_use->version <<
2606            " of package " << ref_use->package <<
2607            " instead of existing " << ref_use->version <<
2608            endl;
2609        }
2610
2611      if (ref_use != new_use) ref_use->discard ();
2612      selected = new_use;
2613      selected->done = false; // Will read the new requirements
2614    }
2615  else if (new_r < old_r)
2616    {
2617      if (!Cmt::get_quiet ())
2618        {
2619          cout << "# keep release " << ref_use->version <<
2620            " of package " << ref_use->package <<
2621            " (ignore release " << new_use->version << ")" <<
2622            endl;
2623        }
2624
2625      if (ref_use != new_use) new_use->discard ();
2626    }
2627  else if (new_r > old_r)
2628    {
2629      if (!Cmt::get_quiet ())
2630        {
2631          cout << "# Select release " << new_use->version <<
2632            " of package " << ref_use->package <<
2633            " instead of existing " << ref_use->version <<
2634            endl;
2635        }
2636
2637      if (ref_use != new_use) ref_use->discard ();
2638      selected = new_use;
2639      selected->done = false; // Will read the new requirements
2640    }
2641  else if (new_p > old_p)
2642    {
2643      if (!Cmt::get_quiet ())
2644        {
2645          cout << "# Select patch " << new_use->version <<
2646            " of package " << ref_use->package <<
2647            " instead of existing " << ref_use->version <<
2648            endl;
2649        }
2650
2651      if (ref_use != new_use) ref_use->discard ();
2652      selected = new_use;
2653      selected->done = false; // Will read the new requirements
2654    }
2655  else if (new_pp != old_pp) // same version-r-p but from different path
2656    {
2657      if (ref_use != new_use) ref_use->discard ();
2658      selected = new_use;
2659      selected->done = false; // Will read the new requirements
2660    }
2661
2662  return (selected);
2663}
2664
2665//----------------------------------------------------------
2666Use* FirstChoiceSelector::operate (Use* ref_use, Use* new_use)
2667{
2668  ref_use->undiscard ();
2669  new_use->undiscard ();
2670
2671  new_use->done = false; // Will read the new requirements
2672  if (ref_use != new_use) new_use->discard ();
2673  return (ref_use);
2674}
2675
2676//----------------------------------------------------------
2677Use* LastChoiceSelector::operate (Use* ref_use, Use* new_use)
2678{
2679  ref_use->undiscard ();
2680  new_use->undiscard ();
2681
2682  new_use->done = false; // Will read the new requirements
2683  if (ref_use != new_use) ref_use->discard ();
2684  return (new_use);
2685}
2686
2687//----------------------------------------------------------
2688Use* KeepAllSelector::operate (Use* ref_use, Use* new_use)
2689{
2690  ref_use->undiscard ();
2691  new_use->undiscard ();
2692
2693  new_use->done = false; // Will read the new requirements
2694  return (new_use);
2695}
Note: See TracBrowser for help on using the repository browser.