Mercurial > octave-nkf
diff libinterp/corefcn/variables.cc @ 16892:68fc671a9339
maint: Collapse interpfcn and interpfcn-core directories into corefcn directory.
* libgui/src/module.mk: Remove -I references to interp-core, interpfcn, add
reference to corefcn.
* libinterp/Makefile.am: Remove -I references to interp-core, interpfcn, add
reference to corefcn.
* libinterp/corefcn/module.mk: Add files from interp-core, interpfcn to
build system. Copy over special rules from module.mk files in interp-core
andd interpfcn.
* src/Makefile.am: Replace references to interp-core, interpfcn with those
to corefcn.
* libinterp/corefcn/Cell.cc, libinterp/corefcn/Cell.h,
libinterp/corefcn/action-container.h, libinterp/corefcn/c-file-ptr-stream.cc,
libinterp/corefcn/c-file-ptr-stream.h, libinterp/corefcn/comment-list.cc,
libinterp/corefcn/comment-list.h, libinterp/corefcn/cutils.c,
libinterp/corefcn/cutils.h, libinterp/corefcn/data.cc,
libinterp/corefcn/data.h, libinterp/corefcn/debug.cc,
libinterp/corefcn/debug.h, libinterp/corefcn/defaults.cc,
libinterp/corefcn/defaults.in.h, libinterp/corefcn/defun-dld.h,
libinterp/corefcn/defun-int.h, libinterp/corefcn/defun.cc,
libinterp/corefcn/defun.h, libinterp/corefcn/dirfns.cc,
libinterp/corefcn/dirfns.h, libinterp/corefcn/display.cc,
libinterp/corefcn/display.h, libinterp/corefcn/dynamic-ld.cc,
libinterp/corefcn/dynamic-ld.h, libinterp/corefcn/error.cc,
libinterp/corefcn/error.h, libinterp/corefcn/event-queue.h,
libinterp/corefcn/file-io.cc, libinterp/corefcn/file-io.h,
libinterp/corefcn/gl-render.cc, libinterp/corefcn/gl-render.h,
libinterp/corefcn/gl2ps-renderer.cc, libinterp/corefcn/gl2ps-renderer.h,
libinterp/corefcn/gl2ps.c, libinterp/corefcn/gl2ps.h,
libinterp/corefcn/graphics.cc, libinterp/corefcn/graphics.in.h,
libinterp/corefcn/gripes.cc, libinterp/corefcn/gripes.h,
libinterp/corefcn/help.cc, libinterp/corefcn/help.h,
libinterp/corefcn/hook-fcn.cc, libinterp/corefcn/hook-fcn.h,
libinterp/corefcn/input.cc, libinterp/corefcn/input.h,
libinterp/corefcn/jit-ir.cc, libinterp/corefcn/jit-ir.h,
libinterp/corefcn/jit-typeinfo.cc, libinterp/corefcn/jit-typeinfo.h,
libinterp/corefcn/jit-util.cc, libinterp/corefcn/jit-util.h,
libinterp/corefcn/load-path.cc, libinterp/corefcn/load-path.h,
libinterp/corefcn/load-save.cc, libinterp/corefcn/load-save.h,
libinterp/corefcn/ls-ascii-helper.cc, libinterp/corefcn/ls-ascii-helper.h,
libinterp/corefcn/ls-hdf5.cc, libinterp/corefcn/ls-hdf5.h,
libinterp/corefcn/ls-mat-ascii.cc, libinterp/corefcn/ls-mat-ascii.h,
libinterp/corefcn/ls-mat4.cc, libinterp/corefcn/ls-mat4.h,
libinterp/corefcn/ls-mat5.cc, libinterp/corefcn/ls-mat5.h,
libinterp/corefcn/ls-oct-ascii.cc, libinterp/corefcn/ls-oct-ascii.h,
libinterp/corefcn/ls-oct-binary.cc, libinterp/corefcn/ls-oct-binary.h,
libinterp/corefcn/ls-utils.cc, libinterp/corefcn/ls-utils.h,
libinterp/corefcn/matherr.c, libinterp/corefcn/mex.cc, libinterp/corefcn/mex.h,
libinterp/corefcn/mexproto.h, libinterp/corefcn/mxarray.in.h,
libinterp/corefcn/oct-errno.h, libinterp/corefcn/oct-errno.in.cc,
libinterp/corefcn/oct-fstrm.cc, libinterp/corefcn/oct-fstrm.h,
libinterp/corefcn/oct-hdf5.h, libinterp/corefcn/oct-hist.cc,
libinterp/corefcn/oct-hist.h, libinterp/corefcn/oct-iostrm.cc,
libinterp/corefcn/oct-iostrm.h, libinterp/corefcn/oct-lvalue.cc,
libinterp/corefcn/oct-lvalue.h, libinterp/corefcn/oct-map.cc,
libinterp/corefcn/oct-map.h, libinterp/corefcn/oct-obj.cc,
libinterp/corefcn/oct-obj.h, libinterp/corefcn/oct-prcstrm.cc,
libinterp/corefcn/oct-prcstrm.h, libinterp/corefcn/oct-procbuf.cc,
libinterp/corefcn/oct-procbuf.h, libinterp/corefcn/oct-stdstrm.h,
libinterp/corefcn/oct-stream.cc, libinterp/corefcn/oct-stream.h,
libinterp/corefcn/oct-strstrm.cc, libinterp/corefcn/oct-strstrm.h,
libinterp/corefcn/oct.h, libinterp/corefcn/octave-link.cc,
libinterp/corefcn/octave-link.h, libinterp/corefcn/pager.cc,
libinterp/corefcn/pager.h, libinterp/corefcn/pr-output.cc,
libinterp/corefcn/pr-output.h, libinterp/corefcn/procstream.cc,
libinterp/corefcn/procstream.h, libinterp/corefcn/profiler.cc,
libinterp/corefcn/profiler.h, libinterp/corefcn/pt-jit.cc,
libinterp/corefcn/pt-jit.h, libinterp/corefcn/sighandlers.cc,
libinterp/corefcn/sighandlers.h, libinterp/corefcn/siglist.c,
libinterp/corefcn/siglist.h, libinterp/corefcn/sparse-xdiv.cc,
libinterp/corefcn/sparse-xdiv.h, libinterp/corefcn/sparse-xpow.cc,
libinterp/corefcn/sparse-xpow.h, libinterp/corefcn/symtab.cc,
libinterp/corefcn/symtab.h, libinterp/corefcn/sysdep.cc,
libinterp/corefcn/sysdep.h, libinterp/corefcn/toplev.cc,
libinterp/corefcn/toplev.h, libinterp/corefcn/txt-eng-ft.cc,
libinterp/corefcn/txt-eng-ft.h, libinterp/corefcn/txt-eng.h,
libinterp/corefcn/unwind-prot.cc, libinterp/corefcn/unwind-prot.h,
libinterp/corefcn/utils.cc, libinterp/corefcn/utils.h,
libinterp/corefcn/variables.cc, libinterp/corefcn/variables.h,
libinterp/corefcn/workspace-element.h, libinterp/corefcn/xdiv.cc,
libinterp/corefcn/xdiv.h, libinterp/corefcn/xgl2ps.c,
libinterp/corefcn/xnorm.cc, libinterp/corefcn/xnorm.h,
libinterp/corefcn/xpow.cc, libinterp/corefcn/xpow.h,
libinterp/corefcn/zfstream.cc, libinterp/corefcn/zfstream.h:
Files moved from interp-core and interpfcn directories.
* libinterp/interp-core/Cell.cc, libinterp/interp-core/Cell.h,
libinterp/interp-core/action-container.h,
libinterp/interp-core/c-file-ptr-stream.cc,
libinterp/interp-core/c-file-ptr-stream.h,
libinterp/interp-core/comment-list.cc, libinterp/interp-core/comment-list.h,
libinterp/interp-core/cutils.c, libinterp/interp-core/cutils.h,
libinterp/interp-core/defun-dld.h, libinterp/interp-core/defun-int.h,
libinterp/interp-core/display.cc, libinterp/interp-core/display.h,
libinterp/interp-core/dynamic-ld.cc, libinterp/interp-core/dynamic-ld.h,
libinterp/interp-core/event-queue.h, libinterp/interp-core/gl-render.cc,
libinterp/interp-core/gl-render.h, libinterp/interp-core/gl2ps-renderer.cc,
libinterp/interp-core/gl2ps-renderer.h, libinterp/interp-core/gl2ps.c,
libinterp/interp-core/gl2ps.h, libinterp/interp-core/gripes.cc,
libinterp/interp-core/gripes.h, libinterp/interp-core/jit-ir.cc,
libinterp/interp-core/jit-ir.h, libinterp/interp-core/jit-typeinfo.cc,
libinterp/interp-core/jit-typeinfo.h, libinterp/interp-core/jit-util.cc,
libinterp/interp-core/jit-util.h, libinterp/interp-core/ls-ascii-helper.cc,
libinterp/interp-core/ls-ascii-helper.h, libinterp/interp-core/ls-hdf5.cc,
libinterp/interp-core/ls-hdf5.h, libinterp/interp-core/ls-mat-ascii.cc,
libinterp/interp-core/ls-mat-ascii.h, libinterp/interp-core/ls-mat4.cc,
libinterp/interp-core/ls-mat4.h, libinterp/interp-core/ls-mat5.cc,
libinterp/interp-core/ls-mat5.h, libinterp/interp-core/ls-oct-binary.cc,
libinterp/interp-core/ls-oct-binary.h, libinterp/interp-core/ls-utils.cc,
libinterp/interp-core/ls-utils.h, libinterp/interp-core/matherr.c,
libinterp/interp-core/mex.cc, libinterp/interp-core/mex.h,
libinterp/interp-core/mexproto.h, libinterp/interp-core/module.mk,
libinterp/interp-core/mxarray.in.h, libinterp/interp-core/oct-errno.h,
libinterp/interp-core/oct-errno.in.cc, libinterp/interp-core/oct-fstrm.cc,
libinterp/interp-core/oct-fstrm.h, libinterp/interp-core/oct-hdf5.h,
libinterp/interp-core/oct-iostrm.cc, libinterp/interp-core/oct-iostrm.h,
libinterp/interp-core/oct-lvalue.cc, libinterp/interp-core/oct-lvalue.h,
libinterp/interp-core/oct-map.cc, libinterp/interp-core/oct-map.h,
libinterp/interp-core/oct-obj.cc, libinterp/interp-core/oct-obj.h,
libinterp/interp-core/oct-prcstrm.cc, libinterp/interp-core/oct-prcstrm.h,
libinterp/interp-core/oct-procbuf.cc, libinterp/interp-core/oct-procbuf.h,
libinterp/interp-core/oct-stdstrm.h, libinterp/interp-core/oct-stream.cc,
libinterp/interp-core/oct-stream.h, libinterp/interp-core/oct-strstrm.cc,
libinterp/interp-core/oct-strstrm.h, libinterp/interp-core/oct.h,
libinterp/interp-core/procstream.cc, libinterp/interp-core/procstream.h,
libinterp/interp-core/pt-jit.cc, libinterp/interp-core/pt-jit.h,
libinterp/interp-core/siglist.c, libinterp/interp-core/siglist.h,
libinterp/interp-core/sparse-xdiv.cc, libinterp/interp-core/sparse-xdiv.h,
libinterp/interp-core/sparse-xpow.cc, libinterp/interp-core/sparse-xpow.h,
libinterp/interp-core/txt-eng-ft.cc, libinterp/interp-core/txt-eng-ft.h,
libinterp/interp-core/txt-eng.h, libinterp/interp-core/unwind-prot.cc,
libinterp/interp-core/unwind-prot.h, libinterp/interp-core/xdiv.cc,
libinterp/interp-core/xdiv.h, libinterp/interp-core/xgl2ps.c,
libinterp/interp-core/xnorm.cc, libinterp/interp-core/xnorm.h,
libinterp/interp-core/xpow.cc, libinterp/interp-core/xpow.h,
libinterp/interp-core/zfstream.cc, libinterp/interp-core/zfstream.h,
libinterp/interpfcn/data.cc, libinterp/interpfcn/data.h,
libinterp/interpfcn/debug.cc, libinterp/interpfcn/debug.h,
libinterp/interpfcn/defaults.cc, libinterp/interpfcn/defaults.in.h,
libinterp/interpfcn/defun.cc, libinterp/interpfcn/defun.h,
libinterp/interpfcn/dirfns.cc, libinterp/interpfcn/dirfns.h,
libinterp/interpfcn/error.cc, libinterp/interpfcn/error.h,
libinterp/interpfcn/file-io.cc, libinterp/interpfcn/file-io.h,
libinterp/interpfcn/graphics.cc, libinterp/interpfcn/graphics.in.h,
libinterp/interpfcn/help.cc, libinterp/interpfcn/help.h,
libinterp/interpfcn/hook-fcn.cc, libinterp/interpfcn/hook-fcn.h,
libinterp/interpfcn/input.cc, libinterp/interpfcn/input.h,
libinterp/interpfcn/load-path.cc, libinterp/interpfcn/load-path.h,
libinterp/interpfcn/load-save.cc, libinterp/interpfcn/load-save.h,
libinterp/interpfcn/ls-oct-ascii.cc, libinterp/interpfcn/ls-oct-ascii.h,
libinterp/interpfcn/module.mk, libinterp/interpfcn/oct-hist.cc,
libinterp/interpfcn/oct-hist.h, libinterp/interpfcn/octave-link.cc,
libinterp/interpfcn/octave-link.h, libinterp/interpfcn/pager.cc,
libinterp/interpfcn/pager.h, libinterp/interpfcn/pr-output.cc,
libinterp/interpfcn/pr-output.h, libinterp/interpfcn/profiler.cc,
libinterp/interpfcn/profiler.h, libinterp/interpfcn/sighandlers.cc,
libinterp/interpfcn/sighandlers.h, libinterp/interpfcn/symtab.cc,
libinterp/interpfcn/symtab.h, libinterp/interpfcn/sysdep.cc,
libinterp/interpfcn/sysdep.h, libinterp/interpfcn/toplev.cc,
libinterp/interpfcn/toplev.h, libinterp/interpfcn/utils.cc,
libinterp/interpfcn/utils.h, libinterp/interpfcn/variables.cc,
libinterp/interpfcn/variables.h, libinterp/interpfcn/workspace-element.h:
deleted files.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 03 Jul 2013 17:43:48 -0700 |
parents | libinterp/interpfcn/variables.cc@6a8e63dadfad |
children | 99122191d3dd |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libinterp/corefcn/variables.cc Wed Jul 03 17:43:48 2013 -0700 @@ -0,0 +1,2606 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton +Copyright (C) 2009-2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdio> +#include <cstring> + +#include <iomanip> +#include <set> +#include <string> + +#include "file-stat.h" +#include "oct-env.h" +#include "file-ops.h" +#include "glob-match.h" +#include "regexp.h" +#include "str-vec.h" + +#include <defaults.h> +#include "Cell.h" +#include "defun.h" +#include "dirfns.h" +#include "error.h" +#include "gripes.h" +#include "help.h" +#include "input.h" +#include "lex.h" +#include "load-path.h" +#include "octave-link.h" +#include "oct-map.h" +#include "oct-obj.h" +#include "ov.h" +#include "ov-class.h" +#include "ov-usr-fcn.h" +#include "pager.h" +#include "parse.h" +#include "symtab.h" +#include "toplev.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" + +// Defines layout for the whos/who -long command +static std::string Vwhos_line_format + = " %a:4; %ln:6; %cs:16:6:1; %rb:12; %lc:-1;\n"; + +void +clear_mex_functions (void) +{ + symbol_table::clear_mex_functions (); +} + +void +clear_function (const std::string& nm) +{ + symbol_table::clear_function (nm); +} + +void +clear_variable (const std::string& nm) +{ + symbol_table::clear_variable (nm); +} + +void +clear_symbol (const std::string& nm) +{ + symbol_table::clear_symbol (nm); +} + +// Attributes of variables and functions. + +// Is this octave_value a valid function? + +octave_function * +is_valid_function (const std::string& fcn_name, + const std::string& warn_for, bool warn) +{ + octave_function *ans = 0; + + if (! fcn_name.empty ()) + { + octave_value val = symbol_table::find_function (fcn_name); + + if (val.is_defined ()) + ans = val.function_value (true); + } + + if (! ans && warn) + error ("%s: the symbol '%s' is not valid as a function", + warn_for.c_str (), fcn_name.c_str ()); + + return ans; +} + +octave_function * +is_valid_function (const octave_value& arg, + const std::string& warn_for, bool warn) +{ + octave_function *ans = 0; + + std::string fcn_name; + + if (arg.is_string ()) + { + fcn_name = arg.string_value (); + + if (! error_state) + ans = is_valid_function (fcn_name, warn_for, warn); + else if (warn) + error ("%s: expecting function name as argument", warn_for.c_str ()); + } + else if (warn) + error ("%s: expecting function name as argument", warn_for.c_str ()); + + return ans; +} + +octave_function * +extract_function (const octave_value& arg, const std::string& warn_for, + const std::string& fname, const std::string& header, + const std::string& trailer) +{ + octave_function *retval = 0; + + retval = is_valid_function (arg, warn_for, 0); + + if (! retval) + { + std::string s = arg.string_value (); + + std::string cmd = header; + cmd.append (s); + cmd.append (trailer); + + if (! error_state) + { + int parse_status; + + eval_string (cmd, true, parse_status, 0); + + if (parse_status == 0) + { + retval = is_valid_function (fname, warn_for, 0); + + if (! retval) + { + error ("%s: '%s' is not valid as a function", + warn_for.c_str (), fname.c_str ()); + return retval; + } + + warning ("%s: passing function body as a string is obsolete; please use anonymous functions", + warn_for.c_str ()); + } + else + error ("%s: '%s' is not valid as a function", + warn_for.c_str (), fname.c_str ()); + } + else + error ("%s: expecting first argument to be a string", + warn_for.c_str ()); + } + + return retval; +} + +string_vector +get_struct_elts (const std::string& text) +{ + int n = 1; + + size_t pos = 0; + + size_t len = text.length (); + + while ((pos = text.find ('.', pos)) != std::string::npos) + { + if (++pos == len) + break; + + n++; + } + + string_vector retval (n); + + pos = 0; + + for (int i = 0; i < n; i++) + { + len = text.find ('.', pos); + + if (len != std::string::npos) + len -= pos; + + retval[i] = text.substr (pos, len); + + if (len != std::string::npos) + pos += len + 1; + } + + return retval; +} + +static inline bool +is_variable (const std::string& name) +{ + bool retval = false; + + if (! name.empty ()) + { + octave_value val = symbol_table::varval (name); + + retval = val.is_defined (); + } + + return retval; +} + +string_vector +generate_struct_completions (const std::string& text, + std::string& prefix, std::string& hint) +{ + string_vector names; + + size_t pos = text.rfind ('.'); + + if (pos != std::string::npos) + { + if (pos == text.length ()) + hint = ""; + else + hint = text.substr (pos+1); + + prefix = text.substr (0, pos); + + std::string base_name = prefix; + + pos = base_name.find_first_of ("{(."); + + if (pos != std::string::npos) + base_name = base_name.substr (0, pos); + + if (is_variable (base_name)) + { + int parse_status; + + unwind_protect frame; + + frame.protect_var (error_state); + frame.protect_var (warning_state); + + frame.protect_var (discard_error_messages); + frame.protect_var (discard_warning_messages); + + discard_error_messages = true; + discard_warning_messages = true; + + octave_value tmp = eval_string (prefix, true, parse_status); + + frame.run (); + + if (tmp.is_defined () && (tmp.is_map () || tmp.is_java ())) + names = tmp.map_keys (); + } + } + + return names; +} + +// FIXME -- this will have to be much smarter to work +// "correctly". + +bool +looks_like_struct (const std::string& text) +{ + bool retval = (! text.empty () + && text != "." + && text.find_first_of (file_ops::dir_sep_chars ()) == std::string::npos + && text.find ("..") == std::string::npos + && text.rfind ('.') != std::string::npos); + +#if 0 + symbol_record *sr = curr_sym_tab->lookup (text); + + if (sr && ! sr->is_function ()) + { + int parse_status; + + unwind_protect frame; + + frame.protect_var (discard_error_messages); + frame.protect_var (error_state); + + discard_error_messages = true; + + octave_value tmp = eval_string (text, true, parse_status); + + frame.run (); + + retval = (tmp.is_defined () && tmp.is_map ()); + } +#endif + + return retval; +} + +static octave_value +do_isglobal (const octave_value_list& args) +{ + octave_value retval = false; + + int nargin = args.length (); + + if (nargin != 1) + { + print_usage (); + return retval; + } + + std::string name = args(0).string_value (); + + if (error_state) + { + error ("isglobal: NAME must be a string"); + return retval; + } + + return symbol_table::is_global (name); +} + +DEFUN (isglobal, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} isglobal (@var{name})\n\ +Return true if @var{name} is a globally visible variable.\n\ +For example:\n\ +\n\ +@example\n\ +@group\n\ +global x\n\ +isglobal (\"x\")\n\ + @result{} 1\n\ +@end group\n\ +@end example\n\ +@seealso{isvarname, exist}\n\ +@end deftypefn") +{ + return do_isglobal (args); +} + +static octave_value +safe_symbol_lookup (const std::string& symbol_name) +{ + octave_value retval; + + unwind_protect frame; + interpreter_try (frame); + + retval = symbol_table::find (symbol_name); + + error_state = 0; + + return retval; +} + +int +symbol_exist (const std::string& name, const std::string& type) +{ + int retval = 0; + + std::string struct_elts; + std::string symbol_name = name; + + size_t pos = name.find ('.'); + + if (pos != std::string::npos && pos > 0) + { + struct_elts = name.substr (pos+1); + symbol_name = name.substr (0, pos); + } + + // We shouldn't need to look in the global symbol table, since any + // name that is visible in the current scope will be in the local + // symbol table. + + octave_value val = safe_symbol_lookup (symbol_name); + + if (val.is_defined ()) + { + bool not_a_struct = struct_elts.empty (); + bool var_ok = not_a_struct /* || val.is_map_element (struct_elts) */; + + if (! retval + && var_ok + && (type == "any" || type == "var") + && (val.is_constant () || val.is_object () + || val.is_function_handle () + || val.is_anonymous_function () + || val.is_inline_function ())) + { + retval = 1; + } + + if (! retval + && (type == "any" || type == "builtin")) + { + if (not_a_struct && val.is_builtin_function ()) + { + retval = 5; + } + } + + if (! retval + && not_a_struct + && (type == "any" || type == "file") + && (val.is_user_function () || val.is_dld_function ())) + { + octave_function *f = val.function_value (true); + std::string s = f ? f->fcn_file_name () : std::string (); + + retval = s.empty () ? 103 : (val.is_user_function () ? 2 : 3); + } + } + + if (! (type == "var" || type == "builtin")) + { + if (! retval) + { + std::string file_name = lookup_autoload (name); + + if (file_name.empty ()) + file_name = load_path::find_fcn (name); + + size_t len = file_name.length (); + + if (len > 0) + { + if (type == "any" || type == "file") + { + if (len > 4 && (file_name.substr (len-4) == ".oct" + || file_name.substr (len-4) == ".mex")) + retval = 3; + else + retval = 2; + } + } + } + + if (! retval) + { + std::string file_name = file_in_path (name, ""); + + if (file_name.empty ()) + file_name = name; + + file_stat fs (file_name); + + if (fs) + { + if (type == "any" || type == "file") + retval = fs.is_dir () ? 7 : 2; + else if (type == "dir" && fs.is_dir ()) + retval = 7; + } + } + } + + return retval; +} + +#define GET_IDX(LEN) \ + static_cast<int> ((LEN-1) * static_cast<double> (rand ()) / RAND_MAX) + +std::string +unique_symbol_name (const std::string& basename) +{ + static const std::string alpha + = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + static size_t len = alpha.length (); + + std::string nm = basename + alpha[GET_IDX (len)]; + + size_t pos = nm.length (); + + if (nm.substr (0, 2) == "__") + nm.append ("__"); + + while (symbol_exist (nm, "any")) + nm.insert (pos++, 1, alpha[GET_IDX (len)]); + + return nm; +} + +DEFUN (exist, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} exist (@var{name}, @var{type})\n\ +Return 1 if the name exists as a variable, 2 if the name is an\n\ +absolute file name, an ordinary file in Octave's @code{path}, or (after\n\ +appending @samp{.m}) a function file in Octave's @code{path}, 3 if the\n\ +name is a @samp{.oct} or @samp{.mex} file in Octave's @code{path},\n\ +5 if the name is a built-in function, 7 if the name is a directory, or 103\n\ +if the name is a function not associated with a file (entered on\n\ +the command line).\n\ +\n\ +Otherwise, return 0.\n\ +\n\ +This function also returns 2 if a regular file called @var{name}\n\ +exists in Octave's search path. If you want information about\n\ +other types of files, you should use some combination of the functions\n\ +@code{file_in_path} and @code{stat} instead.\n\ +\n\ +If the optional argument @var{type} is supplied, check only for\n\ +symbols of the specified type. Valid types are\n\ +\n\ +@table @asis\n\ +@item \"var\"\n\ +Check only for variables.\n\ +\n\ +@item \"builtin\"\n\ +Check only for built-in functions.\n\ +\n\ +@item \"file\"\n\ +Check only for files and directories.\n\ +\n\ +@item \"dir\"\n\ +Check only for directories.\n\ +@end table\n\ +\n\ +@seealso{file_in_loadpath, file_in_path, stat}\n\ +@end deftypefn") +{ + octave_value retval = false; + + int nargin = args.length (); + + if (nargin == 1 || nargin == 2) + { + std::string name = args(0).string_value (); + + if (! error_state) + { + std::string type + = (nargin == 2) ? args(1).string_value () : std::string ("any"); + + if (! error_state) + retval = symbol_exist (name, type); + else + error ("exist: TYPE must be a string"); + } + else + error ("exist: NAME must be a string"); + } + else + print_usage (); + + return retval; +} + +/* +%!test +%! if (isunix ()) +%! assert (exist ("/tmp") == 7); +%! assert (exist ("/tmp", "file") == 7); +%! assert (exist ("/tmp", "dir") == 7); +%! assert (exist ("/bin/sh") == 2); +%! assert (exist ("/bin/sh", "file") == 2); +%! assert (exist ("/bin/sh", "dir") == 0); +%! assert (exist ("/dev/null") == 2); +%! assert (exist ("/dev/null", "file") == 2); +%! assert (exist ("/dev/null", "dir") == 0); +%! endif +*/ + +octave_value +lookup_function_handle (const std::string& nm) +{ + octave_value val = symbol_table::varval (nm); + + return val.is_function_handle () ? val : octave_value (); +} + +octave_value +get_global_value (const std::string& nm, bool silent) +{ + octave_value val = symbol_table::global_varval (nm); + + if (val.is_undefined () && ! silent) + error ("get_global_value: undefined symbol '%s'", nm.c_str ()); + + return val; +} + +void +set_global_value (const std::string& nm, const octave_value& val) +{ + symbol_table::global_assign (nm, val); +} + +octave_value +get_top_level_value (const std::string& nm, bool silent) +{ + octave_value val = symbol_table::top_level_varval (nm); + + if (val.is_undefined () && ! silent) + error ("get_top_level_value: undefined symbol '%s'", nm.c_str ()); + + return val; +} + +void +set_top_level_value (const std::string& nm, const octave_value& val) +{ + symbol_table::top_level_assign (nm, val); +} + +// Variable values. + +static bool +wants_local_change (const octave_value_list& args, int& nargin) +{ + bool retval = false; + + if (nargin == 2) + { + if (args(1).is_string () && args(1).string_value () == "local") + { + nargin = 1; + retval = true; + } + else + { + error_with_cfn ("expecting second argument to be \"local\""); + nargin = 0; + } + } + + return retval; +} + +template <class T> +bool try_local_protect (T& var) +{ + octave_user_code *curr_usr_code = octave_call_stack::caller_user_code (); + octave_user_function *curr_usr_fcn = 0; + if (curr_usr_code && curr_usr_code->is_user_function ()) + curr_usr_fcn = dynamic_cast<octave_user_function *> (curr_usr_code); + + if (curr_usr_fcn && curr_usr_fcn->local_protect (var)) + return true; + else + return false; +} + +octave_value +set_internal_variable (bool& var, const octave_value_list& args, + int nargout, const char *nm) +{ + octave_value retval; + + int nargin = args.length (); + + if (nargout > 0 || nargin == 0) + retval = var; + + if (wants_local_change (args, nargin)) + { + if (! try_local_protect (var)) + warning ("\"local\" has no effect outside a function"); + } + + if (nargin == 1) + { + bool bval = args(0).bool_value (); + + if (! error_state) + var = bval; + else + error ("%s: expecting arg to be a logical value", nm); + } + else if (nargin > 1) + print_usage (); + + return retval; +} + +octave_value +set_internal_variable (char& var, const octave_value_list& args, + int nargout, const char *nm) +{ + octave_value retval; + + int nargin = args.length (); + + if (nargout > 0 || nargin == 0) + retval = var; + + if (wants_local_change (args, nargin)) + { + if (! try_local_protect (var)) + warning ("\"local\" has no effect outside a function"); + } + + if (nargin == 1) + { + std::string sval = args(0).string_value (); + + if (! error_state) + { + switch (sval.length ()) + { + case 1: + var = sval[0]; + break; + + case 0: + var = '\0'; + break; + + default: + error ("%s: argument must be a single character", nm); + break; + } + } + else + error ("%s: argument must be a single character", nm); + } + else if (nargin > 1) + print_usage (); + + return retval; +} + +octave_value +set_internal_variable (int& var, const octave_value_list& args, + int nargout, const char *nm, + int minval, int maxval) +{ + octave_value retval; + + int nargin = args.length (); + + if (nargout > 0 || nargin == 0) + retval = var; + + if (wants_local_change (args, nargin)) + { + if (! try_local_protect (var)) + warning ("\"local\" has no effect outside a function"); + } + + if (nargin == 1) + { + int ival = args(0).int_value (); + + if (! error_state) + { + if (ival < minval) + error ("%s: expecting arg to be greater than %d", nm, minval); + else if (ival > maxval) + error ("%s: expecting arg to be less than or equal to %d", + nm, maxval); + else + var = ival; + } + else + error ("%s: expecting arg to be an integer value", nm); + } + else if (nargin > 1) + print_usage (); + + return retval; +} + +octave_value +set_internal_variable (double& var, const octave_value_list& args, + int nargout, const char *nm, + double minval, double maxval) +{ + octave_value retval; + + int nargin = args.length (); + + if (nargout > 0 || nargin == 0) + retval = var; + + if (wants_local_change (args, nargin)) + { + if (! try_local_protect (var)) + warning ("\"local\" has no effect outside a function"); + } + + if (nargin == 1) + { + double dval = args(0).scalar_value (); + + if (! error_state) + { + if (dval < minval) + error ("%s: expecting arg to be greater than %g", minval); + else if (dval > maxval) + error ("%s: expecting arg to be less than or equal to %g", maxval); + else + var = dval; + } + else + error ("%s: expecting arg to be a scalar value", nm); + } + else if (nargin > 1) + print_usage (); + + return retval; +} + +octave_value +set_internal_variable (std::string& var, const octave_value_list& args, + int nargout, const char *nm, bool empty_ok) +{ + octave_value retval; + + int nargin = args.length (); + + if (nargout > 0 || nargin == 0) + retval = var; + + if (wants_local_change (args, nargin)) + { + if (! try_local_protect (var)) + warning ("\"local\" has no effect outside a function"); + } + + if (nargin == 1) + { + std::string sval = args(0).string_value (); + + if (! error_state) + { + if (empty_ok || ! sval.empty ()) + var = sval; + else + error ("%s: value must not be empty", nm); + } + else + error ("%s: expecting arg to be a character string", nm); + } + else if (nargin > 1) + print_usage (); + + return retval; +} + +octave_value +set_internal_variable (int& var, const octave_value_list& args, + int nargout, const char *nm, const char **choices) +{ + octave_value retval; + int nchoices = 0; + while (choices[nchoices] != 0) + nchoices++; + + int nargin = args.length (); + assert (var < nchoices); + + if (nargout > 0 || nargin == 0) + retval = choices[var]; + + if (wants_local_change (args, nargin)) + { + if (! try_local_protect (var)) + warning ("\"local\" has no effect outside a function"); + } + + if (nargin == 1) + { + std::string sval = args(0).string_value (); + + if (! error_state) + { + int i = 0; + for (; i < nchoices; i++) + { + if (sval == choices[i]) + { + var = i; + break; + } + } + if (i == nchoices) + error ("%s: value not allowed (\"%s\")", nm, sval.c_str ()); + } + else + error ("%s: expecting arg to be a character string", nm); + } + else if (nargin > 1) + print_usage (); + + return retval; +} + +struct +whos_parameter +{ + char command; + char modifier; + int parameter_length; + int first_parameter_length; + int balance; + std::string text; + std::string line; +}; + +static void +print_descriptor (std::ostream& os, std::list<whos_parameter> params) +{ + // This method prints a line of information on a given symbol + std::list<whos_parameter>::iterator i = params.begin (); + std::ostringstream param_buf; + + while (i != params.end ()) + { + whos_parameter param = *i; + + if (param.command != '\0') + { + // Do the actual printing + switch (param.modifier) + { + case 'l': + os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + break; + + case 'r': + os << std::setiosflags (std::ios::right) << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::right) << std::setw (param.parameter_length); + break; + + case 'c': + if (param.command != 's') + { + os << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + } + break; + + default: + os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length); + } + + if (param.command == 's' && param.modifier == 'c') + { + int a, b; + + if (param.modifier == 'c') + { + a = param.first_parameter_length - param.balance; + a = (a < 0 ? 0 : a); + b = param.parameter_length - a - param.text . length (); + b = (b < 0 ? 0 : b); + os << std::setiosflags (std::ios::left) << std::setw (a) + << "" << std::resetiosflags (std::ios::left) << param.text + << std::setiosflags (std::ios::left) + << std::setw (b) << "" + << std::resetiosflags (std::ios::left); + param_buf << std::setiosflags (std::ios::left) << std::setw (a) + << "" << std::resetiosflags (std::ios::left) << param.line + << std::setiosflags (std::ios::left) + << std::setw (b) << "" + << std::resetiosflags (std::ios::left); + } + } + else + { + os << param.text; + param_buf << param.line; + } + os << std::resetiosflags (std::ios::left) + << std::resetiosflags (std::ios::right); + param_buf << std::resetiosflags (std::ios::left) + << std::resetiosflags (std::ios::right); + i++; + } + else + { + os << param.text; + param_buf << param.line; + i++; + } + } + + os << param_buf.str (); +} + +// FIXME -- This is a bit of a kluge. We'd like to just use val.dims() +// and if val is an object, expect that dims will call size if it is +// overloaded by a user-defined method. But there are currently some +// unresolved const issues that prevent that solution from working. + +std::string +get_dims_str (const octave_value& val) +{ + octave_value tmp = val; + + Matrix sz = tmp.size (); + + dim_vector dv = dim_vector::alloc (sz.numel ()); + + for (octave_idx_type i = 0; i < dv.length (); i++) + dv(i) = sz(i); + + return dv.str (); +} + +class +symbol_info_list +{ +private: + struct symbol_info + { + symbol_info (const symbol_table::symbol_record& sr, + const std::string& expr_str = std::string (), + const octave_value& expr_val = octave_value ()) + : name (expr_str.empty () ? sr.name () : expr_str), + varval (expr_val.is_undefined () ? sr.varval () : expr_val), + is_automatic (sr.is_automatic ()), + is_complex (varval.is_complex_type ()), + is_formal (sr.is_formal ()), + is_global (sr.is_global ()), + is_persistent (sr.is_persistent ()) + { } + + void display_line (std::ostream& os, + const std::list<whos_parameter>& params) const + { + std::string dims_str = get_dims_str (varval); + + std::list<whos_parameter>::const_iterator i = params.begin (); + + while (i != params.end ()) + { + whos_parameter param = *i; + + if (param.command != '\0') + { + // Do the actual printing. + + switch (param.modifier) + { + case 'l': + os << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + break; + + case 'r': + os << std::setiosflags (std::ios::right) + << std::setw (param.parameter_length); + break; + + case 'c': + if (param.command == 's') + { + int front = param.first_parameter_length + - dims_str.find ('x'); + int back = param.parameter_length + - dims_str.length () + - front; + front = (front > 0) ? front : 0; + back = (back > 0) ? back : 0; + + os << std::setiosflags (std::ios::left) + << std::setw (front) + << "" + << std::resetiosflags (std::ios::left) + << dims_str + << std::setiosflags (std::ios::left) + << std::setw (back) + << "" + << std::resetiosflags (std::ios::left); + } + else + { + os << std::setiosflags (std::ios::left) + << std::setw (param.parameter_length); + } + break; + + default: + error ("whos_line_format: modifier '%c' unknown", + param.modifier); + + os << std::setiosflags (std::ios::right) + << std::setw (param.parameter_length); + } + + switch (param.command) + { + case 'a': + { + char tmp[6]; + + tmp[0] = (is_automatic ? 'a' : ' '); + tmp[1] = (is_complex ? 'c' : ' '); + tmp[2] = (is_formal ? 'f' : ' '); + tmp[3] = (is_global ? 'g' : ' '); + tmp[4] = (is_persistent ? 'p' : ' '); + tmp[5] = 0; + + os << tmp; + } + break; + + case 'b': + os << varval.byte_size (); + break; + + case 'c': + os << varval.class_name (); + break; + + case 'e': + os << varval.capacity (); + break; + + case 'n': + os << name; + break; + + case 's': + if (param.modifier != 'c') + os << dims_str; + break; + + case 't': + os << varval.type_name (); + break; + + default: + error ("whos_line_format: command '%c' unknown", + param.command); + } + + os << std::resetiosflags (std::ios::left) + << std::resetiosflags (std::ios::right); + i++; + } + else + { + os << param.text; + i++; + } + } + } + + std::string name; + octave_value varval; + bool is_automatic; + bool is_complex; + bool is_formal; + bool is_global; + bool is_persistent; + }; + +public: + symbol_info_list (void) : lst () { } + + symbol_info_list (const symbol_info_list& sil) : lst (sil.lst) { } + + symbol_info_list& operator = (const symbol_info_list& sil) + { + if (this != &sil) + lst = sil.lst; + + return *this; + } + + ~symbol_info_list (void) { } + + void append (const symbol_table::symbol_record& sr) + { + lst.push_back (symbol_info (sr)); + } + + void append (const symbol_table::symbol_record& sr, + const std::string& expr_str, + const octave_value& expr_val) + { + lst.push_back (symbol_info (sr, expr_str, expr_val)); + } + + size_t size (void) const { return lst.size (); } + + bool empty (void) const { return lst.empty (); } + + octave_map + map_value (const std::string& caller_function_name, int nesting_level) const + { + size_t len = lst.size (); + + Cell name_info (len, 1); + Cell size_info (len, 1); + Cell bytes_info (len, 1); + Cell class_info (len, 1); + Cell global_info (len, 1); + Cell sparse_info (len, 1); + Cell complex_info (len, 1); + Cell nesting_info (len, 1); + Cell persistent_info (len, 1); + + std::list<symbol_info>::const_iterator p = lst.begin (); + + for (size_t j = 0; j < len; j++) + { + const symbol_info& si = *p++; + + octave_scalar_map ni; + + ni.assign ("function", caller_function_name); + ni.assign ("level", nesting_level); + + name_info(j) = si.name; + global_info(j) = si.is_global; + persistent_info(j) = si.is_persistent; + + octave_value val = si.varval; + + size_info(j) = val.size (); + bytes_info(j) = val.byte_size (); + class_info(j) = val.class_name (); + sparse_info(j) = val.is_sparse_type (); + complex_info(j) = val.is_complex_type (); + nesting_info(j) = ni; + } + + octave_map info; + + info.assign ("name", name_info); + info.assign ("size", size_info); + info.assign ("bytes", bytes_info); + info.assign ("class", class_info); + info.assign ("global", global_info); + info.assign ("sparse", sparse_info); + info.assign ("complex", complex_info); + info.assign ("nesting", nesting_info); + info.assign ("persistent", persistent_info); + + return info; + } + + void display (std::ostream& os) + { + if (! lst.empty ()) + { + size_t bytes = 0; + size_t elements = 0; + + std::list<whos_parameter> params = parse_whos_line_format (); + + print_descriptor (os, params); + + octave_stdout << "\n"; + + for (std::list<symbol_info>::const_iterator p = lst.begin (); + p != lst.end (); p++) + { + p->display_line (os, params); + + octave_value val = p->varval; + + elements += val.capacity (); + bytes += val.byte_size (); + } + + os << "\nTotal is " << elements + << (elements == 1 ? " element" : " elements") + << " using " << bytes << (bytes == 1 ? " byte" : " bytes") + << "\n"; + } + } + + // Parse the string whos_line_format, and return a parameter list, + // containing all information needed to print the given + // attributtes of the symbols. + std::list<whos_parameter> parse_whos_line_format (void) + { + int idx; + size_t format_len = Vwhos_line_format.length (); + char garbage; + std::list<whos_parameter> params; + + size_t bytes1; + int elements1; + + std::string param_string = "abcenst"; + Array<int> param_length (dim_vector (param_string.length (), 1)); + Array<std::string> param_names (dim_vector (param_string.length (), 1)); + size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t; + + pos_a = param_string.find ('a'); // Attributes + pos_b = param_string.find ('b'); // Bytes + pos_c = param_string.find ('c'); // Class + pos_e = param_string.find ('e'); // Elements + pos_n = param_string.find ('n'); // Name + pos_s = param_string.find ('s'); // Size + pos_t = param_string.find ('t'); // Type + + param_names(pos_a) = "Attr"; + param_names(pos_b) = "Bytes"; + param_names(pos_c) = "Class"; + param_names(pos_e) = "Elements"; + param_names(pos_n) = "Name"; + param_names(pos_s) = "Size"; + param_names(pos_t) = "Type"; + + for (size_t i = 0; i < param_string.length (); i++) + param_length(i) = param_names(i).length (); + + // The attribute column needs size 5. + param_length(pos_a) = 5; + + // Calculating necessary spacing for name column, + // bytes column, elements column and class column + + for (std::list<symbol_info>::const_iterator p = lst.begin (); + p != lst.end (); p++) + { + std::stringstream ss1, ss2; + std::string str; + + str = p->name; + param_length(pos_n) = ((str.length () + > static_cast<size_t> (param_length(pos_n))) + ? str.length () : param_length(pos_n)); + + octave_value val = p->varval; + + str = val.type_name (); + param_length(pos_t) = ((str.length () + > static_cast<size_t> (param_length(pos_t))) + ? str.length () : param_length(pos_t)); + + elements1 = val.capacity (); + ss1 << elements1; + str = ss1.str (); + param_length(pos_e) = ((str.length () + > static_cast<size_t> (param_length(pos_e))) + ? str.length () : param_length(pos_e)); + + bytes1 = val.byte_size (); + ss2 << bytes1; + str = ss2.str (); + param_length(pos_b) = ((str.length () + > static_cast<size_t> (param_length(pos_b))) + ? str.length () : param_length (pos_b)); + } + + idx = 0; + while (static_cast<size_t> (idx) < format_len) + { + whos_parameter param; + param.command = '\0'; + + if (Vwhos_line_format[idx] == '%') + { + bool error_encountered = false; + param.modifier = 'r'; + param.parameter_length = 0; + + int a = 0, b = -1, balance = 1; + unsigned int items; + size_t pos; + std::string cmd; + + // Parse one command from whos_line_format + cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ()); + pos = cmd.find (';'); + if (pos != std::string::npos) + cmd = cmd.substr (0, pos+1); + else + error ("parameter without ; in whos_line_format"); + + idx += cmd.length (); + + // FIXME -- use iostream functions instead of sscanf! + + if (cmd.find_first_of ("crl") != 1) + items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;", + &garbage, ¶m.command, &a, &b, &balance); + else + items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;", + &garbage, ¶m.modifier, ¶m.command, + &a, &b, &balance) - 1; + + if (items < 2) + { + error ("whos_line_format: parameter structure without command in whos_line_format"); + error_encountered = true; + } + + // Insert data into parameter + param.first_parameter_length = 0; + pos = param_string.find (param.command); + if (pos != std::string::npos) + { + param.parameter_length = param_length(pos); + param.text = param_names(pos); + param.line.assign (param_names(pos).length (), '='); + + param.parameter_length = (a > param.parameter_length + ? a : param.parameter_length); + if (param.command == 's' && param.modifier == 'c' && b > 0) + param.first_parameter_length = b; + } + else + { + error ("whos_line_format: '%c' is not a command", + param.command); + error_encountered = true; + } + + if (param.command == 's') + { + // Have to calculate space needed for printing + // matrix dimensions Space needed for Size column is + // hard to determine in prior, because it depends on + // dimensions to be shown. That is why it is + // recalculated for each Size-command int first, + // rest = 0, total; + int rest = 0; + int first = param.first_parameter_length; + int total = param.parameter_length; + + for (std::list<symbol_info>::const_iterator p = lst.begin (); + p != lst.end (); p++) + { + octave_value val = p->varval; + std::string dims_str = get_dims_str (val); + int first1 = dims_str.find ('x'); + int total1 = dims_str.length (); + int rest1 = total1 - first1; + rest = (rest1 > rest ? rest1 : rest); + first = (first1 > first ? first1 : first); + total = (total1 > total ? total1 : total); + } + + if (param.modifier == 'c') + { + if (first < balance) + first += balance - first; + if (rest + balance < param.parameter_length) + rest += param.parameter_length - rest - balance; + + param.parameter_length = first + rest; + param.first_parameter_length = first; + param.balance = balance; + } + else + { + param.parameter_length = total; + param.first_parameter_length = 0; + } + } + else if (param.modifier == 'c') + { + error ("whos_line_format: modifier 'c' not available for command '%c'", + param.command); + error_encountered = true; + } + + // What happens if whos_line_format contains negative numbers + // at param_length positions? + param.balance = (b < 0 ? 0 : param.balance); + param.first_parameter_length = (b < 0 ? 0 : + param.first_parameter_length); + param.parameter_length = (a < 0 + ? 0 + : (param.parameter_length + < param_length(pos_s) + ? param_length(pos_s) + : param.parameter_length)); + + // Parameter will not be pushed into parameter list if ... + if (! error_encountered) + params.push_back (param); + } + else + { + // Text string, to be printed as it is ... + std::string text; + size_t pos; + text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ()); + pos = text.find ('%'); + if (pos != std::string::npos) + text = text.substr (0, pos); + + // Push parameter into list ... + idx += text.length (); + param.text=text; + param.line.assign (text.length (), ' '); + params.push_back (param); + } + } + + return params; + } + +private: + std::list<symbol_info> lst; + +}; + +static octave_value +do_who (int argc, const string_vector& argv, bool return_list, + bool verbose = false, std::string msg = std::string ()) +{ + octave_value retval; + + std::string my_name = argv[0]; + + bool global_only = false; + bool have_regexp = false; + + int i; + for (i = 1; i < argc; i++) + { + if (argv[i] == "-file") + { + // FIXME. This is an inefficient manner to implement this as the + // variables are loaded in to a temporary context and then treated. + // It would be better to refecat symbol_info_list to not store the + // symbol records and then use it in load-save.cc (do_load) to + // implement this option there so that the variables are never + // stored at all. + if (i == argc - 1) + error ("whos: -file argument must be followed by a file name"); + else + { + std::string nm = argv[i + 1]; + + unwind_protect frame; + + // Set up temporary scope. + + symbol_table::scope_id tmp_scope = symbol_table::alloc_scope (); + frame.add_fcn (symbol_table::erase_scope, tmp_scope); + + symbol_table::set_scope (tmp_scope); + + octave_call_stack::push (tmp_scope, 0); + frame.add_fcn (octave_call_stack::pop); + + frame.add_fcn (symbol_table::clear_variables); + + feval ("load", octave_value (nm), 0); + + if (! error_state) + { + std::string newmsg = std::string ("Variables in the file ") + + nm + ":\n\n"; + + retval = do_who (i, argv, return_list, verbose, newmsg); + } + } + + return retval; + } + else if (argv[i] == "-regexp") + have_regexp = true; + else if (argv[i] == "global") + global_only = true; + else if (argv[i][0] == '-') + warning ("%s: unrecognized option '%s'", my_name.c_str (), + argv[i].c_str ()); + else + break; + } + + int npats = argc - i; + string_vector pats; + if (npats > 0) + { + pats.resize (npats); + for (int j = 0; j < npats; j++) + pats[j] = argv[i+j]; + } + else + { + pats.resize (++npats); + pats[0] = "*"; + } + + symbol_info_list symbol_stats; + std::list<std::string> symbol_names; + + for (int j = 0; j < npats; j++) + { + std::string pat = pats[j]; + + if (have_regexp) + { + std::list<symbol_table::symbol_record> tmp = global_only + ? symbol_table::regexp_global_variables (pat) + : symbol_table::regexp_variables (pat); + + for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin (); + p != tmp.end (); p++) + { + if (p->is_variable ()) + { + if (verbose) + symbol_stats.append (*p); + else + symbol_names.push_back (p->name ()); + } + } + } + else + { + size_t pos = pat.find_first_of (".({"); + + if (pos != std::string::npos && pos > 0) + { + if (verbose) + { + // NOTE: we can only display information for + // expressions based on global values if the variable is + // global in the current scope because we currently have + // no way of looking up the base value in the global + // scope and then evaluating the arguments in the + // current scope. + + std::string base_name = pat.substr (0, pos); + + if (symbol_table::is_variable (base_name)) + { + symbol_table::symbol_record sr + = symbol_table::find_symbol (base_name); + + if (! global_only || sr.is_global ()) + { + int parse_status; + + octave_value expr_val + = eval_string (pat, true, parse_status); + + if (! error_state) + symbol_stats.append (sr, pat, expr_val); + else + return retval; + } + } + } + } + else + { + std::list<symbol_table::symbol_record> tmp = global_only + ? symbol_table::glob_global_variables (pat) + : symbol_table::glob_variables (pat); + + for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin (); + p != tmp.end (); p++) + { + if (p->is_variable ()) + { + if (verbose) + symbol_stats.append (*p); + else + symbol_names.push_back (p->name ()); + } + } + } + } + } + + if (return_list) + { + if (verbose) + { + std::string caller_function_name; + octave_function *caller = octave_call_stack::caller (); + if (caller) + caller_function_name = caller->name (); + + retval = symbol_stats.map_value (caller_function_name, 1); + } + else + retval = Cell (string_vector (symbol_names)); + } + else if (! (symbol_stats.empty () && symbol_names.empty ())) + { + if (msg.length () == 0) + if (global_only) + octave_stdout << "Global variables:\n\n"; + else + octave_stdout << "Variables in the current scope:\n\n"; + else + octave_stdout << msg; + + if (verbose) + symbol_stats.display (octave_stdout); + else + { + string_vector names (symbol_names); + + names.list_in_columns (octave_stdout); + } + + octave_stdout << "\n"; + } + + return retval; +} + +DEFUN (who, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Command} {} who\n\ +@deftypefnx {Command} {} who pattern @dots{}\n\ +@deftypefnx {Command} {} who option pattern @dots{}\n\ +@deftypefnx {Command} {C =} who (\"pattern\", @dots{})\n\ +List currently defined variables matching the given patterns. Valid\n\ +pattern syntax is the same as described for the @code{clear} command.\n\ +If no patterns are supplied, all variables are listed.\n\ +By default, only variables visible in the local scope are displayed.\n\ +\n\ +The following are valid options but may not be combined.\n\ +\n\ +@table @code\n\ +@item global\n\ +List variables in the global scope rather than the current scope.\n\ +\n\ +@item -regexp\n\ +The patterns are considered to be regular expressions when matching the\n\ +variables to display. The same pattern syntax accepted by\n\ +the @code{regexp} function is used.\n\ +\n\ +@item -file\n\ +The next argument is treated as a filename. All variables found within the\n\ +specified file are listed. No patterns are accepted when reading variables\n\ +from a file.\n\ +@end table\n\ +\n\ +If called as a function, return a cell array of defined variable names\n\ +matching the given patterns.\n\ +@seealso{whos, isglobal, isvarname, exist, regexp}\n\ +@end deftypefn") +{ + octave_value retval; + + if (nargout < 2) + { + int argc = args.length () + 1; + + string_vector argv = args.make_argv ("who"); + + if (! error_state) + retval = do_who (argc, argv, nargout == 1); + } + else + print_usage (); + + return retval; +} + +DEFUN (whos, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Command} {} whos\n\ +@deftypefnx {Command} {} whos pattern @dots{}\n\ +@deftypefnx {Command} {} whos option pattern @dots{}\n\ +@deftypefnx {Command} {S =} whos (\"pattern\", @dots{})\n\ +Provide detailed information on currently defined variables matching the\n\ +given patterns. Options and pattern syntax are the same as for the\n\ +@code{who} command. Extended information about each variable is\n\ +summarized in a table with the following default entries.\n\ +\n\ +@table @asis\n\ +@item Attr\n\ +Attributes of the listed variable. Possible attributes are:\n\ +\n\ +@table @asis\n\ +@item blank\n\ +Variable in local scope\n\ +\n\ +@item @code{a}\n\ +Automatic variable. An automatic variable is one created by the\n\ +interpreter, for example @code{argn}.\n\ +\n\ +@item @code{c}\n\ +Variable of complex type.\n\ +\n\ +@item @code{f}\n\ +Formal parameter (function argument).\n\ +\n\ +@item @code{g}\n\ +Variable with global scope.\n\ +\n\ +@item @code{p}\n\ +Persistent variable.\n\ +@end table\n\ +\n\ +@item Name\n\ +The name of the variable.\n\ +\n\ +@item Size\n\ +The logical size of the variable. A scalar is 1x1, a vector is\n\ +@nospell{1xN} or @nospell{Nx1}, a 2-D matrix is @nospell{MxN}.\n\ +\n\ +@item Bytes\n\ +The amount of memory currently used to store the variable.\n\ +\n\ +@item Class\n\ +The class of the variable. Examples include double, single, char, uint16,\n\ +cell, and struct.\n\ +@end table\n\ +\n\ +The table can be customized to display more or less information through\n\ +the function @code{whos_line_format}.\n\ +\n\ +If @code{whos} is called as a function, return a struct array of defined\n\ +variable names matching the given patterns. Fields in the structure\n\ +describing each variable are: name, size, bytes, class, global, sparse,\n\ +complex, nesting, persistent.\n\ +@seealso{who, whos_line_format}\n\ +@end deftypefn") +{ + octave_value retval; + + if (nargout < 2) + { + int argc = args.length () + 1; + + string_vector argv = args.make_argv ("whos"); + + if (! error_state) + retval = do_who (argc, argv, nargout == 1, true); + } + else + print_usage (); + + return retval; +} + +// Defining variables. + +void +bind_ans (const octave_value& val, bool print) +{ + static std::string ans = "ans"; + + if (val.is_defined ()) + { + if (val.is_cs_list ()) + { + octave_value_list lst = val.list_value (); + + for (octave_idx_type i = 0; i < lst.length (); i++) + bind_ans (lst(i), print); + } + else + { + symbol_table::force_assign (ans, val); + + if (print) + val.print_with_name (octave_stdout, ans); + } + } +} + +void +bind_internal_variable (const std::string& fname, const octave_value& val) +{ + octave_value_list args; + + args(0) = val; + + feval (fname, args, 0); +} + +void +mlock (void) +{ + octave_function *fcn = octave_call_stack::current (); + + if (fcn) + fcn->lock (); + else + error ("mlock: invalid use outside a function"); +} + +void +munlock (const std::string& nm) +{ + octave_value val = symbol_table::find_function (nm); + + if (val.is_defined ()) + { + octave_function *fcn = val.function_value (); + + if (fcn) + fcn->unlock (); + } +} + +bool +mislocked (const std::string& nm) +{ + bool retval = false; + + octave_value val = symbol_table::find_function (nm); + + if (val.is_defined ()) + { + octave_function *fcn = val.function_value (); + + if (fcn) + retval = fcn->islocked (); + } + + return retval; +} + +DEFUN (mlock, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} mlock ()\n\ +Lock the current function into memory so that it can't be cleared.\n\ +@seealso{munlock, mislocked, persistent}\n\ +@end deftypefn") +{ + octave_value_list retval; + + if (args.length () == 0) + { + octave_function *fcn = octave_call_stack::caller (); + + if (fcn) + fcn->lock (); + else + error ("mlock: invalid use outside a function"); + } + else + print_usage (); + + return retval; +} + +DEFUN (munlock, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} munlock ()\n\ +@deftypefnx {Built-in Function} {} munlock (@var{fcn})\n\ +Unlock the named function @var{fcn}. If no function is named\n\ +then unlock the current function.\n\ +@seealso{mlock, mislocked, persistent}\n\ +@end deftypefn") +{ + octave_value_list retval; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + munlock (name); + else + error ("munlock: FCN must be a string"); + } + else if (args.length () == 0) + { + octave_function *fcn = octave_call_stack::caller (); + + if (fcn) + fcn->unlock (); + else + error ("munlock: invalid use outside a function"); + } + else + print_usage (); + + return retval; +} + + +DEFUN (mislocked, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} mislocked ()\n\ +@deftypefnx {Built-in Function} {} mislocked (@var{fcn})\n\ +Return true if the named function @var{fcn} is locked. If no function is\n\ +named then return true if the current function is locked.\n\ +@seealso{mlock, munlock, persistent}\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + retval = mislocked (name); + else + error ("mislocked: FCN must be a string"); + } + else if (args.length () == 0) + { + octave_function *fcn = octave_call_stack::caller (); + + if (fcn) + retval = fcn->islocked (); + else + error ("mislocked: invalid use outside a function"); + } + else + print_usage (); + + return retval; +} + +// Deleting names from the symbol tables. + +static inline bool +name_matches_any_pattern (const std::string& nm, const string_vector& argv, + int argc, int idx, bool have_regexp = false) +{ + bool retval = false; + + for (int k = idx; k < argc; k++) + { + std::string patstr = argv[k]; + if (! patstr.empty ()) + { + if (have_regexp) + { + if (is_regexp_match (patstr, nm)) + { + retval = true; + break; + } + } + else + { + glob_match pattern (patstr); + + if (pattern.match (nm)) + { + retval = true; + break; + } + } + } + } + + return retval; +} + +static inline void +maybe_warn_exclusive (bool exclusive) +{ + if (exclusive) + warning ("clear: ignoring --exclusive option"); +} + +static void +do_clear_functions (const string_vector& argv, int argc, int idx, + bool exclusive = false) +{ + if (idx == argc) + symbol_table::clear_functions (); + else + { + if (exclusive) + { + string_vector fcns = symbol_table::user_function_names (); + + int fcount = fcns.length (); + + for (int i = 0; i < fcount; i++) + { + std::string nm = fcns[i]; + + if (! name_matches_any_pattern (nm, argv, argc, idx)) + symbol_table::clear_function (nm); + } + } + else + { + while (idx < argc) + symbol_table::clear_function_pattern (argv[idx++]); + } + } +} + +static void +do_clear_globals (const string_vector& argv, int argc, int idx, + bool exclusive = false) +{ + if (idx == argc) + { + string_vector gvars = symbol_table::global_variable_names (); + + int gcount = gvars.length (); + + for (int i = 0; i < gcount; i++) + symbol_table::clear_global (gvars[i]); + } + else + { + if (exclusive) + { + string_vector gvars = symbol_table::global_variable_names (); + + int gcount = gvars.length (); + + for (int i = 0; i < gcount; i++) + { + std::string nm = gvars[i]; + + if (! name_matches_any_pattern (nm, argv, argc, idx)) + symbol_table::clear_global (nm); + } + } + else + { + while (idx < argc) + symbol_table::clear_global_pattern (argv[idx++]); + } + } +} + +static void +do_clear_variables (const string_vector& argv, int argc, int idx, + bool exclusive = false, bool have_regexp = false) +{ + if (idx == argc) + symbol_table::clear_variables (); + else + { + if (exclusive) + { + string_vector lvars = symbol_table::variable_names (); + + int lcount = lvars.length (); + + for (int i = 0; i < lcount; i++) + { + std::string nm = lvars[i]; + + if (! name_matches_any_pattern (nm, argv, argc, idx, have_regexp)) + symbol_table::clear_variable (nm); + } + } + else + { + if (have_regexp) + while (idx < argc) + symbol_table::clear_variable_regexp (argv[idx++]); + else + while (idx < argc) + symbol_table::clear_variable_pattern (argv[idx++]); + } + } +} + +static void +do_clear_symbols (const string_vector& argv, int argc, int idx, + bool exclusive = false) +{ + if (idx == argc) + symbol_table::clear_variables (); + else + { + if (exclusive) + { + // FIXME -- is this really what we want, or do we + // somehow want to only clear the functions that are not + // shadowed by local variables? It seems that would be a + // bit harder to do. + + do_clear_variables (argv, argc, idx, exclusive); + do_clear_functions (argv, argc, idx, exclusive); + } + else + { + while (idx < argc) + symbol_table::clear_symbol_pattern (argv[idx++]); + } + } +} + +static void +do_matlab_compatible_clear (const string_vector& argv, int argc, int idx) +{ + // This is supposed to be mostly Matlab compatible. + + for (; idx < argc; idx++) + { + if (argv[idx] == "all" + && ! symbol_table::is_local_variable ("all")) + { + symbol_table::clear_all (); + } + else if (argv[idx] == "functions" + && ! symbol_table::is_local_variable ("functions")) + { + do_clear_functions (argv, argc, ++idx); + } + else if (argv[idx] == "global" + && ! symbol_table::is_local_variable ("global")) + { + do_clear_globals (argv, argc, ++idx); + } + else if (argv[idx] == "variables" + && ! symbol_table::is_local_variable ("variables")) + { + symbol_table::clear_variables (); + } + else if (argv[idx] == "classes" + && ! symbol_table::is_local_variable ("classes")) + { + symbol_table::clear_objects (); + octave_class::clear_exemplar_map (); + } + else + { + symbol_table::clear_symbol_pattern (argv[idx]); + } + } +} + +#define CLEAR_OPTION_ERROR(cond) \ + do \ + { \ + if (cond) \ + { \ + print_usage (); \ + return retval; \ + } \ + } \ + while (0) + +DEFUN (clear, args, , + "-*- texinfo -*-\n\ +@deftypefn {Command} {} clear [options] pattern @dots{}\n\ +Delete the names matching the given patterns from the symbol table. The\n\ +pattern may contain the following special characters:\n\ +\n\ +@table @code\n\ +@item ?\n\ +Match any single character.\n\ +\n\ +@item *\n\ +Match zero or more characters.\n\ +\n\ +@item [ @var{list} ]\n\ +Match the list of characters specified by @var{list}. If the first\n\ +character is @code{!} or @code{^}, match all characters except those\n\ +specified by @var{list}. For example, the pattern @samp{[a-zA-Z]} will\n\ +match all lowercase and uppercase alphabetic characters.\n\ +@end table\n\ +\n\ +For example, the command\n\ +\n\ +@example\n\ +clear foo b*r\n\ +@end example\n\ +\n\ +@noindent\n\ +clears the name @code{foo} and all names that begin with the letter\n\ +@code{b} and end with the letter @code{r}.\n\ +\n\ +If @code{clear} is called without any arguments, all user-defined\n\ +variables (local and global) are cleared from the symbol table. If\n\ +@code{clear} is called with at least one argument, only the visible\n\ +names matching the arguments are cleared. For example, suppose you have\n\ +defined a function @code{foo}, and then hidden it by performing the\n\ +assignment @code{foo = 2}. Executing the command @kbd{clear foo} once\n\ +will clear the variable definition and restore the definition of\n\ +@code{foo} as a function. Executing @kbd{clear foo} a second time will\n\ +clear the function definition.\n\ +\n\ +The following options are available in both long and short form\n\ +\n\ +@table @code\n\ +@item -all, -a\n\ +Clears all local and global user-defined variables and all functions\n\ +from the symbol table.\n\ +\n\ +@item -exclusive, -x\n\ +Clears the variables that don't match the following pattern.\n\ +\n\ +@item -functions, -f\n\ +Clears the function names and the built-in symbols names.\n\ +\n\ +@item -global, -g\n\ +Clears the global symbol names.\n\ +\n\ +@item -variables, -v\n\ +Clears the local variable names.\n\ +\n\ +@item -classes, -c\n\ +Clears the class structure table and clears all objects.\n\ +\n\ +@item -regexp, -r\n\ +The arguments are treated as regular expressions as any variables that\n\ +match will be cleared.\n\ +@end table\n\ +\n\ +With the exception of @code{exclusive}, all long options can be used\n\ +without the dash as well.\n\ +@end deftypefn") +{ + octave_value_list retval; + + int argc = args.length () + 1; + + string_vector argv = args.make_argv ("clear"); + + if (! error_state) + { + if (argc == 1) + { + do_clear_globals (argv, argc, true); + do_clear_variables (argv, argc, true); + + octave_link::clear_workspace (); + } + else + { + int idx = 0; + + bool clear_all = false; + bool clear_functions = false; + bool clear_globals = false; + bool clear_variables = false; + bool clear_objects = false; + bool exclusive = false; + bool have_regexp = false; + bool have_dash_option = false; + + while (++idx < argc) + { + if (argv[idx] == "-all" || argv[idx] == "-a") + { + CLEAR_OPTION_ERROR (have_dash_option && ! exclusive); + + have_dash_option = true; + clear_all = true; + } + else if (argv[idx] == "-exclusive" || argv[idx] == "-x") + { + have_dash_option = true; + exclusive = true; + } + else if (argv[idx] == "-functions" || argv[idx] == "-f") + { + CLEAR_OPTION_ERROR (have_dash_option && ! exclusive); + + have_dash_option = true; + clear_functions = true; + } + else if (argv[idx] == "-global" || argv[idx] == "-g") + { + CLEAR_OPTION_ERROR (have_dash_option && ! exclusive); + + have_dash_option = true; + clear_globals = true; + } + else if (argv[idx] == "-variables" || argv[idx] == "-v") + { + CLEAR_OPTION_ERROR (have_dash_option && ! exclusive); + + have_dash_option = true; + clear_variables = true; + } + else if (argv[idx] == "-classes" || argv[idx] == "-c") + { + CLEAR_OPTION_ERROR (have_dash_option && ! exclusive); + + have_dash_option = true; + clear_objects = true; + } + else if (argv[idx] == "-regexp" || argv[idx] == "-r") + { + CLEAR_OPTION_ERROR (have_dash_option && ! exclusive); + + have_dash_option = true; + have_regexp = true; + } + else + break; + } + + if (idx <= argc) + { + if (! have_dash_option) + { + do_matlab_compatible_clear (argv, argc, idx); + } + else + { + if (clear_all) + { + maybe_warn_exclusive (exclusive); + + if (++idx < argc) + warning + ("clear: ignoring extra arguments after -all"); + + symbol_table::clear_all (); + } + else if (have_regexp) + { + do_clear_variables (argv, argc, idx, exclusive, true); + } + else if (clear_functions) + { + do_clear_functions (argv, argc, idx, exclusive); + } + else if (clear_globals) + { + do_clear_globals (argv, argc, idx, exclusive); + } + else if (clear_variables) + { + do_clear_variables (argv, argc, idx, exclusive); + } + else if (clear_objects) + { + symbol_table::clear_objects (); + octave_class::clear_exemplar_map (); + } + else + { + do_clear_symbols (argv, argc, idx, exclusive); + } + } + + octave_link::set_workspace (); + } + } + } + + return retval; +} + +DEFUN (whos_line_format, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} whos_line_format (@var{new_val}, \"local\")\n\ +Query or set the format string used by the command @code{whos}.\n\ +\n\ +A full format string is:\n\ +@c Set example in small font to prevent overfull line\n\ +\n\ +@smallexample\n\ +%[modifier]<command>[:width[:left-min[:balance]]];\n\ +@end smallexample\n\ +\n\ +The following command sequences are available:\n\ +\n\ +@table @code\n\ +@item %a\n\ +Prints attributes of variables (g=global, p=persistent,\n\ +f=formal parameter, a=automatic variable).\n\ +\n\ +@item %b\n\ +Prints number of bytes occupied by variables.\n\ +\n\ +@item %c\n\ +Prints class names of variables.\n\ +\n\ +@item %e\n\ +Prints elements held by variables.\n\ +\n\ +@item %n\n\ +Prints variable names.\n\ +\n\ +@item %s\n\ +Prints dimensions of variables.\n\ +\n\ +@item %t\n\ +Prints type names of variables.\n\ +@end table\n\ +\n\ +Every command may also have an alignment modifier:\n\ +\n\ +@table @code\n\ +@item l\n\ +Left alignment.\n\ +\n\ +@item r\n\ +Right alignment (default).\n\ +\n\ +@item c\n\ +Column-aligned (only applicable to command %s).\n\ +@end table\n\ +\n\ +The @code{width} parameter is a positive integer specifying the minimum\n\ +number of columns used for printing. No maximum is needed as the field will\n\ +auto-expand as required.\n\ +\n\ +The parameters @code{left-min} and @code{balance} are only available when the\n\ +column-aligned modifier is used with the command @samp{%s}.\n\ +@code{balance} specifies the column number within the field width which will\n\ +be aligned between entries. Numbering starts from 0 which indicates the\n\ +leftmost column. @code{left-min} specifies the minimum field width to the\n\ +left of the specified balance column.\n\ +\n\ +The default format is\n\ +@code{\" %a:4; %ln:6; %cs:16:6:1; %rb:12; %lc:-1;\\n\"}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ +@seealso{whos}\n\ +@end deftypefn") +{ + return SET_INTERNAL_VARIABLE (whos_line_format); +} + +static std::string Vmissing_function_hook = "__unimplemented__"; + +DEFUN (missing_function_hook, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {@var{val} =} missing_function_hook ()\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} missing_function_hook (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} missing_function_hook (@var{new_val}, \"local\")\n\ +Query or set the internal variable that specifies the function to call when\n\ +an unknown identifier is requested.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ +@end deftypefn") +{ + return SET_INTERNAL_VARIABLE (missing_function_hook); +} + +void maybe_missing_function_hook (const std::string& name) +{ + // Don't do this if we're handling errors. + if (buffer_error_messages == 0 && ! Vmissing_function_hook.empty ()) + { + octave_value val = symbol_table::find_function (Vmissing_function_hook); + + if (val.is_defined ()) + { + // Ensure auto-restoration. + unwind_protect frame; + frame.protect_var (Vmissing_function_hook); + + // Clear the variable prior to calling the function. + const std::string func_name = Vmissing_function_hook; + Vmissing_function_hook.clear (); + + // Call. + feval (func_name, octave_value (name)); + } + } +} + +DEFUN (__varval__, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} __varval__ (@var{name})\n\ +Undocumented internal function.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + retval = symbol_table::varval (args(0).string_value ()); + else + error ("__varval__: expecting argument to be variable name"); + } + else + print_usage (); + + return retval; +}