source: CMT/v1r19p20061114/source/cmt_system.cxx

Last change on this file was 205, checked in by garonne, 18 years ago

Correct touch function to conserve permission

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