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

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

See C.L. 482

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