GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
oct-env.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 /*
24 
25 The functions listed below were adapted from a similar functions
26 from GNU Bash, the Bourne Again SHell, copyright (C) 1987, 1989, 1991
27 Free Software Foundation, Inc.
28 
29  octave_env::do_absolute_pathname
30  octave_env::do_base_pathname
31  octave_env::do_chdir
32  octave_env::do_getcwd
33  octave_env::do_make_absolute
34  octave_env::do_polite_directory_format
35  octave_env::pathname_backup
36 
37 */
38 
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42 
43 #include <cctype>
44 #include <cstdlib>
45 #include <cstring>
46 
47 #include <string>
48 
49 #include <sys/types.h>
50 #include <unistd.h>
51 
52 #include "progname.h"
53 
54 #include "file-ops.h"
55 #include "lo-error.h"
56 #include "lo-sysdep.h"
57 #include "lo-utils.h"
58 #include "oct-env.h"
59 #include "oct-passwd.h"
60 #include "oct-syscalls.h"
61 #include "singleton-cleanup.h"
62 
64  : follow_symbolic_links (true), verbatim_pwd (true),
65  current_directory (), prog_name (), prog_invocation_name (),
66  user_name (), host_name ()
67 {
68  // Get a real value for the current directory.
69  do_getcwd ();
70 
71  // Etc.
73 
75 }
76 
78 
79 bool
81 {
82  bool retval = true;
83 
84  if (! instance)
85  {
86  instance = new octave_env ();
87 
88  if (instance)
90  }
91 
92  if (! instance)
93  {
94  (*current_liboctave_error_handler)
95  ("unable to create current working directory object!");
96 
97  retval = false;
98  }
99 
100  return retval;
101 }
102 
103 std::string
104 octave_env::polite_directory_format (const std::string& name)
105 {
106  return (instance_ok ())
107  ? instance->do_polite_directory_format (name) : std::string ();
108 }
109 
110 bool
111 octave_env::absolute_pathname (const std::string& s)
112 {
113  return (instance_ok ())
114  ? instance->do_absolute_pathname (s) : false;
115 }
116 
117 bool
119 {
120  return (instance_ok ())
121  ? instance->do_rooted_relative_pathname (s) : false;
122 }
123 
124 std::string
125 octave_env::base_pathname (const std::string& s)
126 {
127  return (instance_ok ())
128  ? instance->do_base_pathname (s) : std::string ();
129 }
130 
131 std::string
132 octave_env::make_absolute (const std::string& s, const std::string& dot_path)
133 {
134  return (instance_ok ())
135  ? instance->do_make_absolute (s, dot_path) : std::string ();
136 }
137 
138 std::string
140 {
141  return (instance_ok ())
142  ? instance->do_getcwd () : std::string ();
143 }
144 
145 std::string
147 {
148  return (instance_ok ())
149  ? instance->do_get_home_directory () : std::string ();
150 }
151 
152 std::string
154 {
155  return (instance_ok ())
156  ? instance->prog_name : std::string ();
157 }
158 
159 std::string
161 {
162  return (instance_ok ())
163  ? instance->prog_invocation_name : std::string ();
164 }
165 
166 void
167 octave_env::set_program_name (const std::string& s)
168 {
169  if (instance_ok ())
171 }
172 
173 std::string
175 {
176  return (instance_ok ())
177  ? instance->do_get_user_name () : std::string ();
178 }
179 
180 std::string
182 {
183  return (instance_ok ())
184  ? instance->do_get_host_name () : std::string ();
185 }
186 
187 // FIXME: this leaves no way to distinguish between a
188 // variable that is not set and one that is set to the empty string.
189 // Is this a problem?
190 
191 std::string
192 octave_env::getenv (const std::string& name)
193 {
194  return (instance_ok ())
195  ? instance->do_getenv (name) : std::string ();
196 }
197 
198 void
199 octave_env::putenv (const std::string& name, const std::string& value)
200 {
201  octave_putenv (name, value);
202 }
203 
204 bool
206 {
207  std::string display = getenv ("DISPLAY");
208 
209  return ! display.empty ();
210 }
211 
212 bool
213 octave_env::chdir (const std::string& newdir)
214 {
215  return (instance_ok ())
216  ? instance->do_chdir (newdir) : false;
217 }
218 
219 void
220 octave_env::do_set_program_name (const std::string& s) const
221 {
222  // For gnulib.
223  ::set_program_name (s.c_str ());
224 
225  // Let gnulib strip off things like the "lt-" prefix from libtool.
226  prog_invocation_name = program_name;
227 
228  size_t pos
229  = prog_invocation_name.find_last_of (file_ops::dir_sep_chars ());
230 
231  // Also keep a shortened version of the program name.
232  prog_name = (pos == std::string::npos)
233  ? prog_invocation_name : prog_invocation_name.substr (pos+1);
234 }
235 
236 // Return a pretty pathname. If the first part of the pathname is the
237 // same as $HOME, then replace that with '~'.
238 
239 std::string
240 octave_env::do_polite_directory_format (const std::string& name) const
241 {
242  std::string retval;
243 
244  std::string home_dir = do_get_home_directory ();
245 
246  size_t len = home_dir.length ();
247 
248  if (len > 1 && home_dir == name.substr (0, len)
249  && (name.length () == len || file_ops::is_dir_sep (name[len])))
250  {
251  retval = "~";
252  retval.append (name.substr (len));
253  }
254  else
255  retval = name;
256 
257  return retval;
258 }
259 
260 bool
261 octave_env::do_absolute_pathname (const std::string& s) const
262 {
263  size_t len = s.length ();
264 
265  if (len == 0)
266  return false;
267 
268  if (file_ops::is_dir_sep (s[0]))
269  return true;
270 
271 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
272  if ((len == 2 && isalpha (s[0]) && s[1] == ':')
273  || (len > 2 && isalpha (s[0]) && s[1] == ':'
274  && file_ops::is_dir_sep (s[2])))
275  return true;
276 #endif
277 
278  return false;
279 }
280 
281 bool
282 octave_env::do_rooted_relative_pathname (const std::string& s) const
283 {
284  size_t len = s.length ();
285 
286  if (len == 0)
287  return false;
288 
289  if (len == 1 && s[0] == '.')
290  return true;
291 
292  if (len > 1 && s[0] == '.' && file_ops::is_dir_sep (s[1]))
293  return true;
294 
295  if (len == 2 && s[0] == '.' && s[1] == '.')
296  return true;
297 
298  if (len > 2 && s[0] == '.' && s[1] == '.' && file_ops::is_dir_sep (s[2]))
299  return true;
300 
301  return false;
302 }
303 
304 // Return the 'basename' of the pathname in STRING (the stuff after
305 // the last directory separator). If STRING is not a full pathname,
306 // simply return it.
307 
308 std::string
309 octave_env::do_base_pathname (const std::string& s) const
310 {
312  return s;
313 
314  size_t pos = s.find_last_of (file_ops::dir_sep_chars ());
315 
316  if (pos == std::string::npos)
317  return s;
318  else
319  return s.substr (pos+1);
320 }
321 
322 // Turn STRING (a pathname) into an absolute pathname, assuming that
323 // DOT_PATH contains the symbolic location of the current directory.
324 
325 std::string
326 octave_env::do_make_absolute (const std::string& s,
327  const std::string& dot_path) const
328 {
329  if (dot_path.empty () || s.empty () || do_absolute_pathname (s))
330  return s;
331 
332  std::string current_dir = dot_path;
333 
334  if (current_dir.empty ())
335  current_dir = do_getcwd ();
336 
337  size_t pos = current_dir.length () - 1;
338 
339  if (! file_ops::is_dir_sep (current_dir[pos]))
340  current_dir.append (file_ops::dir_sep_str ());
341 
342  // FIXME: this is probably not correct for all systems.
343 
344  size_t i = 0;
345  size_t slen = s.length ();
346 
347  while (i < slen)
348  {
349  if (s[i] == '.')
350  {
351  if (i + 1 == slen)
352  return current_dir;
353 
354  if (file_ops::is_dir_sep (s[i+1]))
355  {
356  i += 2;
357  continue;
358  }
359 
360  if (s[i+1] == '.'
361  && (i + 2 == slen || file_ops::is_dir_sep (s[i+2])))
362  {
363  i += 2;
364 
365  if (i != slen)
366  i++;
367 
368  pathname_backup (current_dir, 1);
369 
370  continue;
371  }
372  }
373 
374  size_t tmp = s.find_first_of (file_ops::dir_sep_chars (), i);
375 
376  if (tmp == std::string::npos)
377  {
378  current_dir.append (s, i, tmp-i);
379  break;
380  }
381  else
382  {
383  current_dir.append (s, i, tmp-i+1);
384  i = tmp + 1;
385  }
386  }
387 
388  return current_dir;
389 }
390 
391 // Return a string which is the current working directory.
392 
393 std::string
395 {
396  if (! follow_symbolic_links)
397  current_directory = "";
398 
399  if (verbatim_pwd || current_directory.empty ())
401 
402  return current_directory;
403 }
404 
405 // This value is not cached because it can change while Octave is
406 // running.
407 
408 std::string
410 {
411  std::string hd = do_getenv ("HOME");
412 
413 #if defined (__MINGW32__) || defined (_MSC_VER)
414  // Maybe we are started directly from cmd.exe.
415  if (hd.empty ())
416  {
417  std::string drv = do_getenv ("HOMEDRIVE");
418  if (drv.empty ())
419  hd = do_getenv ("HOMEPATH");
420  else
421  hd = drv + do_getenv ("HOMEPATH");
422  }
423 #endif
424 
425  if (hd.empty ())
426  {
428 
429  hd = pw ? pw.dir () : std::string (file_ops::dir_sep_str ());
430  }
431 
432  return hd;
433 }
434 
435 std::string
437 {
438  if (user_name.empty ())
439  {
441 
442  user_name = pw ? pw.name () : std::string ("unknown");
443  }
444 
445  return user_name;
446 }
447 
448 std::string
450 {
451  if (host_name.empty ())
452  {
453  char hostname[1024];
454 
455  int status = gnulib::gethostname (hostname, 1023);
456 
457  host_name = (status < 0) ? "unknown" : hostname;
458  }
459 
460  return host_name;
461 }
462 
463 std::string
464 octave_env::do_getenv (const std::string& name) const
465 {
466  char *value = ::getenv (name.c_str ());
467 
468  return value ? value : "";
469 }
470 
471 // Do the work of changing to the directory NEWDIR. Handle symbolic
472 // link following, etc.
473 
474 bool
475 octave_env::do_chdir (const std::string& newdir)
476 {
477  bool retval = false;
478 
479  std::string tmp;
480 
482  {
483  if (current_directory.empty ())
484  do_getcwd ();
485 
486  if (current_directory.empty ())
487  tmp = newdir;
488  else
489  tmp = do_make_absolute (newdir, current_directory);
490 
491  // Get rid of trailing directory separator.
492 
493  size_t len = tmp.length ();
494 
495  if (len > 1)
496  {
497  if (file_ops::is_dir_sep (tmp[--len]))
498  tmp.resize (len);
499  }
500 
501  if (! ::octave_chdir (tmp))
502  {
503  current_directory = tmp;
504  retval = true;
505  }
506  }
507  else
508  retval = (! ::octave_chdir (newdir));
509 
510  return retval;
511 }
512 
513 // Remove the last N directories from PATH.
514 
515 void
516 octave_env::pathname_backup (std::string& path, int n) const
517 {
518  if (path.empty ())
519  return;
520 
521  size_t i = path.length () - 1;
522 
523  while (n--)
524  {
525  while (file_ops::is_dir_sep (path[i]) && i > 0)
526  i--;
527 
528  while (! file_ops::is_dir_sep (path[i]) && i > 0)
529  i--;
530 
531  i++;
532  }
533 
534  path.resize (i);
535 }
536 
537 void
538 octave_env::error (int err_num) const
539 {
540  (*current_liboctave_error_handler) ("%s", gnulib::strerror (err_num));
541 }
542 
543 void
544 octave_env::error (const std::string& s) const
545 {
546  (*current_liboctave_error_handler) ("%s", s.c_str ());
547 }