basix_doc 0.1
|
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