source: CMT/HEAD/source/cmt_system.cxx @ 459

Last change on this file since 459 was 459, checked in by rybkin, 16 years ago

See C.L. 360

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