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

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

See C.L. 469

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