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
main.in.cc
Go to the documentation of this file.
1 // %NO_EDIT_WARNING%
2 /*
3 
4 Copyright (C) 2012-2013 John W. Eaton
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 // NOTE: This program is supposed to be a small wrapper that exists
25 // primarily to give up the controlling TTY and then exec Octave with
26 // its GUI. It may also execute Octave without the GUI or the command
27 // line version of Octave that is not linked with GUI libraries. So
28 // that it remains small, it should NOT depend on or be linked with
29 // liboctave or libinterp.
30 
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 
35 #include <cstdlib>
36 #include <cstring>
37 
38 #include <algorithm>
39 #include <iostream>
40 #include <string>
41 
42 #include <sys/types.h>
43 #include <unistd.h>
44 
45 #ifndef OCTAVE_VERSION
46 #define OCTAVE_VERSION %OCTAVE_VERSION%
47 #endif
48 
49 #ifndef OCTAVE_ARCHLIBDIR
50 #define OCTAVE_ARCHLIBDIR %OCTAVE_ARCHLIBDIR%
51 #endif
52 
53 #ifndef OCTAVE_BINDIR
54 #define OCTAVE_BINDIR %OCTAVE_BINDIR%
55 #endif
56 
57 #ifndef OCTAVE_PREFIX
58 #define OCTAVE_PREFIX %OCTAVE_PREFIX%
59 #endif
60 
61 #if defined (__WIN32__) && ! defined (_POSIX_VERSION)
62 
63 #define WIN32_LEAN_AND_MEAN
64 #include <tlhelp32.h>
65 
66 static std::string
67 w32_get_octave_home (void)
68 {
69  std::string retval;
70 
71  std::string bin_dir;
72 
73  HANDLE h = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE
74 #ifdef TH32CS_SNAPMODULE32
75  | TH32CS_SNAPMODULE32
76 #endif
77  , 0);
78 
79  if (h != INVALID_HANDLE_VALUE)
80  {
81  MODULEENTRY32 mod_info;
82 
83  ZeroMemory (&mod_info, sizeof (mod_info));
84  mod_info.dwSize = sizeof (mod_info);
85 
86  if (Module32First (h, &mod_info))
87  {
88  do
89  {
90  std::string mod_name (mod_info.szModule);
91 
92  if (mod_name.find ("octave") != std::string::npos)
93  {
94  bin_dir = mod_info.szExePath;
95 
96  if (bin_dir[bin_dir.length () - 1] != '\\')
97  bin_dir.append (1, '\\');
98 
99  break;
100  }
101  }
102  while (Module32Next (h, &mod_info));
103  }
104 
105  CloseHandle (h);
106  }
107 
108  if (! bin_dir.empty ())
109  {
110  size_t pos = bin_dir.rfind ("\\bin\\");
111 
112  if (pos != std::string::npos)
113  retval = bin_dir.substr (0, pos);
114  }
115 
116  return retval;
117 }
118 
119 #endif
120 
121 #include <cstdlib>
122 
123 #if defined (OCTAVE_USE_WINDOWS_API)
124 #include <windows.h>
125 #elif defined (HAVE_FRAMEWORK_CARBON)
126 #include <Carbon/Carbon.h>
127 #elif defined (HAVE_X_WINDOWS)
128 #include <X11/Xlib.h>
129 #endif
130 
131 bool
132 display_available (std::string& err_msg)
133 {
134  bool dpy_avail = false;
135 
136  err_msg = "";
137 
138 #if defined (OCTAVE_USE_WINDOWS_API)
139 
140  HDC hdc = GetDC (0);
141 
142  if (hdc)
143  dpy_avail = true;
144  else
145  err_msg = "no graphical display found";
146 
147 #elif defined (HAVE_FRAMEWORK_CARBON)
148 
149  CGDirectDisplayID display = CGMainDisplayID ();
150 
151  if (display)
152  dpy_avail = true;
153  else
154  err_msg = "no graphical display found";
155 
156 #elif defined (HAVE_X_WINDOWS)
157 
158  const char *display_name = getenv ("DISPLAY");
159 
160  if (display_name && *display_name)
161  {
162  Display *display = XOpenDisplay (display_name);
163 
164  if (display)
165  {
166  Screen *screen = DefaultScreenOfDisplay (display);
167 
168  if (! screen)
169  err_msg = "X11 display has no default screen";
170 
171  XCloseDisplay (display);
172 
173  dpy_avail = true;
174  }
175  else
176  err_msg = "unable to open X11 DISPLAY";
177  }
178  else
179  err_msg = "X11 DISPLAY environment variable not set";
180 
181 #else
182 
183  err_msg = "no graphical display found";
184 
185 #endif
186 
187  return dpy_avail;
188 }
189 
190 #if (defined (HAVE_OCTAVE_GUI) \
191  && ! defined (__WIN32__) || defined (__CYGWIN__))
192 
193 #include <signal.h>
194 #include <fcntl.h>
195 
196 // This is a liboctave header, but it doesn't include any other Octave
197 // headers or declare any functions that are defined in liboctave.
198 #include "syswait.h"
199 
200 typedef void sig_handler (int);
201 
202 // Forward signals to the GUI process.
203 
204 static pid_t gui_pid = 0;
205 
206 static int caught_signal = -1;
207 
208 static void
209 gui_driver_sig_handler (int sig)
210 {
211  if (gui_pid > 0)
212  caught_signal = sig;
213 }
214 
215 static sig_handler *
216 octave_set_signal_handler (int sig, sig_handler *handler)
217 {
218  struct sigaction act, oact;
219 
220  act.sa_handler = handler;
221  act.sa_flags = 0;
222 
223  gnulib::sigemptyset (&act.sa_mask);
224  gnulib::sigemptyset (&oact.sa_mask);
225 
226  gnulib::sigaction (sig, &act, &oact);
227 
228  return oact.sa_handler;
229 }
230 
231 static void
233 {
234 
235 #ifdef SIGINT
236  octave_set_signal_handler (SIGINT, gui_driver_sig_handler);
237 #endif
238 
239 #ifdef SIGBREAK
240  octave_set_signal_handler (SIGBREAK, gui_driver_sig_handler);
241 #endif
242 
243 #ifdef SIGABRT
244  octave_set_signal_handler (SIGABRT, gui_driver_sig_handler);
245 #endif
246 
247 #ifdef SIGALRM
248  octave_set_signal_handler (SIGALRM, gui_driver_sig_handler);
249 #endif
250 
251 #ifdef SIGBUS
252  octave_set_signal_handler (SIGBUS, gui_driver_sig_handler);
253 #endif
254 
255  // SIGCHLD
256  // SIGCLD
257  // SIGCONT
258 
259 #ifdef SIGEMT
260  octave_set_signal_handler (SIGEMT, gui_driver_sig_handler);
261 #endif
262 
263 #ifdef SIGFPE
264  octave_set_signal_handler (SIGFPE, gui_driver_sig_handler);
265 #endif
266 
267 #ifdef SIGHUP
268  octave_set_signal_handler (SIGHUP, gui_driver_sig_handler);
269 #endif
270 
271 #ifdef SIGILL
272  octave_set_signal_handler (SIGILL, gui_driver_sig_handler);
273 #endif
274 
275  // SIGINFO
276  // SIGINT
277 
278 #ifdef SIGIOT
279  octave_set_signal_handler (SIGIOT, gui_driver_sig_handler);
280 #endif
281 
282 #ifdef SIGLOST
283  octave_set_signal_handler (SIGLOST, gui_driver_sig_handler);
284 #endif
285 
286 #ifdef SIGPIPE
287  octave_set_signal_handler (SIGPIPE, gui_driver_sig_handler);
288 #endif
289 
290 #ifdef SIGPOLL
291  octave_set_signal_handler (SIGPOLL, gui_driver_sig_handler);
292 #endif
293 
294  // SIGPROF
295  // SIGPWR
296 
297 #ifdef SIGQUIT
298  octave_set_signal_handler (SIGQUIT, gui_driver_sig_handler);
299 #endif
300 
301 #ifdef SIGSEGV
302  octave_set_signal_handler (SIGSEGV, gui_driver_sig_handler);
303 #endif
304 
305  // SIGSTOP
306 
307 #ifdef SIGSYS
308  octave_set_signal_handler (SIGSYS, gui_driver_sig_handler);
309 #endif
310 
311 #ifdef SIGTERM
312  octave_set_signal_handler (SIGTERM, gui_driver_sig_handler);
313 #endif
314 
315 #ifdef SIGTRAP
316  octave_set_signal_handler (SIGTRAP, gui_driver_sig_handler);
317 #endif
318 
319  // SIGTSTP
320  // SIGTTIN
321  // SIGTTOU
322  // SIGURG
323 
324 #ifdef SIGUSR1
325  octave_set_signal_handler (SIGUSR1, gui_driver_sig_handler);
326 #endif
327 
328 #ifdef SIGUSR2
329  octave_set_signal_handler (SIGUSR2, gui_driver_sig_handler);
330 #endif
331 
332 #ifdef SIGVTALRM
333  octave_set_signal_handler (SIGVTALRM, gui_driver_sig_handler);
334 #endif
335 
336 #ifdef SIGIO
337  octave_set_signal_handler (SIGIO, gui_driver_sig_handler);
338 #endif
339 
340  // SIGWINCH
341 
342 #ifdef SIGXCPU
343  octave_set_signal_handler (SIGXCPU, gui_driver_sig_handler);
344 #endif
345 
346 #ifdef SIGXFSZ
347  octave_set_signal_handler (SIGXFSZ, gui_driver_sig_handler);
348 #endif
349 
350 }
351 
352 static bool
353 have_controlling_terminal (void)
354 {
355  int retval = false;
356 
357 #if defined (HAVE_CTERMID)
358  const char *ctty = ctermid (0);
359 #else
360  const char *ctty = "/dev/tty";
361 #endif
362 
363  int fd = gnulib::open (ctty, O_RDWR, 0);
364 
365  if (fd >= 0)
366  {
367  gnulib::close (fd);
368 
369  retval = true;
370  }
371 
372  return retval;
373 }
374 
375 #endif
376 
377 // Find the directory where the octave binary is supposed to be
378 // installed.
379 
380 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM) \
381  && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
382 static const char dir_sep_char = '\\';
383 #else
384 static const char dir_sep_char = '/';
385 #endif
386 
387 static std::string
388 octave_getenv (const std::string& name)
389 {
390  char *value = ::getenv (name.c_str ());
391 
392  return value ? value : "";
393 }
394 
395 static std::string
397 {
398  std::string oh = octave_getenv ("OCTAVE_HOME");
399 
400 #if defined (__WIN32__) && ! defined (_POSIX_VERSION)
401  if (oh.empty ())
402  oh = w32_get_octave_home ();
403 #endif
404 
405  return oh.empty () ? std::string (OCTAVE_PREFIX) : oh;
406 }
407 
408 static std::string
409 subst_octave_home (const std::string& s)
410 {
411  std::string retval;
412 
413  std::string octave_home = get_octave_home ();
414 
415  std::string prefix = OCTAVE_PREFIX;
416 
417  retval = s;
418 
419  if (octave_home != prefix)
420  {
421  octave_idx_type len = prefix.length ();
422 
423  if (s.substr (0, len) == prefix)
424  retval.replace (0, len, octave_home);
425  }
426 
427  if (dir_sep_char != '/')
428  std::replace (retval.begin (), retval.end (), '/', dir_sep_char);
429 
430  return retval;
431 }
432 
433 static std::string
435 {
436  // Accept value from the environment literally, but substitute
437  // OCTAVE_HOME in the configuration value OCTAVE_BINDIR in case Octave
438  // has been relocated to some installation directory other than the
439  // one originally configured.
440 
441  std::string obd = octave_getenv ("OCTAVE_BINDIR");
442 
443  return obd.empty () ? subst_octave_home (std::string (OCTAVE_BINDIR)) : obd;
444 }
445 
446 static std::string
448 {
449  // Accept value from the environment literally, but substitute
450  // OCTAVE_HOME in the configuration value OCTAVE_ARCHLIBDIR in case
451  // Octave has been relocated to some installation directory other than
452  // the one originally configured.
453 
454  std::string dir = octave_getenv ("OCTAVE_ARCHLIBDIR");
455 
456  return dir.empty ()
457  ? subst_octave_home (std::string (OCTAVE_ARCHLIBDIR)) : dir;
458 }
459 
460 // Adapted from libtool wrapper.
461 #if defined (__WIN32__) && ! defined (__CYGWIN__)
462 
463 /* Prepares an argument vector before calling spawn().
464  Note that spawn() does not by itself call the command interpreter
465  (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
466  ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
467  GetVersionEx(&v);
468  v.dwPlatformId == VER_PLATFORM_WIN32_NT;
469  }) ? "cmd.exe" : "command.com").
470  Instead it simply concatenates the arguments, separated by ' ', and calls
471  CreateProcess(). We must quote the arguments since Win32 CreateProcess()
472  interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
473  special way:
474  - Space and tab are interpreted as delimiters. They are not treated as
475  delimiters if they are surrounded by double quotes: "...".
476  - Unescaped double quotes are removed from the input. Their only effect is
477  that within double quotes, space and tab are treated like normal
478  characters.
479  - Backslashes not followed by double quotes are not special.
480  - But 2*n+1 backslashes followed by a double quote become
481  n backslashes followed by a double quote (n >= 0):
482  \" -> "
483  \\\" -> \"
484  \\\\\" -> \\"
485  */
486 #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
487 #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
488 char **
489 prepare_spawn (char **argv)
490 {
491  size_t argc;
492  char **new_argv;
493  size_t i;
494 
495  /* Count number of arguments. */
496  for (argc = 0; argv[argc] != NULL; argc++)
497  ;
498 
499  /* Allocate new argument vector. */
500  new_argv = new char* [argc + 1];
501 
502  /* Put quoted arguments into the new argument vector. */
503  for (i = 0; i < argc; i++)
504  {
505  const char *string = argv[i];
506 
507  if (string[0] == '\0')
508  new_argv[i] = strdup ("\"\"");
509  else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
510  {
511  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
512  size_t length;
513  unsigned int backslashes;
514  const char *s;
515  char *quoted_string;
516  char *p;
517 
518  length = 0;
519  backslashes = 0;
520  if (quote_around)
521  length++;
522  for (s = string; *s != '\0'; s++)
523  {
524  char c = *s;
525  if (c == '"')
526  length += backslashes + 1;
527  length++;
528  if (c == '\\')
529  backslashes++;
530  else
531  backslashes = 0;
532  }
533  if (quote_around)
534  length += backslashes + 1;
535 
536  quoted_string = new char [length + 1];
537 
538  p = quoted_string;
539  backslashes = 0;
540  if (quote_around)
541  *p++ = '"';
542  for (s = string; *s != '\0'; s++)
543  {
544  char c = *s;
545  if (c == '"')
546  {
547  unsigned int j;
548  for (j = backslashes + 1; j > 0; j--)
549  *p++ = '\\';
550  }
551  *p++ = c;
552  if (c == '\\')
553  backslashes++;
554  else
555  backslashes = 0;
556  }
557  if (quote_around)
558  {
559  unsigned int j;
560  for (j = backslashes; j > 0; j--)
561  *p++ = '\\';
562  *p++ = '"';
563  }
564  *p = '\0';
565 
566  new_argv[i] = quoted_string;
567  }
568  else
569  new_argv[i] = (char *) string;
570  }
571  new_argv[argc] = NULL;
572 
573  return new_argv;
574 }
575 
576 #endif // __WIN32__ && ! __CYGWIN__
577 
578 static int
579 octave_exec (const std::string& file, char **argv)
580 {
581 #if defined (__WIN32__) && ! defined (__CYGWIN__)
582  argv = prepare_spawn (argv);
583  return _spawnv (_P_WAIT, file.c_str (), argv);
584 #else
585  execv (file.c_str (), argv);
586 
587  std::cerr << "octave: failed to exec '" << file << "'" << std::endl;
588 
589  return 1;
590 #endif
591 }
592 
593 static char *
594 strsave (const char *s)
595 {
596  if (! s)
597  return 0;
598 
599  int len = strlen (s);
600  char *tmp = new char [len+1];
601  tmp = strcpy (tmp, s);
602  return tmp;
603 }
604 
605 int
606 main (int argc, char **argv)
607 {
608  int retval = 0;
609 
610  bool start_gui = false;
611  bool gui_libs = false;
612 
613  std::string octave_bindir = get_octave_bindir ();
614  std::string octave_archlibdir = get_octave_archlibdir ();
615 
616  std::string file
617  = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;;
618 
619  char **new_argv = new char * [argc + 1];
620 
621  int k = 1;
622 
623  bool warn_display = true;
624 
625  for (int i = 1; i < argc; i++)
626  {
627  if (! strcmp (argv[i], "--force-gui"))
628  {
629  start_gui = true;
630  gui_libs = true;
631 #if defined (HAVE_OCTAVE_GUI)
632  // The Octave version number is already embedded in the
633  // octave_archlibdir directory name so we don't need to
634  // append it to the octave-gui file name.
635 
636  file = octave_archlibdir + dir_sep_char + "octave-gui";
637 #else
638  file = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
639 #endif
640  new_argv[k++] = argv[i];
641  }
642  else if (! strcmp (argv[i], "--no-gui-libs"))
643  {
644  // Run the version of Octave that is not linked with any GUI
645  // libraries. It may not be possible to do plotting or any
646  // ui* calls, but it will be a little faster to start and
647  // require less memory. Don't pass the --no-gui-libs option
648  // on as that option is not recognized by Octave.
649 
650  // This is the default for 3.8 release.
651  }
652  else if (! strcmp (argv[i], "--no-gui"))
653  {
654  // If we see this option, then we can just exec octave; we
655  // don't have to create a child process and wait for it to
656  // exit. But do exec "octave-gui", not "octave-cli", because
657  // even if the --no-gui option is given, we may be asked to do
658  // some plotting or ui* calls.
659 
660  // This option calls the cli executable for the 3.8 release.
661  }
662  else if (! strcmp (argv[i], "--silent") || ! strcmp (argv[i], "-q")
663  || ! strcmp (argv[i], "--quiet"))
664  {
665  warn_display = false;
666  new_argv[k++] = argv[i];
667  }
668  else
669  new_argv[k++] = argv[i];
670  }
671 
672  new_argv[k] = 0;
673 
674  if (gui_libs || start_gui)
675  {
676  std::string display_check_err_msg;
677 
678  if (! display_available (display_check_err_msg))
679  {
680  start_gui = false;
681  gui_libs = false;
682 
683  file = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
684 
685  if (warn_display)
686  {
687  std::cerr << "octave: " << display_check_err_msg << std::endl;
688  std::cerr << "octave: disabling GUI features" << std::endl;
689  }
690  }
691  }
692 
693 #if defined (__WIN32__) && ! defined (__CYGWIN__)
694  file += ".exe";
695 #endif
696 
697  new_argv[0] = strsave (file.c_str ());
698 
699 #if (defined (HAVE_OCTAVE_GUI) \
700  && ! defined (__WIN32__) || defined (__CYGWIN__))
701 
702  if (gui_libs && start_gui && have_controlling_terminal ())
703  {
705 
706  gui_pid = fork ();
707 
708  if (gui_pid < 0)
709  {
710  std::cerr << "octave: fork failed!" << std::endl;
711 
712  retval = 1;
713  }
714  else if (gui_pid == 0)
715  {
716  // Child.
717 
718  if (setsid () < 0)
719  {
720  std::cerr << "octave: error calling setsid!" << std::endl;
721 
722  retval = 1;
723  }
724 
725  retval = octave_exec (file, new_argv);
726  }
727  else
728  {
729  // Parent. Forward signals to child while waiting for it to exit.
730 
731  int status;
732 
733  while (true)
734  {
735  WAITPID (gui_pid, &status, 0);
736 
737  if (caught_signal > 0)
738  {
739  int sig = caught_signal;
740 
741  caught_signal = -1;
742 
743  kill (gui_pid, sig);
744  }
745  else if (WIFEXITED (status))
746  {
747  retval = WEXITSTATUS (status);
748  break;
749  }
750  else if (WIFSIGNALLED (status))
751  {
752  std::cerr << "octave exited with signal "
753  << WTERMSIG (status) << std::endl;
754  break;
755  }
756  }
757  }
758  }
759  else
760  retval = octave_exec (file, new_argv);
761 
762 #else
763 
764  retval = octave_exec (file, new_argv);
765 
766 #endif
767 
768  return retval;
769 }
770 
771 /*!
772 @mainpage Source code documentation for GNU Octave
773 
774 GNU Octave is a high-level language, primarily intended for numerical
775 computations. It provides a convenient interactive command line
776 interface for solving linear and nonlinear problems numerically, and
777 for performing other numerical experiments. It may also be used as a
778 batch-oriented language for data processing.
779 
780 GNU Octave is free software. You may redistribute it and/or modify it
781 under the terms of the <a href="http://www.gnu.org/licenses/">GNU
782 General Public License</a> as published by the Free Software Foundation.
783 
784 This is the developer documentation for Octave's own source code. It is
785 intended to help for hacking Octave. It may also be useful for
786 understanding the Octave API when writing your own .oct files.
787 */