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

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

See C.L. 476

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