GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
main.in.cc
Go to the documentation of this file.
1// %NO_EDIT_WARNING%
2
3////////////////////////////////////////////////////////////////////////
4//
5// Copyright (C) 2012-2025 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
100gui_driver_sig_handler (int sig)
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
114install_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
171static std::string
172get_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
185static std::string
186get_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
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
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 {
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 'G':
318 // option "--no-gui"
319 // If we see this option, then we can just exec octave; we don't
320 // have to create a child process and wait for it to exit. But do
321 // exec "octave-gui", not "octave-cli", because even if the
322 // --no-gui option is given, we may be asked to do some plotting or
323 // ui* calls.
324 start_gui = false;
325 new_argv[k++] = argv[old_optind];
326 break;
327
328 case 'g':
329 // option "--gui"
330 // If we see this option, then we fork and exec octave with the
331 // --gui option, while continuing to handle signals in the terminal.
332 // Do not copy the arg now, since we still not know if the gui
333 // should really be launched. Just store the index.
334 start_gui = true;
335 idx_gui = old_optind;
336 break;
337
339 // If we see this option, then we don't fork and exec.
340 fork_and_exec = false;
341 new_argv[k++] = argv[old_optind];
342 break;
343
344 case PERSIST_OPTION:
345 // FIXME: How can we reliably detect if this option appears after
346 // a FILE argument. In this case octave ignores the option,
347 // but the GUI might still be launched if --gui is also
348 // given.
349 persist_octave = true;
350 new_argv[k++] = argv[old_optind];
351 break;
352
353 case SERVER_OPTION:
354 server = true;
355 new_argv[k++] = argv[old_optind];
356 break;
357
358 case 'e':
359 // option "--eval"
360 eval_code = true;
361 for (int i = old_optind; i < next_optind; i++)
362 new_argv[k++] = argv[i];
363 break;
364
365 case 'q':
366 // options "--quiet" or "--silent"
367 warn_display = false;
368 new_argv[k++] = argv[old_optind];
369 break;
370
371 case 'W':
372 // option "--no-window-system"
373 no_display = true;
374 new_argv[k++] = argv[old_optind];
375 break;
376
377 default:
378 for (int i = old_optind; i < next_optind; i++)
379 new_argv[k++] = argv[i];
380 break;
381 }
382 }
383
384 // Treat trailing arguments as commands to be executed
385 if (next_optind < argc)
386 {
387 eval_code = true;
388 for (int i = next_optind; i < argc; i++)
389 new_argv[k++] = argv[i];
390 }
391
392 if (start_gui && eval_code && ! persist_octave)
393 start_gui = false;
394
395 // At this point, we definitely know whether the gui has to
396 // be launched or not.
397 // gui_libs and start_gui are just about options, not
398 // the environment. Exit if they don't make sense.
399 if (start_gui)
400 {
401 // GUI should be started
402 if (! gui_libs)
403 {
404 std::cerr << "octave: conflicting options: --no-gui-libs and --gui"
405 << std::endl;
406 return 1;
407 }
408
409 if (server)
410 {
411 std::cerr << "octave: conflicting options: --server and --gui"
412 << std::endl;
413 return 1;
414 }
415
416#if ! defined (HAVE_OCTAVE_QT_GUI)
417 std::cerr << "octave: GUI features missing or disabled in this build"
418 << std::endl;
419 return 1;
420#endif
421
422 // Finally, add --gui to the command line options. We can not
423 // just append it since options after a given file are ignored.
424 for (int j = k; j > 1; j--)
425 new_argv[j] = new_argv[j-1];
426
427 new_argv[1] = argv[idx_gui];
428 k++;
429 }
430
431 new_argv[k] = nullptr;
432
433 if (no_display)
434 {
435 start_gui = false;
436 gui_libs = false;
437
438 file = octave_cli;
439 }
440 else if (gui_libs || start_gui)
441 {
442 int dpy_avail;
443
444 const char *display_check_err_msg = display_available (&dpy_avail);
445
446 if (! dpy_avail)
447 {
448 start_gui = false;
449 gui_libs = false;
450
451 file = octave_cli;
452
453 if (warn_display)
454 {
455 if (! display_check_err_msg)
456 display_check_err_msg = "graphical display unavailable";
457
458 std::cerr << "octave: " << display_check_err_msg << std::endl;
459 std::cerr << "octave: disabling GUI features" << std::endl;
460 }
461 }
462 }
463
464#if defined (OCTAVE_USE_WINDOWS_API)
465 file += ".exe";
466#endif
467
468 new_argv[0] = strsave (file.c_str ());
469
470 // The Octave interpreter may be multithreaded. If so, we attempt to
471 // ensure that signals are delivered to the main interpreter thread
472 // and no others by blocking signals before we exec the Octave
473 // interpreter executable. When that process starts, it will unblock
474 // signals in the main interpreter thread. When running the GUI as a
475 // subprocess, we also unblock signals that the parent process handles
476 // so we can forward them to the child.
477
479 octave_block_signal_by_name ("SIGTSTP");
480
481 if (fork_and_exec && gui_libs && start_gui)
482 {
483 // Fork and exec when starting the GUI so that we will call
484 // setsid to give up the controlling terminal (if any) and so that
485 // the GUI process will be in a separate process group.
486 //
487 // The GUI process must be in a separate process group so that we
488 // can send an interrupt signal to all child processes when
489 // interrupting the interpreter. See also bug #49609 and the
490 // function pthread_thread_manager::interrupt in the file
491 // libgui/src/thread-manager.cc.
492
493 gui_pid = octave_fork_wrapper ();
494
495 if (gui_pid < 0)
496 {
497 std::cerr << "octave: fork failed!" << std::endl;
498
499 retval = 1;
500 }
501 else if (gui_pid == 0)
502 {
503 // Child.
504
505 if (octave_setsid_wrapper () < 0)
506 {
507 std::cerr << "octave: error calling setsid!" << std::endl;
508
509 retval = 1;
510 }
511 else
512 retval = octave_exec (file, new_argv);
513 }
514 else
515 {
516 // Parent. Forward signals to child while waiting for it to exit.
517
518 install_signal_handlers ();
519
522
523 int status;
524
525 while (true)
526 {
527 octave_waitpid_wrapper (gui_pid, &status, 0);
528
529 if (caught_signal > 0)
530 {
531 int sig = caught_signal;
532
533 caught_signal = -1;
534
535 octave_kill_wrapper (gui_pid, sig);
536 }
537 else if (octave_wifexited_wrapper (status))
538 {
539 retval = octave_wexitstatus_wrapper (status);
540 break;
541 }
542 else if (octave_wifsignaled_wrapper (status))
543 {
544 std::cerr << "octave exited with signal "
545 << octave_wtermsig_wrapper (status) << std::endl;
546 break;
547 }
548 }
549 }
550 }
551 else
552 {
553 retval = octave_exec (file, new_argv);
554
555 if (retval < 0)
556 std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
557 }
558
559
560 return retval;
561}
void octave_unblock_async_signals()
void octave_block_async_signals()
program main
std::string prepend_octave_exec_home(const std::string &s)
Definition defaults.cc:136
const char * display_available(int *dpy_avail)
char dir_sep_char()
Definition file-ops.cc:232
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
#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_LIBS_OPTION
Definition options.h:48
#define SERVER_OPTION
Definition options.h:54
#define EXPERIMENTAL_TERMINAL_WIDGET_OPTION
Definition options.h:43
struct octave_getopt_options long_opts[]
Definition options.h:57
#define PERSIST_OPTION
Definition options.h:53
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)
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