source: CMT/v1r21/source/cmt_system.cxx @ 660

Last change on this file since 660 was 542, checked in by rybkin, 14 years ago

See C.L. 429

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