source: CMT/v1r25-branch/source/cmt_system.cxx

Last change on this file was 664, checked in by rybkin, 10 years ago

merge -r 646:663 HEAD

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