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
sysdep.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1993-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 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <cfloat>
28 #include <cstddef>
29 #include <cstdio>
30 #include <cstdlib>
31 #include <cstring>
32 
33 #include <iostream>
34 #include <string>
35 
36 #include <sys/types.h>
37 #include <unistd.h>
38 
39 #if defined (HAVE_TERMIOS_H)
40 #include <termios.h>
41 #elif defined (HAVE_TERMIO_H)
42 #include <termio.h>
43 #elif defined (HAVE_SGTTY_H)
44 #include <sgtty.h>
45 #endif
46 
47 #if defined (HAVE_CONIO_H)
48 #include <conio.h>
49 #endif
50 
51 #if defined (HAVE_SYS_IOCTL_H)
52 #include <sys/ioctl.h>
53 #endif
54 
55 #if defined (HAVE_FLOATINGPOINT_H)
56 #include <floatingpoint.h>
57 #endif
58 
59 #if defined (HAVE_IEEEFP_H)
60 #include <ieeefp.h>
61 #endif
62 
63 #include "cmd-edit.h"
64 #include "file-ops.h"
65 #include "lo-mappers.h"
66 #include "lo-math.h"
67 #include "mach-info.h"
68 #include "oct-env.h"
69 #include "quit.h"
70 
71 #include "Cell.h"
72 #include "builtins.h"
73 #include "defun.h"
74 #include "display.h"
75 #include "error.h"
76 #include "input.h"
77 #include "oct-obj.h"
78 #include "ov.h"
79 #include "pager.h"
80 #include "parse.h"
81 #include "sighandlers.h"
82 #include "sysdep.h"
83 #include "toplev.h"
84 #include "utils.h"
85 #include "file-stat.h"
86 
87 #ifndef STDIN_FILENO
88 #define STDIN_FILENO 1
89 #endif
90 
91 #if defined (__386BSD__) || defined (__FreeBSD__) || defined (__NetBSD__)
92 static void
93 BSD_init (void)
94 {
95 #if defined (HAVE_FLOATINGPOINT_H)
96  // Disable trapping on common exceptions.
97 #ifndef FP_X_DNML
98 #define FP_X_DNML 0
99 #endif
100  fpsetmask (~(FP_X_OFL|FP_X_INV|FP_X_DZ|FP_X_DNML|FP_X_UFL|FP_X_IMP));
101 #endif
102 }
103 #endif
104 
105 #if defined (__WIN32__) && ! defined (_POSIX_VERSION)
106 
107 #define WIN32_LEAN_AND_MEAN
108 #include <tlhelp32.h>
109 
110 static void
111 w32_set_octave_home (void)
112 {
113  std::string bin_dir;
114 
115  HANDLE h = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE
116 #ifdef TH32CS_SNAPMODULE32
117  | TH32CS_SNAPMODULE32
118 #endif
119  , 0);
120 
121  if (h != INVALID_HANDLE_VALUE)
122  {
123  MODULEENTRY32 mod_info;
124 
125  ZeroMemory (&mod_info, sizeof (mod_info));
126  mod_info.dwSize = sizeof (mod_info);
127 
128  if (Module32First (h, &mod_info))
129  {
130  do
131  {
132  std::string mod_name (mod_info.szModule);
133 
134  if (mod_name.find ("octinterp") != std::string::npos)
135  {
136  bin_dir = mod_info.szExePath;
137  if (bin_dir[bin_dir.length () - 1] != '\\')
138  bin_dir.append (1, '\\');
139  break;
140  }
141  }
142  while (Module32Next (h, &mod_info));
143  }
144 
145  CloseHandle (h);
146  }
147 
148  if (! bin_dir.empty ())
149  {
150  size_t pos = bin_dir.rfind ("\\bin\\");
151 
152  if (pos != std::string::npos)
153  octave_env::putenv ("OCTAVE_HOME", bin_dir.substr (0, pos));
154  }
155 }
156 
157 void
159 {
160  // Let the user close the console window or shutdown without the
161  // pesky dialog.
162  //
163  // FIXME: should this be user configurable?
164  SetProcessShutdownParameters (0x280, SHUTDOWN_NORETRY);
165 }
166 
167 void
168 MINGW_signal_cleanup (void)
169 {
171 }
172 #endif
173 
174 #if defined (__MINGW32__)
175 static void
176 MINGW_init (void)
177 {
178  w32_set_octave_home ();
179 }
180 #endif
181 
182 #if defined (_MSC_VER)
183 static void
184 MSVC_init (void)
185 {
186  w32_set_octave_home ();
187 }
188 #endif
189 
190 
191 // Return TRUE if FILE1 and FILE2 refer to the same (physical) file.
192 
193 bool
194 same_file_internal (const std::string& file1, const std::string& file2)
195 {
196 #ifdef OCTAVE_USE_WINDOWS_API
197 
198  bool retval = false;
199 
200  const char *f1 = file1.c_str ();
201  const char *f2 = file2.c_str ();
202 
203  bool f1_is_dir = GetFileAttributes (f1) & FILE_ATTRIBUTE_DIRECTORY;
204  bool f2_is_dir = GetFileAttributes (f2) & FILE_ATTRIBUTE_DIRECTORY;
205 
206  // Windows native code
207  // Reference: http://msdn2.microsoft.com/en-us/library/aa363788.aspx
208 
209  DWORD share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
210 
211  HANDLE hfile1
212  = CreateFile (f1, 0, share, 0, OPEN_EXISTING,
213  f1_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
214 
215  if (hfile1 != INVALID_HANDLE_VALUE)
216  {
217  HANDLE hfile2
218  = CreateFile (f2, 0, share, 0, OPEN_EXISTING,
219  f2_is_dir ? FILE_FLAG_BACKUP_SEMANTICS : 0, 0);
220 
221  if (hfile2 != INVALID_HANDLE_VALUE)
222  {
223  BY_HANDLE_FILE_INFORMATION hfi1;
224  BY_HANDLE_FILE_INFORMATION hfi2;
225 
226  if (GetFileInformationByHandle (hfile1, &hfi1)
227  && GetFileInformationByHandle (hfile2, &hfi2))
228  {
229  retval = (hfi1.dwVolumeSerialNumber == hfi2.dwVolumeSerialNumber
230  && hfi1.nFileIndexHigh == hfi2.nFileIndexHigh
231  && hfi1.nFileIndexLow == hfi2.nFileIndexLow);
232  }
233 
234  CloseHandle (hfile2);
235  }
236 
237  CloseHandle (hfile1);
238  }
239 
240  return retval;
241 
242 #else
243 
244  // POSIX Code
245 
246  file_stat fs_file1 (file1);
247  file_stat fs_file2 (file2);
248 
249  return (fs_file1 && fs_file2
250  && fs_file1.ino () == fs_file2.ino ()
251  && fs_file1.dev () == fs_file2.dev ());
252 
253 #endif
254 }
255 
256 void
258 {
259 #if defined (__386BSD__) || defined (__FreeBSD__) || defined (__NetBSD__)
260  BSD_init ();
261 #elif defined (__MINGW32__)
262  MINGW_init ();
263 #elif defined (_MSC_VER)
264  MSVC_init ();
265 #endif
266 }
267 
268 void
270 {
272 }
273 
274 // Set terminal in raw mode. From less-177.
275 //
276 // Change terminal to "raw mode", or restore to "normal" mode.
277 // "Raw mode" means
278 // 1. An outstanding read will complete on receipt of a single keystroke.
279 // 2. Input is not echoed.
280 // 3. On output, \n is mapped to \r\n.
281 // 4. \t is NOT expanded into spaces.
282 // 5. Signal-causing characters such as ctrl-C (interrupt),
283 // etc. are NOT disabled.
284 // It doesn't matter whether an input \n is mapped to \r, or vice versa.
285 
286 void
287 raw_mode (bool on, bool wait)
288 {
289  static bool curr_on = false;
290 
291  int tty_fd = STDIN_FILENO;
292  if (! gnulib::isatty (tty_fd))
293  {
294  if (interactive)
295  error ("stdin is not a tty!");
296  return;
297  }
298 
299  if (on == curr_on)
300  return;
301 
302 #if defined (HAVE_TERMIOS_H)
303  {
304  struct termios s;
305  static struct termios save_term;
306 
307  if (on)
308  {
309  // Get terminal modes.
310 
311  tcgetattr (tty_fd, &s);
312 
313  // Save modes and set certain variables dependent on modes.
314 
315  save_term = s;
316 // ospeed = s.c_cflag & CBAUD;
317 // erase_char = s.c_cc[VERASE];
318 // kill_char = s.c_cc[VKILL];
319 
320  // Set the modes to the way we want them.
321 
322  s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
323  s.c_oflag |= (OPOST|ONLCR);
324 #if defined (OCRNL)
325  s.c_oflag &= ~(OCRNL);
326 #endif
327 #if defined (ONOCR)
328  s.c_oflag &= ~(ONOCR);
329 #endif
330 #if defined (ONLRET)
331  s.c_oflag &= ~(ONLRET);
332 #endif
333  s.c_cc[VMIN] = wait ? 1 : 0;
334  s.c_cc[VTIME] = 0;
335  }
336  else
337  {
338  // Restore saved modes.
339 
340  s = save_term;
341  }
342 
343  tcsetattr (tty_fd, wait ? TCSAFLUSH : TCSADRAIN, &s);
344  }
345 #elif defined (HAVE_TERMIO_H)
346  {
347  struct termio s;
348  static struct termio save_term;
349 
350  if (on)
351  {
352  // Get terminal modes.
353 
354  ioctl (tty_fd, TCGETA, &s);
355 
356  // Save modes and set certain variables dependent on modes.
357 
358  save_term = s;
359 // ospeed = s.c_cflag & CBAUD;
360 // erase_char = s.c_cc[VERASE];
361 // kill_char = s.c_cc[VKILL];
362 
363  // Set the modes to the way we want them.
364 
365  s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
366  s.c_oflag |= (OPOST|ONLCR);
367 #if defined (OCRNL)
368  s.c_oflag &= ~(OCRNL);
369 #endif
370 #if defined (ONOCR)
371  s.c_oflag &= ~(ONOCR);
372 #endif
373 #if defined (ONLRET)
374  s.c_oflag &= ~(ONLRET);
375 #endif
376  s.c_cc[VMIN] = wait ? 1 : 0;
377  }
378  else
379  {
380  // Restore saved modes.
381 
382  s = save_term;
383  }
384 
385  ioctl (tty_fd, TCSETAW, &s);
386  }
387 #elif defined (HAVE_SGTTY_H)
388  {
389  struct sgttyb s;
390  static struct sgttyb save_term;
391 
392  if (on)
393  {
394  // Get terminal modes.
395 
396  ioctl (tty_fd, TIOCGETP, &s);
397 
398  // Save modes and set certain variables dependent on modes.
399 
400  save_term = s;
401 // ospeed = s.sg_ospeed;
402 // erase_char = s.sg_erase;
403 // kill_char = s.sg_kill;
404 
405  // Set the modes to the way we want them.
406 
407  s.sg_flags |= CBREAK;
408  s.sg_flags &= ~(ECHO);
409  }
410  else
411  {
412  // Restore saved modes.
413 
414  s = save_term;
415  }
416 
417  ioctl (tty_fd, TIOCSETN, &s);
418  }
419 #else
420  warning ("no support for raw mode console I/O on this system");
421 
422  // Make sure the current mode doesn't toggle.
423  on = curr_on;
424 #endif
425 
426  curr_on = on;
427 }
428 
429 FILE *
430 octave_popen (const char *command, const char *mode)
431 {
432 #if defined (__MINGW32__) || defined (_MSC_VER)
433  if (mode && mode[0] && ! mode[1])
434  {
435  char tmode[3];
436  tmode[0] = mode[0];
437  tmode[1] = 'b';
438  tmode[2] = 0;
439 
440  return _popen (command, tmode);
441  }
442  else
443  return _popen (command, mode);
444 #else
445  return popen (command, mode);
446 #endif
447 }
448 
449 int
451 {
452 #if defined (__MINGW32__) || defined (_MSC_VER)
453  return _pclose (f);
454 #else
455  return pclose (f);
456 #endif
457 }
458 
459 // Read one character from the terminal.
460 
461 int
462 octave_kbhit (bool wait)
463 {
464 #ifdef HAVE__KBHIT
465  int c = (! wait && ! _kbhit ()) ? 0 : std::cin.get ();
466 #else
467  raw_mode (true, wait);
468 
469  // Get current handler.
470  octave_interrupt_handler saved_interrupt_handler
472 
473  // Restore it, disabling system call restarts (if possible) so the
474  // read can be interrupted.
475 
476  octave_set_interrupt_handler (saved_interrupt_handler, false);
477 
478  int c = std::cin.get ();
479 
480  if (std::cin.fail () || std::cin.eof ())
481  std::cin.clear ();
482 
483  // Restore it, enabling system call restarts (if possible).
484  octave_set_interrupt_handler (saved_interrupt_handler, true);
485 
486  raw_mode (false, true);
487 #endif
488 
489  return c;
490 }
491 
492 std::string
494 {
495 #if defined (__WIN32__) && ! defined (_POSIX_VERSION)
496 
497  std::string retval;
498 
499 #if defined (P_tmpdir)
500  retval = P_tmpdir;
501 #endif
502 
503  // Apparently some versions of MinGW and MSVC either don't define
504  // P_tmpdir, or they define it to a single backslash, neither of which
505  // is particularly helpful.
506 
507  if (retval.empty () || retval == "\\")
508  {
509  retval = octave_env::getenv ("TEMP");
510 
511  if (retval.empty ())
512  retval = octave_env::getenv ("TMP");
513 
514  if (retval.empty ())
515  retval = "c:\\temp";
516  }
517 
518  return retval;
519 
520 #elif defined (P_tmpdir)
521 
522  return P_tmpdir;
523 
524 #else
525 
526  return "/tmp";
527 
528 #endif
529 }
530 
531 DEFUN (clc, , ,
532  "-*- texinfo -*-\n\
533 @deftypefn {Built-in Function} {} clc ()\n\
534 @deftypefnx {Built-in Function} {} home ()\n\
535 Clear the terminal screen and move the cursor to the upper left corner.\n\
536 @end deftypefn")
537 {
538  bool skip_redisplay = true;
539 
540  command_editor::clear_screen (skip_redisplay);
541 
542  return octave_value_list ();
543 }
544 
545 DEFALIAS (home, clc);
546 
547 DEFUN (getenv, args, ,
548  "-*- texinfo -*-\n\
549 @deftypefn {Built-in Function} {} getenv (@var{var})\n\
550 Return the value of the environment variable @var{var}. For example,\n\
551 \n\
552 @example\n\
553 getenv (\"PATH\")\n\
554 @end example\n\
555 \n\
556 @noindent\n\
557 returns a string containing the value of your path.\n\
558 @end deftypefn")
559 {
560  octave_value retval;
561 
562  int nargin = args.length ();
563 
564  if (nargin == 1)
565  {
566  std::string name = args(0).string_value ();
567 
568  if (! error_state)
569  retval = octave_env::getenv (name);
570  }
571  else
572  print_usage ();
573 
574  return retval;
575 }
576 
577 DEFUN (putenv, args, ,
578  "-*- texinfo -*-\n\
579 @deftypefn {Built-in Function} {} putenv (@var{var}, @var{value})\n\
580 @deftypefnx {Built-in Function} {} setenv (@var{var}, @var{value})\n\
581 Set the value of the environment variable @var{var} to @var{value}.\n\
582 @end deftypefn")
583 {
584  octave_value_list retval;
585 
586  int nargin = args.length ();
587 
588  if (nargin == 2 || nargin == 1)
589  {
590  std::string var = args(0).string_value ();
591 
592  if (! error_state)
593  {
594  std::string val = (nargin == 2
595  ? args(1).string_value () : std::string ());
596 
597  if (! error_state)
598  octave_env::putenv (var, val);
599  else
600  error ("putenv: VALUE must be a string");
601  }
602  else
603  error ("putenv: VAR must be a string");
604  }
605  else
606  print_usage ();
607 
608  return retval;
609 }
610 
611 DEFALIAS (setenv, putenv);
612 
613 /*
614 %!assert (ischar (getenv ("OCTAVE_HOME")))
615 %!test
616 %! setenv ("dummy_variable_that_cannot_matter", "foobar");
617 %! assert (getenv ("dummy_variable_that_cannot_matter"), "foobar");
618 */
619 
620 // FIXME: perhaps kbhit should also be able to print a prompt?
621 
622 DEFUN (kbhit, args, ,
623  "-*- texinfo -*-\n\
624 @deftypefn {Built-in Function} {} kbhit ()\n\
625 @deftypefnx {Built-in Function} {} kbhit (1)\n\
626 Read a single keystroke from the keyboard. If called with an\n\
627 argument, don't wait for a keypress. For example,\n\
628 \n\
629 @example\n\
630 x = kbhit ();\n\
631 @end example\n\
632 \n\
633 @noindent\n\
634 will set @var{x} to the next character typed at the keyboard as soon as\n\
635 it is typed.\n\
636 \n\
637 @example\n\
638 x = kbhit (1);\n\
639 @end example\n\
640 \n\
641 @noindent\n\
642 is identical to the above example, but doesn't wait for a keypress,\n\
643 returning the empty string if no key is available.\n\
644 @seealso{input}\n\
645 @end deftypefn")
646 {
647  octave_value retval;
648 
649  // FIXME: add timeout and default value args?
650 
652  {
653  Fdrawnow ();
654 
655  int c = octave_kbhit (args.length () == 0);
656 
657  if (c == -1)
658  c = 0;
659 
660  char s[2] = { static_cast<char> (c), '\0' };
661 
662  retval = s;
663  }
664 
665  return retval;
666 }
667 
668 DEFUN (pause, args, ,
669  "-*- texinfo -*-\n\
670 @deftypefn {Built-in Function} {} pause (@var{seconds})\n\
671 Suspend the execution of the program. If invoked without any arguments,\n\
672 Octave waits until you type a character. With a numeric argument, it\n\
673 pauses for the given number of seconds. For example, the following\n\
674 statement prints a message and then waits 5 seconds before clearing the\n\
675 screen.\n\
676 \n\
677 @example\n\
678 @group\n\
679 fprintf (stderr, \"wait please...\\n\");\n\
680 pause (5);\n\
681 clc;\n\
682 @end group\n\
683 @end example\n\
684 @end deftypefn")
685 {
686  octave_value_list retval;
687 
688  int nargin = args.length ();
689 
690  if (! (nargin == 0 || nargin == 1))
691  {
692  print_usage ();
693  return retval;
694  }
695 
696  if (nargin == 1)
697  {
698  double dval = args(0).double_value ();
699 
700  if (! error_state)
701  {
702  if (! xisnan (dval))
703  {
704  Fdrawnow ();
705 
706  if (xisinf (dval))
707  {
709  octave_kbhit ();
710  }
711  else
712  octave_sleep (dval);
713  }
714  else
715  warning ("pause: NaN is an invalid delay");
716  }
717  }
718  else
719  {
720  Fdrawnow ();
722  octave_kbhit ();
723  }
724 
725  return retval;
726 }
727 
728 /*
729 %!test
730 %! pause (1);
731 
732 %!error (pause (1, 2))
733 */
734 
735 DEFUN (sleep, args, ,
736  "-*- texinfo -*-\n\
737 @deftypefn {Built-in Function} {} sleep (@var{seconds})\n\
738 Suspend the execution of the program for the given number of seconds.\n\
739 @end deftypefn")
740 {
741  octave_value_list retval;
742 
743  if (args.length () == 1)
744  {
745  double dval = args(0).double_value ();
746 
747  if (! error_state)
748  {
749  if (xisnan (dval))
750  warning ("sleep: NaN is an invalid delay");
751  else
752  {
753  Fdrawnow ();
754  octave_sleep (dval);
755  }
756  }
757  }
758  else
759  print_usage ();
760 
761  return retval;
762 }
763 
764 /*
765 %!test
766 %! sleep (1);
767 
768 %!error (sleep ())
769 %!error (sleep (1, 2))
770 */
771 
772 DEFUN (usleep, args, ,
773  "-*- texinfo -*-\n\
774 @deftypefn {Built-in Function} {} usleep (@var{microseconds})\n\
775 Suspend the execution of the program for the given number of\n\
776 microseconds. On systems where it is not possible to sleep for periods\n\
777 of time less than one second, @code{usleep} will pause the execution for\n\
778 @code{round (@var{microseconds} / 1e6)} seconds.\n\
779 @end deftypefn")
780 {
781  octave_value_list retval;
782 
783  if (args.length () == 1)
784  {
785  double dval = args(0).double_value ();
786 
787  if (! error_state)
788  {
789  if (xisnan (dval))
790  warning ("usleep: NaN is an invalid delay");
791  else
792  {
793  Fdrawnow ();
794 
795  int delay = NINT (dval);
796 
797  if (delay > 0)
798  octave_usleep (delay);
799  }
800  }
801  }
802  else
803  print_usage ();
804 
805  return retval;
806 }
807 
808 /*
809 %!test
810 %! usleep (1000);
811 
812 %!error (usleep ())
813 %!error (usleep (1, 2))
814 */
815 
816 // FIXME: maybe this should only return 1 if IEEE floating
817 // point functions really work.
818 
819 DEFUN (isieee, , ,
820  "-*- texinfo -*-\n\
821 @deftypefn {Built-in Function} {} isieee ()\n\
822 Return true if your computer @emph{claims} to conform to the IEEE standard\n\
823 for floating point calculations. No actual tests are performed.\n\
824 @end deftypefn")
825 {
827 
830 }
831 
832 /*
833 %!assert (islogical (isieee ()))
834 */
835 
836 DEFUN (native_float_format, , ,
837  "-*- texinfo -*-\n\
838 @deftypefn {Built-in Function} {} native_float_format ()\n\
839 Return the native floating point format as a string\n\
840 @end deftypefn")
841 {
843 
845 }
846 
847 /*
848 %!assert (ischar (native_float_format ()))
849 */
850 
851 DEFUN (tilde_expand, args, ,
852  "-*- texinfo -*-\n\
853 @deftypefn {Built-in Function} {} tilde_expand (@var{string})\n\
854 Perform tilde expansion on @var{string}. If @var{string} begins with a\n\
855 tilde character, (@samp{~}), all of the characters preceding the first\n\
856 slash (or all characters, if there is no slash) are treated as a\n\
857 possible user name, and the tilde and the following characters up to the\n\
858 slash are replaced by the home directory of the named user. If the\n\
859 tilde is followed immediately by a slash, the tilde is replaced by the\n\
860 home directory of the user running Octave. For example:\n\
861 \n\
862 @example\n\
863 @group\n\
864 tilde_expand (\"~joeuser/bin\")\n\
865  @result{} \"/home/joeuser/bin\"\n\
866 tilde_expand (\"~/bin\")\n\
867  @result{} \"/home/jwe/bin\"\n\
868 @end group\n\
869 @end example\n\
870 @end deftypefn")
871 {
872  octave_value retval;
873 
874  int nargin = args.length ();
875 
876  if (nargin == 1)
877  {
878  octave_value arg = args(0);
879 
880  string_vector sv = arg.all_strings ();
881 
882  if (! error_state)
883  {
884  sv = file_ops::tilde_expand (sv);
885 
886  if (arg.is_cellstr ())
887  retval = Cell (arg.dims (), sv);
888  else
889  retval = sv;
890  }
891  else
892  error ("tilde_expand: expecting argument to be char or cellstr object");
893  }
894  else
895  print_usage ();
896 
897  return retval;
898 }
899 
900 /*
901 %!test
902 %! if (isempty (getenv ("HOME")))
903 %! setenv ("HOME", "foobar");
904 %! endif
905 %! home = getenv ("HOME");
906 %! assert (tilde_expand ("~/foobar"), strcat (home, "/foobar"));
907 %! assert (tilde_expand ("/foo/bar"), "/foo/bar");
908 %! assert (tilde_expand ("foo/bar"), "foo/bar");
909 */
910 
911 // This function really belongs in display.cc, but including defun.h in
912 // that file results in conflicts with symbols from headers that are
913 // needed for X11 and Carbon functions.
914 
915 DEFUN (have_window_system, , ,
916  "-*- texinfo -*-\n\
917 @deftypefn {Built-in Function} {} have_window_system ()\n\
918 Return true if Octave a window system is available (X11, Windows,\n\
919 or Apple OS X) and false otherwise.\n\
920 @end deftypefn")
921 {
923 }