Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cmt_system.cxx

Go to the documentation of this file.
00001 //-----------------------------------------------------------
00002 // Copyright Christian Arnault LAL-Orsay CNRS
00003 // arnault@lal.in2p3.fr
00004 // See the complete license in cmt_license.txt "http://www.cecill.info". 
00005 //-----------------------------------------------------------
00006 
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include <errno.h>
00011 
00012 #ifdef WIN32
00013 #include <direct.h>
00014 #define chdir _chdir
00015 #define rmdir _rmdir
00016 //#define mkdir _mkdir
00017 #define getcwd _getcwd
00018 #define popen _popen
00019 #define pclose _pclose
00020 #define S_IFDIR _S_IFDIR
00021 #define USE_GETCWD 1
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <time.h>
00026 #include <io.h>
00027 #include <windows.h>
00028 
00029 #define stat _stat
00030 
00031 #else
00032 #include <unistd.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <time.h>
00036 #include <dirent.h>
00037 #endif
00038 
00039 #ifdef __hpux__
00040 #define USE_GETCWD 1
00041 #endif
00042 
00043 #ifdef __linux__
00044 #define USE_GETCWD 1
00045 #endif
00046 
00047 #ifdef USE_GETCWD
00048 char* getwd (const char* name)
00049 {
00050   char dir[256];
00051   getcwd (dir, sizeof (dir));
00052   strcpy ((char*) name, dir);
00053   return ((char*) name);
00054 }
00055 #endif
00056 
00057 #include "cmt_system.h"
00058 #include "cmt_error.h"
00059 
00060 //--------------------------------------------------
00061 cmt_string CmtSystem::pwd ()
00062 {
00063   char buffer[256] = "";
00064   char* ptr = 0;
00065   char* pwd_env = 0;
00066 
00067 #ifdef USE_PWD
00068   pwd_env = ::getenv ("PWD");  
00069 #endif
00070 
00071   if (pwd_env != 0)
00072     {
00073       strcpy (buffer, pwd_env);
00074     }
00075   else
00076     {
00077       ptr = getcwd (buffer, sizeof (buffer));
00078     }
00079 
00080   const char* t = &buffer[0];
00081   return ((cmt_string) t);
00082 }
00083 
00084 //--------------------------------------------------
00085 bool CmtSystem::cd (const cmt_string& dir)
00086 {
00087   static cmt_string new_dir;
00088 
00089   if ((dir.size () == 2) && (dir[1] == ':'))
00090     {
00091       new_dir = dir;
00092       new_dir += file_separator ();
00093       if (chdir (new_dir.c_str ()) == 0) 
00094         {
00095 #ifdef USE_PWD
00096           new_dir = "PWD=";
00097           new_dir += dir;
00098           new_dir += file_separator ();
00099           putenv (new_dir);
00100 #endif
00101 
00102           return (true);
00103         }
00104       return (false);
00105     }
00106   else
00107     {
00108       if (chdir (dir.c_str ()) == 0) 
00109         {
00110 #ifdef USE_PWD
00111           new_dir = "PWD=";
00112           new_dir += dir;
00113           putenv (new_dir);
00114 #endif
00115 
00116           return (true);
00117         }
00118       return (false);
00119     }
00120 }
00121 
00122 //--------------------------------------------------
00123 void CmtSystem::basename (const cmt_string& file_name, cmt_string& result)
00124 {
00125   int pos = file_name.find_last_of ('/');
00126   if (pos == cmt_string::npos)
00127     {
00128       pos = file_name.find_last_of ('\\');
00129     }
00130 
00131   if (pos == cmt_string::npos)
00132     {
00133       result = file_name;
00134     }
00135   else
00136     {
00137       file_name.substr (pos + 1, result);
00138     }
00139 }
00140 
00141 //--------------------------------------------------
00142 void CmtSystem::basename (const cmt_string& file_name,
00143                           const cmt_string& /*suffix*/,
00144                           cmt_string& result)
00145 {
00146   basename (file_name, result);
00147 
00148   int pos;
00149 
00150   pos = result.find_last_of ('.');
00151 
00152   if (pos != cmt_string::npos)
00153     {
00154       result.erase (pos);
00155     }
00156 }
00157 
00158 //--------------------------------------------------
00159 void CmtSystem::dirname (const cmt_string& file_name, cmt_string& result)
00160 {
00161   int pos = file_name.find_last_of ('/');
00162   if (pos == cmt_string::npos)
00163     {
00164       pos = file_name.find_last_of ('\\');
00165     }
00166 
00167   if (pos == cmt_string::npos)
00168     {
00169       result = "";
00170     }
00171   else
00172     {
00173       result = file_name;
00174       result.erase (pos);
00175     }
00176 }
00177 
00178 //--------------------------------------------------
00179 void CmtSystem::name (const cmt_string& file_name, cmt_string& result)
00180 {
00181   int pos;
00182 
00183   result = file_name;
00184 
00185   // remove the suffix
00186 
00187   pos = result.find_last_of ('.');
00188 
00189   if (pos != cmt_string::npos)
00190     {
00191       result.erase (pos);
00192     }
00193 
00194   // remove the directory name
00195 
00196   pos = result.find_last_of ('/');
00197   if (pos == cmt_string::npos)
00198     {
00199       pos = result.find_last_of ('\\');
00200     }
00201 
00202   if (pos != cmt_string::npos)
00203     {
00204       result.erase (0, pos + 1);
00205     }
00206 }
00207 
00208 //-------------------------------------------------
00209 void CmtSystem::get_suffix (const cmt_string& file, cmt_string& result)
00210 {
00211   int pos = file.find_last_of ('.');
00212   int sep = file.find_last_of (file_separator ());
00213 
00214   if ((pos == cmt_string::npos) || (pos < sep))
00215     {
00216       result = "";
00217     }
00218   else
00219     {
00220       file.substr (pos + 1, result);
00221     }
00222 }
00223 
00224 //-------------------------------------------------
00225 void CmtSystem::get_dot_suffix (const cmt_string& file, cmt_string& result)
00226 {
00227   int pos = file.find_last_of ('.');
00228   int sep = file.find_last_of (file_separator ());
00229 
00230   if ((pos == cmt_string::npos) || (pos < sep))
00231     {
00232       result = "";
00233     }
00234   else
00235     {
00236       file.substr (pos, result);
00237     }
00238 }
00239 
00240 //--------------------------------------------------
00241 bool CmtSystem::has_prefix (const cmt_string& name)
00242 {
00243   if ((name.find ('/') == cmt_string::npos) &&
00244       (name.find ('\\') == cmt_string::npos))
00245     {
00246       return (false);
00247     }
00248 
00249   return (true);
00250 }
00251 
00252 //--------------------------------------------------
00253 bool CmtSystem::absolute_path (const cmt_string& name)
00254 {
00255   if (name.size () == 0) return (false);
00256 
00257   if ((name[0] == '/') ||
00258       (name[0] == '\\')) return (true);
00259 
00260   if (name.size () >= 2)
00261     {
00262       if (name[1] == ':')
00263         {
00264           return (true);
00265         }
00266     }
00267   return (false);
00268 }
00269 
00270 //--------------------------------------------------
00271 bool CmtSystem::has_device (const cmt_string& name)
00272 {
00273 #ifdef WIN32
00274   if (name.size () == 0) return (false);
00275 
00276   if (name.size () >= 2)
00277     {
00278       if (name[1] == ':')
00279         {
00280           return (true);
00281         }
00282       else if ((name[0] == '\\') && (name[1] == '\\'))
00283         {
00284           return (true);
00285         }
00286     }
00287 #endif
00288 
00289   return (false);
00290 }
00291 
00292 //--------------------------------------------------
00293 cmt_string CmtSystem::current_branch ()
00294 {
00295   cmt_string result;
00296 
00297   basename (pwd (), result);
00298 
00299   return (result);
00300 }
00301 
00302 //--------------------------------------------------
00303 bool CmtSystem::test_directory (const cmt_string& name)
00304 {
00305   struct stat file_stat;
00306   int status;
00307 
00308   status = stat (name.c_str (), &file_stat);
00309 
00310   //cerr << "status(stat) for " << name << " : " << status << " st_mode=" << file_stat.st_mode << endl;
00311 
00312   if (status == 0)
00313     {
00314       if ((file_stat.st_mode & S_IFDIR) == 0)
00315         {
00316           return (false);
00317         }
00318       else
00319         {
00320           return (true);
00321         }
00322     }
00323   else
00324     {
00325       return (false);
00326     }
00327 }
00328 
00329 //--------------------------------------------------
00330 bool CmtSystem::test_file (const cmt_string& name)
00331 {
00332   struct stat file_stat;
00333   int status;
00334 
00335   status = stat (name.c_str (), &file_stat);
00336 
00337   if (status == 0)
00338     {
00339       if ((file_stat.st_mode & S_IFDIR) == 0)
00340         {
00341           return (true);
00342         }
00343       else
00344         {
00345           return (false);
00346         }
00347     }
00348   else
00349     {
00350       return (false);
00351     }
00352 }
00353 
00354 //--------------------------------------------------
00355 bool CmtSystem::compare_files (const cmt_string& name1,
00356                                const cmt_string& name2)
00357 {
00358   struct stat file_stat1;
00359   struct stat file_stat2;
00360   int status;
00361 
00362   status = stat (name1.c_str (), &file_stat1);
00363 
00364   if (status == 0)
00365     {
00366       if ((file_stat1.st_mode & S_IFDIR) != 0)
00367         {
00368           return (false);
00369         }
00370     }
00371   else
00372     {
00373       return (false);
00374     }
00375 
00376   status = stat (name2.c_str (), &file_stat2);
00377 
00378   if (status == 0)
00379     {
00380       if ((file_stat2.st_mode & S_IFDIR) != 0)
00381         {
00382           return (false);
00383         }
00384     }
00385   else
00386     {
00387       return (false);
00388     }
00389 
00390   if (((int) file_stat1.st_size) != ((int) file_stat2.st_size))
00391     {
00392       return (false);
00393     }
00394 
00395   static cmt_string s1;
00396   static cmt_string s2;
00397 
00398   s1.read (name1);
00399   s2.read (name2);
00400 
00401   return ((s1 == s2));
00402 }
00403 
00404 //--------------------------------------------------
00405 //
00406 // Check if the file "name1" is identical to "name2"
00407 // if they are identical, "name1" will be simply deleted
00408 // otherwise "name1" will be copied to "name2" and deleted afterwards
00409 //
00410 //--------------------------------------------------
00411 bool CmtSystem::compare_and_update_files (const cmt_string& name1,
00412                                           const cmt_string& name2)
00413 {
00414   struct stat file_stat1;
00415   struct stat file_stat2;
00416   static cmt_string s1;
00417   static cmt_string s2;
00418   int status;
00419 
00420   status = stat (name1.c_str (), &file_stat1);
00421 
00422   if (status == 0)
00423     {
00424       if ((file_stat1.st_mode & S_IFDIR) != 0)
00425         {
00426           // name1 is a directory.
00427           return (false);
00428         }
00429     }
00430   else
00431     {
00432       // name1 does not exist
00433       return (false);
00434     }
00435 
00436   s1.read (name1);
00437 
00438   status = stat (name2.c_str (), &file_stat2);
00439 
00440   if (status == 0)
00441     {
00442       if ((file_stat2.st_mode & S_IFDIR) != 0)
00443         {
00444           // name2 is a directory
00445           return (false);
00446         }
00447 
00448       if (((int) file_stat1.st_size) == ((int) file_stat2.st_size))
00449         {
00450           s2.read (name2);
00451           if (s1 == s2)
00452             {
00453               unlink (name1);
00454               return (true);
00455             }
00456         }
00457     }
00458 
00459   FILE* f = fopen (name2, "wb");
00460   if (f != NULL)
00461     {
00462       s1.write (f);
00463       fclose (f);
00464 
00465       unlink (name1);
00466 
00467       return (true);
00468     }
00469   else
00470     {
00471       //
00472       // keep the new file "name1" since it cannot be
00473       // copied to "name2"
00474       //
00475       return (false);
00476     }
00477 }
00478 
00479 //--------------------------------------------------
00480 int CmtSystem::file_size (const cmt_string& name)
00481 {
00482   struct stat file_stat;
00483   int status;
00484 
00485   status = stat (name.c_str (), &file_stat);
00486 
00487   if (status == 0)
00488     {
00489       return ((int) file_stat.st_size);
00490     }
00491   else
00492     {
00493       return (0);
00494     }
00495 }
00496 
00497 //--------------------------------------------------
00498 char CmtSystem::file_separator ()
00499 {
00500 #ifdef WIN32
00501   return ('\\');
00502 #else
00503   return ('/');
00504 #endif
00505 }
00506 
00511 void CmtSystem::reduce_file_separators (cmt_string& text)
00512 {
00513   if (file_separator () == '/')
00514     {
00515       text.replace_all ("\\", "/");
00516       while (text.find ("//") != cmt_string::npos)
00517         {
00518           text.replace_all ("//", "/");
00519         }
00520     }
00521   else
00522     {
00523       text.replace_all ("/", "\\");
00524       while (text.find ("\\\\") != cmt_string::npos)
00525         {
00526           text.replace_all ("\\\\", "\\");
00527         }
00528     }
00529 }
00530 
00531 //--------------------------------------------------
00532 char CmtSystem::path_separator ()
00533 {
00534 #ifdef WIN32
00535   return (';');
00536 #else
00537   return (':');
00538 #endif
00539 }
00540 
00541 //--------------------------------------------------
00542 char CmtSystem::command_separator ()
00543 {
00544 #ifdef WIN32
00545   return ('&');
00546 #else
00547   return (';');
00548 #endif
00549 }
00550 
00551 //--------------------------------------------------
00552 const cmt_string& CmtSystem::ev_open ()
00553 {
00554 #ifdef WIN32
00555   static const cmt_string s = "%";
00556 #else
00557   static const cmt_string s = "${";
00558 #endif
00559 
00560   return (s);
00561 }
00562 
00563 //--------------------------------------------------
00564 const cmt_string& CmtSystem::ev_close ()
00565 {
00566 #ifdef WIN32
00567   static const cmt_string s = "%";
00568 #else
00569   static const cmt_string s = "}";
00570 #endif
00571 
00572   return (s);
00573 }
00574 
00575 //-------------------------------------------------
00576 bool CmtSystem::create_symlink (const cmt_string& oldname,
00577                                 const cmt_string& newname)
00578 {
00579   ::unlink (newname.c_str ());
00580 
00581 #ifdef WIN32
00582   int status = 1;
00583 #else
00584   int status = ::symlink (oldname.c_str (), newname.c_str ());
00585 #endif
00586 
00587   if (status == 0) return (true);
00588   return (false);
00589 }
00590 
00591 //-------------------------------------------------
00592 bool CmtSystem::remove_file (const cmt_string& name)
00593 {
00594   if (::unlink (name) != 0)
00595     {
00596       cerr << "#CMT> Cannot remove file " << name << endl;
00597       return (false);
00598     }
00599 
00600   return (true);
00601 }
00602 
00603 //-------------------------------------------------
00604 bool CmtSystem::remove_directory (const cmt_string& name)
00605 {
00606   //cerr << "Try to remove directory " << name << endl;
00607 
00608   cmt_string_vector files;
00609 
00610   scan_dir (name, files);
00611 
00612   for (int i = 0; i < files.size (); i++)
00613     {
00614       cmt_string& file = files[i];
00615 
00616       if (test_directory (file))
00617         {
00618           //cerr << "D=" << file << endl;
00619           if (!remove_directory (file)) return (false);
00620         }
00621       else
00622         {
00623           //cerr << "F=" << file << endl;
00624           if (!remove_file (file)) return (false);
00625         }
00626     }
00627 
00628   int status = ::rmdir (name);
00629   if (status != 0)
00630     {
00631       cerr << "#CMT> Cannot remove directory " << name << " errno=" << errno << endl;
00632       return (false);
00633     }
00634 
00635   return (true);
00636 }
00637 
00638 //-------------------------------------------------
00639 bool CmtSystem::mkdir (const cmt_string& name)
00640 {
00641   static cmt_string_vector path_vector;
00642   int i;
00643   static cmt_string full_path;
00644   char double_fs[] = "  ";
00645 
00646   double_fs[0] = file_separator ();
00647   double_fs[1] = file_separator ();
00648 
00649   full_path = name;
00650 
00651   if (file_separator () == '/')
00652     {
00653       full_path.replace_all ("\\", file_separator ());
00654     }
00655   else
00656     {
00657       full_path.replace_all ("/", file_separator ());
00658     }
00659 
00660   full_path.replace_all (double_fs, file_separator ());
00661 
00662   split (full_path, file_separator (), path_vector);
00663 
00664   full_path = "";
00665 
00666   if (absolute_path (name))
00667     {
00668       if (!has_device (name))
00669         {
00670           full_path = file_separator ();
00671         }
00672     }
00673 
00674   for (i = 0; i < path_vector.size (); i++)
00675     {
00676       const cmt_string& path = path_vector[i];
00677 
00678       if (i > 0) full_path += file_separator ();
00679       full_path += path;
00680 
00681       if (has_device (path)) continue;
00682 
00683       if (!test_directory (full_path))
00684         {
00685 #ifdef WIN32
00686           if (::_mkdir (full_path.c_str ()) != 0)
00687             {
00688                 // cerr << "CMT> cannot create directory " << full_path << endl;
00689               return (false);
00690             }
00691 #else
00692           if (::mkdir (full_path.c_str (), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) != 0)
00693             {
00694                 // cerr << "CMT> cannot create directory " << full_path << endl;
00695               return (false);
00696             }
00697 #endif
00698         }
00699     }
00700 
00701   return (true);
00702 }
00703 
00704 //----------------------------------------------------------
00705 void CmtSystem::scan_dir (const cmt_string& dir_name,
00706                           cmt_string_vector& list)
00707 {
00708   static cmt_string dir_prefix;
00709   static cmt_string name_prefix;
00710 
00711   dir_prefix = dir_name;
00712   if (dir_name == "") dir_prefix = ".";
00713 
00714   if (!test_directory (dir_prefix))
00715     {
00716       dirname (dir_prefix, dir_prefix);
00717       basename (dir_name, name_prefix);
00718     }
00719   else
00720     {
00721     }
00722 
00723   bool need_filter = false;
00724 
00725   int wild_card;
00726 
00727   wild_card = name_prefix.find ('*');
00728   if (wild_card != cmt_string::npos)
00729     {
00730       name_prefix.erase (wild_card);
00731     }
00732 
00733   if (name_prefix.size () > 0)
00734     {
00735       need_filter = true;
00736     }
00737 
00738   list.clear ();
00739 
00740 #ifdef WIN32
00741 
00742   long dir;
00743   struct _finddata_t entry;
00744 
00745   static cmt_string search;
00746 
00747   search = dir_prefix;
00748   search += file_separator ();
00749   search += "*";
00750 
00751   dir = _findfirst (search.c_str (), &entry);
00752   if (dir > 0)
00753     {
00754       for (;;)
00755         {
00756           if ((strcmp ((char*) entry.name, ".") != 0) &&
00757               (strcmp ((char*) entry.name, "..") != 0) &&
00758               (strncmp ((char*) entry.name, ".nfs", 4) != 0))
00759             {
00760               const char* name = entry.name;
00761 
00762               if (!need_filter ||
00763                   (strncmp (name, name_prefix.c_str (), name_prefix.size ()) == 0))
00764                 {
00765                   cmt_string& name_entry = list.add ();
00766 
00767                   name_entry = dir_prefix;
00768                   name_entry += file_separator ();
00769                   name_entry += name;
00770                 }
00771             }
00772 
00773           int status = _findnext (dir, &entry);
00774           if (status != 0)
00775             {
00776               break;
00777             }
00778         }
00779 
00780       _findclose (dir);
00781     }
00782 #else
00783 
00784   //cout << "scan_dir> dir=" << dir_name << endl;
00785 
00786   DIR* dir = opendir (dir_prefix.c_str ());
00787 
00788   struct dirent* entry;
00789 
00790   if (dir != 0)
00791     {
00792       while ((entry = readdir (dir)) != 0)
00793         {
00794           //if (entry->d_name[0] == '.') continue;
00795           if (!strcmp ((char*) entry->d_name, ".")) continue;
00796           if (!strcmp ((char*) entry->d_name, "..")) continue;
00797           if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue;
00798 
00799           const char* name = entry->d_name;
00800 
00801           if (need_filter &&
00802               (strncmp (name, name_prefix.c_str (), name_prefix.size ()) != 0)) continue;
00803 
00804           //cout << "scan_dir> name=" << name << endl;
00805 
00806           cmt_string& name_entry = list.add ();
00807 
00808           name_entry = dir_prefix;
00809           name_entry += file_separator ();
00810           name_entry += name;
00811         }
00812 
00813       closedir (dir);
00814     }
00815 #endif
00816 
00817 }
00818 
00819 //----------------------------------------------------------
00820 void CmtSystem::scan_dir (const cmt_string& dir_name,
00821                           const cmt_regexp& expression,
00822                           cmt_string_vector& list)
00823 {
00824   static cmt_string dir_prefix;
00825 
00826   dir_prefix = dir_name;
00827   if (dir_name == "") dir_prefix = ".";
00828 
00829   if (!test_directory (dir_prefix))
00830     {
00831       dirname (dir_prefix, dir_prefix);
00832     }
00833 
00834   list.clear ();
00835 
00836 #ifdef WIN32
00837 
00838   long dir;
00839   struct _finddata_t entry;
00840 
00841   static cmt_string search;
00842 
00843   search = dir_prefix;
00844   search += file_separator ();
00845   search += "*";
00846 
00847   dir = _findfirst (search.c_str (), &entry);
00848   if (dir > 0)
00849     {
00850       for (;;)
00851         {
00852           if ((entry.name[0] != '.') &&
00853               (strcmp ((char*) entry.name, ".") != 0) &&
00854               (strcmp ((char*) entry.name, "..") != 0) &&
00855               (strncmp ((char*) entry.name, ".nfs", 4) != 0))
00856             {
00857               const char* name = entry.name;
00858               
00859               if (expression.match (name))
00860                 {
00861                   cmt_string& name_entry = list.add ();
00862 
00863                   name_entry = dir_prefix;
00864                   name_entry += file_separator ();
00865                   name_entry += name;
00866                 }
00867             }
00868 
00869           int status = _findnext (dir, &entry);
00870           if (status != 0)
00871             {
00872               break;
00873             }
00874         }
00875       _findclose (dir);
00876     }
00877 #else
00878 
00879   //cout << "scan_dir> dir=" << dir_name << endl;
00880 
00881   DIR* dir = opendir (dir_prefix.c_str ());
00882 
00883   struct dirent* entry;
00884 
00885   if (dir != 0)
00886     {
00887       while ((entry = readdir (dir)) != 0)
00888         {
00889           //if (entry->d_name[0] == '.') continue;
00890           if (!strcmp ((char*) entry->d_name, ".")) continue;
00891           if (!strcmp ((char*) entry->d_name, "..")) continue;
00892           if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue;
00893 
00894           const char* name = entry->d_name;
00895 
00896           if (!expression.match (name)) continue;
00897 
00898           cmt_string& name_entry = list.add ();
00899 
00900           name_entry = dir_prefix;
00901           name_entry += file_separator ();
00902           name_entry += name;
00903         }
00904 
00905       closedir (dir);
00906     }
00907 #endif
00908 
00909 }
00910 
00911 //----------------------------------------------------------
00912 CmtSystem::cmt_string_vector& CmtSystem::scan_dir (const cmt_string& dir_name)
00913 {
00914   static cmt_string_vector result;
00915 
00916   scan_dir (dir_name, result);
00917 
00918   return (result);
00919 }
00920 
00921 //----------------------------------------------------------
00922 const cmt_string& CmtSystem::get_cmt_root ()
00923 {
00924   static cmt_string root;
00925 
00926   root = "";
00927 
00928   const char* env = ::getenv ("CMTROOT");
00929   if (env != 0)
00930     {
00931       root = env;
00932 
00933       dirname (root, root);
00934       dirname (root, root);
00935       root.replace_all ("\"", "");
00936       return (root);
00937     }
00938 
00939 #ifdef WIN32
00940   LONG status;
00941   HKEY key = 0;
00942 
00943   status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
00944                          0, KEY_READ, &key);
00945   if (status == ERROR_SUCCESS)
00946     {
00947       char temp[256];
00948       DWORD length = sizeof (temp) - 1;
00949       DWORD type;
00950 
00951       status = RegQueryValueEx (key, "root", 0, &type, (LPBYTE) temp, &length);
00952       if (status == ERROR_SUCCESS)
00953         {
00954           root = temp;
00955           return (root);
00956         }
00957     }
00958 #endif
00959 
00960   return (root);
00961 }
00962 
00963 //----------------------------------------------------------
00964 void CmtSystem::get_cmt_version (cmt_string& version)
00965 {
00966   version = "";
00967 
00968   const char* env = ::getenv ("CMTROOT");
00969   if (env != 0)
00970     {
00971       cmt_string s = env;
00972       basename (s, version);
00973       version.replace_all ("\"", "");
00974     }
00975   else
00976     {
00977 #ifdef WIN32
00978       LONG status;
00979       HKEY key = 0;
00980 
00981       status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
00982                              0, KEY_READ, &key);
00983       if (status == ERROR_SUCCESS)
00984         {
00985           char temp[256];
00986           DWORD length = sizeof (temp) - 1;
00987           DWORD type;
00988           
00989           status = RegQueryValueEx (key, "version", 0, &type, 
00990                                     (LPBYTE) temp, &length);
00991           if (status == ERROR_SUCCESS)
00992             {
00993               version = temp;
00994             }
00995         }
00996 #endif
00997     }
00998 }
00999 
01000 //----------------------------------------------------------
01001 cmt_string CmtSystem::get_cmt_config ()
01002 {
01003   const char* env = ::getenv ("CMTCONFIG");
01004   if (env != 0)
01005     {
01006       return (cmt_string (env));
01007     }
01008 
01009   env = ::getenv ("CMTBIN");
01010   if (env != 0)
01011     {
01012       return (cmt_string (env));
01013     }
01014 
01015 #ifdef WIN32
01016   LONG status;
01017   HKEY key = 0;
01018 
01019   status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
01020                          0, KEY_READ, &key);
01021   if (status == ERROR_SUCCESS)
01022     {
01023       char temp[256];
01024       DWORD length = sizeof (temp) - 1;
01025       DWORD type;
01026 
01027       status = RegQueryValueEx (key, "config", 0, &type, 
01028                                 (LPBYTE) temp, &length);
01029       if (status == ERROR_SUCCESS)
01030         {
01031           cmt_string config (temp);
01032           return (config);
01033         }
01034     }
01035 
01036   return ("VisualC");
01037 #endif
01038 
01039   return ("");
01040 
01041 }
01042 
01043 //----------------------------------------------------------
01044 cmt_string CmtSystem::get_cmt_site ()
01045 {
01046   const char* env = ::getenv ("CMTSITE");
01047   if (env != 0)
01048     {
01049       return (cmt_string (env));
01050     }
01051 
01052 #ifdef WIN32
01053   LONG status;
01054   HKEY key = 0;
01055 
01056   status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
01057                          0, KEY_READ, &key);
01058   if (status == ERROR_SUCCESS)
01059     {
01060       char temp[256];
01061       DWORD length = sizeof (temp) - 1;
01062       DWORD type;
01063 
01064       status = RegQueryValueEx (key, "site", 0, &type, (LPBYTE) temp, &length);
01065       if (status == ERROR_SUCCESS)
01066         {
01067           cmt_string site (temp);
01068           return (site);
01069         }
01070     }
01071 #endif
01072 
01073   return ("");
01074 }
01075 
01076 //----------------------------------------------------------
01077 void CmtSystem::get_uname (cmt_string& uname)
01078 {
01079 #ifdef WIN32
01080   uname = "WIN32";
01081 #else
01082 
01083   uname = "";
01084 
01085   FILE* file;
01086 
01087   file = popen ("uname", "r");
01088 
01089   if (file != 0)
01090     {
01091       char line[1024];
01092       char* ptr;
01093       char* nl;
01094 
01095       line[0] = 0;
01096       ptr = fgets (line, sizeof (line), file);
01097       if (ptr != 0)
01098         {
01099           nl = strrchr (ptr, '\n');
01100           if (nl != 0) *nl = 0;
01101 
01102           uname = ptr;
01103         }
01104       pclose (file);
01105     }
01106 #endif
01107 }
01108 
01109 //----------------------------------------------------------
01110 void CmtSystem::get_hosttype (cmt_string& hosttype)
01111 {
01112   hosttype = "";
01113 
01114   char* ptr;
01115 
01116   ptr = ::getenv ("HOSTTYPE");
01117   if (ptr != 0)
01118     {
01119       hosttype = ptr;
01120     }
01121 }
01122 
01123 //----------------------------------------------------------
01124 cmt_string CmtSystem::get_temporary_name ()
01125 {
01126   cmt_string name;
01127 
01128   name = ::tmpnam (NULL);
01129 
01130   return (name);
01131 }
01132 
01133 //----------------------------------------------------------
01134 cmt_string CmtSystem::get_home_package ()
01135 {
01136   cmt_string name = "CMTHOME";
01137 
01138   return (name);
01139 }
01140 
01141 //----------------------------------------------------------
01142 bool CmtSystem::is_home_package (const cmt_string& name,
01143                                  const cmt_string& version)
01144 {
01145   if (name == "CMTHOME") return (true);
01146 
01147   return (false);
01148 }
01149 
01150 //----------------------------------------------------------
01151 cmt_string CmtSystem::get_user_context_package ()
01152 {
01153   cmt_string name = "CMTUSERCONTEXT";
01154 
01155   return (name);
01156 }
01157 
01158 //----------------------------------------------------------
01159 bool CmtSystem::is_user_context_package (const cmt_string& name,
01160                                          const cmt_string& version)
01161 {
01162   if (name == "CMTUSERCONTEXT") return (true);
01163 
01164   return (false);
01165 }
01166 
01167 //----------------------------------------------------------
01168 cmt_string CmtSystem::get_project_package ()
01169 {
01170   cmt_string name = "PROJECT";
01171 
01172   return (name);
01173 }
01174 
01175 //----------------------------------------------------------
01176 bool CmtSystem::is_project_package (const cmt_string& name,
01177                                     const cmt_string& version)
01178 {
01179   if (name == "PROJECT") return (true);
01180 
01181   return (false);
01182 }
01183 
01184 //----------------------------------------------------------
01185 bool CmtSystem::testenv (const cmt_string& name)
01186 {
01187   const char* env = ::getenv (name);
01188   if (env == 0) return (false);
01189   return (true);
01190 }
01191 
01192 //----------------------------------------------------------
01193 cmt_string CmtSystem::getenv (const cmt_string& name)
01194 {
01195   cmt_string result;
01196 
01197   const char* env = ::getenv (name);
01198   if (env != 0)
01199     {
01200       result = env;
01201     }
01202 
01203   if (name == "CMTCONFIG")
01204   {
01205     return (get_cmt_config ());
01206   }
01207 
01208   /*
01209   if (name == "CMTROOT")
01210   {
01211           return (get_cmt_root ());
01212   }
01213 
01214   if (name == "CMTSITE")
01215   {
01216           return (get_cmt_site ());
01217   }
01218   */
01219 
01220   return (result);
01221 }
01222 
01223 //----------------------------------------------------------
01224 bool CmtSystem::putenv (const cmt_string& name_value)
01225 {
01226   int status = ::putenv ((char*) name_value.c_str ());
01227 
01228   if (status == 0) return (true);
01229   else return (false);
01230 }
01231 
01232 //----------------------------------------------------------
01233 //
01234 // This singleton interacts with the ProjectFactory to consistently create
01235 // the project graph.
01236 //
01237 // In particular a single-depth stack of the top project is maintained.
01238 //
01239 //----------------------------------------------------------
01240 class CMTPathManager
01241 {
01242 public:
01243   static CMTPathManager& instance ();
01244   static void reset ();
01245   static void add_cmt_path (const cmt_string& path,
01246                             const cmt_string& path_source,
01247                             IProjectFactory& factory);
01248 
01249 private:
01250   CMTPathManager () : m_project (0)
01251   {
01252   }
01253 
01254   void do_reset ()
01255   {
01256     m_project = 0;
01257   }
01258 
01259   void do_add_cmt_path (const cmt_string& path,
01260                         const cmt_string& path_source,
01261                         IProjectFactory& factory)
01262   {
01263     cmt_string npath = path;
01264 
01265     if (npath == "") return;
01266 
01267 #ifdef WIN32
01268     if (npath.size () == 2)
01269       {
01270         if (npath[1] == ':')
01271           {
01272             npath += CmtSystem::file_separator ();
01273           }
01274       }
01275 #endif
01276 
01277     npath.replace_all ("\\", CmtSystem::file_separator ());
01278     npath.replace_all ("/", CmtSystem::file_separator ());
01279 
01280     if (!CmtSystem::absolute_path (npath))
01281       {
01282         cmt_string h = CmtSystem::pwd ();
01283         h += CmtSystem::file_separator ();
01284         h += npath;
01285         npath = h;
01286       }
01287     
01288     CmtSystem::compress_path (npath);
01289 
01290     //cerr << "adding npath=" << npath << endl;
01291 
01292     while (npath[npath.size ()-1] == CmtSystem::file_separator ())
01293       {
01294         npath.erase (npath.size ()-1);
01295       }
01296     
01297     //cerr << "adding npath=[" << npath << "]" << endl;
01298     
01299     if (npath != "")
01300       {
01301         if (!CmtSystem::test_directory (npath))
01302           {
01303             CmtError::set (CmtError::path_not_found, npath);
01304             return;
01305           }
01306 
01307         cmt_string project_name;
01308 
01309         if ((path_source == "CMTUSERCONTEXT") ||
01310             (path_source == "CMTHOME"))
01311           {
01312             project_name = path_source;
01313           }
01314 
01315         m_project = factory.create_project (project_name, npath, path_source, m_project);
01316       }
01317   }
01318 
01319   Project* m_project;
01320 };
01321 
01322 CMTPathManager& CMTPathManager::instance ()
01323 {
01324   static CMTPathManager me;
01325   
01326   return (me);
01327 }
01328 
01329 void CMTPathManager::reset ()
01330 {
01331   static CMTPathManager& me = instance ();
01332   me.do_reset ();
01333 }
01334 
01335 void CMTPathManager::add_cmt_path (const cmt_string& path,
01336                                    const cmt_string& path_source,
01337                                    IProjectFactory& factory)
01338 {
01339   static CMTPathManager& me = instance ();
01340   me.do_add_cmt_path (path, path_source, factory);
01341 }
01342 
01343 
01344 
01345 //----------------------------------------------------------
01346 static void add_cmt_paths_from_text (const cmt_string& text,
01347                                      const cmt_string& context,
01348                                      IProjectFactory& factory)
01349 {
01350   static CmtSystem::cmt_string_vector path_vector;
01351   int i;
01352 
01353   CmtSystem::split (text, CmtSystem::path_separator (), path_vector);
01354 
01355   for (i = 0; i < path_vector.size (); i++)
01356     {
01357       const cmt_string& path = path_vector[i];
01358 
01359       CMTPathManager::add_cmt_path (path, context, factory);
01360     }
01361 }
01362 
01363 //----------------------------------------------------------
01364 static void add_cmt_paths_from_file (const cmt_string& file_name, IProjectFactory& factory)
01365 {
01366   if (!CmtSystem::test_file (file_name)) return;
01367 
01368   static cmt_string text;
01369 
01370   text.read (file_name);
01371 
01372   int pos = text.find ("CMTPATH");
01373   if (pos == cmt_string::npos) return;
01374   pos += strlen ("CMTPATH");
01375   pos = text.find (pos, "=");
01376   if (pos == cmt_string::npos) return;
01377   pos++;
01378 
01379   text.erase (0, pos);
01380 
01381   int nl = text.find (pos, "\n");
01382   if (nl != cmt_string::npos) text.erase (nl);
01383 
01384   add_cmt_paths_from_text (text, file_name, factory);
01385 }
01386 
01387 //----------------------------------------------------------
01388 //
01389 // With this function we analyse all possible ways of
01390 // externally entering CMTPATH items
01391 //  + from the environment variable
01392 //  + from .cmtrc files
01393 //  + from registry on Windows
01394 //  + from EV settings for CMTUSERCONTEXT and CMTHOME
01395 // 
01396 // Then projects are created from these settings.
01397 //
01398 // (The other way to enter project graph is through project files)
01399 //----------------------------------------------------------
01400 void CmtSystem::get_cmt_paths (IProjectFactory& factory, 
01401                                const cmt_string& init_text,
01402                                const cmt_string& cmt_user_context,
01403                                const cmt_string& cmt_home)
01404 {
01405   CMTPathManager::reset ();
01406 
01407   if (init_text != "")
01408     {
01409       add_cmt_paths_from_text (init_text, "initialization", factory);
01410     }
01411 
01412 #ifdef WIN32
01413   LONG status;
01414   HKEY key = 0;
01415 
01416   status = RegOpenKeyEx (HKEY_CURRENT_USER, "Software\\CMT\\path",
01417                          0, KEY_READ, &key);
01418   if (status == ERROR_SUCCESS)
01419     {
01420       DWORD index = 0;
01421       char name[256];
01422       char temp[256];
01423 
01424       for (;;)
01425         {
01426           DWORD name_length = sizeof (name) - 1;
01427           DWORD length = sizeof (temp) - 1;
01428           DWORD type;
01429           status = RegEnumValue (key, index,
01430                                  name, &name_length, 0, &type,
01431                                  (LPBYTE) temp, &length);
01432           if ((status == ERROR_SUCCESS) ||
01433               (status == 234))
01434             {
01435               const cmt_string path = temp;
01436               CMTPathManager::add_cmt_path (path, "HKEY_CURRENT_USER", factory);
01437             }
01438 
01439           if (status == 259)
01440             {
01441               break;
01442             }
01443 
01444           index++;
01445         }
01446     }
01447 
01448   status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT\\path",
01449                          0, KEY_READ, &key);
01450   if (status == ERROR_SUCCESS)
01451     {
01452       DWORD index = 0;
01453       char name[256];
01454       char temp[256];
01455 
01456       for (;;)
01457         {
01458           DWORD type;
01459           DWORD name_length = sizeof (name) - 1;
01460           DWORD length = sizeof (temp) - 1;
01461 
01462 
01463           status = RegEnumValue (key, index,
01464                                  name, &name_length, 0, &type,
01465                                  (LPBYTE) temp, &length);
01466           if (status != ERROR_NO_MORE_ITEMS)
01467             {
01468               const cmt_string path = temp;
01469               CMTPathManager::add_cmt_path (path, "HKEY_LOCAL_MACHINE", factory);
01470             }
01471           else
01472             {
01473               break;
01474             }
01475           index++;
01476         }
01477     }
01478 
01479 #endif
01480 
01481   //-----------------------------------------
01482   // look for .cmtrc files :
01483   //  first look in ./
01484   //  then in "~/"
01485   //  then in ${CMTROOT}/mgr
01486   //-----------------------------------------
01487   cmt_string rc_name;
01488 
01489   add_cmt_paths_from_file (".cmtrc", factory);
01490 
01491   if (get_home_directory (rc_name))
01492     {
01493       rc_name += file_separator ();
01494       rc_name += ".cmtrc";
01495       add_cmt_paths_from_file (rc_name, factory);
01496     }
01497 
01498   rc_name = get_cmt_root ();
01499   rc_name += file_separator ();
01500   rc_name += "CMT";
01501   rc_name += file_separator ();
01502   cmt_string version;
01503   get_cmt_version (version);
01504   rc_name += version;
01505   rc_name += file_separator ();
01506   rc_name += "mgr";
01507   rc_name += file_separator ();
01508   rc_name += ".cmtrc";
01509 
01510   add_cmt_paths_from_file (rc_name, factory);
01511 
01512   CMTPathManager::add_cmt_path (cmt_user_context, "CMTUSERCONTEXT", factory);
01513   CMTPathManager::add_cmt_path (cmt_home, "CMTHOME", factory);
01514 }
01515 
01516 //----------------------------------------------------------
01517 int CmtSystem::execute (const cmt_string& command)
01518 {
01519   //cout << "CmtSystem::execute1> [" << command << "]" << endl;
01520 
01521   return (system (command.c_str ()));
01522 }
01523 
01524 //----------------------------------------------------------
01525 int CmtSystem::execute (const cmt_string& command, cmt_string& output)
01526 {
01527   output = "";
01528 
01529   //cout << "CmtSystem::execute2> [" << command << "]" << endl;
01530 
01531   FILE* f = popen (command.c_str (), "r"); 
01532   
01533   if (f != 0) 
01534     { 
01535       char line[256]; 
01536       char* ptr;
01537 
01538       while ((ptr = fgets (line, sizeof (line), f)) != NULL) 
01539         {
01540           output += ptr;
01541         } 
01542       pclose (f);
01543 
01544       return (0);
01545     }
01546 
01547   return (1);
01548 }
01549 
01550 //----------------------------------------------------------
01551 bool CmtSystem::is_package_directory (const cmt_string& name)
01552 {
01553   cmt_string_vector dirs;
01554 
01555   cmt_regexp exp ("^[a-zA-Z.][0-9]+([a-zA-Z.][0-9]+([a-zA-Z.][0-9]+)?)?");
01556 
01557   scan_dir (name, exp, dirs);
01558 
01559   cmt_string req;
01560 
01561   req = name;
01562   req += file_separator ();
01563   req += "cmt";
01564   req += file_separator ();
01565   req += "requirements";
01566 
01567   if (test_file (req)) return (true);
01568 
01569   if (dirs.size () == 0) 
01570     {
01571       return (false);
01572     }
01573 
01574   for (int i = 0; i < dirs.size (); i++)
01575       {
01576         const cmt_string& d = dirs[i];
01577 
01578         req = d;
01579         req += file_separator ();
01580         req += "mgr";
01581         req += file_separator ();
01582         req += "requirements";
01583 
01584         if (test_file (req)) return (true);
01585 
01586       req = d;
01587       req += file_separator ();
01588       req += "cmt";
01589       req += file_separator ();
01590       req += "requirements";
01591       
01592       if (test_file (req)) return (true);
01593     }
01594 
01595   return (false);
01596 }
01597 
01598 //----------------------------------------------------------
01599 bool CmtSystem::is_version_directory (const cmt_string& name)
01600 {
01601   int v;
01602   int r;
01603   int p;
01604 
01605   return (is_version_directory (name, v, r, p));
01606 }
01607 
01608 //----------------------------------------------------------
01609 bool CmtSystem::is_version_directory (const cmt_string& name,
01610                                       int& v,
01611                                       int& r,
01612                                       int& p)
01613 {
01614   if ((name == "HEAD") || (name == "head"))
01615     {
01616       v = 0;
01617       r = 0;
01618       p = 0;
01619 
01620       return (true);
01621     }
01622 
01623   static const cmt_string numbers = "0123456789";
01624 
01625   static const int id_version = 0;
01626   static const int id_release = 1;
01627   static const int id_patch   = 2;
01628 
01629   cmt_string buffer;
01630 
01631   enum 
01632   {
01633     starting,
01634     at_key,
01635     at_number
01636   } state;
01637 
01638   int id;
01639   int pos;
01640   int value;
01641 
01642   v = 0;
01643   r = 0;
01644   p = 0;
01645 
01646   //
01647   // version : v-field
01648   //         | v-field r-field
01649   //         | v-field r-field p-field
01650   //
01651   // v-field : field
01652   // r-field : field
01653   // p-field : field
01654   //
01655   // field   : key '*'
01656   //         | key number
01657   //
01658   // key     : letters
01659   //
01660 
01661   state = starting;
01662   id    = id_version;
01663 
01664   for (pos = 0; pos < name.size (); pos++)
01665     {
01666       char c = name[pos];
01667 
01668       if (c == '*')
01669         {
01670           // A wild card
01671           switch (state)
01672             {
01673             case starting:
01674               // cannot start with a wild card ??
01675               v = -1;
01676               r = -1;
01677               p = -1;
01678               return (false);
01679             case at_key:
01680               // the numeric field is valued with a wild card
01681               switch (id)
01682                 {
01683                 case id_version:
01684                   v = -1;
01685                 case id_release:
01686                   r = -1;
01687                 case id_patch:
01688                   p = -1;
01689                   break;
01690                 }
01691               return (true);
01692             case at_number:
01693               // question:
01694               // a number followed by a wild-card is considered as:
01695               //   1) a wild card on the number itself (1* comp with 1, 10, 12, 120, etc)
01696               //   2) a wild card on the next fields (1* comp with 1r1, 1-12 etc)
01697               //
01698 
01699               //  Here we select option 1)
01700 
01701               sscanf (buffer.c_str (), "%d", &value);
01702               switch (id)
01703                 {
01704                 case id_version:
01705                   //
01706                   // lazy option 1 implies v = -1;
01707                   // strict option 1 would imply v = -value;
01708                   // option 2 implies v = value;
01709                   //
01710 
01711                   v = -1;
01712                   r = -1;
01713                   p = -1;
01714                   break;
01715                 case id_release:
01716                   r = value;
01717                   p = -1;
01718                   break;
01719                 case id_patch:
01720                   p = value;
01721                   break;
01722                 }
01723 
01724               return (true);
01725             }
01726         }
01727       else if (numbers.find (c) == cmt_string::npos)
01728         {
01729           // A letter
01730           switch (state)
01731             {
01732             case starting:
01733               state = at_key;
01734               break;
01735             case at_key:
01736               // Multiple letter key (is it permitted??)
01737               break;
01738             case at_number:
01739               sscanf (buffer.c_str (), "%d", &value);
01740               switch (id)
01741                 {
01742                 case id_version:
01743                   v = value;
01744                   break;
01745                 case id_release:
01746                   r = value;
01747                   break;
01748                 case id_patch:
01749                   p = value;
01750                   break;
01751                 }
01752               buffer = "";
01753               id++;
01754               state = at_key;
01755               break;
01756             }
01757         }
01758       else
01759         {
01760           // a number
01761           switch (state)
01762             {
01763             case starting:
01764               // not starting by a letter (syntax error)
01765               return (false);
01766             case at_key:
01767               // the numeric field for the current id is starting now
01768               buffer += c;
01769               state = at_number;
01770               break;
01771             case at_number:
01772               // continuing the current numeric field
01773               buffer += c;
01774               break;
01775             }
01776         }
01777     }
01778 
01779   switch (state)
01780     {
01781     case starting:
01782       // Empty version string
01783       return (false);
01784     case at_key:
01785       // Syntax error (when only letters. Ending letters is not an error)
01786       if (id == id_version) return (false);
01787       else return (true);
01788     case at_number:
01789       sscanf (buffer.c_str (), "%d", &value);
01790       switch (id)
01791         {
01792         case id_version:
01793           v = value;
01794           break;
01795         case id_release:
01796           r = value;
01797           break;
01798         case id_patch:
01799           p = value;
01800           break;
01801         }
01802       id++;
01803       state = at_key;
01804       return (true);
01805     }
01806 
01807   return (false);
01808 }
01809 
01810 //----------------------------------------------------------
01811 //  Split a line into words. Separators are spaces and tabs
01812 //  Text enclosed in double quotes is one word.
01813 //----------------------------------------------------------
01814 void CmtSystem::split (const cmt_string& text,
01815                        const cmt_string& separators,
01816                        cmt_string_vector& strings)
01817 {
01818   static char* buffer = 0;
01819   static int allocated = 0;
01820 
01821   bool finished = false;
01822 
01823   strings.clear ();
01824 
01825   if (text.size () == 0) return;
01826 
01827   /*
01828     We are going to work in a copy of the text, since
01829     \0 will be inserted right after each found word.
01830 
01831     Then the vector of strings is iteratively filled by each found word.
01832   */
01833 
01834   if (buffer == 0)
01835     {
01836       allocated = text.size ();
01837       buffer = (char*) malloc (allocated + 1);
01838     }
01839   else
01840     {
01841       if (text.size () > allocated)
01842         {
01843           allocated = text.size ();
01844           buffer = (char*) realloc (buffer, allocated + 1);
01845         }
01846     }
01847 
01848   strcpy (buffer, text.c_str ());
01849 
01850   /*
01851     Algorithm :
01852 
01853     We look for words separated by <separators> which may be
01854     o spaces (' ' or '\t')
01855     o other characters such as ':'
01856 
01857     A word is a character string not containing any separator. A substring in
01858     this word my be enclosed between quotes (" or ') which permits separator
01859     inclusion within words.
01860   */
01861 
01862   char* current_word = buffer;
01863 
01864   while (*current_word != 0)
01865     {
01866       size_t prefix_length;
01867       size_t word_length;
01868 
01869       /*
01870         while ((*current_word == ' ') ||
01871         (*current_word == '\t'))
01872         {
01873         current_word++;
01874         }
01875       */
01876 
01877       // first skip all starting separators.
01878 
01879       prefix_length = strspn (current_word, separators.c_str ());
01880       if (prefix_length > 0)
01881         {
01882           // Move to the first non-separator character
01883 
01884           current_word += prefix_length;
01885         }
01886 
01887       /*
01888         Parse the next word.
01889 
01890         It may contain enclosures in quote characters or not.
01891         Quotes must be identical on both sides of each enclosure.
01892       */
01893 
01894       char* running_char = current_word;
01895 
01896       word_length = 0;
01897 
01898       for (;;)
01899         {
01900           size_t unquoted_length;
01901           size_t separator_offset;
01902 
01903           for (int p = 0;;)
01904             {
01905               unquoted_length = strcspn (running_char + p, "\"\'") + p;
01906               if ((unquoted_length > 0) && (running_char[unquoted_length-1] == '\\'))
01907                 {
01908                   p = unquoted_length + 1;
01909                 }
01910               else
01911                 {
01912                   break;
01913                 }
01914             }
01915 
01916           separator_offset = strcspn (running_char, separators.c_str ());
01917 
01918           if (separator_offset <= unquoted_length)
01919             {
01920               // no quote in this word -> we are finished for this one.
01921               running_char += separator_offset;
01922               break;
01923             }
01924 
01925           // We have found a quoted enclosure. Move to it.
01926 
01927           running_char += unquoted_length;
01928 
01929           char quote = running_char[0];
01930 
01931           // Remove it.
01932           {
01933             char* p = running_char;
01934             while (p[1] != 0)
01935               {
01936                 *p = p[1];
01937                 p++;
01938               }
01939             *p = 0;
01940           }
01941 
01942           // Look for the next occurence of this quote.
01943           {
01944             char* p = strchr (running_char, quote);
01945             if (p == 0)
01946               {
01947                 // Unmatched quote : the rest of the line will be taken as a word...
01948                 running_char += strlen (running_char);
01949                 finished = true;
01950                 break;
01951               }
01952             else
01953               {
01954                 running_char = p;
01955               }
01956           }
01957 
01958           // Now we remove the ending quote from the word
01959           // (by shifting all remaining characters by one place to the left)
01960 
01961           {
01962             char* p = running_char;
01963             while (p[1] != 0)
01964               {
01965                 *p = p[1];
01966                 p++;
01967               }
01968             *p = 0;
01969           }
01970         }
01971 
01972       word_length = running_char - current_word;
01973 
01974       if (current_word[word_length] == 0)
01975         {
01976           finished = true;
01977         }
01978       else
01979         {
01980           current_word[word_length] = 0;
01981         }
01982 
01983       /*
01984         if ((t[0] == '"') ||
01985         (t[0] == '\'') ||
01986         (t[0] == ':'))
01987         {
01988         char* quote;
01989 
01990         t++;
01991         quote = strchr (t, sep);
01992         if (quote != 0) *quote = 0;
01993         else finished = true;
01994         }
01995         else
01996         {
01997         int offset;
01998 
01999         offset = strcspn (t, " \t:");
02000         if ((offset < 0) || (t[offset] == 0)) finished = true;
02001         if (!finished)
02002         {
02003         space = t + offset;
02004         *space = 0;
02005         }
02006         }
02007       */
02008 
02009       // Store the current word into the vector of strings
02010 
02011       {
02012         cmt_string& s = strings.add ();
02013         s = current_word;
02014       }
02015 
02016       if (finished) break;
02017 
02018       // Move to the next possible word.
02019       current_word += word_length + 1;
02020     }
02021 }
02022 
02023 //----------------------------------------------------------
02024 void CmtSystem::compress_path (const cmt_string& dir, cmt_string& new_dir)
02025 {
02026   new_dir = dir;
02027 
02028   compress_path (new_dir);
02029 }
02030 
02031 //----------------------------------------------------------
02032 //
02033 //  We try to detect the aaaa/xxxx/../bbbb patterns which should be 
02034 // equivalent to aaaa/bbbb
02035 //  this therefore consists in removing all /xxxx/../ when 
02036 //     xxxx is different from ".."
02037 //     xxxx is different from "."
02038 //     xxxx does not contain any macro reference
02039 //
02040 //----------------------------------------------------------
02041 void CmtSystem::compress_path (cmt_string& dir)
02042 {
02043 #ifdef WIN32
02044   static const char pattern[] = "\\..";
02045   static const char fs[] = "\\\\";
02046 #else
02047   static const char pattern[] = "/..";
02048   static const char fs[] = "//";
02049 #endif
02050 
02051   if (dir.size () == 0) return;
02052 
02053   //
02054   // We first synchronize to using file_separator() in any case.
02055   //
02056 
02057   if (file_separator () == '/')
02058     {
02059       dir.replace_all ("\\", file_separator ());
02060     }
02061   else
02062     {
02063       dir.replace_all ("/", file_separator ());
02064     }
02065 
02066   // Suppress all duplicated file separators
02067   dir.replace_all (fs, file_separator ());
02068 
02069   for (;;)
02070     {
02071       int pos1;
02072       int pos2;
02073       int pos3;
02074 
02075       pos1 = dir.find (pattern);
02076       if (pos1 == cmt_string::npos) break;
02077 
02078         //
02079         // extract "aaaa/xxxx" from "aaaa/xxxx/../bbbb"
02080         //
02081       cmt_string p = dir.substr (0, pos1);
02082 
02083       cmt_string dn;
02084       basename (p, dn);
02085       if (dn == "..") break;
02086       if (dn == ".") break;
02087       if (dn == "") break;
02088       
02089         //
02090         // Is "aaaa/xxxx" only made of "xxxx" ?
02091         // 
02092       pos2 = p.find_last_of (file_separator ());
02093       
02094       if (pos2 == cmt_string::npos) 
02095         {
02096           // the pattern was xxxx/..
02097           //
02098           // so xxxx is [0:pos1-1]
02099           //
02100           pos3 = p.find ("$");
02101           if (pos3 == cmt_string::npos)
02102             {
02103               dir.erase (0, pos1 + 3);
02104             }
02105           else
02106             {
02107               break;
02108             }
02109         }
02110       else
02111         {
02112           //    01234567890123456
02113           //    aaaa/xxxx/../bbbb
02114           //        2    1   3
02115           //
02116           // erase the "/xxxx/.." pattern
02117           // result will be "aaaa/bbbb"
02118           //
02119           // Here xxxx is [pos2+1:pos1-1]
02120           //
02121 
02122           pos3 = p.find (pos2, "$");
02123           if (pos3 == cmt_string::npos)
02124             {
02125               dir.erase (pos2, pos1 + 3 - pos2);
02126             }
02127           else
02128             {
02129               break;
02130             }
02131         }
02132     }
02133 
02134     //if (dir[dir.size () - 1] == file_separator ()) dir.erase (dir.size () - 1);
02135 }
02136 
02137 //----------------------------------------------------------
02138 cmt_string CmtSystem::now ()
02139 {
02140   cmt_string result;
02141 
02142   time_t ltime;
02143   time (&ltime);
02144   result = ctime (&ltime);
02145 
02146   result.replace_all ("\n", "");
02147 
02148   return (result);
02149 }
02150 
02151 //----------------------------------------------------------
02152 cmt_string CmtSystem::user ()
02153 {
02154 #ifdef _WIN32
02155   cmt_string result = getenv ("USERNAME");
02156 #else
02157   cmt_string result = getenv ("USER");
02158 #endif
02159 
02160   return (result);
02161 }
02162 
02163 //----------------------------------------------------------
02164 void CmtSystem::get_cvsroot (cmt_string& cvsroot)
02165 {
02166   cvsroot = "";
02167 
02168   const char* env = ::getenv ("CVSROOT");
02169   if (env != 0)
02170     {
02171       cvsroot = env;
02172       return;
02173     }
02174 
02175 #ifdef WIN32
02176   LONG status;
02177   HKEY key = 0;
02178 
02179   status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\CMT", 
02180                          0, KEY_READ, &key);
02181   if (status == ERROR_SUCCESS)
02182     {
02183       char temp[256];
02184       DWORD length = sizeof (temp) - 1;
02185       DWORD type;
02186 
02187       status = RegQueryValueEx (key, "CVSROOT", 0, &type, 
02188                                 (LPBYTE) temp, &length);
02189       if (status == ERROR_SUCCESS)
02190         {
02191           cvsroot = temp;
02192           return;
02193         }
02194     }
02195 #endif
02196 }
02197 
02198 //----------------------------------------------------------
02199 bool CmtSystem::get_home_directory (cmt_string& dir)
02200 {
02201   bool status = false;
02202 
02203 #ifdef WIN32
02204   const char* homedrive = ::getenv ("HOMEDRIVE");
02205   const char* homepath = ::getenv ("HOMEPATH");
02206 
02207   if ((homedrive != 0) && (homepath != 0))
02208     {
02209       dir = homedrive;
02210       dir += homepath;
02211       status = true;
02212     }
02213 
02214 #else
02215   const char* home_env = ::getenv ("HOME");
02216   if (home_env != 0)
02217     {
02218       dir = home_env;
02219       status = true;
02220     }
02221 #endif
02222 
02223   return (status);
02224 }
02225 

Generated on Mon May 2 10:25:06 2005 for CMT by doxygen 1.3.5