1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1995-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 #  include "config.h"
28 #endif
29 
30 #include <cerrno>
31 #include <cstdlib>
32 
33 #include <new>
34 #include <sstream>
35 #include <string>
36 
37 #if defined (OCTAVE_USE_WINDOWS_API)
38 #  define WIN32_LEAN_AND_MEAN 1
39 #  include <windows.h>
40 #endif
41 
42 #include "async-system-wrapper.h"
43 #include "child-list.h"
44 #include "lo-error.h"
45 #include "oct-fftw.h"
46 #include "oct-locbuf.h"
47 #include "oct-syscalls.h"
48 #include "signal-wrappers.h"
49 #include "str-vec.h"
50 #include "wait-for-input.h"
51 
52 #include "build-env.h"
53 #include "liboctinterp-build-info.h"
54 #include "defaults.h"
55 #include "defun.h"
56 #include "error.h"
57 #include "file-io.h"
58 #include "help.h"
59 #include "interpreter-private.h"
60 #include "octave.h"
61 #include "oct-map.h"
62 #include "ovl.h"
63 #include "ov.h"
64 #include "pager.h"
65 #include "procstream.h"
66 #include "sysdep.h"
67 #include "unwind-prot.h"
68 #include "utils.h"
69 #include "version.h"
70 
71 #if ! defined (SHELL_PATH)
72 #  define SHELL_PATH "/bin/sh"
73 #endif
74 
75 DEFUN (warranty, , ,
76        doc: /* -*- texinfo -*-
77 @deftypefn {} {} warranty ()
78 Describe the conditions for copying and distributing Octave.
79 @end deftypefn */)
80 {
81   octave_stdout << "\n" << octave_name_version_and_copyright () << "\n\
82 \n\
83 GNU Octave is free software: you can redistribute it and/or modify it\n\
84 under the terms of the GNU General Public License as published by\n\
85 the Free Software Foundation, either version 3 of the License, or\n\
86 (at your option) any later version.\n\
87 \n\
88 GNU Octave is distributed in the hope that it will be useful, but\n\
89 WITHOUT ANY WARRANTY; without even the implied warranty of\n\
90 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
91 GNU General Public License for more details.\n\
92 \n\
93 You should have received a copy of the GNU General Public License\n\
94 along with GNU Octave; see the file COPYING.  If not, see\n\
95 <https://www.gnu.org/licenses/>.\n\
96 \n";
97 
98   return ovl ();
99 }
100 
101 // Execute a shell command.
102 
103 static octave_value_list
run_command_and_return_output(const std::string & cmd_str)104 run_command_and_return_output (const std::string& cmd_str)
105 {
106   octave_value_list retval;
107   octave::unwind_protect frame;
108 
109   iprocstream *cmd = new iprocstream (cmd_str.c_str ());
110   frame.add_delete (cmd);
111 
112   octave::child_list& kids
113     = octave::__get_child_list__ ("run_command_and_return_output");
114   frame.add_method (kids, &octave::child_list::remove, cmd->pid ());
115 
116   if (! *cmd)
117     error ("system: unable to start subprocess for '%s'", cmd_str.c_str ());
118 
119   int fid = cmd->file_number ();
120 
121   std::ostringstream output_buf;
122 
123   char ch;
124 
125   for (;;)
126     {
127       if (cmd->get (ch))
128         output_buf.put (ch);
129       else
130         {
131           if (! cmd->eof () && errno == EAGAIN)
132             {
133               cmd->clear ();
134 
135               if (octave_wait_for_input (fid) != 1)
136                 break;
137             }
138           else
139             break;
140         }
141     }
142 
143   int cmd_status = cmd->close ();
144 
145   if (octave::sys::wifexited (cmd_status))
146     cmd_status = octave::sys::wexitstatus (cmd_status);
147   else
148     cmd_status = 127;
149 
150   retval = ovl (cmd_status, output_buf.str ());
151 
152   return retval;
153 }
154 
155 // Combine alloc+get in one action.
156 
157 static void *
get_signal_mask(void)158 get_signal_mask (void)
159 {
160   void *mask = octave_alloc_signal_mask ();
161 
162   octave_get_signal_mask (mask);
163 
164   return mask;
165 }
166 
167 // Combine set+free in one action.
168 
169 static void
restore_signal_mask(void * mask)170 restore_signal_mask (void *mask)
171 {
172   octave_set_signal_mask (mask);
173 
174   octave_free_signal_mask (mask);
175 }
176 
177 enum system_exec_type { et_sync, et_async };
178 
179 DEFUN (system, args, nargout,
180        doc: /* -*- texinfo -*-
181 @deftypefn  {} {} system ("@var{string}")
182 @deftypefnx {} {} system ("@var{string}", @var{return_output})
183 @deftypefnx {} {} system ("@var{string}", @var{return_output}, @var{type})
184 @deftypefnx {} {[@var{status}, @var{output}] =} system (@dots{})
185 Execute a shell command specified by @var{string}.
186 
187 If @var{system} is called with one or more output arguments, or if the optional
188 argument @var{return_output} is true and the subprocess is started
189 synchronously, then the output from the command is returned as a variable.
190 Otherwise, if the subprocess is executed synchronously, its output is sent to
191 the standard output.  To send the output of a command executed with
192 @code{system} through the pager, use a command like
193 
194 @example
195 @group
196 [~, text] = system ("cmd");
197 more on;
198 disp (text);
199 @end group
200 @end example
201 
202 @noindent
203 or
204 
205 @example
206 @group
207 more on;
208 printf ("%s\n", nthargout (2, "system", "cmd"));
209 @end group
210 @end example
211 
212 If the optional argument @var{type} is @qcode{"async"}, the process is started
213 in the background and the process ID of the child process is returned
214 immediately.  Otherwise, the child process is started and Octave waits until it
215 exits.  If the @var{type} argument is omitted, it defaults to the value
216 @qcode{"sync"}.
217 
218 The @code{system} function can return two values.  The first is the exit status
219 of the command and the second is any output from the command that was written
220 to the standard output stream.  For example,
221 
222 @example
223 [status, output] = system ("echo foo & exit 2");
224 @end example
225 
226 @noindent
227 will set the variable @var{output} to the string @samp{foo}, and the variable
228 @var{status} to the integer @samp{2}.
229 
230 For commands run asynchronously, @var{status} is the process id of the command
231 shell that is started to run the command.
232 
233 The shell used for executing commands varies with operating system and is
234 typically @file{/bin/sh} for UNIX systems and @nospell{@file{cmd.exe}} for
235 Windows systems.
236 @seealso{unix, dos}
237 @end deftypefn */)
238 {
239   int nargin = args.length ();
240 
241   if (nargin == 0 || nargin > 3)
242     print_usage ();
243 
244   system_exec_type type = et_sync;
245   if (nargin == 3)
246     {
247       std::string type_str = args(2).xstring_value ("system: TYPE must be a string");
248 
249       if (type_str == "sync")
250         type = et_sync;
251       else if (type_str == "async")
252         type = et_async;
253       else
254         error (R"(system: TYPE must be "sync" or "async")");
255     }
256 
257   octave_value_list retval;
258 
259   bool return_output = (nargin == 1 && nargout > 1);
260 
261   if (nargin > 1)
262     {
263       try
264         {
265           return_output = args(1).is_true ();
266         }
267       catch (octave::execution_exception& e)
268         {
269           error (e, "system: RETURN_OUTPUT must be boolean value true or false");
270         }
271     }
272 
273   if (return_output && type == et_async)
274     error ("system: can't return output from commands run asynchronously");
275 
276   std::string cmd_str = args(0).xstring_value ("system: first argument must be a string");
277 
278 #if defined (OCTAVE_USE_WINDOWS_API)
279   // Work around weird double-quote handling on Windows systems.
280   if (type == et_sync)
281     cmd_str = '"' + cmd_str + '"';
282 #endif
283 
284   octave::unwind_protect frame;
285 
286   frame.add_fcn (restore_signal_mask, get_signal_mask ());
287 
288   octave_unblock_async_signals ();
289   octave_unblock_signal_by_name ("SIGTSTP");
290 
291   if (type == et_async)
292     retval(0) = octave_async_system_wrapper (cmd_str.c_str ());
293   else if (return_output)
294     retval = run_command_and_return_output (cmd_str);
295   else
296     {
297       int status = system (cmd_str.c_str ());
298 
299       // The value in status is as returned by waitpid.  If
300       // the process exited normally, extract the actual exit
301       // status of the command.  Otherwise, return 127 as a
302       // failure code.
303 
304       if (octave::sys::wifexited (status))
305         status = octave::sys::wexitstatus (status);
306 
307       retval(0) = status;
308     }
309 
310   return retval;
311 }
312 
313 /*
314 %!test
315 %! cmd = ls_command ();
316 %! [status, output] = system (cmd);
317 %! assert (status, 0);
318 %! assert (ischar (output));
319 %! assert (! isempty (output));
320 
321 %!error system ()
322 %!error system (1, 2, 3)
323 */
324 
325 static octave_value
find_config_info(const octave_scalar_map & m,const std::string & key)326 find_config_info (const octave_scalar_map& m, const std::string& key)
327 {
328   if (m.isfield (key))
329     {
330       Cell c = m.contents (key);
331 
332       if (! c.isempty ())
333         return c(0);
334     }
335 
336   return octave_value ();
337 }
338 
339 DEFUN (__octave_config_info__, args, ,
340        doc: /* -*- texinfo -*-
341 @deftypefn  {} {} __octave_config_info__ ()
342 @deftypefnx {} {} __octave_config_info__ (@var{option})
343 Return a structure containing configuration and installation information for
344 Octave.
345 
346 If @var{option} is a string, return the configuration information for the
347 specified option.
348 
349 @seealso{computer}
350 @end deftypefn */)
351 {
352   static octave_scalar_map config;
353   static octave_scalar_map build_env;
354   static octave_scalar_map build_features;
355 
356   static bool initialized = false;
357 
358   if (! initialized)
359     {
360       std::map<std::string, octave_value> conf_info_map
361         = {{ "DEFAULT_PAGER", octave::config::default_pager () },
362 
363 #if defined (OCTAVE_ENABLE_64)
364            { "ENABLE_64", true },
365 #else
366            { "ENABLE_64", false },
367 #endif
368 
369 #if defined (OCTAVE_ENABLE_COMMAND_LINE_PUSH_PARSER)
370            { "ENABLE_COMMAND_LINE_PUSH_PARSER", true },
371 #else
372            { "ENABLE_COMMAND_LINE_PUSH_PARSER", false },
373 #endif
374 
375 #if defined (ENABLE_DOCS)
376            { "ENABLE_DOCS", true },
377 #else
378            { "ENABLE_DOCS", false },
379 #endif
380 
381 #if defined (OCTAVE_ENABLE_FLOAT_TRUNCATE)
382            { "ENABLE_FLOAT_TRUNCATE", true },
383 #else
384            { "ENABLE_FLOAT_TRUNCATE", false },
385 #endif
386 
387 #if defined (ENABLE_JIT)
388            { "ENABLE_JIT", true },
389 #else
390            { "ENABLE_JIT", false },
391 #endif
392 
393 #if defined (OCTAVE_ENABLE_OPENMP)
394            { "ENABLE_OPENMP", true },
395 #else
396            { "ENABLE_OPENMP", false },
397 #endif
398 
399            { "api_version", OCTAVE_API_VERSION },
400            { "archlibdir", octave::config::arch_lib_dir () },
401            { "bindir", octave::config::bin_dir () },
402            { "canonical_host_type", octave::config::canonical_host_type () },
403            { "datadir", octave::config::data_dir () },
404            { "datarootdir", octave::config::dataroot_dir () },
405            { "fcnfiledir", octave::config::fcn_file_dir () },
406            { "fftw_version", octave::fftw_version () },
407            { "fftwf_version", octave::fftwf_version () },
408            { "imagedir", octave::config::image_dir () },
409            { "includedir", octave::config::include_dir () },
410            { "infodir", octave::config::info_dir () },
411            { "libdir", octave::config::lib_dir () },
412            { "libexecdir", octave::config::libexec_dir () },
413            // Each library and executable has its own definition of the hg
414            // id.  We check for consistency when Octave starts so we just
415            // store and report one of them here.
416            { "hg_id", liboctinterp_hg_id () },
417            { "localapiarchlibdir", octave::config::local_api_arch_lib_dir () },
418            { "localapifcnfiledir", octave::config::local_api_fcn_file_dir () },
419            { "localapioctfiledir", octave::config::local_api_oct_file_dir () },
420            { "localarchlibdir", octave::config::local_arch_lib_dir () },
421            { "localfcnfiledir", octave::config::local_fcn_file_dir () },
422            { "localoctfiledir", octave::config::local_oct_file_dir () },
423            { "localstartupfiledir", octave::config::local_startupfile_dir () },
424            { "localverarchlibdir", octave::config::local_ver_arch_lib_dir () },
425            { "localverfcnfiledir", octave::config::local_ver_fcn_file_dir () },
426            { "localveroctfiledir", octave::config::local_ver_oct_file_dir () },
427            { "man1dir", octave::config::man1_dir () },
428            { "man1ext", octave::config::man1_ext () },
429            { "mandir", octave::config::man_dir () },
430            { "octdatadir", octave::config::oct_data_dir () },
431            { "octdocdir", octave::config::oct_doc_dir () },
432            { "octetcdir", octave::config::oct_etc_dir () },
433            { "octfiledir", octave::config::oct_file_dir () },
434            { "octfontsdir", octave::config::oct_fonts_dir () },
435            { "octincludedir", octave::config::oct_include_dir () },
436            { "octlibdir", octave::config::oct_lib_dir () },
437            { "octtestsdir", octave::config::oct_tests_dir () },
438            { "release_date", OCTAVE_RELEASE_DATE },
439            { "startupfiledir", octave::config::startupfile_dir () },
440            { "version", OCTAVE_VERSION }};
441 
442       std::map<std::string, octave_value> build_env_map
443         = {{ "AMD_CPPFLAGS", octave::build_env::AMD_CPPFLAGS },
444            { "AMD_LDFLAGS", octave::build_env::AMD_LDFLAGS },
445            { "AMD_LIBS", octave::build_env::AMD_LIBS },
446            { "AR", octave::build_env::AR },
447            { "ARFLAGS", octave::build_env::ARFLAGS },
448            { "ARPACK_CPPFLAGS", octave::build_env::ARPACK_CPPFLAGS },
449            { "ARPACK_LDFLAGS", octave::build_env::ARPACK_LDFLAGS },
450            { "ARPACK_LIBS", octave::build_env::ARPACK_LIBS },
451            { "BLAS_LIBS", octave::build_env::BLAS_LIBS },
452            { "CAMD_CPPFLAGS", octave::build_env::CAMD_CPPFLAGS },
453            { "CAMD_LDFLAGS", octave::build_env::CAMD_LDFLAGS },
454            { "CAMD_LIBS", octave::build_env::CAMD_LIBS },
455            { "CARBON_LIBS", octave::build_env::CARBON_LIBS },
456            { "CC", octave::build_env::CC },
457            { "CCOLAMD_CPPFLAGS", octave::build_env::CCOLAMD_CPPFLAGS },
458            { "CCOLAMD_LDFLAGS", octave::build_env::CCOLAMD_LDFLAGS },
459            { "CCOLAMD_LIBS", octave::build_env::CCOLAMD_LIBS },
460            { "CFLAGS", octave::build_env::CFLAGS },
461            { "CHOLMOD_CPPFLAGS", octave::build_env::CHOLMOD_CPPFLAGS },
462            { "CHOLMOD_LDFLAGS", octave::build_env::CHOLMOD_LDFLAGS },
463            { "CHOLMOD_LIBS", octave::build_env::CHOLMOD_LIBS },
464            { "COLAMD_CPPFLAGS", octave::build_env::COLAMD_CPPFLAGS },
465            { "COLAMD_LDFLAGS", octave::build_env::COLAMD_LDFLAGS },
466            { "COLAMD_LIBS", octave::build_env::COLAMD_LIBS },
467            { "CPICFLAG", octave::build_env::CPICFLAG },
468            { "CPPFLAGS", octave::build_env::CPPFLAGS },
469            { "CURL_CPPFLAGS", octave::build_env::CURL_CPPFLAGS },
470            { "CURL_LDFLAGS", octave::build_env::CURL_LDFLAGS },
471            { "CURL_LIBS", octave::build_env::CURL_LIBS },
472            { "CXSPARSE_CPPFLAGS", octave::build_env::CXSPARSE_CPPFLAGS },
473            { "CXSPARSE_LDFLAGS", octave::build_env::CXSPARSE_LDFLAGS },
474            { "CXSPARSE_LIBS", octave::build_env::CXSPARSE_LIBS },
475            { "CXX", octave::build_env::CXX },
476            { "CXXCPP", octave::build_env::CXXCPP },
477            { "CXXFLAGS", octave::build_env::CXXFLAGS },
478            { "CXXPICFLAG", octave::build_env::CXXPICFLAG },
479            { "DEFS", octave::build_env::DEFS },
480            { "DL_LDFLAGS", octave::build_env::DL_LDFLAGS },
481            { "GCC_VERSION", octave::build_env::GCC_VERSION },
482            { "GXX_VERSION", octave::build_env::GXX_VERSION },
483            { "EXEEXT", octave::build_env::EXEEXT },
484            { "F77", octave::build_env::F77 },
485            { "F77_FLOAT_STORE_FLAG", octave::build_env::F77_FLOAT_STORE_FLAG },
486            { "F77_INTEGER_8_FLAG", octave::build_env::F77_INTEGER_8_FLAG },
487            { "FFLAGS", octave::build_env::FFLAGS },
488            { "FFTW3_CPPFLAGS", octave::build_env::FFTW3_CPPFLAGS },
489            { "FFTW3_LDFLAGS", octave::build_env::FFTW3_LDFLAGS },
490            { "FFTW3_LIBS", octave::build_env::FFTW3_LIBS },
491            { "FFTW3F_CPPFLAGS", octave::build_env::FFTW3F_CPPFLAGS },
492            { "FFTW3F_LDFLAGS", octave::build_env::FFTW3F_LDFLAGS },
493            { "FFTW3F_LIBS", octave::build_env::FFTW3F_LIBS },
494            { "FLIBS", octave::build_env::FLIBS },
495            { "FLTK_CPPFLAGS", octave::build_env::FLTK_CPPFLAGS },
496            { "FLTK_LDFLAGS", octave::build_env::FLTK_LDFLAGS },
497            { "FLTK_LIBS", octave::build_env::FLTK_LIBS },
498            { "FONTCONFIG_CPPFLAGS", octave::build_env::FONTCONFIG_CPPFLAGS },
499            { "FONTCONFIG_LIBS", octave::build_env::FONTCONFIG_LIBS },
500            { "FPICFLAG", octave::build_env::FPICFLAG },
501            { "FT2_CPPFLAGS", octave::build_env::FT2_CPPFLAGS },
502            { "FT2_LIBS", octave::build_env::FT2_LIBS },
503            { "GLPK_CPPFLAGS", octave::build_env::GLPK_CPPFLAGS },
504            { "GLPK_LDFLAGS", octave::build_env::GLPK_LDFLAGS },
505            { "GLPK_LIBS", octave::build_env::GLPK_LIBS },
506            { "GNUPLOT", octave::build_env::GNUPLOT },
507            { "HDF5_CPPFLAGS", octave::build_env::HDF5_CPPFLAGS },
508            { "HDF5_LDFLAGS", octave::build_env::HDF5_LDFLAGS },
509            { "HDF5_LIBS", octave::build_env::HDF5_LIBS },
510            { "LAPACK_LIBS", octave::build_env::LAPACK_LIBS },
511            { "LDFLAGS", octave::build_env::LDFLAGS },
512            { "LD_STATIC_FLAG", octave::build_env::LD_STATIC_FLAG },
513            { "LEX", octave::build_env::LEX },
514            { "LEXLIB", octave::build_env::LEXLIB },
515            { "LFLAGS", octave::build_env::LFLAGS },
516            { "LIBOCTAVE", octave::build_env::LIBOCTAVE },
517            { "LIBOCTINTERP", octave::build_env::LIBOCTINTERP },
518            { "LIBS", octave::build_env::LIBS },
519            { "LLVM_CPPFLAGS", octave::build_env::LLVM_CPPFLAGS },
520            { "LLVM_LDFLAGS", octave::build_env::LLVM_LDFLAGS },
521            { "LLVM_LIBS", octave::build_env::LLVM_LIBS },
522            { "LN_S", octave::build_env::LN_S },
523            { "MAGICK_CPPFLAGS", octave::build_env::MAGICK_CPPFLAGS },
524            { "MAGICK_LDFLAGS", octave::build_env::MAGICK_LDFLAGS },
525            { "MAGICK_LIBS", octave::build_env::MAGICK_LIBS },
526            { "MKOCTFILE_DL_LDFLAGS", octave::build_env::MKOCTFILE_DL_LDFLAGS },
527            { "OCTAVE_LINK_DEPS", octave::build_env::OCTAVE_LINK_DEPS },
528            { "OCTAVE_LINK_OPTS", octave::build_env::OCTAVE_LINK_OPTS },
529            { "OCT_LINK_DEPS", octave::build_env::OCT_LINK_DEPS },
530            { "OCT_LINK_OPTS", octave::build_env::OCT_LINK_OPTS },
531            { "OPENGL_LIBS", octave::build_env::OPENGL_LIBS },
532            { "PCRE_CPPFLAGS", octave::build_env::PCRE_CPPFLAGS },
533            { "PCRE_LDFLAGS", octave::build_env::PCRE_LDFLAGS },
534            { "PCRE_LIBS", octave::build_env::PCRE_LIBS },
535            { "PTHREAD_CFLAGS", octave::build_env::PTHREAD_CFLAGS },
536            { "PTHREAD_LIBS", octave::build_env::PTHREAD_LIBS },
537            { "QHULL_CPPFLAGS", octave::build_env::QHULL_CPPFLAGS },
538            { "QHULL_LDFLAGS", octave::build_env::QHULL_LDFLAGS },
539            { "QHULL_LIBS", octave::build_env::QHULL_LIBS },
540            { "QRUPDATE_CPPFLAGS", octave::build_env::QRUPDATE_CPPFLAGS },
541            { "QRUPDATE_LDFLAGS", octave::build_env::QRUPDATE_LDFLAGS },
542            { "QRUPDATE_LIBS", octave::build_env::QRUPDATE_LIBS },
543            { "QT_CPPFLAGS", octave::build_env::QT_CPPFLAGS },
544            { "QT_LDFLAGS", octave::build_env::QT_LDFLAGS },
545            { "QT_LIBS", octave::build_env::QT_LIBS },
546            { "QT_OPENGL_LIBS", octave::build_env::QT_OPENGL_LIBS },
547            { "RANLIB", octave::build_env::RANLIB },
548            { "RDYNAMIC_FLAG", octave::build_env::RDYNAMIC_FLAG },
549            { "READLINE_LIBS", octave::build_env::READLINE_LIBS },
550            { "SHARED_LIBS", octave::build_env::SHARED_LIBS },
551            { "SH_LDFLAGS", octave::build_env::SH_LDFLAGS },
552            { "STATIC_LIBS", octave::build_env::STATIC_LIBS },
553            { "SUITESPARSECONFIG_LIBS", octave::build_env::SUITESPARSECONFIG_LIBS },
554            { "TERM_LIBS", octave::build_env::TERM_LIBS },
555            { "UMFPACK_CPPFLAGS", octave::build_env::UMFPACK_CPPFLAGS },
556            { "UMFPACK_LDFLAGS", octave::build_env::UMFPACK_LDFLAGS },
557            { "UMFPACK_LIBS", octave::build_env::UMFPACK_LIBS },
558            { "WARN_CFLAGS", octave::build_env::WARN_CFLAGS },
559            { "WARN_CXXFLAGS", octave::build_env::WARN_CXXFLAGS },
560            { "X11_INCFLAGS", octave::build_env::X11_INCFLAGS },
561            { "X11_LIBS", octave::build_env::X11_LIBS },
562            { "XTRA_CFLAGS", octave::build_env::XTRA_CFLAGS },
563            { "XTRA_CXXFLAGS", octave::build_env::XTRA_CXXFLAGS },
564            { "YACC", octave::build_env::YACC },
565            { "YFLAGS", octave::build_env::YFLAGS },
566            { "Z_CPPFLAGS", octave::build_env::Z_CPPFLAGS },
567            { "Z_LDFLAGS", octave::build_env::Z_LDFLAGS },
568            { "Z_LIBS", octave::build_env::Z_LIBS },
569            { "config_opts", octave::build_env::config_opts }};
570 
571       config = octave_scalar_map (conf_info_map);
572       build_env = octave_scalar_map (build_env_map);
573       build_features = octave::build_env::features ();
574 
575       bool unix_system = true;
576       bool mac_system = false;
577       bool windows_system = false;
578 
579 #if defined (__WIN32__)
580       windows_system = true;
581 #if ! defined (__CYGWIN__)
582       unix_system = false;
583 #endif
584 #endif
585 
586 #if defined (OCTAVE_USE_OS_X_API)
587       mac_system = true;
588 #endif
589 
590       config.assign ("unix", octave_value (unix_system));
591       config.assign ("mac", octave_value (mac_system));
592       config.assign ("windows", octave_value (windows_system));
593 
594       octave::mach_info::float_format ff = octave::mach_info::native_float_format ();
595       config.assign ("float_format",
596                      octave_value (octave::mach_info::float_format_as_string (ff)));
597 
598       config.assign ("words_big_endian",
599                      octave_value (octave::mach_info::words_big_endian ()));
600 
601       config.assign ("words_little_endian",
602                      octave_value (octave::mach_info::words_little_endian ()));
603 
604       config.assign ("build_environment", octave_value (build_env));
605 
606       config.assign ("build_features", octave_value (build_features));
607 
608       initialized = true;
609     }
610 
611   int nargin = args.length ();
612 
613   if (nargin > 1)
614     print_usage ();
615 
616   octave_value_list retval;
617 
618   if (nargin == 1)
619     {
620       std::string arg = args(0).xstring_value ("__octave_config_info__: OPTION argument must be a string");
621 
622       octave_value info = find_config_info (config, arg);
623 
624       if (info.is_undefined ())
625         info = find_config_info (build_env, arg);
626 
627       if (info.is_undefined ())
628         info = find_config_info (build_features, arg);
629 
630       if (info.is_undefined ())
631         error ("__octave_config_info__: no info for '%s'", arg.c_str ());
632 
633       return info;
634     }
635   else
636     retval = ovl (config);
637 
638   return retval;
639 }
640 
641 /*
642 %!assert (ischar (__octave_config_info__ ("version")))
643 %!assert (__octave_config_info__ ("version"), OCTAVE_VERSION ())
644 %!test
645 %! x = __octave_config_info__ ();
646 %! assert (isstruct (x));
647 %! assert (! isempty (x));
648 %! assert (x.version, OCTAVE_VERSION ());
649 
650 %!error __octave_config_info__ (1, 2)
651 */
652 
653 #if defined (__GNUG__) && defined (DEBUG_NEW_DELETE)
654 
655 int debug_new_delete = 0;
656 
657 typedef void (*vfp)(void);
658 extern vfp __new_handler;
659 
660 void *
__builtin_new(std::size_t sz)661 __builtin_new (std::size_t sz)
662 {
663   void *p;
664 
665   // malloc (0) is unpredictable; avoid it.
666   if (sz == 0)
667     sz = 1;
668   p = std::malloc (sz);
669   while (p == 0)
670     {
671       (*__new_handler) ();
672       p = std::malloc (sz);
673     }
674 
675   if (debug_new_delete)
676     std::cerr << "__builtin_new: " << p << std::endl;
677 
678   return p;
679 }
680 
681 void
__builtin_delete(void * ptr)682 __builtin_delete (void *ptr)
683 {
684   if (debug_new_delete)
685     std::cerr << "__builtin_delete: " << ptr << std::endl;
686 
687   free (ptr);
688 }
689 
690 #endif
691