oct-env.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 /*
00024 
00025 The functions listed below were adapted from a similar functions
00026 from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
00027 Free Software Foundation, Inc.
00028 
00029   octave_env::do_absolute_pathname
00030   octave_env::do_base_pathname
00031   octave_env::do_chdir
00032   octave_env::do_getcwd
00033   octave_env::do_make_absolute
00034   octave_env::do_polite_directory_format
00035   octave_env::pathname_backup
00036 
00037 */
00038 
00039 #ifdef HAVE_CONFIG_H
00040 #include <config.h>
00041 #endif
00042 
00043 #include <cctype>
00044 #include <cstdlib>
00045 #include <cstring>
00046 
00047 #include <string>
00048 
00049 #include <sys/types.h>
00050 #include <unistd.h>
00051 
00052 #include "progname.h"
00053 
00054 #include "file-ops.h"
00055 #include "lo-error.h"
00056 #include "lo-sysdep.h"
00057 #include "lo-utils.h"
00058 #include "oct-env.h"
00059 #include "oct-passwd.h"
00060 #include "oct-syscalls.h"
00061 #include "singleton-cleanup.h"
00062 
00063 octave_env::octave_env (void)
00064   : follow_symbolic_links (true), verbatim_pwd (true),
00065     current_directory (), prog_name (), prog_invocation_name (),
00066     user_name (), host_name ()
00067 {
00068   // Get a real value for the current directory.
00069   do_getcwd ();
00070 
00071   // Etc.
00072   do_get_user_name ();
00073 
00074   do_get_host_name ();
00075 }
00076 
00077 octave_env *octave_env::instance = 0;
00078 
00079 bool
00080 octave_env::instance_ok (void)
00081 {
00082   bool retval = true;
00083 
00084   if (! instance)
00085     {
00086       instance = new octave_env ();
00087 
00088       if (instance)
00089         singleton_cleanup_list::add (cleanup_instance);
00090     }
00091 
00092   if (! instance)
00093     {
00094       (*current_liboctave_error_handler)
00095         ("unable to create current working directory object!");
00096 
00097       retval = false;
00098     }
00099 
00100   return retval;
00101 }
00102 
00103 std::string
00104 octave_env::polite_directory_format (const std::string& name)
00105 {
00106   return (instance_ok ())
00107     ? instance->do_polite_directory_format (name) : std::string ();
00108 }
00109 
00110 bool
00111 octave_env::absolute_pathname (const std::string& s)
00112 {
00113   return (instance_ok ())
00114     ? instance->do_absolute_pathname (s) : false;
00115 }
00116 
00117 bool
00118 octave_env::rooted_relative_pathname (const std::string& s)
00119 {
00120   return (instance_ok ())
00121     ? instance->do_rooted_relative_pathname (s) : false;
00122 }
00123 
00124 std::string
00125 octave_env::base_pathname (const std::string& s)
00126 {
00127   return (instance_ok ())
00128     ? instance->do_base_pathname (s) : std::string ();
00129 }
00130 
00131 std::string
00132 octave_env::make_absolute (const std::string& s, const std::string& dot_path)
00133 {
00134   return (instance_ok ())
00135     ? instance->do_make_absolute (s, dot_path) : std::string ();
00136 }
00137 
00138 std::string
00139 octave_env::get_current_directory ()
00140 {
00141   return (instance_ok ())
00142     ? instance->do_getcwd () : std::string ();
00143 }
00144 
00145 std::string
00146 octave_env::get_home_directory ()
00147 {
00148   return (instance_ok ())
00149     ? instance->do_get_home_directory () : std::string ();
00150 }
00151 
00152 std::string
00153 octave_env::get_program_name (void)
00154 {
00155   return (instance_ok ())
00156     ? instance->prog_name : std::string ();
00157 }
00158 
00159 std::string
00160 octave_env::get_program_invocation_name (void)
00161 {
00162   return (instance_ok ())
00163     ? instance->prog_invocation_name : std::string ();
00164 }
00165 
00166 void
00167 octave_env::set_program_name (const std::string& s)
00168 {
00169   if (instance_ok ())
00170     instance->do_set_program_name (s);
00171 }
00172 
00173 std::string
00174 octave_env::get_user_name (void)
00175 {
00176   return (instance_ok ())
00177     ? instance->do_get_user_name () : std::string ();
00178 }
00179 
00180 std::string
00181 octave_env::get_host_name (void)
00182 {
00183   return (instance_ok ())
00184     ? instance->do_get_host_name () : std::string ();
00185 }
00186 
00187 // FIXME -- this leaves no way to distinguish between a
00188 // variable that is not set and one that is set to the empty string.
00189 // Is this a problem?
00190 
00191 std::string
00192 octave_env::getenv (const std::string& name)
00193 {
00194   return (instance_ok ())
00195     ? instance->do_getenv (name) : std::string ();
00196 }
00197 
00198 void
00199 octave_env::putenv (const std::string& name, const std::string& value)
00200 {
00201   octave_putenv (name, value);
00202 }
00203 
00204 bool
00205 octave_env::have_x11_display (void)
00206 {
00207   std::string display = getenv ("DISPLAY");
00208 
00209   return ! display.empty ();
00210 }
00211 
00212 bool
00213 octave_env::chdir (const std::string& newdir)
00214 {
00215   return (instance_ok ())
00216     ? instance->do_chdir (newdir) : false;
00217 }
00218 
00219 void
00220 octave_env::do_set_program_name (const std::string& s) const
00221 {
00222   // For gnulib.
00223   ::set_program_name (s.c_str ());
00224 
00225   // Let gnulib strip off things like the "lt-" prefix from libtool.
00226   prog_invocation_name = program_name;
00227 
00228   size_t pos
00229     = prog_invocation_name.find_last_of (file_ops::dir_sep_chars ());
00230 
00231   // Also keep a shortened version of the program name.
00232   prog_name = (pos == std::string::npos)
00233     ? prog_invocation_name : prog_invocation_name.substr (pos+1);
00234 }
00235 
00236 // Return a pretty pathname.  If the first part of the pathname is the
00237 // same as $HOME, then replace that with '~'.
00238 
00239 std::string
00240 octave_env::do_polite_directory_format (const std::string& name) const
00241 {
00242   std::string retval;
00243 
00244   std::string home_dir = do_get_home_directory ();
00245 
00246   size_t len = home_dir.length ();
00247 
00248   if (len > 1 && home_dir == name.substr (0, len)
00249       && (name.length () == len || file_ops::is_dir_sep (name[len])))
00250     {
00251       retval = "~";
00252       retval.append (name.substr (len));
00253     }
00254   else
00255     retval = name;
00256 
00257   return retval;
00258 }
00259 
00260 bool
00261 octave_env::do_absolute_pathname (const std::string& s) const
00262 {
00263   size_t len = s.length ();
00264 
00265   if (len == 0)
00266     return false;
00267 
00268   if (file_ops::is_dir_sep (s[0]))
00269     return true;
00270 
00271 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
00272   if ((len == 2 && isalpha (s[0]) && s[1] == ':')
00273       || (len > 2 && isalpha (s[0]) && s[1] == ':'
00274           && file_ops::is_dir_sep (s[2])))
00275     return true;
00276 #endif
00277 
00278   return false;
00279 }
00280 
00281 bool
00282 octave_env::do_rooted_relative_pathname (const std::string& s) const
00283 {
00284   size_t len = s.length ();
00285 
00286   if (len == 0)
00287     return false;
00288 
00289   if (len == 1 && s[0] == '.')
00290     return true;
00291 
00292   if (len > 1 && s[0] == '.' && file_ops::is_dir_sep (s[1]))
00293     return true;
00294 
00295   if (len == 2 && s[0] == '.' && s[1] == '.')
00296     return true;
00297 
00298   if (len > 2 && s[0] == '.' && s[1] == '.' && file_ops::is_dir_sep (s[2]))
00299     return true;
00300 
00301   return false;
00302 }
00303 
00304 // Return the 'basename' of the pathname in STRING (the stuff after
00305 // the last directory separator).  If STRING is not a full pathname,
00306 // simply return it.
00307 
00308 std::string
00309 octave_env::do_base_pathname (const std::string& s) const
00310 {
00311   if (! (do_absolute_pathname (s) || do_rooted_relative_pathname (s)))
00312     return s;
00313 
00314   size_t pos = s.find_last_of (file_ops::dir_sep_chars ());
00315 
00316   if (pos == std::string::npos)
00317     return s;
00318   else
00319     return s.substr (pos+1);
00320 }
00321 
00322 // Turn STRING (a pathname) into an absolute pathname, assuming that
00323 // DOT_PATH contains the symbolic location of the current directory.
00324 
00325 std::string
00326 octave_env::do_make_absolute (const std::string& s,
00327                               const std::string& dot_path) const
00328 {
00329   if (dot_path.empty () || s.empty () || do_absolute_pathname (s))
00330     return s;
00331 
00332   std::string current_dir = dot_path;
00333 
00334   if (current_dir.empty ())
00335     current_dir = do_getcwd ();
00336 
00337   size_t pos = current_dir.length () - 1;
00338 
00339   if (! file_ops::is_dir_sep (current_dir[pos]))
00340     current_dir.append (file_ops::dir_sep_str ());
00341 
00342   // FIXME -- this is probably not correct for all systems.
00343 
00344   size_t i = 0;
00345   size_t slen = s.length ();
00346 
00347   while (i < slen)
00348     {
00349       if (s[i] == '.')
00350         {
00351           if (i + 1 == slen)
00352             return current_dir;
00353 
00354           if (file_ops::is_dir_sep (s[i+1]))
00355             {
00356               i += 2;
00357               continue;
00358             }
00359 
00360           if (s[i+1] == '.'
00361               && (i + 2 == slen || file_ops::is_dir_sep (s[i+2])))
00362             {
00363               i += 2;
00364 
00365               if (i != slen)
00366                 i++;
00367 
00368               pathname_backup (current_dir, 1);
00369 
00370               continue;
00371             }
00372         }
00373 
00374       size_t tmp = s.find_first_of (file_ops::dir_sep_chars (), i);
00375 
00376       if (tmp == std::string::npos)
00377         {
00378           current_dir.append (s, i, tmp-i);
00379           break;
00380         }
00381       else
00382         {
00383           current_dir.append (s, i, tmp-i+1);
00384           i = tmp + 1;
00385         }
00386     }
00387 
00388   return current_dir;
00389 }
00390 
00391 // Return a string which is the current working directory.
00392 
00393 std::string
00394 octave_env::do_getcwd () const
00395 {
00396   if (! follow_symbolic_links)
00397     current_directory = "";
00398 
00399   if (verbatim_pwd || current_directory.empty ())
00400     current_directory = ::octave_getcwd ();
00401 
00402   return current_directory;
00403 }
00404 
00405 // This value is not cached because it can change while Octave is
00406 // running.
00407 
00408 std::string
00409 octave_env::do_get_home_directory (void) const
00410 {
00411   std::string hd = do_getenv ("HOME");
00412 
00413 #if defined (__MINGW32__) || defined (_MSC_VER)
00414   // Maybe we are started directly from cmd.exe.
00415   if (hd.empty ())
00416     {
00417       std::string drv = do_getenv ("HOMEDRIVE");
00418       if (drv.empty ())
00419         hd = do_getenv ("HOMEPATH");
00420       else
00421         hd = drv + do_getenv ("HOMEPATH");
00422     }
00423 #endif
00424 
00425   if (hd.empty ())
00426     {
00427       octave_passwd pw = octave_passwd::getpwuid (octave_syscalls::getuid ());
00428 
00429       hd = pw ? pw.dir () : std::string (file_ops::dir_sep_str ());
00430     }
00431 
00432   return hd;
00433 }
00434 
00435 std::string
00436 octave_env::do_get_user_name (void) const
00437 {
00438   if (user_name.empty ())
00439     {
00440       octave_passwd pw = octave_passwd::getpwuid (octave_syscalls::getuid ());
00441 
00442       user_name = pw ? pw.name () : std::string ("unknown");
00443     }
00444 
00445   return user_name;
00446 }
00447 
00448 std::string
00449 octave_env::do_get_host_name (void) const
00450 {
00451   if (host_name.empty ())
00452     {
00453       char hostname[1024];
00454 
00455       int status = gnulib::gethostname (hostname, 1023);
00456 
00457       host_name = (status < 0) ? "unknown" : hostname;
00458     }
00459 
00460   return host_name;
00461 }
00462 
00463 std::string
00464 octave_env::do_getenv (const std::string& name) const
00465 {
00466   char *value = ::getenv (name.c_str ());
00467 
00468   return value ? value : "";
00469 }
00470 
00471 // Do the work of changing to the directory NEWDIR.  Handle symbolic
00472 // link following, etc.
00473 
00474 bool
00475 octave_env::do_chdir (const std::string& newdir)
00476 {
00477   bool retval = false;
00478 
00479   std::string tmp;
00480 
00481   if (follow_symbolic_links)
00482     {
00483       if (current_directory.empty ())
00484         do_getcwd ();
00485 
00486       if (current_directory.empty ())
00487         tmp = newdir;
00488       else
00489         tmp = do_make_absolute (newdir, current_directory);
00490 
00491       // Get rid of trailing directory separator.
00492 
00493       size_t len = tmp.length ();
00494 
00495       if (len > 1)
00496         {
00497           if (file_ops::is_dir_sep (tmp[--len]))
00498             tmp.resize (len);
00499         }
00500 
00501       if (! ::octave_chdir (tmp))
00502         {
00503           current_directory = tmp;
00504           retval = true;
00505         }
00506     }
00507   else
00508     retval = (! ::octave_chdir (newdir));
00509 
00510   return retval;
00511 }
00512 
00513 // Remove the last N directories from PATH.
00514 
00515 void
00516 octave_env::pathname_backup (std::string& path, int n) const
00517 {
00518   if (path.empty ())
00519     return;
00520 
00521   size_t i = path.length () - 1;
00522 
00523   while (n--)
00524     {
00525       while (file_ops::is_dir_sep (path[i]) && i > 0)
00526         i--;
00527 
00528       while (! file_ops::is_dir_sep (path[i]) && i > 0)
00529         i--;
00530 
00531       i++;
00532     }
00533 
00534   path.resize (i);
00535 }
00536 
00537 void
00538 octave_env::error (int err_num) const
00539 {
00540   (*current_liboctave_error_handler) ("%s", gnulib::strerror (err_num));
00541 }
00542 
00543 void
00544 octave_env::error (const std::string& s) const
00545 {
00546   (*current_liboctave_error_handler) ("%s", s.c_str ());
00547 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines