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

Last change on this file since 597 was 597, checked in by rybkin, 13 years ago

See C.L. 474

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