source: CMT/v1r20p20070517/source/cmt_system.cxx

Last change on this file was 411, checked in by arnault, 17 years ago

Management of the -quiet option
Bug fixing in cmt_cvs.cxx
CL 329

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