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

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

See C.L. 485

  • 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// 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                       const bool& unquote)
2235{
2236  static char* buffer = 0;
2237  static int allocated = 0;
2238
2239  strings.clear ();
2240
2241  if (text.size () == 0) return;
2242
2243  /*
2244    We are going to work in a copy of the text, since
2245    \0 will be inserted right after each found word.
2246
2247    Then the vector of strings is iteratively filled by each found word.
2248  */
2249
2250  if (buffer == 0)
2251    {
2252      allocated = text.size ();
2253      buffer = (char*) malloc (allocated + 1);
2254    }
2255  else
2256    {
2257      if (text.size () > allocated)
2258        {
2259          allocated = text.size ();
2260          buffer = (char*) realloc (buffer, allocated + 1);
2261        }
2262    }
2263
2264  strcpy (buffer, text.c_str ());
2265
2266  /*
2267    Algorithm :
2268
2269    We look for words separated by <separators> which may be
2270    o spaces (' ' or '\t')
2271    o other characters such as ':'
2272
2273    A word is a character string not containing any separator. A substring in
2274    this word my be enclosed between quotes (" or ') which permits separator
2275    inclusion within words.
2276  */
2277
2278  char * b = buffer;
2279  char * begin = b;
2280  char * e;
2281  char * pq = 0;
2282  char * pqm = 0;
2283  char q, ev;
2284  char * token = 0;
2285  bool before_q = false;
2286  bool after_q = false;
2287  bool matched = false;
2288
2289//   cerr << "split: " << buffer << endl;
2290//   cerr << "seps: `";
2291//   for (int i = 0; i < separators.size (); i++)
2292//     cerr << separators[i];
2293//   cerr << "'" << endl;
2294
2295  // sep...ab..."cd"ef...sep...
2296  while (pq = strpbrk (begin, "\"\'"))
2297    {
2298      if (begin < pq && *(pq - 1) == '\\')
2299        {// quote considered escaped
2300          begin = pq + 1;
2301          continue;
2302        }
2303
2304      if ((b < pq && NULL == strchr (separators.c_str (), *(pq - 1))) ||
2305          (b == pq && after_q))
2306        before_q = true;
2307      else
2308        before_q = false;
2309
2310      // save quote found
2311      q = *pq;
2312      // terminate string for standard string functions
2313      *pq = 0;
2314
2315      // parse string - up to quote - into a sequence of tokens
2316      if (token = strtok (b, separators.c_str ()))
2317        {
2318          if (after_q)
2319            strings.back () += token;
2320          else
2321            strings.add () = token;
2322
2323//        cerr << (after_q ? "append: " : "add: ")
2324//             << "[" << token << "]{" << strings.back () << "}";
2325
2326          while (token = strtok (NULL, separators.c_str ()))
2327            {
2328              strings.add () = token;
2329              //strings.push_back (token);
2330              //cerr << "[" << token << "]{" << strings.back () << "}";
2331            } // while ( token = strtok (NULL, separators.c_str ()) )
2332          //cerr << endl;
2333        }
2334
2335      if (unquote)
2336        {
2337          b = pq + 1;
2338        }
2339      else
2340        {
2341          // restore quote found
2342          *pq = q;
2343          b = pq;
2344        }
2345      begin = pq + 1;
2346
2347      // look for matching quote
2348      matched = false;
2349      while (pqm = strchr (begin, q))
2350        {
2351          // commented out because of
2352          // inconsistency of quoting rules
2353          // and backward compatibility
2354//        if (begin < pqm && *(pqm - 1) == '\\')
2355//          {// quote considered escaped
2356//            begin = pqm + 1;
2357//            continue;
2358//          }
2359          matched = true;
2360
2361          if (*(pqm + 1) && NULL == strchr (separators.c_str (), *(pqm + 1)))
2362            after_q = true;
2363          else
2364            after_q = false;
2365
2366          if (unquote)
2367            {
2368              e = pqm;
2369            }
2370          else
2371            {
2372              e = pqm + 1;
2373              ev = *e;
2374            }
2375          // terminate string for standard string functions
2376          *e = 0;
2377         
2378          if (before_q)
2379            strings.back () += b;
2380          else
2381            strings.add () = b;
2382
2383//        cerr << (before_q ? "append: " : "add: ")
2384//             << "|" << b << "|{" << strings.back () << "}" << endl;
2385         
2386          // restore e value
2387          if (!unquote)
2388            {
2389              *e = ev;
2390            }
2391          b = pqm + 1;
2392          begin = b;
2393          break;
2394        } // while (pqm = strchr (begin, q))
2395
2396      if (!matched)
2397        { // unmatched quote : the rest of the line will be taken as a token
2398          if (before_q)
2399            strings.back () += b;
2400          else
2401            strings.add () = b;
2402
2403          // append quote to match
2404          if (!unquote)
2405            strings.back () += q;
2406         
2407//        cerr << (before_q ? "append: " : "add: ")
2408//             << "|" << b << "|{" << strings.back () << "}" << endl;
2409
2410          b = buffer + strlen(buffer);
2411          begin = b;
2412          break;
2413        }
2414
2415    } // while (pq = strpbrk (begin, "\"\'"))
2416
2417      // parse string - up to end - into a sequence of tokens
2418      if (token = strtok (b, separators.c_str ()))
2419        {
2420          if (after_q)
2421            strings.back () += token;
2422          else
2423            strings.add () = token;
2424
2425//        cerr << (after_q ? "append: " : "add: ")
2426//             << "<" << token << ">{" << strings.back () << "}";
2427
2428          while (token = strtok (NULL, separators.c_str ()))
2429            {
2430              strings.add () = token;
2431              //cerr << "<" << token << ">{" << strings.back () << "}";
2432            } // while ( token = strtok (NULL, separators.c_str ()) )
2433          //cerr << endl;
2434        }
2435//       cerr << "strings:";
2436//       for (int i = 0; i < strings.size (); i++)
2437//      cerr << " {" << strings[i] << "}";
2438//       //     cerr << " `" << strings[i] << "'";
2439//       cerr << endl;
2440}
2441
2442//-------------------------------------------------------------
2443//  Quote separators (spaces and tabs) with double quotes,
2444//  double quotes with single quotes,
2445//  single quotes with double quotes in text.
2446//  Note: quotes preceded by backslash (i.e., \" or \') are NOT quoted
2447//  (considered escaped)
2448//-------------------------------------------------------------
2449cmt_string CmtSystem::quote (const cmt_string& text,
2450                             const cmt_string& separators)
2451{
2452  //cerr << "quote: `" << text << "'" << endl;
2453  cmt_string result;
2454  if (text.size () == 0) return result;
2455
2456  size_t allocated = 3 * text.size (); // if EACH character of text quoted with " or '
2457  char* const buffer = (char*) malloc (allocated + 1);
2458  if (0 == buffer)
2459    {
2460      char num[32]; sprintf (num, "%lu", allocated + 1);
2461      cmt_string msg ("Cannot allocate ");
2462      msg += num;
2463      msg += " bytes";
2464      cmt_string e = errno ? ": " + cmt_string (strerror (errno)) : "";
2465      CmtMessage::error (msg + e);
2466      exit (EXIT_FAILURE);
2467    }
2468  char* b (buffer);
2469
2470  //  char* const beg (buffer);
2471  const char* p = text.c_str ();
2472  const char* const text_c (p);
2473  //  const char* const beg_t (p);
2474  //  cerr << "quote: p = `" << p << "'" << endl;
2475
2476  while (*p)
2477    //  while (*p != '\0')
2478    {
2479      size_t l_nonsep = strcspn (p, separators.c_str ());
2480      //cerr << "quote: l_nonsep = " << l_nonsep << " *p = '" << *p << "'" << endl;
2481      while (l_nonsep--)
2482        {
2483          if (*p == '\"' &&
2484              (p > text_c && *(p - 1) != '\\' || p == text_c))
2485            { // quote " with '
2486              *b++ = '\'';
2487              *b++ = *p++;
2488              *b++ = '\'';
2489            }
2490          else if (*p == '\'' &&
2491                   (p > text_c && *(p - 1) != '\\' || p == text_c))
2492            { // quote ' with "
2493              *b++ = '\"';
2494              *b++ = *p++;
2495              *b++ = '\"';
2496            }
2497          else
2498            { // simply copy
2499              *b++ = *p++;
2500            }
2501        }
2502      size_t l_sep = strspn (p, separators.c_str ());
2503      //cerr << "quote: l_sep = " << l_sep << " *p = '" << *p << "'" << endl;
2504      if (l_sep)
2505        { // quote separators with "
2506          // place quote before all backslashes preceding separators, if any
2507          char* r = b;
2508          while (r > buffer && *(r - 1) == '\\')
2509            r--;
2510          if (r == b)
2511            *b++ = '\"';
2512          else
2513            *r = '\"', *b++ = '\\';
2514          while (l_sep--)
2515            *b++ = *p++;
2516          *b++ = '\"';
2517        }
2518    }
2519  *b = '\0';
2520  result = buffer;
2521  free (buffer);
2522  return result;
2523}
2524
2525//----------------------------------------------------------
2526//  Mangle text so that it consists solely of
2527//  letters, digits, and underscores
2528//  the first character being not digit
2529//  (any other characters are replaced with character '_').
2530//  The out can be used as shell variable name.
2531//  Return the number of characters replaced with character '_'.
2532//----------------------------------------------------------
2533int CmtSystem::mangle (const cmt_string& text, cmt_string& out)
2534{
2535  int result (0);
2536  size_t allocated = text.size ();
2537  //allocated = 3000000000;
2538  char* const buffer = (char*) malloc (allocated + 1);
2539  if (0 == buffer)
2540    {
2541      char num[32]; sprintf (num, "%lu", allocated + 1);
2542      cmt_string msg ("Cannot allocate ");
2543      msg += num;
2544      msg += " bytes";
2545      cmt_string e = errno ? ": " + cmt_string (strerror (errno)) : "";
2546      CmtMessage::error (msg + e);
2547      exit (EXIT_FAILURE);
2548    }
2549  char* b (buffer);
2550  const char* t = text.c_str ();
2551  while (*t)
2552    {
2553      if (isalnum (*t) || *t == '_')
2554        *b++ = *t++;
2555      else
2556        {
2557          *b++ = '_'; t++;
2558          result++;
2559        }
2560    }
2561  *b = '\0';
2562  if (0 != allocated && isdigit (*buffer))
2563    {
2564      *buffer = '_';
2565      result++;
2566    }
2567  out = buffer;
2568  free (buffer);
2569  return result;
2570}
2571
2572cmt_string CmtSystem::mangle (const cmt_string& text)
2573{
2574  cmt_string result;
2575  mangle (text, result);
2576  return result;
2577}
2578
2579//----------------------------------------------------------
2580void CmtSystem::compress_path (const cmt_string& dir, cmt_string& new_dir)
2581{
2582  new_dir = dir;
2583
2584  compress_path (new_dir);
2585}
2586
2587//----------------------------------------------------------
2588//
2589//  We try to detect the aaaa/xxxx/../bbbb patterns which should be
2590// equivalent to aaaa/bbbb
2591//  this therefore consists in removing all /xxxx/../ when
2592//     xxxx is different from ".."
2593//     xxxx is different from "."
2594//     xxxx does not contain any macro reference
2595//
2596// Also replace "/.." with "/". One cannot walk down past the root.
2597//----------------------------------------------------------
2598void CmtSystem::compress_path (cmt_string& dir)
2599{
2600#ifdef WIN32
2601  static const char pattern[] = "\\..";
2602  static const char fs[] = "\\\\";
2603#else
2604  static const char pattern[] = "/..";
2605  static const char fs[] = "//";
2606#endif
2607
2608  if (dir.size () == 0) return;
2609
2610  //
2611  // We first synchronize to using file_separator() in any case.
2612  //
2613
2614  if (file_separator () == '/')
2615    {
2616      dir.replace_all ("\\", file_separator ());
2617    }
2618  else
2619    {
2620      dir.replace_all ("/", file_separator ());
2621    }
2622
2623  // Suppress all duplicated file separators
2624  dir.replace_all (fs, file_separator ());
2625
2626  for (;;)
2627    {
2628      int pos0 (0);
2629      int pos1;
2630      int pos2;
2631      int pos3;
2632
2633      //pos1 = dir.find (pattern);
2634      //if (pos1 == cmt_string::npos) break;
2635
2636      do
2637        {
2638          pos1 = dir.find (pos0, pattern);
2639          if (pos1 == cmt_string::npos) break;
2640          pos0 = pos1 + 3;
2641        }
2642      while (pos0 < dir.size () && dir[pos0] != file_separator ());
2643
2644      if (pos1 == cmt_string::npos) break;
2645
2646      //
2647      // One cannot walk down past the root: "/.." is the same as "/".
2648      //
2649#ifdef WIN32
2650      if (pos1 == 0)
2651        {
2652          dir.erase (pos1, 3);
2653          if (dir == "")
2654            dir = file_separator ();
2655          continue;
2656        }
2657      else if (pos1 == 2 && dir[1] == ':')
2658        {
2659          dir.erase (pos1, 3);
2660          if (dir.size () == 2)
2661            dir += file_separator ();
2662          continue;
2663        }
2664#else
2665      if (pos1 == 0)
2666        {
2667          dir.erase (pos1, 3);
2668          if (dir == "")
2669            dir = file_separator ();
2670          continue;
2671        }
2672#endif
2673
2674      //
2675      // extract "aaaa/xxxx" from "aaaa/xxxx/../bbbb"
2676      //
2677      cmt_string p = dir.substr (0, pos1);
2678
2679      cmt_string dn;
2680      basename (p, dn);
2681      if (dn == "..") break;
2682      if (dn == ".") break;
2683      if (dn == "") break;
2684     
2685      //
2686      // Is "aaaa/xxxx" only made of "xxxx" ?
2687      //
2688      pos2 = p.find_last_of (file_separator ());
2689     
2690      if (pos2 == cmt_string::npos) 
2691        {
2692          // the pattern was xxxx/../bbbb
2693          //
2694          // so xxxx is [0:pos1-1]
2695          //
2696          // erase the "xxxx/.." pattern
2697          // result will be "/bbbb"
2698          // so, need to process a little more
2699          //
2700          pos3 = p.find ("$");
2701          if (pos3 == cmt_string::npos)
2702            {
2703              dir.erase (0, pos1 + 3);
2704              if (dir.size () < 2)
2705                {
2706                  dir = ".";
2707                }
2708              else
2709                {
2710                  dir.erase (0, 1);
2711                }
2712            }
2713          else
2714            {
2715              break;
2716            }
2717        }
2718      else
2719        {
2720          //    01234567890123456
2721          //    aaaa/xxxx/../bbbb
2722          //        2    1   3
2723          //
2724          // erase the "/xxxx/.." pattern
2725          // result will be "aaaa/bbbb"
2726          //
2727          // Here xxxx is [pos2+1:pos1-1]
2728          //
2729
2730          pos3 = p.find (pos2, "$");
2731          if (pos3 == cmt_string::npos)
2732            {
2733              dir.erase (pos2, pos1 + 3 - pos2);
2734#ifdef WIN32
2735              if (dir == "")
2736                {
2737                  dir = file_separator ();
2738                }
2739              else if (dir.size () == 2 && dir[1] == ':')
2740                {
2741                  dir += file_separator ();
2742                }
2743#else
2744              if (dir == "")
2745                dir = file_separator ();
2746#endif
2747            }
2748          else
2749            {
2750              break;
2751            }
2752        }
2753    }
2754
2755  //if (dir[dir.size () - 1] == file_separator ()) dir.erase (dir.size () - 1);
2756}
2757
2758//----------------------------------------------------------
2759cmt_string CmtSystem::now ()
2760{
2761  cmt_string result;
2762
2763  time_t ltime;
2764  time (&ltime);
2765  result = ctime (&ltime);
2766
2767  result.replace_all ("\n", "");
2768
2769  return (result);
2770}
2771
2772//----------------------------------------------------------
2773cmt_string CmtSystem::user ()
2774{
2775#ifdef _WIN32
2776  cmt_string result = ::getenv ("USERNAME");
2777#else
2778  cmt_string result = ::getenv ("USER");
2779#endif
2780
2781  return (result);
2782}
2783
2784//----------------------------------------------------------
2785void CmtSystem::get_cvsroot (cmt_string& cvsroot)
2786{
2787  cvsroot = "";
2788
2789  const char* env = ::getenv ("CVSROOT");
2790  if (env != 0)
2791    {
2792      cvsroot = env;
2793      return;
2794    }
2795
2796#ifdef WIN32
2797  LONG status;
2798  HKEY key = 0;
2799
2800  status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
2801                         0, KEY_READ, &key);
2802  if (status == ERROR_SUCCESS)
2803    {
2804      char temp[256];
2805      DWORD length = sizeof (temp) - 1;
2806      DWORD type;
2807
2808      status = RegQueryValueEx (key, "CVSROOT", 0, &type, 
2809                                (LPBYTE) temp, &length);
2810      if (status == ERROR_SUCCESS)
2811        {
2812          cvsroot = temp;
2813          return;
2814        }
2815    }
2816#endif
2817}
2818
2819//----------------------------------------------------------
2820bool CmtSystem::get_home_directory (cmt_string& dir)
2821{
2822  bool status = false;
2823
2824#ifdef WIN32
2825  const char* homedrive = ::getenv ("HOMEDRIVE");
2826  const char* homepath = ::getenv ("HOMEPATH");
2827
2828  if ((homedrive != 0) && (homepath != 0))
2829    {
2830      dir = homedrive;
2831      dir += homepath;
2832      status = true;
2833    }
2834
2835#else
2836  const char* home_env = ::getenv ("HOME");
2837  if (home_env != 0)
2838    {
2839      dir = home_env;
2840      status = true;
2841    }
2842#endif
2843
2844  return (status);
2845}
2846
2847//----------------------------------------------------------
2848cmt_string CmtSystem::get_makefile_suffix ()
2849{
2850#ifdef WIN32
2851  return "nmake";
2852#else
2853  return "make";
2854#endif
2855}
2856
2857//----------------------------------------------------------
2858void CmtSystem::close_ostream (FILE *stream, const cmt_string& name)
2859{
2860  cmt_string msg ("Cannot write");
2861  cmt_string n = (name != "") ? " " + name : "";
2862  if (stream == NULL)
2863    {
2864      CmtMessage::error (msg + n);
2865      exit (EXIT_FAILURE);
2866    }
2867
2868  int prev_fail = ferror (stream);
2869  int fclose_fail = fclose (stream);
2870//   bool prev_fail = ferror (stream);
2871//   bool fclose_fail = fclose (stream);
2872
2873  if (prev_fail || fclose_fail)
2874    {
2875      int err = fclose_fail ? errno : 0;
2876      cmt_string e = err ? ": " + cmt_string (strerror (err)) : "";
2877      CmtMessage::error (msg + n + e);
2878      exit (EXIT_FAILURE);
2879    }
2880}
2881
2882//----------------------------------------------------------
2883void CmtSystem::close_stdout (void)
2884{
2885  /*
2886   * The idea and, to some extent, implementation of this function
2887   * were borrowed from the GNU core utilities of the Free Software Foundation
2888   * http://www.gnu.org/software/coreutils/
2889   */
2890  close_ostream (stdout, "stdout");
2891}
2892
2893//----------------------------------------------------------
2894FilePath::FilePath ()
2895{
2896  p_name = "";
2897  l_name = "";
2898  alternates.resize (0);
2899}
2900
2901//----------------------------------------------------------
2902FilePath::FilePath (const FilePath& other)
2903{
2904  set (other);
2905}
2906
2907//----------------------------------------------------------
2908FilePath::FilePath (const cmt_string& other)
2909{
2910  set (other);
2911}
2912
2913//----------------------------------------------------------
2914FilePath::FilePath (const char* other)
2915{
2916  set (other);
2917}
2918
2919//----------------------------------------------------------
2920FilePath& FilePath::operator = (const FilePath& other)
2921{
2922  FilePath& me = *this;
2923
2924  me.set (other);
2925
2926  return (me);
2927}
2928
2929//----------------------------------------------------------
2930FilePath& FilePath::operator = (const cmt_string& other)
2931{
2932  FilePath& me = *this;
2933
2934  me.set (other);
2935
2936  return (me);
2937}
2938
2939//----------------------------------------------------------
2940FilePath& FilePath::operator = (const char* other)
2941{
2942  FilePath& me = *this;
2943
2944  me.set (other);
2945
2946  return (me);
2947}
2948
2949//----------------------------------------------------------
2950bool FilePath::operator == (const FilePath& other) const
2951{
2952  if (other.p_name == p_name) return (true);
2953  return (false);
2954}
2955
2956//----------------------------------------------------------
2957bool FilePath::operator == (const cmt_string& other) const
2958{
2959  if (p_name == other) return (true);
2960  if (l_name == other) return (true);
2961
2962  for (int i = 0; i < alternates.size (); i++)
2963    {
2964      if (alternates[i] == other) return (true);
2965    }
2966
2967  cmt_string here = CmtSystem::pwd ();
2968  CmtSystem::cd (other);
2969  cmt_string p = CmtSystem::pwd ();
2970  CmtSystem::cd (here);
2971
2972  if (p_name == p) return (true);
2973
2974  return (false);
2975}
2976
2977//----------------------------------------------------------
2978bool FilePath::operator == (const char* other) const
2979{
2980  const FilePath& me = *this;
2981
2982  const cmt_string o = other;
2983
2984  return ((me == o));
2985
2986  return (false);
2987}
2988
2989//----------------------------------------------------------
2990bool FilePath::operator != (const FilePath& other) const
2991{
2992  const FilePath& me = *this;
2993
2994  return (!(me == other));
2995}
2996
2997//----------------------------------------------------------
2998bool FilePath::operator != (const cmt_string& other) const
2999{
3000  const FilePath& me = *this;
3001
3002  return (!(me == other));
3003}
3004
3005//----------------------------------------------------------
3006bool FilePath::operator != (const char* other) const
3007{
3008  const FilePath& me = *this;
3009
3010  return (!(me == other));
3011}
3012
3013//----------------------------------------------------------
3014bool FilePath::cd () const
3015{
3016  CmtSystem::cd (l_name);
3017
3018  return (false);
3019}
3020
3021//----------------------------------------------------------
3022void FilePath::set (const FilePath& other)
3023{
3024  p_name = other.p_name;
3025  l_name = other.l_name;
3026  alternates = other.alternates;
3027}
3028
3029//----------------------------------------------------------
3030void FilePath::set (const cmt_string& other)
3031{
3032  // Skip if no change.
3033
3034  if (p_name == other) return;
3035  if (l_name == other) return;
3036
3037  for (int i = 0; i < alternates.size (); i++)
3038    {
3039      if (alternates[i] == other) return;
3040    }
3041
3042  // Something changes
3043
3044  cmt_string here = CmtSystem::pwd ();
3045  CmtSystem::cd (other);
3046  cmt_string p = CmtSystem::pwd ();
3047  CmtSystem::cd (here);
3048
3049  if (p == p_name)
3050    {
3051      // The physical name does not change => we are just adding a new logical
3052
3053      if (l_name == "")
3054        {
3055          // the logical name was not set => set it
3056          l_name = other;
3057        }
3058      else
3059        {
3060          // add a new logical name
3061          cmt_string& n = alternates.add ();
3062          n = other;
3063        }
3064    }
3065  else
3066    {
3067      // The physical names differ => we completely reset the object
3068
3069      p_name = p;
3070      l_name = other;
3071      alternates.resize (0);
3072    }
3073}
3074
3075//----------------------------------------------------------
3076void FilePath::set (const char* other)
3077{
3078  const cmt_string o = other;
3079  set (o);
3080}
3081
3082//----------------------------------------------------------
3083const cmt_string& FilePath::name () const
3084{
3085  if (l_name != "") return (l_name);
3086  else return (p_name);
3087}
3088
3089//----------------------------------------------------------
3090FilePath::operator const cmt_string& () const
3091{
3092  if (l_name != "") return (l_name);
3093  else return (p_name);
3094}
3095
3096//----------------------------------------------------------
3097bool FilePath::in (const FilePath& other) const
3098{
3099  const cmt_string& o = other.name ();
3100
3101  return (in (o));
3102
3103  return (false);
3104}
3105
3106//----------------------------------------------------------
3107bool FilePath::in (const cmt_string& other) const
3108{
3109  if (p_name.find (other) == 0) return (true);
3110  if (l_name.find (other) == 0) return (true);
3111
3112  for (int i = 0; i < alternates.size (); i++)
3113    {
3114      const cmt_string& a = alternates[i];
3115      if (a.find (other) == 0) return (true);
3116    }
3117
3118  return (false);
3119}
3120
3121//----------------------------------------------------------
3122bool FilePath::in (const char* other) const
3123{
3124  const cmt_string o = other;
3125
3126  return (in (o));
3127}
Note: See TracBrowser for help on using the repository browser.