view liboctave/system/oct-env.cc @ 20651:e54ecb33727e

lo-array-gripes.cc: Remove FIXME's related to buffer size. * lo-array-gripes.cc: Remove FIXME's related to buffer size. Shorten sprintf buffers from 100 to 64 characters (still well more than 19 required). Use 'const' decorator on constant value for clarity. Remove extra space between variable and array bracket.
author Rik <rik@octave.org>
date Mon, 12 Oct 2015 21:13:47 -0700
parents 4197fc428c7d
children
line wrap: on
line source

/*

Copyright (C) 1996-2015 John W. Eaton

This file is part of Octave.

Octave is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

Octave is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with Octave; see the file COPYING.  If not, see
<http://www.gnu.org/licenses/>.

*/

/*

The functions listed below were adapted from a similar functions
from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
Free Software Foundation, Inc.

  octave_env::do_absolute_pathname
  octave_env::do_base_pathname
  octave_env::do_chdir
  octave_env::do_getcwd
  octave_env::do_make_absolute
  octave_env::do_polite_directory_format
  octave_env::pathname_backup

*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <cctype>
#include <cstdlib>
#include <cstring>

#include <string>

#include <sys/types.h>
#include <unistd.h>

#include "progname.h"

#include "file-ops.h"
#include "lo-error.h"
#include "lo-sysdep.h"
#include "lo-utils.h"
#include "oct-env.h"
#include "oct-passwd.h"
#include "oct-syscalls.h"
#include "singleton-cleanup.h"

octave_env::octave_env (void)
  : follow_symbolic_links (true), verbatim_pwd (true),
    current_directory (), prog_name (), prog_invocation_name (),
    user_name (), host_name ()
{
  // Get a real value for the current directory.
  do_getcwd ();

  // Etc.
  do_get_user_name ();

  do_get_host_name ();
}

octave_env *octave_env::instance = 0;

bool
octave_env::instance_ok (void)
{
  bool retval = true;

  if (! instance)
    {
      instance = new octave_env ();

      if (instance)
        singleton_cleanup_list::add (cleanup_instance);
    }

  if (! instance)
    {
      (*current_liboctave_error_handler)
        ("unable to create current working directory object!");

      retval = false;
    }

  return retval;
}

std::string
octave_env::polite_directory_format (const std::string& name)
{
  return (instance_ok ())
         ? instance->do_polite_directory_format (name) : std::string ();
}

bool
octave_env::absolute_pathname (const std::string& s)
{
  return (instance_ok ())
         ? instance->do_absolute_pathname (s) : false;
}

bool
octave_env::rooted_relative_pathname (const std::string& s)
{
  return (instance_ok ())
         ? instance->do_rooted_relative_pathname (s) : false;
}

std::string
octave_env::base_pathname (const std::string& s)
{
  return (instance_ok ())
         ? instance->do_base_pathname (s) : std::string ();
}

std::string
octave_env::make_absolute (const std::string& s, const std::string& dot_path)
{
  return (instance_ok ())
         ? instance->do_make_absolute (s, dot_path) : std::string ();
}

std::string
octave_env::get_current_directory ()
{
  return (instance_ok ())
         ? instance->do_getcwd () : std::string ();
}

std::string
octave_env::get_home_directory ()
{
  return (instance_ok ())
         ? instance->do_get_home_directory () : std::string ();
}

std::string
octave_env::get_temp_directory ()
{
  return (instance_ok ())
         ? instance->do_get_temp_directory () : std::string ();
}

std::string
octave_env::get_program_name (void)
{
  return (instance_ok ())
         ? instance->prog_name : std::string ();
}

std::string
octave_env::get_program_invocation_name (void)
{
  return (instance_ok ())
         ? instance->prog_invocation_name : std::string ();
}

void
octave_env::set_program_name (const std::string& s)
{
  if (instance_ok ())
    instance->do_set_program_name (s);
}

std::string
octave_env::get_user_name (void)
{
  return (instance_ok ())
         ? instance->do_get_user_name () : std::string ();
}

std::string
octave_env::get_host_name (void)
{
  return (instance_ok ())
         ? instance->do_get_host_name () : std::string ();
}

std::string
octave_env::do_get_temp_directory (void) const
{
  std::string tempd;

#if defined (__MINGW32__) || defined (_MSC_VER)

  tempd = do_getenv ("TEMP");

  if (tempd.empty ())
    tempd = do_getenv ("TMP");

  #if defined (P_tmpdir)
  if (tempd.empty ())
    tempd = P_tmpdir;
  #endif

  // Some versions of MinGW and MSVC either don't define P_tmpdir, or
  // define it to a single backslash.  In such cases just use C:\temp.
  if (tempd.empty () || tempd == "\\")
    tempd = "c:\\temp";

#else    // Unix-like OS

  tempd = do_getenv ("TMP");

  #if defined (P_tmpdir)
  if (tempd.empty ())
    tempd = P_tmpdir;
  #else
  if (tempd.empty ())
    tempd = "/tmp";
  #endif

#endif

  return tempd;
}

// FIXME: this leaves no way to distinguish between a
// variable that is not set and one that is set to the empty string.
// Is this a problem?

std::string
octave_env::getenv (const std::string& name)
{
  return (instance_ok ())
         ? instance->do_getenv (name) : std::string ();
}

void
octave_env::putenv (const std::string& name, const std::string& value)
{
  octave_putenv (name, value);
}

bool
octave_env::have_x11_display (void)
{
  std::string display = getenv ("DISPLAY");

  return ! display.empty ();
}

bool
octave_env::chdir (const std::string& newdir)
{
  return (instance_ok ())
         ? instance->do_chdir (newdir) : false;
}

void
octave_env::do_set_program_name (const std::string& s) const
{
  // For gnulib.
  ::set_program_name (s.c_str ());

  // Let gnulib strip off things like the "lt-" prefix from libtool.
  prog_invocation_name = program_name;

  size_t pos
    = prog_invocation_name.find_last_of (file_ops::dir_sep_chars ());

  // Also keep a shortened version of the program name.
  prog_name = (pos == std::string::npos)
              ? prog_invocation_name : prog_invocation_name.substr (pos+1);
}

// Return a pretty pathname.  If the first part of the pathname is the
// same as $HOME, then replace that with '~'.

std::string
octave_env::do_polite_directory_format (const std::string& name) const
{
  std::string retval;

  std::string home_dir = do_get_home_directory ();

  size_t len = home_dir.length ();

  if (len > 1 && home_dir == name.substr (0, len)
      && (name.length () == len || file_ops::is_dir_sep (name[len])))
    {
      retval = "~";
      retval.append (name.substr (len));
    }
  else
    retval = name;

  return retval;
}

bool
octave_env::do_absolute_pathname (const std::string& s) const
{
  size_t len = s.length ();

  if (len == 0)
    return false;

  if (file_ops::is_dir_sep (s[0]))
    return true;

#if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
  if ((len == 2 && isalpha (s[0]) && s[1] == ':')
      || (len > 2 && isalpha (s[0]) && s[1] == ':'
          && file_ops::is_dir_sep (s[2])))
    return true;
#endif

  return false;
}

bool
octave_env::do_rooted_relative_pathname (const std::string& s) const
{
  size_t len = s.length ();

  if (len == 0)
    return false;

  if (len == 1 && s[0] == '.')
    return true;

  if (len > 1 && s[0] == '.' && file_ops::is_dir_sep (s[1]))
    return true;

  if (len == 2 && s[0] == '.' && s[1] == '.')
    return true;

  if (len > 2 && s[0] == '.' && s[1] == '.' && file_ops::is_dir_sep (s[2]))
    return true;

  return false;
}

// Return the 'basename' of the pathname in STRING (the stuff after
// the last directory separator).  If STRING is not a full pathname,
// simply return it.

std::string
octave_env::do_base_pathname (const std::string& s) const
{
  if (! (do_absolute_pathname (s) || do_rooted_relative_pathname (s)))
    return s;

  size_t pos = s.find_last_of (file_ops::dir_sep_chars ());

  if (pos == std::string::npos)
    return s;
  else
    return s.substr (pos+1);
}

// Turn STRING (a pathname) into an absolute pathname, assuming that
// DOT_PATH contains the symbolic location of the current directory.

std::string
octave_env::do_make_absolute (const std::string& s,
                              const std::string& dot_path) const
{
  if (dot_path.empty () || s.empty () || do_absolute_pathname (s))
    return s;

  std::string current_dir = dot_path;

  if (current_dir.empty ())
    current_dir = do_getcwd ();

  size_t pos = current_dir.length () - 1;

  if (! file_ops::is_dir_sep (current_dir[pos]))
    current_dir.append (file_ops::dir_sep_str ());

  // FIXME: this is probably not correct for all systems.

  size_t i = 0;
  size_t slen = s.length ();

  while (i < slen)
    {
      if (s[i] == '.')
        {
          if (i + 1 == slen)
            return current_dir;

          if (file_ops::is_dir_sep (s[i+1]))
            {
              i += 2;
              continue;
            }

          if (s[i+1] == '.'
              && (i + 2 == slen || file_ops::is_dir_sep (s[i+2])))
            {
              i += 2;

              if (i != slen)
                i++;

              pathname_backup (current_dir, 1);

              continue;
            }
        }

      size_t tmp = s.find_first_of (file_ops::dir_sep_chars (), i);

      if (tmp == std::string::npos)
        {
          current_dir.append (s, i, tmp-i);
          break;
        }
      else
        {
          current_dir.append (s, i, tmp-i+1);
          i = tmp + 1;
        }
    }

  return current_dir;
}

// Return a string which is the current working directory.

std::string
octave_env::do_getcwd () const
{
  if (! follow_symbolic_links)
    current_directory = "";

  if (verbatim_pwd || current_directory.empty ())
    current_directory = ::octave_getcwd ();

  return current_directory;
}

// This value is not cached because it can change while Octave is
// running.

std::string
octave_env::do_get_home_directory (void) const
{
  std::string hd = do_getenv ("HOME");

#if defined (__MINGW32__) || defined (_MSC_VER)
  // Maybe we are started directly from cmd.exe.
  if (hd.empty ())
    {
      std::string drv = do_getenv ("HOMEDRIVE");
      if (drv.empty ())
        hd = do_getenv ("HOMEPATH");
      else
        hd = drv + do_getenv ("HOMEPATH");
    }
#endif

  if (hd.empty ())
    {
      octave_passwd pw = octave_passwd::getpwuid (octave_syscalls::getuid ());

      hd = pw ? pw.dir () : std::string (file_ops::dir_sep_str ());
    }

  return hd;
}

std::string
octave_env::do_get_user_name (void) const
{
  if (user_name.empty ())
    {
      octave_passwd pw = octave_passwd::getpwuid (octave_syscalls::getuid ());

      user_name = pw ? pw.name () : std::string ("unknown");
    }

  return user_name;
}

std::string
octave_env::do_get_host_name (void) const
{
  if (host_name.empty ())
    {
      char hostname[1024];

      int status = gnulib::gethostname (hostname, 1023);

      host_name = (status < 0) ? "unknown" : hostname;
    }

  return host_name;
}

std::string
octave_env::do_getenv (const std::string& name) const
{
  char *value = ::getenv (name.c_str ());

  return value ? value : "";
}

// Do the work of changing to the directory NEWDIR.  Handle symbolic
// link following, etc.

bool
octave_env::do_chdir (const std::string& newdir)
{
  bool retval = false;

  std::string tmp;

  if (follow_symbolic_links)
    {
      if (current_directory.empty ())
        do_getcwd ();

      if (current_directory.empty ())
        tmp = newdir;
      else
        tmp = do_make_absolute (newdir, current_directory);

      // Get rid of trailing directory separator.

      size_t len = tmp.length ();

      if (len > 1)
        {
          if (file_ops::is_dir_sep (tmp[--len]))
            tmp.resize (len);
        }

      if (! ::octave_chdir (tmp))
        {
          current_directory = tmp;
          retval = true;
        }
    }
  else
    retval = (! ::octave_chdir (newdir));

  return retval;
}

// Remove the last N directories from PATH.

void
octave_env::pathname_backup (std::string& path, int n) const
{
  if (path.empty ())
    return;

  size_t i = path.length () - 1;

  while (n--)
    {
      while (file_ops::is_dir_sep (path[i]) && i > 0)
        i--;

      while (! file_ops::is_dir_sep (path[i]) && i > 0)
        i--;

      i++;
    }

  path.resize (i);
}

void
octave_env::error (int err_num) const
{
  (*current_liboctave_error_handler) ("%s", gnulib::strerror (err_num));
}

void
octave_env::error (const std::string& s) const
{
  (*current_liboctave_error_handler) ("%s", s.c_str ());
}