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

Last change on this file since 595 was 595, checked in by rybkin, 12 years ago

See C.L. 472

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