basix_doc 0.1
/Users/mourrain/Devel/mmx/basix/src/system.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : system.cpp
00004 * DESCRIPTION: Operating system interface
00005 * COPYRIGHT  : (C) 2000  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license and comes WITHOUT
00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
00009 * If you don't have this file, write to the Free Software Foundation, Inc.,
00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00011 ******************************************************************************/
00012 
00013 #define USE_STANDARD_NEW_DELETE
00014 #include <basix/system.hpp>
00015 #include <basix/vector_sort.hpp>
00016 #include <stdlib.h>
00017 #include <math.h>
00018 #include <dirent.h>
00019 #include <unistd.h>
00020 
00021 #if defined (BASIX_HAVE_SYS_TYPES_H) && defined (BASIX_HAVE_SYS_STAT_H)
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024 #endif
00025 
00026 namespace mmx {
00027 
00028 bool var_load (const string& file_name, string& s);
00029 bool var_load (const string& file_path, const string& file_name, string& s);
00030 bool var_mkdir (const string& name);
00031 
00032 /******************************************************************************
00033 * System commands
00034 ******************************************************************************/
00035 
00036 string
00037 get_env (const string& var) {
00038   char* _var= as_charp (var);
00039   char* _ret= getenv (_var);
00040   free_charp (_var);
00041   if (_ret == NULL) return "";
00042   string ret (_ret);
00043   return ret;
00044   // do not delete _ret !
00045 }
00046 
00047 // int
00048 // set_env (const string& var, const string& value) {
00049 //   char* _var= as_charp (var);
00050 //   char* _value= as_charp (value);
00051 //   int ret= setenv (_var, _value, 1);
00052 //   free_charp (_var);
00053 //   free_charp (_value);
00054 //   return ret;
00055 // }
00056 
00057 int
00058 system (const string& s) {
00059   //mmout << "Execute] " << s << "\n";
00060   char* _s= as_charp (s);
00061   int r= ::system (_s);
00062   free_charp (_s);
00063   return r;
00064 }
00065 
00066 void
00067 init_system () {
00068   string path = user_dir ();
00069   if (!file_exists (path)) {
00070     printf ("This is your first use of Mathemagix.\n");
00071     printf ("I am creating a .mathemagix directory in your home directory\n");
00072     var_mkdir (path);
00073   }
00074   var_mkdir (path * "/etc");
00075   var_mkdir (path * "/lib");
00076   var_mkdir (path * "/var");
00077   var_mkdir (path * "/mmx");
00078   var_mkdir (path * "/tmp");
00079 }
00080 
00081 struct system_instance {
00082   system_instance () {
00083     init_system (); }
00084 };
00085 
00086 system_instance system_inst;
00087 
00088 string
00089 user_dir () {
00090   string dir= get_env ("MMX_USER_DIR");
00091   if (dir == "") {
00092     string home = get_env ("HOME");
00093     ASSERT (home != "", "Can not determine user's directory.\n Please set $MMX_USER_DIR or $HOME.\n");
00094     dir= home * "/.mathemagix";
00095   }
00096   return dir;
00097 }
00098   
00099 string
00100 prefix_dir () {
00101   string dir= get_env ("MMX_PREFIX_DIR");
00102   if (dir == "") dir= string (BASIX_PREFIX);
00103   if (!file_exists (dir)) dir= eval_system ("basix-config --prefix");
00104   return dir;
00105 }
00106 
00107 string
00108 sysconf_dir () {
00109   string dir= get_env ("MMX_SYSCONF_DIR");
00110   if (dir == "") dir= prefix_dir () * "/etc";
00111   return dir;
00112 }
00113 
00114 string
00115 load_path () {
00116   string path= get_env ("MMX_LOAD_PATH");
00117   if (path != "" && path[0] != ':') path= ":" * path;
00118   path= ".:" * user_dir () * "/mmx:" * prefix_dir () * "/share:"
00119              * prefix_dir () * "/share/mmx" * path;
00120   return path;
00121 }
00122 
00123 string
00124 eval_system (const string& s) {
00125   init_system ();
00126   string temp= user_dir () * "/tmp/eval_system";
00127   system (s * " > " * temp);
00128   string r;
00129   bool flag= var_load (temp, r);
00130   system ("rm -rf " * temp);
00131   if (flag) return "";
00132   while ((N(r)>0) && (r[N(r)-1] == '\n')) r= r (0, N(r)-1);
00133   return r;
00134 }
00135 
00136 /******************************************************************************
00137 * Routines for file names
00138 ******************************************************************************/
00139 
00140 string
00141 decode_name (const string& name) {
00142   if (name == "~") return get_env ("HOME");
00143   if (starts (name, "~/")) return get_env ("HOME") * "/" * name (2, N(name));
00144   if (starts (name, "$")) {
00145     nat i;
00146     for (i=0; i<N(name); i++)
00147       if (name[i] == '/') break;
00148     string r= get_env (name (1, i));
00149     if (i == N(name)) return r;
00150     return r * "/" * name (i+1, N(name));
00151   }
00152   return name;
00153 }
00154 
00155 bool
00156 file_exists (const string& name) {
00157   string name_s= decode_name (name);
00158   char* temp= as_charp (name_s);
00159   FILE* f= fopen (temp, "r");
00160   free_charp (temp);
00161   if (f == NULL) return false;
00162   fclose (f);
00163   return true;
00164 }
00165 
00166 string
00167 canonical_name (const string& name) {
00168   for (int i= N(name)-1; i>=0; i--)
00169     if (name[i] == '/') {
00170       nat j=i;
00171       while (j>0 && name[j-1] == '/') j--;
00172       string pre = canonical_name (name (0, j));
00173       string post= name (i+1, N(name));
00174       if (pre == "") return "/" * post;
00175       else if (pre == ".") return post;
00176       else if (post == ".") return pre;
00177       else if (ends (pre, "..") && post == "..") return pre * "/" * post;
00178       else if (post == "..") return get_directory (pre);
00179       else return pre * "/" * post;
00180     }
00181   return name;
00182 }
00183 
00184 string
00185 path_name (const string& file_path, const string& file_name) {
00186   //mmout << "path_name " << file_path << ", " << file_name << "\n";
00187   if (N (file_name) > 0 && file_name[0] == '/') {
00188     if (file_exists (file_name)) return canonical_name (file_name);
00189     else return "";
00190   }
00191   else {
00192     nat i, n= N(file_path), start= 0;
00193     for (i=0; i<=n; i++)
00194       if ((i==n) || (file_path[i] == ':')) {
00195         string ss= file_path (start, i);
00196         if ((N(ss) > 0) && (ss[0] == '$')) {
00197           init_system ();
00198           if (ss == "$MMX_LOAD_PATH") ss= load_path ();
00199           else ss= get_env (ss (1, N(ss)));
00200           string r= path_name (ss, file_name);
00201           if (r != "") return r;
00202         }
00203         else {
00204           if (ss == "" || ss == ".") ss= get_env ("PWD");
00205           if (ss[N(ss)-1] != '/') ss= ss * "/";
00206           if (file_exists (ss * file_name))
00207             return canonical_name (ss * file_name);
00208         }
00209         start= i+1;
00210       }
00211     return "";
00212   }
00213 }
00214 
00215 bool
00216 file_is_script (const string& file_name) {
00217   char* _file_name= as_charp (file_name);
00218   FILE* f= fopen (_file_name, "r");
00219   free_charp (_file_name);
00220   if (f == NULL) return false;
00221   char c;
00222   string s= string ("");
00223   while ((c = fgetc (f)) != EOF && c != '\n') s << c;
00224   fclose (f);
00225   return starts (s, "#!/usr/bin/env mmx-light");
00226 
00227   /*
00228   port f= input_file_port (file_name);
00229   if (error_flag (f)) return false;
00230   char c;
00231   string s= "";
00232   while (can_read (f) > 0) {
00233     f >> c;
00234     if (c == '\n') break;
00235     s << c;
00236   }
00237   return starts (s, "#!/usr/bin/env mmx-light");
00238   */
00239 }
00240 
00241 string
00242 get_directory (const string& name) {
00243   for (int i= N(name)-1; i>=0; i--)
00244     if (name[i]=='/')
00245       return name (0, i);
00246   return ".";
00247 }
00248 
00249 string
00250 strip_directory (const string& name) {
00251   for (int i= N(name)-1; i>=0; i--)
00252     if (name[i]=='/')
00253       return name (i+1, N(name));
00254   return name;
00255 }
00256 
00257 string
00258 strip_extension (const string& name) {
00259   for (int i= N(name)-1; i>=0; i--)
00260     if (name[i]=='.')
00261       return name (0, i);
00262     else if (name[i]=='/')
00263       return name;
00264   return name;
00265 }
00266 
00267 string
00268 get_extension (const string& name) {
00269   for (int i= N(name)-1; i>=0; i--)
00270     if (name[i]=='.')
00271       return name (i+1, N(name));
00272     else if (name[i]=='/')
00273       return "";
00274   return "";
00275 }
00276 
00277 string
00278 relative_name (const string& base, const string& name) {
00279   string file_name= name;
00280   if (base != "" && file_name != "" && file_name[0] != '/') {
00281     int i;
00282     for (i= N(base)-1; i>=0; i--)
00283       if (base[i] == '/') break;
00284     file_name= base (0, i+1) * file_name;
00285   }
00286   return canonical_name (file_name);
00287 }
00288 
00289 string
00290 resolve_name (const string& base, const string& name) {
00291   //mmout << "Resolve " << base << ", " << name << "\n";
00292   string r= relative_name (base, name);
00293   if (file_exists (r)) return r;
00294   if (get_directory (name) != ".") {
00295     r= relative_name (canonical_name (base * "/.."), name);
00296     if (file_exists (r)) return r;
00297   }
00298   r= path_name ("$MMX_LOAD_PATH", name);
00299   if (r != "") return r;
00300   nat i;
00301   for (i=0; i<N(name); i++)
00302     if (name[i] == '/') break;
00303   if (i == N(name)) return "";
00304   string d= name (0, i);
00305   string f= name (i+1, N(name));
00306   r= path_name ("$MMX_LOAD_PATH", d * "/mmx/" * f);
00307   if (r != "") return r;
00308   r= path_name ("$MMX_LOAD_PATH", d * "/glue/" * f);
00309   if (r != "") return r;
00310   return "";
00311 }
00312 
00313 #ifdef BASIX_HAVE_SYS_STAT_H
00314 
00315 static bool
00316 get_attributes (const string& name, struct stat* buf) {
00317   string name_s= decode_name (name);
00318   bool flag;
00319   char* temp= as_charp (name_s);
00320   flag= stat (temp, buf);
00321   free_charp (temp);
00322   return flag;
00323 }
00324 
00325 bool
00326 file_test (const string& name, const string& filter) {
00327   if (filter == "") return true;
00328   struct stat buf;
00329   if (get_attributes (name, &buf)) return false;
00330   int i, n= N (filter);
00331   for (i=0; i<n; i++)
00332     switch (filter [i]) {
00333       // FIXME: should check user id and group id for r, w and x
00334     case 'f':
00335       if (!S_ISREG (buf.st_mode)) return false;
00336       break;
00337     case 'd':
00338       if (!S_ISDIR (buf.st_mode)) return false;
00339       break;
00340     case 'r':
00341 #ifndef __MINGW32__
00342       if ((buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) return false;
00343 #else
00344       if ((buf.st_mode & 292) == 0) return false;
00345 #endif
00346       break;
00347     case 'w':
00348 #ifndef __MINGW32__
00349       if ((buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) return false;
00350 #else
00351       if ((buf.st_mode & 146) == 0) return false;
00352 #endif
00353       break;
00354     case 'x':
00355 #ifdef OS_WIN32
00356       if (suffix(name) == "bat") break;
00357 #endif
00358 #ifndef __MINGW32__
00359       if ((buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) return false;
00360 #else
00361       if ((buf.st_mode & 73) == 0) return false;
00362 #endif
00363       break;
00364     }
00365   return true;
00366 }
00367 
00368 double
00369 file_last_modified (const string& name) {
00370   struct stat u_stat;
00371   ASSERT (!get_attributes (name, &u_stat), "could not stat file");
00372   return (double) u_stat.st_mtime;
00373 }
00374 
00375 #else // !BASIX_HAVE_SYS_STAT_H
00376 
00377 static bool
00378 get_attributes (const string& name, struct stat* buf) {
00379   (void) name; (void) buf;
00380   return 1;
00381 }
00382 
00383 bool
00384 file_test (const string& name, const string& filter) {
00385   (void) name; (void) buf;
00386 }
00387 
00388 double
00389 file_last_modified (const string& name) {
00390   ERROR ("could not get file's last modification time");
00391 }
00392 
00393 #endif // BASIX_HAVE_SYS_STAT_H
00394 
00395 string
00396 follow_link (const string& name, const bool& recurse) {
00397   char buf[1024];
00398   string name_s= decode_name (name);
00399   char* temp= as_charp (name_s);
00400   int n= readlink (temp, buf, 1024);
00401   free_charp (temp);
00402   if (n >= 0 && n < 1024) {
00403     string r (buf, n);
00404     if (recurse) return follow_link (r, true);
00405     else return r;
00406   }
00407   else {
00408     if (recurse) return name;
00409     else return "";
00410   }
00411 }
00412 
00413 bool file_is_file (const string& name) { return file_test (name, "f"); }
00414 bool file_is_directory (const string& name) { return file_test (name, "d"); }
00415 
00416 /******************************************************************************
00417 * Loading and saving
00418 ******************************************************************************/
00419 
00420 bool
00421 var_load (const string& file_name, string& s) {
00422   port f= input_file_port (file_name);
00423   if (error_flag (f)) return true;
00424   char c;
00425   while (can_read (f) > 0) {
00426     f >> c;
00427     s << c;
00428   }
00429   return false;
00430 }
00431 
00432 bool
00433 load (const string& orig_file_name, string& s) {
00434   return var_load (decode_name (orig_file_name), s);
00435 }
00436 
00437 bool
00438 var_load (const string& file_path, const string& file_name, string& s) {
00439   if ((N(file_name) > 0) && (file_name[0] == '/'))
00440     return var_load (file_name, s);
00441   nat i, n= N(file_path), start= 0;
00442   for (i=0; i<=n; i++)
00443     if ((i==n) || (file_path[i] == ':')) {
00444       string ss= file_path (start, i);
00445       if ((N(ss) > 0) && (ss[0] == '$')) {
00446         init_system ();
00447         if (ss == "$MMX_LOAD_PATH") ss= load_path ();
00448         else ss= get_env (ss (1, N(ss)));
00449         if (!var_load (ss, file_name, s)) return false;
00450       }
00451       else {
00452         if (ss == "") ss= ".";
00453         if (ss[N(ss)-1] != '/') ss= ss * "/";
00454         if (!var_load (ss * file_name, s)) return false;
00455       }
00456       start= i+1;
00457     }
00458   return true;
00459 }
00460 
00461 bool
00462 load (const string& file_path, const string& file_name, string& s) {
00463   return var_load (file_path, decode_name (file_name), s);
00464 }
00465 
00466 bool
00467 save (const string& orig_file_name, const string& s) {
00468   string file_name= decode_name (orig_file_name);
00469   port f= output_file_port (file_name);
00470   if (error_flag (f)) return true;
00471   f << s;
00472   return false;
00473 }
00474 
00475 bool
00476 load_directory (const string& orig_name, vector<string>& dir) {
00477   string name= decode_name (orig_name);
00478   DIR* dp;
00479   char* temp= as_charp (name);
00480   dp= opendir (temp);
00481   free_charp (temp);
00482   dir= vector<string> ();
00483   if (dp == NULL) return true;
00484 
00485   struct dirent* ep;
00486   while (true) {
00487     ep= readdir (dp);
00488     if (ep == NULL) break;
00489     dir << string (ep->d_name);
00490   }
00491   (void) closedir (dp);
00492   sort (dir);
00493   return false;
00494 }
00495 
00496 /******************************************************************************
00497 * Commands on files
00498 ******************************************************************************/
00499 
00500 bool
00501 var_mkdir (const string& name) {
00502 #if defined (BASIX_HAVE_SYS_TYPES_H) && defined (BASIX_HAVE_SYS_STAT_H)
00503   if (file_exists (name)) return false;
00504   char* _name= as_charp (name);
00505 #if defined(__MINGW__) || defined(__MINGW32__)
00506   int r= ::mkdir (_name);
00507   ::chmod (_name, 744);
00508 #else
00509   int r= ::mkdir (_name, S_IRWXU + S_IRGRP + S_IROTH);
00510 #endif
00511   free_charp (_name);
00512   return r != 0;
00513 #else  
00514   return system ("mkdir -m 744 -p " * orig_name) != 0;
00515 #endif
00516 }
00517 
00518 bool
00519 mkdir (const string& name) {
00520   return var_mkdir (decode_name (name));
00521 }
00522 
00523 } // namespace mmx
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines