GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
main.in.cc
Go to the documentation of this file.
1 // %NO_EDIT_WARNING%
2 
3 ////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2012-2024 The Octave Project Developers
6 //
7 // See the file COPYRIGHT.md in the top-level directory of this
8 // distribution or <https://octave.org/copyright/>.
9 //
10 // This file is part of Octave.
11 //
12 // Octave is free software: you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Octave is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with Octave; see the file COPYING. If not, see
24 // <https://www.gnu.org/licenses/>.
25 //
26 ////////////////////////////////////////////////////////////////////////
27 
28 // NOTE: This program is supposed to be a small wrapper that exists
29 // primarily to give up the controlling TTY and then exec Octave with
30 // its GUI. It may also execute Octave without the GUI or the command
31 // line version of Octave that is not linked with GUI libraries. So
32 // that it remains small, it should NOT depend on or be linked with
33 // liboctave or libinterp.
34 
35 #if defined (HAVE_CONFIG_H)
36 # include "config.h"
37 #endif
38 
39 #include <cstdlib>
40 #include <cstring>
41 
42 #include <algorithm>
43 #include <iostream>
44 #include <string>
45 
46 #if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
47 # include <vector>
48 # include <locale>
49 # include <codecvt>
50 #endif
51 
52 // We are linking against static libs so do not decorate with dllimport.
53 // FIXME: This should be done by the build system.
54 #undef OCTAVE_API
55 #define OCTAVE_API
56 #include "fcntl-wrappers.h"
57 #include "getopt-wrapper.h"
58 #include "signal-wrappers.h"
59 #include "unistd-wrappers.h"
60 #include "wait-wrappers.h"
61 
62 #if ! defined (OCTAVE_VERSION)
63 # define OCTAVE_VERSION %OCTAVE_VERSION%
64 #endif
65 
66 #if ! defined (OCTAVE_ARCHLIBDIR)
67 # define OCTAVE_ARCHLIBDIR %OCTAVE_ARCHLIBDIR%
68 #endif
69 
70 #if ! defined (OCTAVE_BINDIR)
71 # define OCTAVE_BINDIR %OCTAVE_BINDIR%
72 #endif
73 
74 #if ! defined (OCTAVE_PREFIX)
75 # define OCTAVE_PREFIX %OCTAVE_PREFIX%
76 #endif
77 
78 #if ! defined (OCTAVE_EXEC_PREFIX)
79 # define OCTAVE_EXEC_PREFIX %OCTAVE_EXEC_PREFIX%
80 #endif
81 
82 #include "display-available.h"
83 #include "options.h"
84 #include "shared-fcns.h"
85 
86 #if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
87 static bool fork_and_exec = true;
88 #else
89 static bool fork_and_exec = false;
90 #endif
91 
92 // If we fork and exec, we'll need the following signal handling code to
93 // forward signals to the GUI process.
94 
95 static pid_t gui_pid = 0;
96 
97 static int caught_signal = -1;
98 
99 static void
100 gui_driver_sig_handler (int sig)
101 {
102  if (gui_pid > 0)
103  caught_signal = sig;
104 }
105 
106 static void
107 gui_driver_set_signal_handler (const char *signame,
108  octave_sig_handler *handler)
109 {
110  octave_set_signal_handler_by_name (signame, handler, false);
111 }
112 
113 static void
114 install_signal_handlers ()
115 {
116  // FIXME: do we need to handle and forward all the signals that Octave
117  // handles, or is it sufficient to only forward things like SIGINT,
118  // SIGBREAK, SIGABRT, SIGQUIT, and possibly a few others?
119 
120  gui_driver_set_signal_handler ("SIGINT", gui_driver_sig_handler);
121  gui_driver_set_signal_handler ("SIGBREAK", gui_driver_sig_handler);
122  gui_driver_set_signal_handler ("SIGABRT", gui_driver_sig_handler);
123  gui_driver_set_signal_handler ("SIGALRM", gui_driver_sig_handler);
124  gui_driver_set_signal_handler ("SIGBUS", gui_driver_sig_handler);
125 
126  // SIGCHLD
127  // SIGCLD
128  // SIGCONT
129 
130  gui_driver_set_signal_handler ("SIGEMT", gui_driver_sig_handler);
131  gui_driver_set_signal_handler ("SIGFPE", gui_driver_sig_handler);
132  gui_driver_set_signal_handler ("SIGHUP", gui_driver_sig_handler);
133  gui_driver_set_signal_handler ("SIGILL", gui_driver_sig_handler);
134 
135  // SIGINFO
136  // SIGINT
137 
138  gui_driver_set_signal_handler ("SIGIOT", gui_driver_sig_handler);
139  gui_driver_set_signal_handler ("SIGLOST", gui_driver_sig_handler);
140  gui_driver_set_signal_handler ("SIGPIPE", gui_driver_sig_handler);
141  gui_driver_set_signal_handler ("SIGPOLL", gui_driver_sig_handler);
142 
143  // SIGPROF
144  // SIGPWR
145 
146  gui_driver_set_signal_handler ("SIGQUIT", gui_driver_sig_handler);
147  gui_driver_set_signal_handler ("SIGSEGV", gui_driver_sig_handler);
148 
149  // SIGSTOP
150 
151  gui_driver_set_signal_handler ("SIGSYS", gui_driver_sig_handler);
152  gui_driver_set_signal_handler ("SIGTERM", gui_driver_sig_handler);
153  gui_driver_set_signal_handler ("SIGTRAP", gui_driver_sig_handler);
154 
155  // SIGTSTP
156  // SIGTTIN
157  // SIGTTOU
158  // SIGURG
159 
160  gui_driver_set_signal_handler ("SIGUSR1", gui_driver_sig_handler);
161  gui_driver_set_signal_handler ("SIGUSR2", gui_driver_sig_handler);
162  gui_driver_set_signal_handler ("SIGVTALRM", gui_driver_sig_handler);
163  gui_driver_set_signal_handler ("SIGIO", gui_driver_sig_handler);
164 
165  // SIGWINCH
166 
167  gui_driver_set_signal_handler ("SIGXCPU", gui_driver_sig_handler);
168  gui_driver_set_signal_handler ("SIGXFSZ", gui_driver_sig_handler);
169 }
170 
171 static std::string
172 get_octave_bindir ()
173 {
174  // Accept value from the environment literally, but substitute
175  // OCTAVE_HOME in the configuration value OCTAVE_BINDIR in case Octave
176  // has been relocated to some installation directory other than the
177  // one originally configured.
178 
179  std::string obd = octave_getenv ("OCTAVE_BINDIR");
180 
181  return obd.empty () ? prepend_octave_exec_home (std::string (OCTAVE_BINDIR))
182  : obd;
183 }
184 
185 static std::string
186 get_octave_archlibdir ()
187 {
188  // Accept value from the environment literally, but substitute
189  // OCTAVE_HOME in the configuration value OCTAVE_ARCHLIBDIR in case
190  // Octave has been relocated to some installation directory other than
191  // the one originally configured.
192 
193  std::string dir = octave_getenv ("OCTAVE_ARCHLIBDIR");
194 
195  return dir.empty () ? prepend_octave_exec_home (std::string (OCTAVE_ARCHLIBDIR))
196  : dir;
197 }
198 
199 static int
200 octave_exec (const std::string& file, char **argv)
201 {
202  int status = octave_execv_wrapper (file.c_str (), argv);
203 
204 #if defined (OCTAVE_USE_WINDOWS_API)
205  // The above wrapper uses spawn(P_WAIT,...) instead of exec on Windows.
206  if (status == -1)
207 #endif
208  std::cerr << argv[0] << ": failed to exec '" << file << "'" << std::endl;
209 
210  return status;
211 }
212 
213 static char *
214 strsave (const char *s)
215 {
216  if (! s)
217  return nullptr;
218 
219  int len = strlen (s);
220  char *tmp = new char [len+1];
221  tmp = strcpy (tmp, s);
222  return tmp;
223 }
224 
225 #if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
226 extern "C"
227 int
228 wmain (int argc, wchar_t **wargv)
229 {
230  static char **argv = new char * [argc + 1];
231  std::vector<std::string> argv_str;
232 
233  // convert wide character strings to multibyte UTF-8 strings
234  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
235  for (int i_arg = 0; i_arg < argc; i_arg++)
236  argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
237 
238  // Get pointers to C strings not before vector is stable.
239  for (int i_arg = 0; i_arg < argc; i_arg++)
240  argv[i_arg] = &argv_str[i_arg][0];
241  argv[argc] = nullptr;
242 
243 #else
244 int
245 main (int argc, char **argv)
246 {
247 #endif
248  int retval = 0;
249 
250  int idx_gui = -1;
251  bool server = false;
252  bool start_gui = false;
253  bool gui_libs = true;
254 
255  bool eval_code = false;
256  bool persist_octave = false;
257 
258  set_octave_home ();
259 
260  std::string octave_bindir = get_octave_bindir ();
261  std::string octave_archlibdir = get_octave_archlibdir ();
262  std::string octave_cli
263  = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
264  std::string octave_gui = octave_archlibdir + dir_sep_char + "octave-gui";
265 
266 #if defined (HAVE_OCTAVE_QT_GUI)
267  // The Octave version number is already embedded in the
268  // octave_archlibdir directory name so we don't need to append it to
269  // the octave-gui filename.
270 
271  std::string file = octave_gui;
272 #else
273  std::string file = octave_cli;
274 #endif
275 
276  // Declaring new_argv static avoids leak warnings when using GCC's
277  // --address-sanitizer option.
278  static char **new_argv = new char * [argc + 2];
279 
280  int next_optind = 1;
281  int k = 1;
282 
283  bool warn_display = true;
284  bool no_display = false;
285 
286  // Disable error reporting in getopt. We want to silently recognize
287  // and process a few special arguments here and pass everything on to
288  // the real Octave program where incorrect usage errors may be
289  // reported.
290 
292 
293  while (true)
294  {
295  int long_idx;
296 
297  int optc = octave_getopt_long_wrapper (argc, argv, short_opts, long_opts,
298  &long_idx);
299  int old_optind = next_optind;
300  next_optind = octave_optind_wrapper ();
301 
302  if (optc < 0)
303  break;
304 
305  switch (optc)
306  {
307  case NO_GUI_LIBS_OPTION:
308  // Run the version of Octave that is not linked with any GUI
309  // libraries. It may not be possible to do plotting or any ui*
310  // calls, but it will be a little faster to start and require less
311  // memory. Don't pass the --no-gui-libs option on as that option
312  // is not recognized by Octave.
313  gui_libs = false;
314  file = octave_cli;
315  break;
316 
317  case NO_GUI_OPTION:
318  // If we see this option, then we can just exec octave; we don't
319  // have to create a child process and wait for it to exit. But do
320  // exec "octave-gui", not "octave-cli", because even if the
321  // --no-gui option is given, we may be asked to do some plotting or
322  // ui* calls.
323  start_gui = false;
324  new_argv[k++] = argv[old_optind];
325  break;
326 
327  case GUI_OPTION:
328  // If we see this option, then we fork and exec octave with the
329  // --gui option, while continuing to handle signals in the
330  // terminal.
331  // Do not copy the arg now, since we still not know if the gui
332  // should really be launched. Just store the index.
333  start_gui = true;
334  idx_gui = old_optind;
335  break;
336 
338  // If we see this option, then we don't fork and exec.
339  fork_and_exec = false;
340  new_argv[k++] = argv[old_optind];
341  break;
342 
343  case PERSIST_OPTION:
344  // FIXME: How can we reliably detect if this option appears after
345  // a FILE argument. In this case octave ignores the option,
346  // but the GUI might still be launched if --gui is also
347  // given.
348  persist_octave = true;
349  new_argv[k++] = argv[old_optind];
350  break;
351 
352  case SERVER_OPTION:
353  server = true;
354  new_argv[k++] = argv[old_optind];
355  break;
356 
357  case EVAL_OPTION:
358  eval_code = true;
359  for (int i = old_optind; i < next_optind; i++)
360  new_argv[k++] = argv[i];
361  break;
362 
363  case 'q':
364  // options "--silent" or "--quiet"
365  warn_display = false;
366  new_argv[k++] = argv[old_optind];
367  break;
368 
369  case 'W':
370  // option "--no-window-system"
371  no_display = true;
372  new_argv[k++] = argv[old_optind];
373  break;
374 
375  default:
376  for (int i = old_optind; i < next_optind; i++)
377  new_argv[k++] = argv[i];
378  break;
379  }
380  }
381 
382  // Treat trailing arguments as commands to be executed
383  if (next_optind < argc)
384  {
385  eval_code = true;
386  for (int i = next_optind; i < argc; i++)
387  new_argv[k++] = argv[i];
388  }
389 
390  if (start_gui && eval_code && ! persist_octave)
391  start_gui = false;
392 
393  // At this point, we definitely know whether the gui has to
394  // be launched or not.
395  // gui_libs and start_gui are just about options, not
396  // the environment. Exit if they don't make sense.
397  if (start_gui)
398  {
399  // GUI should be started
400  if (! gui_libs)
401  {
402  std::cerr << "octave: conflicting options: --no-gui-libs and --gui"
403  << std::endl;
404  return 1;
405  }
406 
407  if (server)
408  {
409  std::cerr << "octave: conflicting options: --server and --gui"
410  << std::endl;
411  return 1;
412  }
413 
414 #if ! defined (HAVE_OCTAVE_QT_GUI)
415  std::cerr << "octave: GUI features missing or disabled in this build"
416  << std::endl;
417  return 1;
418 #endif
419 
420  // Finally, add --gui to the command line options. We can not
421  // just append it since options after a given file are ignored.
422  for (int j = k; j > 1; j--)
423  new_argv[j] = new_argv[j-1];
424 
425  new_argv[1] = argv[idx_gui];
426  k++;
427  }
428 
429  new_argv[k] = nullptr;
430 
431  if (no_display)
432  {
433  start_gui = false;
434  gui_libs = false;
435 
436  file = octave_cli;
437  }
438  else if (gui_libs || start_gui)
439  {
440  int dpy_avail;
441 
442  const char *display_check_err_msg = display_available (&dpy_avail);
443 
444  if (! dpy_avail)
445  {
446  start_gui = false;
447  gui_libs = false;
448 
449  file = octave_cli;
450 
451  if (warn_display)
452  {
453  if (! display_check_err_msg)
454  display_check_err_msg = "graphical display unavailable";
455 
456  std::cerr << "octave: " << display_check_err_msg << std::endl;
457  std::cerr << "octave: disabling GUI features" << std::endl;
458  }
459  }
460  }
461 
462 #if defined (OCTAVE_USE_WINDOWS_API)
463  file += ".exe";
464 #endif
465 
466  new_argv[0] = strsave (file.c_str ());
467 
468  // The Octave interpreter may be multithreaded. If so, we attempt to
469  // ensure that signals are delivered to the main interpreter thread
470  // and no others by blocking signals before we exec the Octave
471  // interpreter executable. When that process starts, it will unblock
472  // signals in the main interpreter thread. When running the GUI as a
473  // subprocess, we also unblock signals that the parent process handles
474  // so we can forward them to the child.
475 
477  octave_block_signal_by_name ("SIGTSTP");
478 
479  if (fork_and_exec && gui_libs && start_gui)
480  {
481  // Fork and exec when starting the GUI so that we will call
482  // setsid to give up the controlling terminal (if any) and so that
483  // the GUI process will be in a separate process group.
484  //
485  // The GUI process must be in a separate process group so that we
486  // can send an interrupt signal to all child processes when
487  // interrupting the interpreter. See also bug #49609 and the
488  // function pthread_thread_manager::interrupt in the file
489  // libgui/src/thread-manager.cc.
490 
491  gui_pid = octave_fork_wrapper ();
492 
493  if (gui_pid < 0)
494  {
495  std::cerr << "octave: fork failed!" << std::endl;
496 
497  retval = 1;
498  }
499  else if (gui_pid == 0)
500  {
501  // Child.
502 
503  if (octave_setsid_wrapper () < 0)
504  {
505  std::cerr << "octave: error calling setsid!" << std::endl;
506 
507  retval = 1;
508  }
509  else
510  retval = octave_exec (file, new_argv);
511  }
512  else
513  {
514  // Parent. Forward signals to child while waiting for it to exit.
515 
516  install_signal_handlers ();
517 
519  octave_unblock_signal_by_name ("SIGTSTP");
520 
521  int status;
522 
523  while (true)
524  {
525  octave_waitpid_wrapper (gui_pid, &status, 0);
526 
527  if (caught_signal > 0)
528  {
529  int sig = caught_signal;
530 
531  caught_signal = -1;
532 
533  octave_kill_wrapper (gui_pid, sig);
534  }
535  else if (octave_wifexited_wrapper (status))
536  {
537  retval = octave_wexitstatus_wrapper (status);
538  break;
539  }
540  else if (octave_wifsignaled_wrapper (status))
541  {
542  std::cerr << "octave exited with signal "
543  << octave_wtermsig_wrapper (status) << std::endl;
544  break;
545  }
546  }
547  }
548  }
549  else
550  {
551  retval = octave_exec (file, new_argv);
552 
553  if (retval < 0)
554  std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
555  }
556 
557 
558  return retval;
559 }
void octave_unblock_async_signals()
void octave_block_async_signals()
std::string prepend_octave_exec_home(const std::string &s)
const char * display_available(int *dpy_avail)
char dir_sep_char()
int octave_getopt_long_wrapper(int argc, char **argv, const char *shortopts, const struct octave_getopt_options *longopts, int *longind)
int octave_optind_wrapper(void)
int octave_set_opterr_wrapper(int val)
#define OCTAVE_BINDIR
Definition: main.in.cc:71
#define OCTAVE_ARCHLIBDIR
Definition: main.in.cc:67
int main(int argc, char **argv)
Definition: main.in.cc:245
#define OCTAVE_VERSION
Definition: main.in.cc:63
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:88
#define NO_GUI_OPTION
Definition: options.h:50
#define NO_GUI_LIBS_OPTION
Definition: options.h:51
#define SERVER_OPTION
Definition: options.h:57
#define GUI_OPTION
Definition: options.h:45
#define EXPERIMENTAL_TERMINAL_WIDGET_OPTION
Definition: options.h:44
struct octave_getopt_options long_opts[]
Definition: options.h:60
#define PERSIST_OPTION
Definition: options.h:56
#define EVAL_OPTION
Definition: options.h:42
void octave_block_signal_by_name(const char *signame)
void octave_unblock_signal_by_name(const char *signame)
int octave_kill_wrapper(pid_t pid, int signum)
octave_sig_handler * octave_set_signal_handler_by_name(const char *signame, octave_sig_handler *handler, bool restart_syscalls)
void octave_sig_handler(int)
pid_t octave_setsid_wrapper(void)
pid_t octave_fork_wrapper(void)
int octave_execv_wrapper(const char *file, char *const *argv)
pid_t octave_waitpid_wrapper(pid_t pid, int *statusp, int options)
Definition: wait-wrappers.c:61
bool octave_wifsignaled_wrapper(int status)
int octave_wexitstatus_wrapper(int status)
bool octave_wifexited_wrapper(int status)
int octave_wtermsig_wrapper(int status)
F77_RET_T len
Definition: xerbla.cc:61