GNU Octave 7.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-2022 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)
87static bool fork_and_exec = true;
88#else
89static 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
95static pid_t gui_pid = 0;
96
97static int caught_signal = -1;
98
99static void
101{
102 if (gui_pid > 0)
103 caught_signal = sig;
104}
105
106static void
107gui_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
113static void
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
125
126 // SIGCHLD
127 // SIGCLD
128 // SIGCONT
129
134
135 // SIGINFO
136 // SIGINT
137
142
143 // SIGPROF
144 // SIGPWR
145
148
149 // SIGSTOP
150
154
155 // SIGTSTP
156 // SIGTTIN
157 // SIGTTOU
158 // SIGURG
159
164
165 // SIGWINCH
166
169}
170
171static std::string
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
185static std::string
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
199static int
200octave_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
213static char *
214strsave (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)
226extern "C"
227int
228wmain (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
244int
245main (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
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 {
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
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
517
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
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}
const char * display_available(int *dpy_avail)
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
static pid_t gui_pid
Definition: main.in.cc:95
#define OCTAVE_ARCHLIBDIR
Definition: main.in.cc:67
static char * strsave(const char *s)
Definition: main.in.cc:214
static bool fork_and_exec
Definition: main.in.cc:89
static void gui_driver_set_signal_handler(const char *signame, octave_sig_handler *handler)
Definition: main.in.cc:107
static void gui_driver_sig_handler(int sig)
Definition: main.in.cc:100
static std::string get_octave_archlibdir(void)
Definition: main.in.cc:186
int main(int argc, char **argv)
Definition: main.in.cc:245
#define OCTAVE_VERSION
Definition: main.in.cc:63
static void install_signal_handlers(void)
Definition: main.in.cc:114
static int caught_signal
Definition: main.in.cc:97
static int octave_exec(const std::string &file, char **argv)
Definition: main.in.cc:200
static std::string get_octave_bindir(void)
Definition: main.in.cc:172
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:85
#define NO_GUI_OPTION
Definition: options.h:50
static const char * short_opts
Definition: options.h:36
#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
static void set_octave_home(void)
Definition: shared-fcns.h:111
static std::string prepend_octave_exec_home(const std::string &s)
Definition: shared-fcns.h:195
static const char dir_sep_char
Definition: shared-fcns.h:90
static std::string octave_getenv(const std::string &name)
Definition: shared-fcns.h:100
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)
void octave_unblock_async_signals(void)
octave_sig_handler * octave_set_signal_handler_by_name(const char *signame, octave_sig_handler *handler, bool restart_syscalls)
void octave_block_async_signals(void)
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