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

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

See C.L. 473

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