source: CMT/v1r18p20051108/source/cmt_system.cxx @ 594

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

Permit version directories not starting with a letter - see CL 291

  • Property svn:eol-style set to native
File size: 46.3 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// See the complete license in cmt_license.txt "http://www.cecill.info".
5//-----------------------------------------------------------
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <errno.h>
11
12#ifdef WIN32
13#include <direct.h>
14#define chdir _chdir
15#define rmdir _rmdir
16//#define mkdir _mkdir
17#define getcwd _getcwd
18#define popen _popen
19#define pclose _pclose
20#define S_IFDIR _S_IFDIR
21#define USE_GETCWD 1
22
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <time.h>
26#include <io.h>
27#include <windows.h>
28
29#define stat _stat
30
31#else
32#include <unistd.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <time.h>
36#include <dirent.h>
37#endif
38
39#ifdef __hpux__
40#define USE_GETCWD 1
41#endif
42
43#ifdef __linux__
44#define USE_GETCWD 1
45#endif
46
47#ifdef USE_GETCWD
48char* getwd (const char* name)
49{
50  char dir[256];
51  getcwd (dir, sizeof (dir));
52  strcpy ((char*) name, dir);
53  return ((char*) name);
54}
55#endif
56
57#include "cmt_system.h"
58#include "cmt_error.h"
59
60//--------------------------------------------------
61cmt_string CmtSystem::pwd ()
62{
63  char buffer[256] = "";
64  char* ptr = 0;
65  char* pwd_env = 0;
66
67#ifdef USE_PWD
68  pwd_env = ::getenv ("PWD"); 
69#endif
70
71  if (pwd_env != 0)
72    {
73      strcpy (buffer, pwd_env);
74    }
75  else
76    {
77      ptr = getcwd (buffer, sizeof (buffer));
78    }
79
80  const char* t = &buffer[0];
81  return ((cmt_string) t);
82}
83
84//--------------------------------------------------
85bool CmtSystem::cd (const cmt_string& dir)
86{
87  static cmt_string new_dir;
88
89  if ((dir.size () == 2) && (dir[1] == ':'))
90    {
91      new_dir = dir;
92      new_dir += file_separator ();
93      if (chdir (new_dir.c_str ()) == 0) 
94        {
95#ifdef USE_PWD
96          new_dir = "PWD=";
97          new_dir += dir;
98          new_dir += file_separator ();
99          putenv (new_dir);
100#endif
101
102          return (true);
103        }
104      return (false);
105    }
106  else
107    {
108      if (chdir (dir.c_str ()) == 0) 
109        {
110#ifdef USE_PWD
111          new_dir = "PWD=";
112          new_dir += dir;
113          putenv (new_dir);
114#endif
115
116          return (true);
117        }
118      return (false);
119    }
120}
121
122//--------------------------------------------------
123void CmtSystem::basename (const cmt_string& file_name, cmt_string& result)
124{
125  int pos = file_name.find_last_of ('/');
126  if (pos == cmt_string::npos)
127    {
128      pos = file_name.find_last_of ('\\');
129    }
130
131  if (pos == cmt_string::npos)
132    {
133      result = file_name;
134    }
135  else
136    {
137      file_name.substr (pos + 1, result);
138    }
139}
140
141//--------------------------------------------------
142void CmtSystem::basename (const cmt_string& file_name,
143                          const cmt_string& /*suffix*/,
144                          cmt_string& result)
145{
146  basename (file_name, result);
147
148  int pos;
149
150  pos = result.find_last_of ('.');
151
152  if (pos != cmt_string::npos)
153    {
154      result.erase (pos);
155    }
156}
157
158//--------------------------------------------------
159void CmtSystem::dirname (const cmt_string& file_name, cmt_string& result)
160{
161  int pos = file_name.find_last_of ('/');
162  if (pos == cmt_string::npos)
163    {
164      pos = file_name.find_last_of ('\\');
165    }
166
167  if (pos == cmt_string::npos)
168    {
169      result = "";
170    }
171  else
172    {
173      result = file_name;
174      result.erase (pos);
175    }
176}
177
178//--------------------------------------------------
179void CmtSystem::name (const cmt_string& file_name, cmt_string& result)
180{
181  int pos;
182
183  result = file_name;
184
185  // remove the suffix
186
187  pos = result.find_last_of ('.');
188
189  if (pos != cmt_string::npos)
190    {
191      result.erase (pos);
192    }
193
194  // remove the directory name
195
196  pos = result.find_last_of ('/');
197  if (pos == cmt_string::npos)
198    {
199      pos = result.find_last_of ('\\');
200    }
201
202  if (pos != cmt_string::npos)
203    {
204      result.erase (0, pos + 1);
205    }
206}
207
208//-------------------------------------------------
209void CmtSystem::get_suffix (const cmt_string& file, cmt_string& result)
210{
211  int pos = file.find_last_of ('.');
212  int sep = file.find_last_of (file_separator ());
213
214  if ((pos == cmt_string::npos) || (pos < sep))
215    {
216      result = "";
217    }
218  else
219    {
220      file.substr (pos + 1, result);
221    }
222}
223
224//-------------------------------------------------
225void CmtSystem::get_dot_suffix (const cmt_string& file, cmt_string& result)
226{
227  int pos = file.find_last_of ('.');
228  int sep = file.find_last_of (file_separator ());
229
230  if ((pos == cmt_string::npos) || (pos < sep))
231    {
232      result = "";
233    }
234  else
235    {
236      file.substr (pos, result);
237    }
238}
239
240//--------------------------------------------------
241bool CmtSystem::has_prefix (const cmt_string& name)
242{
243  if ((name.find ('/') == cmt_string::npos) &&
244      (name.find ('\\') == cmt_string::npos))
245    {
246      return (false);
247    }
248
249  return (true);
250}
251
252//--------------------------------------------------
253bool CmtSystem::absolute_path (const cmt_string& name)
254{
255  if (name.size () == 0) return (false);
256
257  if ((name[0] == '/') ||
258      (name[0] == '\\')) return (true);
259
260  if (name.size () >= 2)
261    {
262      if (name[1] == ':')
263        {
264          return (true);
265        }
266    }
267  return (false);
268}
269
270//--------------------------------------------------
271bool CmtSystem::has_device (const cmt_string& name)
272{
273#ifdef WIN32
274  if (name.size () == 0) return (false);
275
276  if (name.size () >= 2)
277    {
278      if (name[1] == ':')
279        {
280          return (true);
281        }
282      else if ((name[0] == '\\') && (name[1] == '\\'))
283        {
284          return (true);
285        }
286    }
287#endif
288
289  return (false);
290}
291
292//--------------------------------------------------
293cmt_string CmtSystem::current_branch ()
294{
295  cmt_string result;
296
297  basename (pwd (), result);
298
299  return (result);
300}
301
302//--------------------------------------------------
303bool CmtSystem::test_directory (const cmt_string& name)
304{
305  struct stat file_stat;
306  int status;
307
308  status = stat (name.c_str (), &file_stat);
309
310  //cerr << "status(stat) for " << name << " : " << status << " st_mode=" << file_stat.st_mode << endl;
311
312  if (status == 0)
313    {
314      if ((file_stat.st_mode & S_IFDIR) == 0)
315        {
316          return (false);
317        }
318      else
319        {
320          return (true);
321        }
322    }
323  else
324    {
325      return (false);
326    }
327}
328
329//--------------------------------------------------
330bool CmtSystem::test_file (const cmt_string& name)
331{
332  struct stat file_stat;
333  int status;
334
335  status = stat (name.c_str (), &file_stat);
336
337  if (status == 0)
338    {
339      if ((file_stat.st_mode & S_IFDIR) == 0)
340        {
341          return (true);
342        }
343      else
344        {
345          return (false);
346        }
347    }
348  else
349    {
350      return (false);
351    }
352}
353
354//--------------------------------------------------
355bool CmtSystem::compare_files (const cmt_string& name1,
356                               const cmt_string& name2)
357{
358  struct stat file_stat1;
359  struct stat file_stat2;
360  int status;
361
362  status = stat (name1.c_str (), &file_stat1);
363
364  if (status == 0)
365    {
366      if ((file_stat1.st_mode & S_IFDIR) != 0)
367        {
368          return (false);
369        }
370    }
371  else
372    {
373      return (false);
374    }
375
376  status = stat (name2.c_str (), &file_stat2);
377
378  if (status == 0)
379    {
380      if ((file_stat2.st_mode & S_IFDIR) != 0)
381        {
382          return (false);
383        }
384    }
385  else
386    {
387      return (false);
388    }
389
390  if (((int) file_stat1.st_size) != ((int) file_stat2.st_size))
391    {
392      return (false);
393    }
394
395  static cmt_string s1;
396  static cmt_string s2;
397
398  s1.read (name1);
399  s2.read (name2);
400
401  return ((s1 == s2));
402}
403
404//--------------------------------------------------
405//
406// Check if the file "name1" is identical to "name2"
407// if they are identical, "name1" will be simply deleted
408// otherwise "name1" will be copied to "name2" and deleted afterwards
409//
410//--------------------------------------------------
411bool CmtSystem::compare_and_update_files (const cmt_string& name1,
412                                          const cmt_string& name2)
413{
414  struct stat file_stat1;
415  struct stat file_stat2;
416  static cmt_string s1;
417  static cmt_string s2;
418  int status;
419
420  status = stat (name1.c_str (), &file_stat1);
421
422  if (status == 0)
423    {
424      if ((file_stat1.st_mode & S_IFDIR) != 0)
425        {
426          // name1 is a directory.
427          return (false);
428        }
429    }
430  else
431    {
432      // name1 does not exist
433      return (false);
434    }
435
436  s1.read (name1);
437
438  status = stat (name2.c_str (), &file_stat2);
439
440  if (status == 0)
441    {
442      if ((file_stat2.st_mode & S_IFDIR) != 0)
443        {
444          // name2 is a directory
445          return (false);
446        }
447
448      if (((int) file_stat1.st_size) == ((int) file_stat2.st_size))
449        {
450          s2.read (name2);
451          if (s1 == s2)
452            {
453              unlink (name1);
454              return (true);
455            }
456        }
457    }
458
459  FILE* f = fopen (name2, "wb");
460  if (f != NULL)
461    {
462      s1.write (f);
463      fclose (f);
464
465      unlink (name1);
466
467      return (true);
468    }
469  else
470    {
471      //
472      // keep the new file "name1" since it cannot be
473      // copied to "name2"
474      //
475      return (false);
476    }
477}
478
479//--------------------------------------------------
480int CmtSystem::file_size (const cmt_string& name)
481{
482  struct stat file_stat;
483  int status;
484
485  status = stat (name.c_str (), &file_stat);
486
487  if (status == 0)
488    {
489      return ((int) file_stat.st_size);
490    }
491  else
492    {
493      return (0);
494    }
495}
496
497//--------------------------------------------------
498char CmtSystem::file_separator ()
499{
500#ifdef WIN32
501  return ('\\');
502#else
503  return ('/');
504#endif
505}
506
507/**
508 *  Transform all / or \ characters in the text into the current file_separator
509 *  Reduce all multiple file_separator into single ones.
510 */
511void CmtSystem::reduce_file_separators (cmt_string& text)
512{
513  if (file_separator () == '/')
514    {
515      text.replace_all ("\\", "/");
516      while (text.find ("//") != cmt_string::npos)
517        {
518          text.replace_all ("//", "/");
519        }
520    }
521  else
522    {
523      text.replace_all ("/", "\\");
524      while (text.find ("\\\\") != cmt_string::npos)
525        {
526          text.replace_all ("\\\\", "\\");
527        }
528    }
529}
530
531//--------------------------------------------------
532char CmtSystem::path_separator ()
533{
534#ifdef WIN32
535  return (';');
536#else
537  return (':');
538#endif
539}
540
541//--------------------------------------------------
542char CmtSystem::command_separator ()
543{
544#ifdef WIN32
545  return ('&');
546#else
547  return (';');
548#endif
549}
550
551//--------------------------------------------------
552const cmt_string& CmtSystem::ev_open ()
553{
554#ifdef WIN32
555  static const cmt_string s = "%";
556#else
557  static const cmt_string s = "${";
558#endif
559
560  return (s);
561}
562
563//--------------------------------------------------
564const cmt_string& CmtSystem::ev_close ()
565{
566#ifdef WIN32
567  static const cmt_string s = "%";
568#else
569  static const cmt_string s = "}";
570#endif
571
572  return (s);
573}
574
575//-------------------------------------------------
576bool CmtSystem::create_symlink (const cmt_string& oldname,
577                                const cmt_string& newname)
578{
579  ::unlink (newname.c_str ());
580
581#ifdef WIN32
582  int status = 1;
583#else
584  int status = ::symlink (oldname.c_str (), newname.c_str ());
585#endif
586
587  if (status == 0) return (true);
588  return (false);
589}
590
591//-------------------------------------------------
592bool CmtSystem::remove_file (const cmt_string& name)
593{
594  if (::unlink (name) != 0)
595    {
596      cerr << "#CMT> Cannot remove file " << name << endl;
597      return (false);
598    }
599
600  return (true);
601}
602
603//-------------------------------------------------
604bool CmtSystem::remove_directory (const cmt_string& name)
605{
606  //cerr << "Try to remove directory " << name << endl;
607
608  cmt_string_vector files;
609
610  scan_dir (name, files);
611
612  for (int i = 0; i < files.size (); i++)
613    {
614      cmt_string& file = files[i];
615
616      if (test_directory (file))
617        {
618          //cerr << "D=" << file << endl;
619          if (!remove_directory (file)) return (false);
620        }
621      else
622        {
623          //cerr << "F=" << file << endl;
624          if (!remove_file (file)) return (false);
625        }
626    }
627
628  int status = ::rmdir (name);
629  if (status != 0)
630    {
631      cerr << "#CMT> Cannot remove directory " << name << " errno=" << errno << endl;
632      return (false);
633    }
634
635  return (true);
636}
637
638//-------------------------------------------------
639bool CmtSystem::mkdir (const cmt_string& name)
640{
641  static cmt_string_vector path_vector;
642  int i;
643  static cmt_string full_path;
644  char double_fs[] = "  ";
645
646  double_fs[0] = file_separator ();
647  double_fs[1] = file_separator ();
648
649  full_path = name;
650
651  if (file_separator () == '/')
652    {
653      full_path.replace_all ("\\", file_separator ());
654    }
655  else
656    {
657      full_path.replace_all ("/", file_separator ());
658    }
659
660  full_path.replace_all (double_fs, file_separator ());
661
662  split (full_path, file_separator (), path_vector);
663
664  full_path = "";
665
666  if (absolute_path (name))
667    {
668      if (!has_device (name))
669        {
670          full_path = file_separator ();
671        }
672    }
673
674  for (i = 0; i < path_vector.size (); i++)
675    {
676      const cmt_string& path = path_vector[i];
677
678      if (i > 0) full_path += file_separator ();
679      full_path += path;
680
681      if (has_device (path)) continue;
682
683      if (!test_directory (full_path))
684        {
685#ifdef WIN32
686          if (::_mkdir (full_path.c_str ()) != 0)
687            {
688                // cerr << "CMT> cannot create directory " << full_path << endl;
689              return (false);
690            }
691#else
692          if (::mkdir (full_path.c_str (), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) != 0)
693            {
694                // cerr << "CMT> cannot create directory " << full_path << endl;
695              return (false);
696            }
697#endif
698        }
699    }
700
701  return (true);
702}
703
704//----------------------------------------------------------
705void CmtSystem::scan_dir (const cmt_string& dir_name,
706                          cmt_string_vector& list)
707{
708  static cmt_string dir_prefix;
709  static cmt_string name_prefix;
710
711  dir_prefix = dir_name;
712  if (dir_name == "") dir_prefix = ".";
713
714  if (!test_directory (dir_prefix))
715    {
716      dirname (dir_prefix, dir_prefix);
717      basename (dir_name, name_prefix);
718    }
719  else
720    {
721      name_prefix = "";
722    }
723
724  bool need_filter = false;
725
726  int wild_card;
727
728  wild_card = name_prefix.find ('*');
729  if (wild_card != cmt_string::npos)
730    {
731      name_prefix.erase (wild_card);
732    }
733
734  if (name_prefix.size () > 0)
735    {
736      need_filter = true;
737    }
738
739  list.clear ();
740
741#ifdef WIN32
742
743  long dir;
744  struct _finddata_t entry;
745
746  static cmt_string search;
747
748  search = dir_prefix;
749  search += file_separator ();
750  search += "*";
751
752  dir = _findfirst (search.c_str (), &entry);
753  if (dir > 0)
754    {
755      for (;;)
756        {
757          if ((strcmp ((char*) entry.name, ".") != 0) &&
758              (strcmp ((char*) entry.name, "..") != 0) &&
759              (strncmp ((char*) entry.name, ".nfs", 4) != 0))
760            {
761              const char* name = entry.name;
762
763              if (!need_filter ||
764                  (strncmp (name, name_prefix.c_str (), name_prefix.size ()) == 0))
765                {
766                  cmt_string& name_entry = list.add ();
767
768                  name_entry = dir_prefix;
769                  name_entry += file_separator ();
770                  name_entry += name;
771                }
772            }
773
774          int status = _findnext (dir, &entry);
775          if (status != 0)
776            {
777              break;
778            }
779        }
780
781      _findclose (dir);
782    }
783#else
784
785  //cout << "scan_dir> dir=" << dir_name << endl;
786
787  DIR* dir = opendir (dir_prefix.c_str ());
788
789  struct dirent* entry;
790
791  if (dir != 0)
792    {
793      while ((entry = readdir (dir)) != 0)
794        {
795          //if (entry->d_name[0] == '.') continue;
796          if (!strcmp ((char*) entry->d_name, ".")) continue;
797          if (!strcmp ((char*) entry->d_name, "..")) continue;
798          if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue;
799
800          const char* name = entry->d_name;
801
802          if (need_filter &&
803              (strncmp (name, name_prefix.c_str (), name_prefix.size ()) != 0)) continue;
804
805          //cout << "scan_dir> name=" << name << endl;
806
807          cmt_string& name_entry = list.add ();
808
809          name_entry = dir_prefix;
810          name_entry += file_separator ();
811          name_entry += name;
812        }
813
814      closedir (dir);
815    }
816#endif
817
818}
819
820//----------------------------------------------------------
821void CmtSystem::scan_dir (const cmt_string& dir_name,
822                          const cmt_regexp& expression,
823                          cmt_string_vector& list)
824{
825  static cmt_string dir_prefix;
826
827  dir_prefix = dir_name;
828  if (dir_name == "") dir_prefix = ".";
829
830  if (!test_directory (dir_prefix))
831    {
832      dirname (dir_prefix, dir_prefix);
833    }
834
835  list.clear ();
836
837#ifdef WIN32
838
839  long dir;
840  struct _finddata_t entry;
841
842  static cmt_string search;
843
844  search = dir_prefix;
845  search += file_separator ();
846  search += "*";
847
848  dir = _findfirst (search.c_str (), &entry);
849  if (dir > 0)
850    {
851      for (;;)
852        {
853          if ((entry.name[0] != '.') &&
854              (strcmp ((char*) entry.name, ".") != 0) &&
855              (strcmp ((char*) entry.name, "..") != 0) &&
856              (strncmp ((char*) entry.name, ".nfs", 4) != 0))
857            {
858              const char* name = entry.name;
859             
860              if (expression.match (name))
861                {
862                  cmt_string& name_entry = list.add ();
863
864                  name_entry = dir_prefix;
865                  name_entry += file_separator ();
866                  name_entry += name;
867                }
868            }
869
870          int status = _findnext (dir, &entry);
871          if (status != 0)
872            {
873              break;
874            }
875        }
876      _findclose (dir);
877    }
878#else
879
880  //cout << "scan_dir> dir=" << dir_name << endl;
881
882  DIR* dir = opendir (dir_prefix.c_str ());
883
884  struct dirent* entry;
885
886  if (dir != 0)
887    {
888      while ((entry = readdir (dir)) != 0)
889        {
890          //if (entry->d_name[0] == '.') continue;
891          if (!strcmp ((char*) entry->d_name, ".")) continue;
892          if (!strcmp ((char*) entry->d_name, "..")) continue;
893          if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue;
894
895          const char* name = entry->d_name;
896
897          if (!expression.match (name)) continue;
898
899          cmt_string& name_entry = list.add ();
900
901          name_entry = dir_prefix;
902          name_entry += file_separator ();
903          name_entry += name;
904        }
905
906      closedir (dir);
907    }
908#endif
909
910}
911
912//----------------------------------------------------------
913CmtSystem::cmt_string_vector& CmtSystem::scan_dir (const cmt_string& dir_name)
914{
915  static cmt_string_vector result;
916
917  scan_dir (dir_name, result);
918
919  return (result);
920}
921
922//----------------------------------------------------------
923const cmt_string& CmtSystem::get_cmt_root ()
924{
925  static cmt_string root;
926
927  root = "";
928
929  const char* env = ::getenv ("CMTROOT");
930  if (env != 0)
931    {
932      root = env;
933
934      dirname (root, root);
935      dirname (root, root);
936      root.replace_all ("\"", "");
937      return (root);
938    }
939
940#ifdef WIN32
941  LONG status;
942  HKEY key = 0;
943
944  status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
945                         0, KEY_READ, &key);
946  if (status == ERROR_SUCCESS)
947    {
948      char temp[256];
949      DWORD length = sizeof (temp) - 1;
950      DWORD type;
951
952      status = RegQueryValueEx (key, "root", 0, &type, (LPBYTE) temp, &length);
953      if (status == ERROR_SUCCESS)
954        {
955          root = temp;
956          return (root);
957        }
958    }
959#endif
960
961  return (root);
962}
963
964//----------------------------------------------------------
965void CmtSystem::get_cmt_version (cmt_string& version)
966{
967  version = "";
968
969  const char* env = ::getenv ("CMTROOT");
970  if (env != 0)
971    {
972      cmt_string s = env;
973      basename (s, version);
974      version.replace_all ("\"", "");
975    }
976  else
977    {
978#ifdef WIN32
979      LONG status;
980      HKEY key = 0;
981
982      status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
983                             0, KEY_READ, &key);
984      if (status == ERROR_SUCCESS)
985        {
986          char temp[256];
987          DWORD length = sizeof (temp) - 1;
988          DWORD type;
989         
990          status = RegQueryValueEx (key, "version", 0, &type, 
991                                    (LPBYTE) temp, &length);
992          if (status == ERROR_SUCCESS)
993            {
994              version = temp;
995            }
996        }
997#endif
998    }
999}
1000
1001//----------------------------------------------------------
1002cmt_string CmtSystem::get_cmt_config ()
1003{
1004  const char* env = ::getenv ("CMTCONFIG");
1005  if (env != 0)
1006    {
1007      return (cmt_string (env));
1008    }
1009
1010  env = ::getenv ("CMTBIN");
1011  if (env != 0)
1012    {
1013      return (cmt_string (env));
1014    }
1015
1016#ifdef WIN32
1017  LONG status;
1018  HKEY key = 0;
1019
1020  status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
1021                         0, KEY_READ, &key);
1022  if (status == ERROR_SUCCESS)
1023    {
1024      char temp[256];
1025      DWORD length = sizeof (temp) - 1;
1026      DWORD type;
1027
1028      status = RegQueryValueEx (key, "config", 0, &type, 
1029                                (LPBYTE) temp, &length);
1030      if (status == ERROR_SUCCESS)
1031        {
1032          cmt_string config (temp);
1033          return (config);
1034        }
1035    }
1036
1037  return ("VisualC");
1038#endif
1039
1040  return ("");
1041
1042}
1043
1044//----------------------------------------------------------
1045cmt_string CmtSystem::get_cmt_site ()
1046{
1047  const char* env = ::getenv ("CMTSITE");
1048  if (env != 0)
1049    {
1050      return (cmt_string (env));
1051    }
1052
1053#ifdef WIN32
1054  LONG status;
1055  HKEY key = 0;
1056
1057  status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
1058                         0, KEY_READ, &key);
1059  if (status == ERROR_SUCCESS)
1060    {
1061      char temp[256];
1062      DWORD length = sizeof (temp) - 1;
1063      DWORD type;
1064
1065      status = RegQueryValueEx (key, "site", 0, &type, (LPBYTE) temp, &length);
1066      if (status == ERROR_SUCCESS)
1067        {
1068          cmt_string site (temp);
1069          return (site);
1070        }
1071    }
1072#endif
1073
1074  return ("");
1075}
1076
1077//----------------------------------------------------------
1078void CmtSystem::get_uname (cmt_string& uname)
1079{
1080#ifdef WIN32
1081  uname = "WIN32";
1082#else
1083
1084  uname = "";
1085
1086  FILE* file;
1087
1088  file = popen ("uname", "r");
1089
1090  if (file != 0)
1091    {
1092      char line[1024];
1093      char* ptr;
1094      char* nl;
1095
1096      line[0] = 0;
1097      ptr = fgets (line, sizeof (line), file);
1098      if (ptr != 0)
1099        {
1100          nl = strrchr (ptr, '\n');
1101          if (nl != 0) *nl = 0;
1102
1103          uname = ptr;
1104        }
1105      pclose (file);
1106    }
1107#endif
1108}
1109
1110//----------------------------------------------------------
1111void CmtSystem::get_hosttype (cmt_string& hosttype)
1112{
1113  hosttype = "";
1114
1115  char* ptr;
1116
1117  ptr = ::getenv ("HOSTTYPE");
1118  if (ptr != 0)
1119    {
1120      hosttype = ptr;
1121    }
1122}
1123
1124//----------------------------------------------------------
1125cmt_string CmtSystem::get_temporary_name ()
1126{
1127  cmt_string name;
1128
1129  name = ::tmpnam (NULL);
1130
1131  return (name);
1132}
1133
1134//----------------------------------------------------------
1135cmt_string CmtSystem::get_home_package ()
1136{
1137  cmt_string name = "CMTHOME";
1138
1139  return (name);
1140}
1141
1142//----------------------------------------------------------
1143bool CmtSystem::is_home_package (const cmt_string& name,
1144                                 const cmt_string& version)
1145{
1146  if (name == "CMTHOME") return (true);
1147
1148  return (false);
1149}
1150
1151//----------------------------------------------------------
1152cmt_string CmtSystem::get_user_context_package ()
1153{
1154  cmt_string name = "CMTUSERCONTEXT";
1155
1156  return (name);
1157}
1158
1159//----------------------------------------------------------
1160bool CmtSystem::is_user_context_package (const cmt_string& name,
1161                                         const cmt_string& version)
1162{
1163  if (name == "CMTUSERCONTEXT") return (true);
1164
1165  return (false);
1166}
1167
1168//----------------------------------------------------------
1169cmt_string CmtSystem::get_project_package ()
1170{
1171  cmt_string name = "PROJECT";
1172
1173  return (name);
1174}
1175
1176//----------------------------------------------------------
1177bool CmtSystem::is_project_package (const cmt_string& name,
1178                                    const cmt_string& version)
1179{
1180  if (name == "PROJECT") return (true);
1181
1182  return (false);
1183}
1184
1185//----------------------------------------------------------
1186bool CmtSystem::testenv (const cmt_string& name)
1187{
1188  const char* env = ::getenv (name);
1189  if (env == 0) return (false);
1190  return (true);
1191}
1192
1193//----------------------------------------------------------
1194cmt_string CmtSystem::getenv (const cmt_string& name)
1195{
1196  cmt_string result;
1197
1198  const char* env = ::getenv (name);
1199  if (env != 0)
1200    {
1201      result = env;
1202    }
1203
1204  if (name == "CMTCONFIG")
1205  {
1206    return (get_cmt_config ());
1207  }
1208
1209  /*
1210  if (name == "CMTROOT")
1211  {
1212          return (get_cmt_root ());
1213  }
1214
1215  if (name == "CMTSITE")
1216  {
1217          return (get_cmt_site ());
1218  }
1219  */
1220
1221  return (result);
1222}
1223
1224//----------------------------------------------------------
1225bool CmtSystem::putenv (const cmt_string& name_value)
1226{
1227  int status = ::putenv ((char*) name_value.c_str ());
1228
1229  if (status == 0) return (true);
1230  else return (false);
1231}
1232
1233//----------------------------------------------------------
1234//
1235// This singleton interacts with the ProjectFactory to consistently create
1236// the project graph.
1237//
1238// In particular a single-depth stack of the top project is maintained.
1239//
1240//----------------------------------------------------------
1241class CMTPathManager
1242{
1243public:
1244  static CMTPathManager& instance ();
1245  static void reset ();
1246  static void add_cmt_path (const cmt_string& path,
1247                            const cmt_string& path_source,
1248                            IProjectFactory& factory);
1249
1250private:
1251  CMTPathManager () : m_project (0)
1252  {
1253  }
1254
1255  void do_reset ()
1256  {
1257    m_project = 0;
1258  }
1259
1260  void do_add_cmt_path (const cmt_string& path,
1261                        const cmt_string& path_source,
1262                        IProjectFactory& factory)
1263  {
1264    cmt_string npath = path;
1265
1266    if (npath == "") return;
1267
1268#ifdef WIN32
1269    if (npath.size () == 2)
1270      {
1271        if (npath[1] == ':')
1272          {
1273            npath += CmtSystem::file_separator ();
1274          }
1275      }
1276#endif
1277
1278    npath.replace_all ("\\", CmtSystem::file_separator ());
1279    npath.replace_all ("/", CmtSystem::file_separator ());
1280
1281    if (!CmtSystem::absolute_path (npath))
1282      {
1283        cmt_string h = CmtSystem::pwd ();
1284        h += CmtSystem::file_separator ();
1285        h += npath;
1286        npath = h;
1287      }
1288   
1289    CmtSystem::compress_path (npath);
1290
1291    //cerr << "adding npath=" << npath << endl;
1292
1293    while (npath[npath.size ()-1] == CmtSystem::file_separator ())
1294      {
1295        npath.erase (npath.size ()-1);
1296      }
1297   
1298    //cerr << "adding npath=[" << npath << "]" << endl;
1299   
1300    if (npath != "")
1301      {
1302        if (!CmtSystem::test_directory (npath))
1303          {
1304            CmtError::set (CmtError::path_not_found, npath);
1305            return;
1306          }
1307
1308        cmt_string project_name;
1309
1310        if ((path_source == "CMTUSERCONTEXT") ||
1311            (path_source == "CMTHOME"))
1312          {
1313            project_name = path_source;
1314          }
1315
1316        m_project = factory.create_project (project_name, npath, path_source, m_project);
1317      }
1318  }
1319
1320  Project* m_project;
1321};
1322
1323CMTPathManager& CMTPathManager::instance ()
1324{
1325  static CMTPathManager me;
1326 
1327  return (me);
1328}
1329
1330void CMTPathManager::reset ()
1331{
1332  static CMTPathManager& me = instance ();
1333  me.do_reset ();
1334}
1335
1336void CMTPathManager::add_cmt_path (const cmt_string& path,
1337                                   const cmt_string& path_source,
1338                                   IProjectFactory& factory)
1339{
1340  static CMTPathManager& me = instance ();
1341  me.do_add_cmt_path (path, path_source, factory);
1342}
1343
1344
1345
1346//----------------------------------------------------------
1347static void add_cmt_paths_from_text (const cmt_string& text,
1348                                     const cmt_string& context,
1349                                     IProjectFactory& factory)
1350{
1351  static CmtSystem::cmt_string_vector path_vector;
1352  int i;
1353
1354  CmtSystem::split (text, CmtSystem::path_separator (), path_vector);
1355
1356  for (i = 0; i < path_vector.size (); i++)
1357    {
1358      const cmt_string& path = path_vector[i];
1359
1360      CMTPathManager::add_cmt_path (path, context, factory);
1361    }
1362}
1363
1364//----------------------------------------------------------
1365static void add_cmt_paths_from_file (const cmt_string& file_name, IProjectFactory& factory)
1366{
1367  if (!CmtSystem::test_file (file_name)) return;
1368
1369  static cmt_string text;
1370
1371  text.read (file_name);
1372
1373  int pos = text.find ("CMTPATH");
1374  if (pos == cmt_string::npos) return;
1375  pos += strlen ("CMTPATH");
1376  pos = text.find (pos, "=");
1377  if (pos == cmt_string::npos) return;
1378  pos++;
1379
1380  text.erase (0, pos);
1381
1382  int nl = text.find (pos, "\n");
1383  if (nl != cmt_string::npos) text.erase (nl);
1384
1385  add_cmt_paths_from_text (text, file_name, factory);
1386}
1387
1388//----------------------------------------------------------
1389//
1390// With this function we analyse all possible ways of
1391// externally entering CMTPATH items
1392//  + from the environment variable
1393//  + from .cmtrc files
1394//  + from registry on Windows
1395//  + from EV settings for CMTUSERCONTEXT and CMTHOME
1396//
1397// Then projects are created from these settings.
1398//
1399// (The other way to enter project graph is through project files)
1400//----------------------------------------------------------
1401void CmtSystem::get_cmt_paths (IProjectFactory& factory, 
1402                               const cmt_string& init_text,
1403                               const cmt_string& cmt_user_context,
1404                               const cmt_string& cmt_home)
1405{
1406  CMTPathManager::reset ();
1407
1408  if (init_text != "")
1409    {
1410      add_cmt_paths_from_text (init_text, "initialization", factory);
1411    }
1412
1413#ifdef WIN32
1414  LONG status;
1415  HKEY key = 0;
1416
1417  status = RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\CMT\\path",
1418                         0, KEY_READ, &key);
1419  if (status == ERROR_SUCCESS)
1420    {
1421      DWORD index = 0;
1422      char name[256];
1423      char temp[256];
1424
1425      for (;;)
1426        {
1427          DWORD name_length = sizeof (name) - 1;
1428          DWORD length = sizeof (temp) - 1;
1429          DWORD type;
1430          status = RegEnumValue (key, index,
1431                                 name, &name_length, 0, &type,
1432                                 (LPBYTE) temp, &length);
1433          if ((status == ERROR_SUCCESS) ||
1434              (status == 234))
1435            {
1436              const cmt_string path = temp;
1437              CMTPathManager::add_cmt_path (path, "HKEY_CURRENT_USER", factory);
1438            }
1439
1440          if (status == 259)
1441            {
1442              break;
1443            }
1444
1445          index++;
1446        }
1447    }
1448
1449  status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT\\path",
1450                         0, KEY_READ, &key);
1451  if (status == ERROR_SUCCESS)
1452    {
1453      DWORD index = 0;
1454      char name[256];
1455      char temp[256];
1456
1457      for (;;)
1458        {
1459          DWORD type;
1460          DWORD name_length = sizeof (name) - 1;
1461          DWORD length = sizeof (temp) - 1;
1462
1463
1464          status = RegEnumValue (key, index,
1465                                 name, &name_length, 0, &type,
1466                                 (LPBYTE) temp, &length);
1467          if (status != ERROR_NO_MORE_ITEMS)
1468            {
1469              const cmt_string path = temp;
1470              CMTPathManager::add_cmt_path (path, "HKEY_LOCAL_MACHINE", factory);
1471            }
1472          else
1473            {
1474              break;
1475            }
1476          index++;
1477        }
1478    }
1479
1480#endif
1481
1482  //-----------------------------------------
1483  // look for .cmtrc files :
1484  //  first look in ./
1485  //  then in "~/"
1486  //  then in ${CMTROOT}/mgr
1487  //-----------------------------------------
1488  cmt_string rc_name;
1489
1490  add_cmt_paths_from_file (".cmtrc", factory);
1491
1492  if (get_home_directory (rc_name))
1493    {
1494      rc_name += file_separator ();
1495      rc_name += ".cmtrc";
1496      add_cmt_paths_from_file (rc_name, factory);
1497    }
1498
1499  rc_name = get_cmt_root ();
1500  rc_name += file_separator ();
1501  rc_name += "CMT";
1502  rc_name += file_separator ();
1503  cmt_string version;
1504  get_cmt_version (version);
1505  rc_name += version;
1506  rc_name += file_separator ();
1507  rc_name += "mgr";
1508  rc_name += file_separator ();
1509  rc_name += ".cmtrc";
1510
1511  add_cmt_paths_from_file (rc_name, factory);
1512
1513  CMTPathManager::add_cmt_path (cmt_user_context, "CMTUSERCONTEXT", factory);
1514  CMTPathManager::add_cmt_path (cmt_home, "CMTHOME", factory);
1515}
1516
1517//----------------------------------------------------------
1518int CmtSystem::execute (const cmt_string& command)
1519{
1520  //cout << "CmtSystem::execute1> [" << command << "]" << endl;
1521
1522  return (system (command.c_str ()));
1523}
1524
1525//----------------------------------------------------------
1526int CmtSystem::execute (const cmt_string& command, cmt_string& output)
1527{
1528  output = "";
1529
1530  //cout << "CmtSystem::execute2> [" << command << "]" << endl;
1531
1532  FILE* f = popen (command.c_str (), "r"); 
1533 
1534  if (f != 0) 
1535    { 
1536      char line[256]; 
1537      char* ptr;
1538
1539      while ((ptr = fgets (line, sizeof (line), f)) != NULL) 
1540        {
1541          output += ptr;
1542        } 
1543      pclose (f);
1544
1545      return (0);
1546    }
1547
1548  return (1);
1549}
1550
1551//----------------------------------------------------------
1552bool CmtSystem::is_package_directory (const cmt_string& name)
1553{
1554  cmt_string_vector dirs;
1555
1556  cmt_regexp exp ("^[a-zA-Z.][0-9]+([a-zA-Z.][0-9]+([a-zA-Z.][0-9]+)?)?");
1557
1558  scan_dir (name, exp, dirs);
1559
1560  cmt_string req;
1561
1562  req = name;
1563  req += file_separator ();
1564  req += "cmt";
1565  req += file_separator ();
1566  req += "requirements";
1567
1568  if (test_file (req)) return (true);
1569
1570  if (dirs.size () == 0) 
1571    {
1572      return (false);
1573    }
1574
1575  for (int i = 0; i < dirs.size (); i++)
1576      {
1577        const cmt_string& d = dirs[i];
1578
1579        req = d;
1580        req += file_separator ();
1581        req += "mgr";
1582        req += file_separator ();
1583        req += "requirements";
1584
1585        if (test_file (req)) return (true);
1586
1587      req = d;
1588      req += file_separator ();
1589      req += "cmt";
1590      req += file_separator ();
1591      req += "requirements";
1592     
1593      if (test_file (req)) return (true);
1594    }
1595
1596  return (false);
1597}
1598
1599//----------------------------------------------------------
1600bool CmtSystem::is_version_directory (const cmt_string& name)
1601{
1602  int v;
1603  int r;
1604  int p;
1605
1606  return (is_version_directory (name, v, r, p));
1607}
1608
1609//----------------------------------------------------------
1610bool CmtSystem::is_version_directory (const cmt_string& name,
1611                                      int& v,
1612                                      int& r,
1613                                      int& p)
1614{
1615  if ((name == "HEAD") || (name == "head"))
1616    {
1617      v = 0;
1618      r = 0;
1619      p = 0;
1620
1621      return (true);
1622    }
1623
1624  static const cmt_string numbers = "0123456789";
1625
1626  static const int id_version = 0;
1627  static const int id_release = 1;
1628  static const int id_patch   = 2;
1629
1630  cmt_string buffer;
1631
1632  enum 
1633  {
1634    starting,
1635    at_key,
1636    at_number
1637  } state;
1638
1639  int id;
1640  int pos;
1641  int value;
1642
1643  v = 0;
1644  r = 0;
1645  p = 0;
1646
1647  //
1648  // version : v-field
1649  //         | v-field r-field
1650  //         | v-field r-field p-field
1651  //
1652  // v-field : field
1653  // r-field : field
1654  // p-field : field
1655  //
1656  // field   : key '*'
1657  //         | key number
1658  //
1659  // key     : letters
1660  //
1661
1662  state = starting;
1663  id    = id_version;
1664
1665  for (pos = 0; pos < name.size (); pos++)
1666    {
1667      char c = name[pos];
1668
1669      if (c == '*')
1670        {
1671          // A wild card
1672          switch (state)
1673            {
1674            case starting:
1675              // cannot start with a wild card ??
1676              v = -1;
1677              r = -1;
1678              p = -1;
1679              return (false);
1680            case at_key:
1681              // the numeric field is valued with a wild card
1682              switch (id)
1683                {
1684                case id_version:
1685                  v = -1;
1686                case id_release:
1687                  r = -1;
1688                case id_patch:
1689                  p = -1;
1690                  break;
1691                }
1692              return (true);
1693            case at_number:
1694              // question:
1695              // a number followed by a wild-card is considered as:
1696              //   1) a wild card on the number itself (1* comp with 1, 10, 12, 120, etc)
1697              //   2) a wild card on the next fields (1* comp with 1r1, 1-12 etc)
1698              //
1699
1700              //  Here we select option 1)
1701
1702              sscanf (buffer.c_str (), "%d", &value);
1703              switch (id)
1704                {
1705                case id_version:
1706                  //
1707                  // lazy option 1 implies v = -1;
1708                  // strict option 1 would imply v = -value;
1709                  // option 2 implies v = value;
1710                  //
1711
1712                  v = -1;
1713                  r = -1;
1714                  p = -1;
1715                  break;
1716                case id_release:
1717                  r = value;
1718                  p = -1;
1719                  break;
1720                case id_patch:
1721                  p = value;
1722                  break;
1723                }
1724
1725              return (true);
1726            }
1727        }
1728      else if (numbers.find (c) == cmt_string::npos)
1729        {
1730          // A letter
1731          switch (state)
1732            {
1733            case starting:
1734              state = at_key;
1735              break;
1736            case at_key:
1737              // Multiple letter key (is it permitted??)
1738              break;
1739            case at_number:
1740              sscanf (buffer.c_str (), "%d", &value);
1741              switch (id)
1742                {
1743                case id_version:
1744                  v = value;
1745                  break;
1746                case id_release:
1747                  r = value;
1748                  break;
1749                case id_patch:
1750                  p = value;
1751                  break;
1752                }
1753              buffer = "";
1754              id++;
1755              state = at_key;
1756              break;
1757            }
1758        }
1759      else
1760        {
1761          // a number
1762          switch (state)
1763            {
1764            case starting:
1765              // not starting by a letter (syntax error)
1766              //return (false);
1767            case at_key:
1768              // the numeric field for the current id is starting now
1769              buffer += c;
1770              state = at_number;
1771              break;
1772            case at_number:
1773              // continuing the current numeric field
1774              buffer += c;
1775              break;
1776            }
1777        }
1778    }
1779
1780  switch (state)
1781    {
1782    case starting:
1783      // Empty version string
1784      return (false);
1785    case at_key:
1786      // Syntax error (when only letters. Ending letters is not an error)
1787      if (id == id_version) return (false);
1788      else return (true);
1789    case at_number:
1790      sscanf (buffer.c_str (), "%d", &value);
1791      switch (id)
1792        {
1793        case id_version:
1794          v = value;
1795          break;
1796        case id_release:
1797          r = value;
1798          break;
1799        case id_patch:
1800          p = value;
1801          break;
1802        }
1803      id++;
1804      state = at_key;
1805      return (true);
1806    }
1807
1808  return (false);
1809}
1810
1811//----------------------------------------------------------
1812//  Split a line into words. Separators are spaces and tabs
1813//  Text enclosed in double quotes is one word.
1814//----------------------------------------------------------
1815void CmtSystem::split (const cmt_string& text,
1816                       const cmt_string& separators,
1817                       cmt_string_vector& strings)
1818{
1819  static char* buffer = 0;
1820  static int allocated = 0;
1821
1822  bool finished = false;
1823
1824  strings.clear ();
1825
1826  if (text.size () == 0) return;
1827
1828  /*
1829    We are going to work in a copy of the text, since
1830    \0 will be inserted right after each found word.
1831
1832    Then the vector of strings is iteratively filled by each found word.
1833  */
1834
1835  if (buffer == 0)
1836    {
1837      allocated = text.size ();
1838      buffer = (char*) malloc (allocated + 1);
1839    }
1840  else
1841    {
1842      if (text.size () > allocated)
1843        {
1844          allocated = text.size ();
1845          buffer = (char*) realloc (buffer, allocated + 1);
1846        }
1847    }
1848
1849  strcpy (buffer, text.c_str ());
1850
1851  /*
1852    Algorithm :
1853
1854    We look for words separated by <separators> which may be
1855    o spaces (' ' or '\t')
1856    o other characters such as ':'
1857
1858    A word is a character string not containing any separator. A substring in
1859    this word my be enclosed between quotes (" or ') which permits separator
1860    inclusion within words.
1861  */
1862
1863  char* current_word = buffer;
1864
1865  while (*current_word != 0)
1866    {
1867      size_t prefix_length;
1868      size_t word_length;
1869
1870      /*
1871        while ((*current_word == ' ') ||
1872        (*current_word == '\t'))
1873        {
1874        current_word++;
1875        }
1876      */
1877
1878      // first skip all starting separators.
1879
1880      prefix_length = strspn (current_word, separators.c_str ());
1881      if (prefix_length > 0)
1882        {
1883          // Move to the first non-separator character
1884
1885          current_word += prefix_length;
1886        }
1887
1888      /*
1889        Parse the next word.
1890
1891        It may contain enclosures in quote characters or not.
1892        Quotes must be identical on both sides of each enclosure.
1893      */
1894
1895      char* running_char = current_word;
1896
1897      word_length = 0;
1898
1899      for (;;)
1900        {
1901          size_t unquoted_length;
1902          size_t separator_offset;
1903
1904          for (int p = 0;;)
1905            {
1906              unquoted_length = strcspn (running_char + p, "\"\'") + p;
1907              if ((unquoted_length > 0) && (running_char[unquoted_length-1] == '\\'))
1908                {
1909                  p = unquoted_length + 1;
1910                }
1911              else
1912                {
1913                  break;
1914                }
1915            }
1916
1917          separator_offset = strcspn (running_char, separators.c_str ());
1918
1919          if (separator_offset <= unquoted_length)
1920            {
1921              // no quote in this word -> we are finished for this one.
1922              running_char += separator_offset;
1923              break;
1924            }
1925
1926          // We have found a quoted enclosure. Move to it.
1927
1928          running_char += unquoted_length;
1929
1930          char quote = running_char[0];
1931
1932          // Remove it.
1933          {
1934            char* p = running_char;
1935            while (p[1] != 0)
1936              {
1937                *p = p[1];
1938                p++;
1939              }
1940            *p = 0;
1941          }
1942
1943          // Look for the next occurence of this quote.
1944          {
1945            char* p = strchr (running_char, quote);
1946            if (p == 0)
1947              {
1948                // Unmatched quote : the rest of the line will be taken as a word...
1949                running_char += strlen (running_char);
1950                finished = true;
1951                break;
1952              }
1953            else
1954              {
1955                running_char = p;
1956              }
1957          }
1958
1959          // Now we remove the ending quote from the word
1960          // (by shifting all remaining characters by one place to the left)
1961
1962          {
1963            char* p = running_char;
1964            while (p[1] != 0)
1965              {
1966                *p = p[1];
1967                p++;
1968              }
1969            *p = 0;
1970          }
1971        }
1972
1973      word_length = running_char - current_word;
1974
1975      if (current_word[word_length] == 0)
1976        {
1977          finished = true;
1978        }
1979      else
1980        {
1981          current_word[word_length] = 0;
1982        }
1983
1984      /*
1985        if ((t[0] == '"') ||
1986        (t[0] == '\'') ||
1987        (t[0] == ':'))
1988        {
1989        char* quote;
1990
1991        t++;
1992        quote = strchr (t, sep);
1993        if (quote != 0) *quote = 0;
1994        else finished = true;
1995        }
1996        else
1997        {
1998        int offset;
1999
2000        offset = strcspn (t, " \t:");
2001        if ((offset < 0) || (t[offset] == 0)) finished = true;
2002        if (!finished)
2003        {
2004        space = t + offset;
2005        *space = 0;
2006        }
2007        }
2008      */
2009
2010      // Store the current word into the vector of strings
2011
2012      {
2013        cmt_string& s = strings.add ();
2014        s = current_word;
2015      }
2016
2017      if (finished) break;
2018
2019      // Move to the next possible word.
2020      current_word += word_length + 1;
2021    }
2022}
2023
2024//----------------------------------------------------------
2025void CmtSystem::compress_path (const cmt_string& dir, cmt_string& new_dir)
2026{
2027  new_dir = dir;
2028
2029  compress_path (new_dir);
2030}
2031
2032//----------------------------------------------------------
2033//
2034//  We try to detect the aaaa/xxxx/../bbbb patterns which should be
2035// equivalent to aaaa/bbbb
2036//  this therefore consists in removing all /xxxx/../ when
2037//     xxxx is different from ".."
2038//     xxxx is different from "."
2039//     xxxx does not contain any macro reference
2040//
2041//----------------------------------------------------------
2042void CmtSystem::compress_path (cmt_string& dir)
2043{
2044#ifdef WIN32
2045  static const char pattern[] = "\\..";
2046  static const char fs[] = "\\\\";
2047#else
2048  static const char pattern[] = "/..";
2049  static const char fs[] = "//";
2050#endif
2051
2052  if (dir.size () == 0) return;
2053
2054  //
2055  // We first synchronize to using file_separator() in any case.
2056  //
2057
2058  if (file_separator () == '/')
2059    {
2060      dir.replace_all ("\\", file_separator ());
2061    }
2062  else
2063    {
2064      dir.replace_all ("/", file_separator ());
2065    }
2066
2067  // Suppress all duplicated file separators
2068  dir.replace_all (fs, file_separator ());
2069
2070  for (;;)
2071    {
2072      int pos1;
2073      int pos2;
2074      int pos3;
2075
2076      pos1 = dir.find (pattern);
2077      if (pos1 == cmt_string::npos) break;
2078
2079        //
2080        // extract "aaaa/xxxx" from "aaaa/xxxx/../bbbb"
2081        //
2082      cmt_string p = dir.substr (0, pos1);
2083
2084      cmt_string dn;
2085      basename (p, dn);
2086      if (dn == "..") break;
2087      if (dn == ".") break;
2088      if (dn == "") break;
2089     
2090        //
2091        // Is "aaaa/xxxx" only made of "xxxx" ?
2092        //
2093      pos2 = p.find_last_of (file_separator ());
2094     
2095      if (pos2 == cmt_string::npos) 
2096        {
2097          // the pattern was xxxx/..
2098          //
2099          // so xxxx is [0:pos1-1]
2100          //
2101          pos3 = p.find ("$");
2102          if (pos3 == cmt_string::npos)
2103            {
2104              dir.erase (0, pos1 + 3);
2105            }
2106          else
2107            {
2108              break;
2109            }
2110        }
2111      else
2112        {
2113          //    01234567890123456
2114          //    aaaa/xxxx/../bbbb
2115          //        2    1   3
2116          //
2117          // erase the "/xxxx/.." pattern
2118          // result will be "aaaa/bbbb"
2119          //
2120          // Here xxxx is [pos2+1:pos1-1]
2121          //
2122
2123          pos3 = p.find (pos2, "$");
2124          if (pos3 == cmt_string::npos)
2125            {
2126              dir.erase (pos2, pos1 + 3 - pos2);
2127            }
2128          else
2129            {
2130              break;
2131            }
2132        }
2133    }
2134
2135    //if (dir[dir.size () - 1] == file_separator ()) dir.erase (dir.size () - 1);
2136}
2137
2138//----------------------------------------------------------
2139cmt_string CmtSystem::now ()
2140{
2141  cmt_string result;
2142
2143  time_t ltime;
2144  time (&ltime);
2145  result = ctime (&ltime);
2146
2147  result.replace_all ("\n", "");
2148
2149  return (result);
2150}
2151
2152//----------------------------------------------------------
2153cmt_string CmtSystem::user ()
2154{
2155#ifdef _WIN32
2156  cmt_string result = getenv ("USERNAME");
2157#else
2158  cmt_string result = getenv ("USER");
2159#endif
2160
2161  return (result);
2162}
2163
2164//----------------------------------------------------------
2165void CmtSystem::get_cvsroot (cmt_string& cvsroot)
2166{
2167  cvsroot = "";
2168
2169  const char* env = ::getenv ("CVSROOT");
2170  if (env != 0)
2171    {
2172      cvsroot = env;
2173      return;
2174    }
2175
2176#ifdef WIN32
2177  LONG status;
2178  HKEY key = 0;
2179
2180  status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
2181                         0, KEY_READ, &key);
2182  if (status == ERROR_SUCCESS)
2183    {
2184      char temp[256];
2185      DWORD length = sizeof (temp) - 1;
2186      DWORD type;
2187
2188      status = RegQueryValueEx (key, "CVSROOT", 0, &type, 
2189                                (LPBYTE) temp, &length);
2190      if (status == ERROR_SUCCESS)
2191        {
2192          cvsroot = temp;
2193          return;
2194        }
2195    }
2196#endif
2197}
2198
2199//----------------------------------------------------------
2200bool CmtSystem::get_home_directory (cmt_string& dir)
2201{
2202  bool status = false;
2203
2204#ifdef WIN32
2205  const char* homedrive = ::getenv ("HOMEDRIVE");
2206  const char* homepath = ::getenv ("HOMEPATH");
2207
2208  if ((homedrive != 0) && (homepath != 0))
2209    {
2210      dir = homedrive;
2211      dir += homepath;
2212      status = true;
2213    }
2214
2215#else
2216  const char* home_env = ::getenv ("HOME");
2217  if (home_env != 0)
2218    {
2219      dir = home_env;
2220      status = true;
2221    }
2222#endif
2223
2224  return (status);
2225}
2226
Note: See TracBrowser for help on using the repository browser.