GNU Octave  4.0.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-2015 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 #include "display-available.h"
62 #include "shared-fcns.h"
63 
64 #include <cstdlib>
65 
66 #if (defined (HAVE_OCTAVE_GUI) \
67  && ! defined (__WIN32__) || defined (__CYGWIN__))
68 
69 #include <signal.h>
70 #include <fcntl.h>
71 
72 // This is a liboctave header, but it doesn't include any other Octave
73 // headers or declare any functions that are defined in liboctave.
74 #include "syswait.h"
75 
76 typedef void sig_handler (int);
77 
78 // Forward signals to the GUI process.
79 
80 static pid_t gui_pid = 0;
81 
82 static int caught_signal = -1;
83 
84 static void
85 gui_driver_sig_handler (int sig)
86 {
87  if (gui_pid > 0)
88  caught_signal = sig;
89 }
90 
91 static sig_handler *
92 octave_set_signal_handler (int sig, sig_handler *handler)
93 {
94  struct sigaction act, oact;
95 
96  act.sa_handler = handler;
97  act.sa_flags = 0;
98 
99  gnulib::sigemptyset (&act.sa_mask);
100  gnulib::sigemptyset (&oact.sa_mask);
101 
102  gnulib::sigaction (sig, &act, &oact);
103 
104  return oact.sa_handler;
105 }
106 
107 static void
109 {
110 
111 #ifdef SIGINT
112  octave_set_signal_handler (SIGINT, gui_driver_sig_handler);
113 #endif
114 
115 #ifdef SIGBREAK
116  octave_set_signal_handler (SIGBREAK, gui_driver_sig_handler);
117 #endif
118 
119 #ifdef SIGABRT
120  octave_set_signal_handler (SIGABRT, gui_driver_sig_handler);
121 #endif
122 
123 #ifdef SIGALRM
124  octave_set_signal_handler (SIGALRM, gui_driver_sig_handler);
125 #endif
126 
127 #ifdef SIGBUS
128  octave_set_signal_handler (SIGBUS, gui_driver_sig_handler);
129 #endif
130 
131  // SIGCHLD
132  // SIGCLD
133  // SIGCONT
134 
135 #ifdef SIGEMT
136  octave_set_signal_handler (SIGEMT, gui_driver_sig_handler);
137 #endif
138 
139 #ifdef SIGFPE
140  octave_set_signal_handler (SIGFPE, gui_driver_sig_handler);
141 #endif
142 
143 #ifdef SIGHUP
144  octave_set_signal_handler (SIGHUP, gui_driver_sig_handler);
145 #endif
146 
147 #ifdef SIGILL
148  octave_set_signal_handler (SIGILL, gui_driver_sig_handler);
149 #endif
150 
151  // SIGINFO
152  // SIGINT
153 
154 #ifdef SIGIOT
155  octave_set_signal_handler (SIGIOT, gui_driver_sig_handler);
156 #endif
157 
158 #ifdef SIGLOST
159  octave_set_signal_handler (SIGLOST, gui_driver_sig_handler);
160 #endif
161 
162 #ifdef SIGPIPE
163  octave_set_signal_handler (SIGPIPE, gui_driver_sig_handler);
164 #endif
165 
166 #ifdef SIGPOLL
167  octave_set_signal_handler (SIGPOLL, gui_driver_sig_handler);
168 #endif
169 
170  // SIGPROF
171  // SIGPWR
172 
173 #ifdef SIGQUIT
174  octave_set_signal_handler (SIGQUIT, gui_driver_sig_handler);
175 #endif
176 
177 #ifdef SIGSEGV
178  octave_set_signal_handler (SIGSEGV, gui_driver_sig_handler);
179 #endif
180 
181  // SIGSTOP
182 
183 #ifdef SIGSYS
184  octave_set_signal_handler (SIGSYS, gui_driver_sig_handler);
185 #endif
186 
187 #ifdef SIGTERM
188  octave_set_signal_handler (SIGTERM, gui_driver_sig_handler);
189 #endif
190 
191 #ifdef SIGTRAP
192  octave_set_signal_handler (SIGTRAP, gui_driver_sig_handler);
193 #endif
194 
195  // SIGTSTP
196  // SIGTTIN
197  // SIGTTOU
198  // SIGURG
199 
200 #ifdef SIGUSR1
201  octave_set_signal_handler (SIGUSR1, gui_driver_sig_handler);
202 #endif
203 
204 #ifdef SIGUSR2
205  octave_set_signal_handler (SIGUSR2, gui_driver_sig_handler);
206 #endif
207 
208 #ifdef SIGVTALRM
209  octave_set_signal_handler (SIGVTALRM, gui_driver_sig_handler);
210 #endif
211 
212 #ifdef SIGIO
213  octave_set_signal_handler (SIGIO, gui_driver_sig_handler);
214 #endif
215 
216  // SIGWINCH
217 
218 #ifdef SIGXCPU
219  octave_set_signal_handler (SIGXCPU, gui_driver_sig_handler);
220 #endif
221 
222 #ifdef SIGXFSZ
223  octave_set_signal_handler (SIGXFSZ, gui_driver_sig_handler);
224 #endif
225 
226 }
227 
228 static bool
229 have_controlling_terminal (void)
230 {
231  int retval = false;
232 
233 #if defined (HAVE_CTERMID)
234  const char *ctty = ctermid (0);
235 #else
236  const char *ctty = "/dev/tty";
237 #endif
238 
239  int fd = gnulib::open (ctty, O_RDWR, 0);
240 
241  if (fd >= 0)
242  {
243  gnulib::close (fd);
244 
245  retval = true;
246  }
247 
248  return retval;
249 }
250 
251 #endif
252 
253 static std::string
255 {
256  // Accept value from the environment literally, but substitute
257  // OCTAVE_HOME in the configuration value OCTAVE_BINDIR in case Octave
258  // has been relocated to some installation directory other than the
259  // one originally configured.
260 
261  std::string obd = octave_getenv ("OCTAVE_BINDIR");
262 
263  return obd.empty () ? subst_octave_home (std::string (OCTAVE_BINDIR)) : obd;
264 }
265 
266 static std::string
268 {
269  // Accept value from the environment literally, but substitute
270  // OCTAVE_HOME in the configuration value OCTAVE_ARCHLIBDIR in case
271  // Octave has been relocated to some installation directory other than
272  // the one originally configured.
273 
274  std::string dir = octave_getenv ("OCTAVE_ARCHLIBDIR");
275 
276  return dir.empty () ? subst_octave_home (std::string (OCTAVE_ARCHLIBDIR))
277  : dir;
278 }
279 
280 // Adapted from libtool wrapper.
281 #if defined (__WIN32__) && ! defined (__CYGWIN__)
282 
283 /* Prepares an argument vector before calling spawn().
284  Note that spawn() does not by itself call the command interpreter
285  (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
286  ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
287  GetVersionEx(&v);
288  v.dwPlatformId == VER_PLATFORM_WIN32_NT;
289  }) ? "cmd.exe" : "command.com").
290  Instead it simply concatenates the arguments, separated by ' ', and calls
291  CreateProcess(). We must quote the arguments since Win32 CreateProcess()
292  interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
293  special way:
294  - Space and tab are interpreted as delimiters. They are not treated as
295  delimiters if they are surrounded by double quotes: "...".
296  - Unescaped double quotes are removed from the input. Their only effect is
297  that within double quotes, space and tab are treated like normal
298  characters.
299  - Backslashes not followed by double quotes are not special.
300  - But 2*n+1 backslashes followed by a double quote become
301  n backslashes followed by a double quote (n >= 0):
302  \" -> "
303  \\\" -> \"
304  \\\\\" -> \\"
305  */
306 #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"
307 #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"
308 char **
309 prepare_spawn (char **argv)
310 {
311  size_t argc;
312  char **new_argv;
313  size_t i;
314 
315  /* Count number of arguments. */
316  for (argc = 0; argv[argc] != NULL; argc++)
317  ;
318 
319  /* Allocate new argument vector. */
320  new_argv = new char* [argc + 1];
321 
322  /* Put quoted arguments into the new argument vector. */
323  for (i = 0; i < argc; i++)
324  {
325  const char *string = argv[i];
326 
327  if (string[0] == '\0')
328  new_argv[i] = strdup ("\"\"");
329  else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
330  {
331  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
332  size_t length;
333  unsigned int backslashes;
334  const char *s;
335  char *quoted_string;
336  char *p;
337 
338  length = 0;
339  backslashes = 0;
340  if (quote_around)
341  length++;
342  for (s = string; *s != '\0'; s++)
343  {
344  char c = *s;
345  if (c == '"')
346  length += backslashes + 1;
347  length++;
348  if (c == '\\')
349  backslashes++;
350  else
351  backslashes = 0;
352  }
353  if (quote_around)
354  length += backslashes + 1;
355 
356  quoted_string = new char [length + 1];
357 
358  p = quoted_string;
359  backslashes = 0;
360  if (quote_around)
361  *p++ = '"';
362  for (s = string; *s != '\0'; s++)
363  {
364  char c = *s;
365  if (c == '"')
366  {
367  unsigned int j;
368  for (j = backslashes + 1; j > 0; j--)
369  *p++ = '\\';
370  }
371  *p++ = c;
372  if (c == '\\')
373  backslashes++;
374  else
375  backslashes = 0;
376  }
377  if (quote_around)
378  {
379  unsigned int j;
380  for (j = backslashes; j > 0; j--)
381  *p++ = '\\';
382  *p++ = '"';
383  }
384  *p = '\0';
385 
386  new_argv[i] = quoted_string;
387  }
388  else
389  new_argv[i] = (char *) string;
390  }
391  new_argv[argc] = NULL;
392 
393  return new_argv;
394 }
395 
396 #endif // __WIN32__ && ! __CYGWIN__
397 
398 static int
399 octave_exec (const std::string& file, char **argv)
400 {
401 #if defined (__WIN32__) && ! defined (__CYGWIN__)
402  argv = prepare_spawn (argv);
403  return _spawnv (_P_WAIT, file.c_str (), argv);
404 #else
405  execv (file.c_str (), argv);
406 
407  std::cerr << "octave: failed to exec '" << file << "'" << std::endl;
408 
409  return 1;
410 #endif
411 }
412 
413 static char *
414 strsave (const char *s)
415 {
416  if (! s)
417  return 0;
418 
419  int len = strlen (s);
420  char *tmp = new char [len+1];
421  tmp = strcpy (tmp, s);
422  return tmp;
423 }
424 
425 int
426 main (int argc, char **argv)
427 {
428  int retval = 0;
429 
430  bool start_gui = true;
431  bool gui_libs = true;
432 
433  std::string octave_bindir = get_octave_bindir ();
434  std::string octave_archlibdir = get_octave_archlibdir ();
435 
436 #if defined (HAVE_OCTAVE_GUI)
437  // The Octave version number is already embedded in the
438  // octave_archlibdir directory name so we don't need to append it to
439  // the octave-gui file name.
440 
441  std::string file = octave_archlibdir + dir_sep_char + "octave-gui";
442 #else
443  std::string file
444  = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
445 #endif
446 
447  char **new_argv = new char * [argc + 1];
448 
449  int k = 1;
450 
451  bool warn_display = true;
452 
453  for (int i = 1; i < argc; i++)
454  {
455  if (! strcmp (argv[i], "--no-gui-libs"))
456  {
457  // Run the version of Octave that is not linked with any GUI
458  // libraries. It may not be possible to do plotting or any
459  // ui* calls, but it will be a little faster to start and
460  // require less memory. Don't pass the --no-gui-libs option
461  // on as that option is not recognized by Octave.
462 
463  start_gui = false;
464  gui_libs = false;
465  file = octave_bindir + dir_sep_char + "octave-cli";
466  }
467  else if (! strcmp (argv[i], "--no-gui"))
468  {
469  // If we see this option, then we can just exec octave; we
470  // don't have to create a child process and wait for it to
471  // exit. But do exec "octave-gui", not "octave-cli", because
472  // even if the --no-gui option is given, we may be asked to do
473  // some plotting or ui* calls.
474 
475  start_gui = false;
476  new_argv[k++] = argv[i];
477  }
478  else if (! strcmp (argv[i], "--silent") || ! strcmp (argv[i], "--quiet")
479  || ! strcmp (argv[i], "-q"))
480  {
481  warn_display = false;
482  new_argv[k++] = argv[i];
483  }
484  else
485  new_argv[k++] = argv[i];
486  }
487 
488  new_argv[k] = 0;
489 
490  if (gui_libs || start_gui)
491  {
492  int dpy_avail;
493 
494  const char *display_check_err_msg = display_available (&dpy_avail);
495 
496  if (! dpy_avail)
497  {
498  start_gui = false;
499  gui_libs = false;
500 
501  file = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
502 
503  if (warn_display)
504  {
505  if (! display_check_err_msg)
506  display_check_err_msg = "graphical display unavailable";
507 
508  std::cerr << "octave: " << display_check_err_msg << std::endl;
509  std::cerr << "octave: disabling GUI features" << std::endl;
510  }
511  }
512  }
513 
514 #if defined (__WIN32__) && ! defined (__CYGWIN__)
515  file += ".exe";
516 #endif
517 
518  new_argv[0] = strsave (file.c_str ());
519 
520 #if (defined (HAVE_OCTAVE_GUI) \
521  && ! defined (__WIN32__) || defined (__CYGWIN__))
522 
523  if (gui_libs && start_gui && have_controlling_terminal ())
524  {
526 
527  gui_pid = fork ();
528 
529  if (gui_pid < 0)
530  {
531  std::cerr << "octave: fork failed!" << std::endl;
532 
533  retval = 1;
534  }
535  else if (gui_pid == 0)
536  {
537  // Child.
538 
539  if (setsid () < 0)
540  {
541  std::cerr << "octave: error calling setsid!" << std::endl;
542 
543  retval = 1;
544  }
545  else
546  retval = octave_exec (file, new_argv);
547  }
548  else
549  {
550  // Parent. Forward signals to child while waiting for it to exit.
551 
552  int status;
553 
554  while (true)
555  {
556  WAITPID (gui_pid, &status, 0);
557 
558  if (caught_signal > 0)
559  {
560  int sig = caught_signal;
561 
562  caught_signal = -1;
563 
564  kill (gui_pid, sig);
565  }
566  else if (WIFEXITED (status))
567  {
568  retval = WEXITSTATUS (status);
569  break;
570  }
571  else if (WIFSIGNALLED (status))
572  {
573  std::cerr << "octave exited with signal "
574  << WTERMSIG (status) << std::endl;
575  break;
576  }
577  }
578  }
579  }
580  else
581  retval = octave_exec (file, new_argv);
582 
583 #else
584 
585  retval = octave_exec (file, new_argv);
586 
587 #endif
588 
589  return retval;
590 }
591 
592 /*!
593 @mainpage Source code documentation for GNU Octave
594 
595 GNU Octave is a high-level language, primarily intended for numerical
596 computations. It provides a convenient interactive command line
597 interface for solving linear and nonlinear problems numerically, and
598 for performing other numerical experiments. It may also be used as a
599 batch-oriented language for data processing.
600 
601 GNU Octave is free software. You may redistribute it and/or modify it
602 under the terms of the <a href="http://www.gnu.org/licenses/">GNU
603 General Public License</a> as published by the Free Software Foundation.
604 
605 This is the developer documentation for Octave's own source code. It is
606 intended to help for hacking Octave. It may also be useful for
607 understanding the Octave API when writing your own .oct files.
608 */
#define OCTAVE_ARCHLIBDIR
Definition: main.in.cc:50
static std::string subst_octave_home(const std::string &s)
Definition: shared-fcns.h:120
const char * display_available(int *dpy_avail)
#define WIFSIGNALLED(stat_val)
Definition: syswait.h:47
static int octave_exec(const std::string &file, char **argv)
Definition: main.in.cc:399
#define OCTAVE_VERSION
Definition: main.in.cc:46
#define OCTAVE_BINDIR
Definition: main.in.cc:54
void install_signal_handlers(void)
Definition: sighandlers.cc:628
#define WIFEXITED(stat_val)
Definition: mkoctfile.cc:49
int main(int argc, char **argv)
Definition: main.in.cc:426
static const char dir_sep_char
Definition: shared-fcns.h:95
static std::string get_octave_bindir(void)
Definition: main.in.cc:254
static char * strsave(const char *s)
Definition: main.in.cc:414
static std::string octave_getenv(const std::string &name)
Definition: shared-fcns.h:99
void sig_handler(int)
Definition: sighandlers.h:46
#define WEXITSTATUS(stat_val)
Definition: mkoctfile.cc:53
#define WAITPID(a, b, c)
Definition: syswait.h:58
static std::string get_octave_archlibdir(void)
Definition: main.in.cc:267
static bool start_gui
Definition: octave.cc:169
sig_handler * octave_set_signal_handler(int sig, sig_handler *handler, bool restart_syscalls)
Definition: sighandlers.cc:360