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

Last change on this file since 515 was 515, checked in by rybkin, 15 years ago

See C.L. 404

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