source: CMT/v1r18p20060301/source/cmt_system.cxx

Last change on this file was 144, checked in by arnault, 18 years ago

Various fixes and message cleanups see CL 294 and 295

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