source: CMT/v1r20p20080222/source/cmt_system.cxx @ 615

Last change on this file since 615 was 444, checked in by rybkin, 16 years ago

See C.L. 348

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