variables.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1993-2012 John W. Eaton
00004 Copyright (C) 2009-2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <cstdio>
00029 #include <cstring>
00030 
00031 #include <iomanip>
00032 #include <set>
00033 #include <string>
00034 
00035 #include "file-stat.h"
00036 #include "oct-env.h"
00037 #include "file-ops.h"
00038 #include "glob-match.h"
00039 #include "regexp.h"
00040 #include "str-vec.h"
00041 
00042 #include <defaults.h>
00043 #include "Cell.h"
00044 #include "defun.h"
00045 #include "dirfns.h"
00046 #include "error.h"
00047 #include "gripes.h"
00048 #include "help.h"
00049 #include "input.h"
00050 #include "lex.h"
00051 #include "load-path.h"
00052 #include "oct-map.h"
00053 #include "oct-obj.h"
00054 #include "ov.h"
00055 #include "ov-class.h"
00056 #include "ov-usr-fcn.h"
00057 #include "pager.h"
00058 #include "parse.h"
00059 #include "symtab.h"
00060 #include "toplev.h"
00061 #include "unwind-prot.h"
00062 #include "utils.h"
00063 #include "variables.h"
00064 
00065 // Defines layout for the whos/who -long command
00066 static std::string Vwhos_line_format
00067   = "  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;\n";
00068 
00069 void
00070 clear_mex_functions (void)
00071 {
00072   symbol_table::clear_mex_functions ();
00073 }
00074 
00075 void
00076 clear_function (const std::string& nm)
00077 {
00078   symbol_table::clear_function (nm);
00079 }
00080 
00081 void
00082 clear_variable (const std::string& nm)
00083 {
00084   symbol_table::clear_variable (nm);
00085 }
00086 
00087 void
00088 clear_symbol (const std::string& nm)
00089 {
00090   symbol_table::clear_symbol (nm);
00091 }
00092 
00093 // Attributes of variables and functions.
00094 
00095 // Is this octave_value a valid function?
00096 
00097 octave_function *
00098 is_valid_function (const std::string& fcn_name,
00099                    const std::string& warn_for, bool warn)
00100 {
00101   octave_function *ans = 0;
00102 
00103   if (! fcn_name.empty ())
00104     {
00105       octave_value val = symbol_table::find_function (fcn_name);
00106 
00107       if (val.is_defined ())
00108         ans = val.function_value (true);
00109     }
00110 
00111   if (! ans && warn)
00112     error ("%s: the symbol '%s' is not valid as a function",
00113            warn_for.c_str (), fcn_name.c_str ());
00114 
00115   return ans;
00116 }
00117 
00118 octave_function *
00119 is_valid_function (const octave_value& arg,
00120                    const std::string& warn_for, bool warn)
00121 {
00122   octave_function *ans = 0;
00123 
00124   std::string fcn_name;
00125 
00126   if (arg.is_string ())
00127     {
00128       fcn_name = arg.string_value ();
00129 
00130       if (! error_state)
00131         ans = is_valid_function (fcn_name, warn_for, warn);
00132       else if (warn)
00133         error ("%s: expecting function name as argument", warn_for.c_str ());
00134     }
00135   else if (warn)
00136     error ("%s: expecting function name as argument", warn_for.c_str ());
00137 
00138   return ans;
00139 }
00140 
00141 octave_function *
00142 extract_function (const octave_value& arg, const std::string& warn_for,
00143                   const std::string& fname, const std::string& header,
00144                   const std::string& trailer)
00145 {
00146   octave_function *retval = 0;
00147 
00148   retval = is_valid_function (arg, warn_for, 0);
00149 
00150   if (! retval)
00151     {
00152       std::string s = arg.string_value ();
00153 
00154       std::string cmd = header;
00155       cmd.append (s);
00156       cmd.append (trailer);
00157 
00158       if (! error_state)
00159         {
00160           int parse_status;
00161 
00162           eval_string (cmd, true, parse_status, 0);
00163 
00164           if (parse_status == 0)
00165             {
00166               retval = is_valid_function (fname, warn_for, 0);
00167 
00168               if (! retval)
00169                 {
00170                   error ("%s: '%s' is not valid as a function",
00171                          warn_for.c_str (), fname.c_str ());
00172                   return retval;
00173                 }
00174 
00175               warning ("%s: passing function body as a string is obsolete; please use anonymous functions",
00176                        warn_for.c_str ());
00177             }
00178           else
00179             error ("%s: '%s' is not valid as a function",
00180                    warn_for.c_str (), fname.c_str ());
00181         }
00182       else
00183         error ("%s: expecting first argument to be a string",
00184                warn_for.c_str ());
00185     }
00186 
00187   return retval;
00188 }
00189 
00190 string_vector
00191 get_struct_elts (const std::string& text)
00192 {
00193   int n = 1;
00194 
00195   size_t pos = 0;
00196 
00197   size_t len = text.length ();
00198 
00199   while ((pos = text.find ('.', pos)) != std::string::npos)
00200     {
00201       if (++pos == len)
00202         break;
00203 
00204       n++;
00205     }
00206 
00207   string_vector retval (n);
00208 
00209   pos = 0;
00210 
00211   for (int i = 0; i < n; i++)
00212     {
00213       len = text.find ('.', pos);
00214 
00215       if (len != std::string::npos)
00216         len -= pos;
00217 
00218       retval[i] = text.substr (pos, len);
00219 
00220       if (len != std::string::npos)
00221         pos += len + 1;
00222     }
00223 
00224   return retval;
00225 }
00226 
00227 static inline bool
00228 is_variable (const std::string& name)
00229 {
00230   bool retval = false;
00231 
00232   if (! name.empty ())
00233     {
00234       octave_value val = symbol_table::varval (name);
00235 
00236       retval = val.is_defined ();
00237     }
00238 
00239   return retval;
00240 }
00241 
00242 string_vector
00243 generate_struct_completions (const std::string& text,
00244                              std::string& prefix, std::string& hint)
00245 {
00246   string_vector names;
00247 
00248   size_t pos = text.rfind ('.');
00249 
00250   if (pos != std::string::npos)
00251     {
00252       if (pos == text.length ())
00253         hint = "";
00254       else
00255         hint = text.substr (pos+1);
00256 
00257       prefix = text.substr (0, pos);
00258 
00259       std::string base_name = prefix;
00260 
00261       pos = base_name.find_first_of ("{(.");
00262 
00263       if (pos != std::string::npos)
00264         base_name = base_name.substr (0, pos);
00265 
00266       if (is_variable (base_name))
00267         {
00268           int parse_status;
00269 
00270           unwind_protect frame;
00271 
00272           frame.protect_var (error_state);
00273           frame.protect_var (warning_state);
00274 
00275           frame.protect_var (discard_error_messages);
00276           frame.protect_var (discard_warning_messages);
00277 
00278           discard_error_messages = true;
00279           discard_warning_messages = true;
00280 
00281           octave_value tmp = eval_string (prefix, true, parse_status);
00282 
00283           frame.run ();
00284 
00285           if (tmp.is_defined () && tmp.is_map ())
00286             names = tmp.map_keys ();
00287         }
00288     }
00289 
00290   return names;
00291 }
00292 
00293 // FIXME -- this will have to be much smarter to work
00294 // "correctly".
00295 
00296 bool
00297 looks_like_struct (const std::string& text)
00298 {
00299   bool retval = (! text.empty ()
00300                  && text != "."
00301                  && text.find_first_of (file_ops::dir_sep_chars ()) == std::string::npos
00302                  && text.find ("..") == std::string::npos
00303                  && text.rfind ('.') != std::string::npos);
00304 
00305 #if 0
00306   symbol_record *sr = curr_sym_tab->lookup (text);
00307 
00308   if (sr && ! sr->is_function ())
00309     {
00310       int parse_status;
00311 
00312       unwind_protect frame;
00313 
00314       frame.protect_var (discard_error_messages);
00315       frame.protect_var (error_state);
00316 
00317       discard_error_messages = true;
00318 
00319       octave_value tmp = eval_string (text, true, parse_status);
00320 
00321       frame.run ();
00322 
00323       retval = (tmp.is_defined () && tmp.is_map ());
00324     }
00325 #endif
00326 
00327   return retval;
00328 }
00329 
00330 static octave_value
00331 do_isglobal (const octave_value_list& args)
00332 {
00333   octave_value retval = false;
00334 
00335   int nargin = args.length ();
00336 
00337   if (nargin != 1)
00338     {
00339       print_usage ();
00340       return retval;
00341     }
00342 
00343   std::string name = args(0).string_value ();
00344 
00345   if (error_state)
00346     {
00347       error ("isglobal: NAME must be a string");
00348       return retval;
00349     }
00350 
00351   return symbol_table::is_global (name);
00352 }
00353 
00354 DEFUN (isglobal, args, ,
00355   "-*- texinfo -*-\n\
00356 @deftypefn {Built-in Function} {} isglobal (@var{name})\n\
00357 Return true if @var{name} is a globally visible variable.\n\
00358 For example:\n\
00359 \n\
00360 @example\n\
00361 @group\n\
00362 global x\n\
00363 isglobal (\"x\")\n\
00364      @result{} 1\n\
00365 @end group\n\
00366 @end example\n\
00367 @seealso{isvarname, exist}\n\
00368 @end deftypefn")
00369 {
00370   return do_isglobal (args);
00371 }
00372 
00373 static octave_value
00374 safe_symbol_lookup (const std::string& symbol_name)
00375 {
00376   octave_value retval;
00377 
00378   unwind_protect frame;
00379   interpreter_try (frame);
00380 
00381   retval = symbol_table::find (symbol_name);
00382 
00383   error_state = 0;
00384 
00385   return retval;
00386 }
00387 
00388 int
00389 symbol_exist (const std::string& name, const std::string& type)
00390 {
00391   int retval = 0;
00392 
00393   std::string struct_elts;
00394   std::string symbol_name = name;
00395 
00396   size_t pos = name.find ('.');
00397 
00398   if (pos != std::string::npos && pos > 0)
00399     {
00400       struct_elts = name.substr (pos+1);
00401       symbol_name = name.substr (0, pos);
00402     }
00403 
00404   // We shouldn't need to look in the global symbol table, since any
00405   // name that is visible in the current scope will be in the local
00406   // symbol table.
00407 
00408   octave_value val = safe_symbol_lookup (symbol_name);
00409 
00410   if (val.is_defined ())
00411     {
00412       bool not_a_struct = struct_elts.empty ();
00413       bool var_ok = not_a_struct /* || val.is_map_element (struct_elts) */;
00414 
00415       if (! retval
00416           && var_ok
00417           && (type == "any" || type == "var")
00418           && (val.is_constant () || val.is_object ()
00419               || val.is_function_handle ()
00420               || val.is_anonymous_function ()
00421               || val.is_inline_function ()))
00422         {
00423           retval = 1;
00424         }
00425 
00426       if (! retval
00427           && (type == "any" || type == "builtin"))
00428         {
00429           if (not_a_struct && val.is_builtin_function ())
00430             {
00431               retval = 5;
00432             }
00433         }
00434 
00435       if (! retval
00436           && not_a_struct
00437           && (type == "any" || type == "file")
00438           && (val.is_user_function () || val.is_dld_function ()))
00439         {
00440           octave_function *f = val.function_value (true);
00441           std::string s = f ? f->fcn_file_name () : std::string ();
00442 
00443           retval = s.empty () ? 103 : (val.is_user_function () ? 2 : 3);
00444         }
00445     }
00446 
00447   if (! (type == "var" || type == "builtin"))
00448     {
00449       if (! retval)
00450         {
00451           std::string file_name = lookup_autoload (name);
00452 
00453           if (file_name.empty ())
00454             file_name = load_path::find_fcn (name);
00455 
00456           size_t len = file_name.length ();
00457 
00458           if (len > 0)
00459             {
00460               if (type == "any" || type == "file")
00461                 {
00462                   if (len > 4 && (file_name.substr (len-4) == ".oct"
00463                                   || file_name.substr (len-4) == ".mex"))
00464                     retval = 3;
00465                   else
00466                     retval = 2;
00467                 }
00468             }
00469         }
00470 
00471       if (! retval)
00472         {
00473           std::string file_name = file_in_path (name, "");
00474 
00475           if (file_name.empty ())
00476             file_name = name;
00477 
00478           file_stat fs (file_name);
00479 
00480           if (fs)
00481             {
00482               if (type == "any" || type == "file")
00483                 retval = fs.is_dir () ? 7 : 2;
00484               else if (type == "dir" && fs.is_dir ())
00485                 retval = 7;
00486             }
00487         }
00488     }
00489 
00490   return retval;
00491 }
00492 
00493 #define GET_IDX(LEN) \
00494   static_cast<int> ((LEN-1) * static_cast<double> (rand ()) / RAND_MAX)
00495 
00496 std::string
00497 unique_symbol_name (const std::string& basename)
00498 {
00499   static const std::string alpha
00500     = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
00501 
00502   static size_t len = alpha.length ();
00503 
00504   std::string nm = basename + alpha[GET_IDX (len)];
00505 
00506   size_t pos = nm.length ();
00507 
00508   if (nm.substr (0, 2) == "__")
00509     nm.append ("__");
00510 
00511   while (symbol_exist (nm, "any"))
00512     nm.insert (pos++, 1, alpha[GET_IDX (len)]);
00513 
00514   return nm;
00515 }
00516 
00517 DEFUN (exist, args, ,
00518   "-*- texinfo -*-\n\
00519 @deftypefn {Built-in Function} {} exist (@var{name}, @var{type})\n\
00520 Return 1 if the name exists as a variable, 2 if the name is an\n\
00521 absolute file name, an ordinary file in Octave's @code{path}, or (after\n\
00522 appending @samp{.m}) a function file in Octave's @code{path}, 3 if the\n\
00523 name is a @samp{.oct} or @samp{.mex} file in Octave's @code{path},\n\
00524 5 if the name is a built-in function, 7 if the name is a directory, or 103\n\
00525 if the name is a function not associated with a file (entered on\n\
00526 the command line).\n\
00527 \n\
00528 Otherwise, return 0.\n\
00529 \n\
00530 This function also returns 2 if a regular file called @var{name}\n\
00531 exists in Octave's search path.  If you want information about\n\
00532 other types of files, you should use some combination of the functions\n\
00533 @code{file_in_path} and @code{stat} instead.\n\
00534 \n\
00535 If the optional argument @var{type} is supplied, check only for\n\
00536 symbols of the specified type.  Valid types are\n\
00537 \n\
00538 @table @asis\n\
00539 @item \"var\"\n\
00540 Check only for variables.\n\
00541 \n\
00542 @item \"builtin\"\n\
00543 Check only for built-in functions.\n\
00544 \n\
00545 @item \"file\"\n\
00546 Check only for files.\n\
00547 \n\
00548 @item \"dir\"\n\
00549 Check only for directories.\n\
00550 @end table\n\
00551 @seealso{file_in_loadpath}\n\
00552 @end deftypefn")
00553 {
00554   octave_value retval = false;
00555 
00556   int nargin = args.length ();
00557 
00558   if (nargin == 1 || nargin == 2)
00559     {
00560       std::string name = args(0).string_value ();
00561 
00562       if (! error_state)
00563         {
00564           std::string type
00565             = (nargin == 2) ? args(1).string_value () : std::string ("any");
00566 
00567           if (! error_state)
00568             retval = symbol_exist (name, type);
00569           else
00570             error ("exist: TYPE must be a string");
00571         }
00572       else
00573         error ("exist: NAME must be a string");
00574     }
00575   else
00576     print_usage ();
00577 
00578   return retval;
00579 }
00580 
00581 /*
00582 %!test
00583 %!  if (isunix ())
00584 %!    assert (exist ("/tmp") == 7);
00585 %!    assert (exist ("/tmp", "file") == 7);
00586 %!    assert (exist ("/tmp", "dir") == 7);
00587 %!    assert (exist ("/bin/sh") == 2);
00588 %!    assert (exist ("/bin/sh", "file") == 2);
00589 %!    assert (exist ("/bin/sh", "dir") == 0);
00590 %!    assert (exist ("/dev/null") == 2);
00591 %!    assert (exist ("/dev/null", "file") == 2);
00592 %!    assert (exist ("/dev/null", "dir") == 0);
00593 %!  endif
00594 */
00595 
00596 octave_value
00597 lookup_function_handle (const std::string& nm)
00598 {
00599   octave_value val = symbol_table::varval (nm);
00600 
00601   return val.is_function_handle () ? val : octave_value ();
00602 }
00603 
00604 octave_value
00605 get_global_value (const std::string& nm, bool silent)
00606 {
00607   octave_value val = symbol_table::global_varval (nm);
00608 
00609   if (val.is_undefined () && ! silent)
00610     error ("get_global_value: undefined symbol '%s'", nm.c_str ());
00611 
00612   return val;
00613 }
00614 
00615 void
00616 set_global_value (const std::string& nm, const octave_value& val)
00617 {
00618   symbol_table::global_varref (nm) = val;
00619 }
00620 
00621 octave_value
00622 get_top_level_value (const std::string& nm, bool silent)
00623 {
00624   octave_value val = symbol_table::top_level_varval (nm);
00625 
00626   if (val.is_undefined () && ! silent)
00627     error ("get_top_level_value: undefined symbol '%s'", nm.c_str ());
00628 
00629   return val;
00630 }
00631 
00632 void
00633 set_top_level_value (const std::string& nm, const octave_value& val)
00634 {
00635   symbol_table::top_level_varref (nm) = val;
00636 }
00637 
00638 // Variable values.
00639 
00640 static bool
00641 wants_local_change (const octave_value_list& args, int& nargin)
00642 {
00643   bool retval = false;
00644 
00645   if (nargin == 2)
00646     {
00647       if (args(1).is_string () && args(1).string_value () == "local")
00648         {
00649           nargin = 1;
00650           retval = true;
00651         }
00652       else
00653         {
00654           error_with_cfn ("expecting second argument to be \"local\"");
00655           nargin = 0;
00656         }
00657     }
00658 
00659   return retval;
00660 }
00661 
00662 template <class T>
00663 bool try_local_protect (T& var)
00664 {
00665   octave_user_code *curr_usr_code = octave_call_stack::caller_user_code ();
00666   octave_user_function *curr_usr_fcn = 0;
00667   if (curr_usr_code && curr_usr_code->is_user_function ())
00668     curr_usr_fcn = dynamic_cast<octave_user_function *> (curr_usr_code);
00669 
00670   if (curr_usr_fcn && curr_usr_fcn->local_protect (var))
00671     return true;
00672   else
00673     return false;
00674 }
00675 
00676 octave_value
00677 set_internal_variable (bool& var, const octave_value_list& args,
00678                        int nargout, const char *nm)
00679 {
00680   octave_value retval;
00681 
00682   int nargin = args.length ();
00683 
00684   if (nargout > 0 || nargin == 0)
00685     retval = var;
00686 
00687   if (wants_local_change (args, nargin))
00688     {
00689       if (! try_local_protect (var))
00690         warning ("\"local\" has no effect outside a function");
00691     }
00692 
00693   if (nargin == 1)
00694     {
00695       bool bval = args(0).bool_value ();
00696 
00697       if (! error_state)
00698         var = bval;
00699       else
00700         error ("%s: expecting arg to be a logical value", nm);
00701     }
00702   else if (nargin > 1)
00703     print_usage ();
00704 
00705   return retval;
00706 }
00707 
00708 octave_value
00709 set_internal_variable (char& var, const octave_value_list& args,
00710                        int nargout, const char *nm)
00711 {
00712   octave_value retval;
00713 
00714   int nargin = args.length ();
00715 
00716   if (nargout > 0 || nargin == 0)
00717     retval = var;
00718 
00719   if (wants_local_change (args, nargin))
00720     {
00721       if (! try_local_protect (var))
00722         warning ("\"local\" has no effect outside a function");
00723     }
00724 
00725   if (nargin == 1)
00726     {
00727       std::string sval = args(0).string_value ();
00728 
00729       if (! error_state)
00730         {
00731           switch (sval.length ())
00732             {
00733             case 1:
00734               var = sval[0];
00735               break;
00736 
00737             case 0:
00738               var = '\0';
00739               break;
00740 
00741             default:
00742               error ("%s: argument must be a single character", nm);
00743               break;
00744             }
00745         }
00746       else
00747         error ("%s: argument must be a single character", nm);
00748     }
00749   else if (nargin > 1)
00750     print_usage ();
00751 
00752   return retval;
00753 }
00754 
00755 octave_value
00756 set_internal_variable (int& var, const octave_value_list& args,
00757                        int nargout, const char *nm,
00758                        int minval, int maxval)
00759 {
00760   octave_value retval;
00761 
00762   int nargin = args.length ();
00763 
00764   if (nargout > 0 || nargin == 0)
00765     retval = var;
00766 
00767   if (wants_local_change (args, nargin))
00768     {
00769       if (! try_local_protect (var))
00770         warning ("\"local\" has no effect outside a function");
00771     }
00772 
00773   if (nargin == 1)
00774     {
00775       int ival = args(0).int_value ();
00776 
00777       if (! error_state)
00778         {
00779           if (ival < minval)
00780             error ("%s: expecting arg to be greater than %d", nm, minval);
00781           else if (ival > maxval)
00782             error ("%s: expecting arg to be less than or equal to %d",
00783                    nm, maxval);
00784           else
00785             var = ival;
00786         }
00787       else
00788         error ("%s: expecting arg to be an integer value", nm);
00789     }
00790   else if (nargin > 1)
00791     print_usage ();
00792 
00793   return retval;
00794 }
00795 
00796 octave_value
00797 set_internal_variable (double& var, const octave_value_list& args,
00798                        int nargout, const char *nm,
00799                        double minval, double maxval)
00800 {
00801   octave_value retval;
00802 
00803   int nargin = args.length ();
00804 
00805   if (nargout > 0 || nargin == 0)
00806     retval = var;
00807 
00808   if (wants_local_change (args, nargin))
00809     {
00810       if (! try_local_protect (var))
00811         warning ("\"local\" has no effect outside a function");
00812     }
00813 
00814   if (nargin == 1)
00815     {
00816       double dval = args(0).scalar_value ();
00817 
00818       if (! error_state)
00819         {
00820           if (dval < minval)
00821             error ("%s: expecting arg to be greater than %g", minval);
00822           else if (dval > maxval)
00823             error ("%s: expecting arg to be less than or equal to %g", maxval);
00824           else
00825             var = dval;
00826         }
00827       else
00828         error ("%s: expecting arg to be a scalar value", nm);
00829     }
00830   else if (nargin > 1)
00831     print_usage ();
00832 
00833   return retval;
00834 }
00835 
00836 octave_value
00837 set_internal_variable (std::string& var, const octave_value_list& args,
00838                        int nargout, const char *nm, bool empty_ok)
00839 {
00840   octave_value retval;
00841 
00842   int nargin = args.length ();
00843 
00844   if (nargout > 0 || nargin == 0)
00845     retval = var;
00846 
00847   if (wants_local_change (args, nargin))
00848     {
00849       if (! try_local_protect (var))
00850         warning ("\"local\" has no effect outside a function");
00851     }
00852 
00853   if (nargin == 1)
00854     {
00855       std::string sval = args(0).string_value ();
00856 
00857       if (! error_state)
00858         {
00859           if (empty_ok || ! sval.empty ())
00860             var = sval;
00861           else
00862             error ("%s: value must not be empty", nm);
00863         }
00864       else
00865         error ("%s: expecting arg to be a character string", nm);
00866     }
00867   else if (nargin > 1)
00868     print_usage ();
00869 
00870   return retval;
00871 }
00872 
00873 octave_value
00874 set_internal_variable (int& var, const octave_value_list& args,
00875                        int nargout, const char *nm, const char **choices)
00876 {
00877   octave_value retval;
00878   int nchoices = 0;
00879   while (choices[nchoices] != 0)
00880     nchoices++;
00881 
00882   int nargin = args.length ();
00883   assert (var < nchoices);
00884 
00885   if (nargout > 0 || nargin == 0)
00886     retval = choices[var];
00887 
00888   if (wants_local_change (args, nargin))
00889     {
00890       if (! try_local_protect (var))
00891         warning ("\"local\" has no effect outside a function");
00892     }
00893 
00894   if (nargin == 1)
00895     {
00896       std::string sval = args(0).string_value ();
00897 
00898       if (! error_state)
00899         {
00900           int i = 0;
00901           for (; i < nchoices; i++)
00902             {
00903               if (sval == choices[i])
00904                 {
00905                   var = i;
00906                   break;
00907                 }
00908             }
00909           if (i == nchoices)
00910             error ("%s: value not allowed (\"%s\")", nm, sval.c_str ());
00911         }
00912       else
00913         error ("%s: expecting arg to be a character string", nm);
00914     }
00915   else if (nargin > 1)
00916     print_usage ();
00917 
00918   return retval;
00919 }
00920 
00921 struct
00922 whos_parameter
00923 {
00924   char command;
00925   char modifier;
00926   int parameter_length;
00927   int first_parameter_length;
00928   int balance;
00929   std::string text;
00930   std::string line;
00931 };
00932 
00933 static void
00934 print_descriptor (std::ostream& os, std::list<whos_parameter> params)
00935 {
00936   // This method prints a line of information on a given symbol
00937   std::list<whos_parameter>::iterator i = params.begin ();
00938   std::ostringstream param_buf;
00939 
00940   while (i != params.end ())
00941     {
00942       whos_parameter param = *i;
00943 
00944       if (param.command != '\0')
00945         {
00946           // Do the actual printing
00947           switch (param.modifier)
00948             {
00949             case 'l':
00950               os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
00951               param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
00952               break;
00953 
00954             case 'r':
00955               os << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
00956               param_buf << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
00957               break;
00958 
00959             case 'c':
00960               if (param.command != 's')
00961                 {
00962                   os << std::setiosflags (std::ios::left)
00963                      << std::setw (param.parameter_length);
00964                   param_buf << std::setiosflags (std::ios::left)
00965                             << std::setw (param.parameter_length);
00966                 }
00967               break;
00968 
00969             default:
00970               os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
00971               param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
00972             }
00973 
00974           if (param.command == 's' && param.modifier == 'c')
00975             {
00976               int a, b;
00977 
00978               if (param.modifier == 'c')
00979                 {
00980                   a = param.first_parameter_length - param.balance;
00981                   a = (a < 0 ? 0 : a);
00982                   b = param.parameter_length - a - param.text . length ();
00983                   b = (b < 0 ? 0 : b);
00984                   os << std::setiosflags (std::ios::left) << std::setw (a)
00985                      << "" << std::resetiosflags (std::ios::left) << param.text
00986                      << std::setiosflags (std::ios::left)
00987                      << std::setw (b) << ""
00988                      << std::resetiosflags (std::ios::left);
00989                   param_buf << std::setiosflags (std::ios::left) << std::setw (a)
00990                      << "" << std::resetiosflags (std::ios::left) << param.line
00991                      << std::setiosflags (std::ios::left)
00992                      << std::setw (b) << ""
00993                      << std::resetiosflags (std::ios::left);
00994                 }
00995             }
00996           else
00997             {
00998               os << param.text;
00999               param_buf << param.line;
01000             }
01001           os << std::resetiosflags (std::ios::left)
01002              << std::resetiosflags (std::ios::right);
01003           param_buf << std::resetiosflags (std::ios::left)
01004                     << std::resetiosflags (std::ios::right);
01005           i++;
01006         }
01007       else
01008         {
01009           os << param.text;
01010           param_buf << param.line;
01011           i++;
01012         }
01013     }
01014 
01015   os << param_buf.str ();
01016 }
01017 
01018 // FIXME -- This is a bit of a kluge.  We'd like to just use val.dims()
01019 // and if val is an object, expect that dims will call size if it is
01020 // overloaded by a user-defined method.  But there are currently some
01021 // unresolved const issues that prevent that solution from working.
01022 
01023 std::string
01024 get_dims_str (const octave_value& val)
01025 {
01026   octave_value tmp = val;
01027 
01028   Matrix sz = tmp.size ();
01029 
01030   dim_vector dv = dim_vector::alloc (sz.numel ());
01031 
01032   for (octave_idx_type i = 0; i < dv.length (); i++)
01033     dv(i) = sz(i);
01034 
01035   return dv.str ();
01036 }
01037 
01038 class
01039 symbol_info_list
01040 {
01041 private:
01042   struct symbol_info
01043   {
01044     symbol_info (const symbol_table::symbol_record& sr,
01045                  const std::string& expr_str = std::string (),
01046                  const octave_value& expr_val = octave_value ())
01047       : name (expr_str.empty () ? sr.name () : expr_str),
01048         varval (expr_val.is_undefined () ? sr.varval () : expr_val),
01049         is_automatic (sr.is_automatic ()),
01050         is_complex (varval.is_complex_type ()),
01051         is_formal (sr.is_formal ()),
01052         is_global (sr.is_global ()),
01053         is_persistent (sr.is_persistent ())
01054     { }
01055 
01056     void display_line (std::ostream& os,
01057                        const std::list<whos_parameter>& params) const
01058     {
01059       std::string dims_str = get_dims_str (varval);
01060 
01061       std::list<whos_parameter>::const_iterator i = params.begin ();
01062 
01063       while (i != params.end ())
01064         {
01065           whos_parameter param = *i;
01066 
01067           if (param.command != '\0')
01068             {
01069               // Do the actual printing.
01070 
01071               switch (param.modifier)
01072                 {
01073                 case 'l':
01074                   os << std::setiosflags (std::ios::left)
01075                      << std::setw (param.parameter_length);
01076                   break;
01077 
01078                 case 'r':
01079                   os << std::setiosflags (std::ios::right)
01080                      << std::setw (param.parameter_length);
01081                   break;
01082 
01083                 case 'c':
01084                   if (param.command == 's')
01085                     {
01086                       int front = param.first_parameter_length
01087                         - dims_str.find ('x');
01088                       int back = param.parameter_length
01089                         - dims_str.length ()
01090                         - front;
01091                       front = (front > 0) ? front : 0;
01092                       back = (back > 0) ? back : 0;
01093 
01094                       os << std::setiosflags (std::ios::left)
01095                          << std::setw (front)
01096                          << ""
01097                          << std::resetiosflags (std::ios::left)
01098                          << dims_str
01099                          << std::setiosflags (std::ios::left)
01100                          << std::setw (back)
01101                          << ""
01102                          << std::resetiosflags (std::ios::left);
01103                     }
01104                   else
01105                     {
01106                       os << std::setiosflags (std::ios::left)
01107                          << std::setw (param.parameter_length);
01108                     }
01109                   break;
01110 
01111                 default:
01112                   error ("whos_line_format: modifier '%c' unknown",
01113                          param.modifier);
01114 
01115                   os << std::setiosflags (std::ios::right)
01116                      << std::setw (param.parameter_length);
01117                 }
01118 
01119               switch (param.command)
01120                 {
01121                 case 'a':
01122                   {
01123                     char tmp[6];
01124 
01125                     tmp[0] = (is_automatic ? 'a' : ' ');
01126                     tmp[1] = (is_complex ? 'c' : ' ');
01127                     tmp[2] = (is_formal ? 'f' : ' ');
01128                     tmp[3] = (is_global ? 'g' : ' ');
01129                     tmp[4] = (is_persistent ? 'p' : ' ');
01130                     tmp[5] = 0;
01131 
01132                     os << tmp;
01133                   }
01134                   break;
01135 
01136                 case 'b':
01137                   os << varval.byte_size ();
01138                   break;
01139 
01140                 case 'c':
01141                   os << varval.class_name ();
01142                   break;
01143 
01144                 case 'e':
01145                   os << varval.capacity ();
01146                   break;
01147 
01148                 case 'n':
01149                   os << name;
01150                   break;
01151 
01152                 case 's':
01153                   if (param.modifier != 'c')
01154                     os << dims_str;
01155                   break;
01156 
01157                 case 't':
01158                   os << varval.type_name ();
01159                   break;
01160 
01161                 default:
01162                   error ("whos_line_format: command '%c' unknown",
01163                          param.command);
01164                 }
01165 
01166               os << std::resetiosflags (std::ios::left)
01167                  << std::resetiosflags (std::ios::right);
01168               i++;
01169             }
01170           else
01171             {
01172               os << param.text;
01173               i++;
01174             }
01175         }
01176     }
01177 
01178     std::string name;
01179     octave_value varval;
01180     bool is_automatic;
01181     bool is_complex;
01182     bool is_formal;
01183     bool is_global;
01184     bool is_persistent;
01185   };
01186 
01187 public:
01188   symbol_info_list (void) : lst () { }
01189 
01190   symbol_info_list (const symbol_info_list& sil) : lst (sil.lst) { }
01191 
01192   symbol_info_list& operator = (const symbol_info_list& sil)
01193   {
01194     if (this != &sil)
01195       lst = sil.lst;
01196 
01197     return *this;
01198   }
01199 
01200   ~symbol_info_list (void) { }
01201 
01202   void append (const symbol_table::symbol_record& sr)
01203   {
01204     lst.push_back (symbol_info (sr));
01205   }
01206 
01207   void append (const symbol_table::symbol_record& sr,
01208                const std::string& expr_str,
01209                const octave_value& expr_val)
01210   {
01211     lst.push_back (symbol_info (sr, expr_str, expr_val));
01212   }
01213 
01214   size_t size (void) const { return lst.size (); }
01215 
01216   bool empty (void) const { return lst.empty (); }
01217 
01218   octave_map
01219   map_value (const std::string& caller_function_name, int nesting_level) const
01220   {
01221     size_t len = lst.size ();
01222 
01223     Cell name_info (len, 1);
01224     Cell size_info (len, 1);
01225     Cell bytes_info (len, 1);
01226     Cell class_info (len, 1);
01227     Cell global_info (len, 1);
01228     Cell sparse_info (len, 1);
01229     Cell complex_info (len, 1);
01230     Cell nesting_info (len, 1);
01231     Cell persistent_info (len, 1);
01232 
01233     std::list<symbol_info>::const_iterator p = lst.begin ();
01234 
01235     for (size_t j = 0; j < len; j++)
01236       {
01237         const symbol_info& si = *p++;
01238 
01239         octave_scalar_map ni;
01240 
01241         ni.assign ("function", caller_function_name);
01242         ni.assign ("level", nesting_level);
01243 
01244         name_info(j) = si.name;
01245         global_info(j) = si.is_global;
01246         persistent_info(j) = si.is_persistent;
01247 
01248         octave_value val = si.varval;
01249 
01250         size_info(j) = val.size ();
01251         bytes_info(j) = val.byte_size ();
01252         class_info(j) = val.class_name ();
01253         sparse_info(j) = val.is_sparse_type ();
01254         complex_info(j) = val.is_complex_type ();
01255         nesting_info(j) = ni;
01256       }
01257 
01258     octave_map info;
01259 
01260     info.assign ("name", name_info);
01261     info.assign ("size", size_info);
01262     info.assign ("bytes", bytes_info);
01263     info.assign ("class", class_info);
01264     info.assign ("global", global_info);
01265     info.assign ("sparse", sparse_info);
01266     info.assign ("complex", complex_info);
01267     info.assign ("nesting", nesting_info);
01268     info.assign ("persistent", persistent_info);
01269 
01270     return info;
01271   }
01272 
01273   void display (std::ostream& os)
01274   {
01275     if (! lst.empty ())
01276       {
01277         size_t bytes = 0;
01278         size_t elements = 0;
01279 
01280         std::list<whos_parameter> params = parse_whos_line_format ();
01281 
01282         print_descriptor (os, params);
01283 
01284         octave_stdout << "\n";
01285 
01286         for (std::list<symbol_info>::const_iterator p = lst.begin ();
01287              p != lst.end (); p++)
01288           {
01289             p->display_line (os, params);
01290 
01291             octave_value val = p->varval;
01292 
01293             elements += val.capacity ();
01294             bytes += val.byte_size ();
01295           }
01296 
01297         os << "\nTotal is " << elements
01298            << (elements == 1 ? " element" : " elements")
01299            << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
01300            << "\n";
01301       }
01302   }
01303 
01304   // Parse the string whos_line_format, and return a parameter list,
01305   // containing all information needed to print the given
01306   // attributtes of the symbols.
01307   std::list<whos_parameter> parse_whos_line_format (void)
01308   {
01309     int idx;
01310     size_t format_len = Vwhos_line_format.length ();
01311     char garbage;
01312     std::list<whos_parameter> params;
01313 
01314     size_t bytes1;
01315     int elements1;
01316 
01317     std::string param_string = "abcenst";
01318     Array<int> param_length (dim_vector (param_string.length (), 1));
01319     Array<std::string> param_names (dim_vector (param_string.length (), 1));
01320     size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
01321 
01322     pos_a = param_string.find ('a'); // Attributes
01323     pos_b = param_string.find ('b'); // Bytes
01324     pos_c = param_string.find ('c'); // Class
01325     pos_e = param_string.find ('e'); // Elements
01326     pos_n = param_string.find ('n'); // Name
01327     pos_s = param_string.find ('s'); // Size
01328     pos_t = param_string.find ('t'); // Type
01329 
01330     param_names(pos_a) = "Attr";
01331     param_names(pos_b) = "Bytes";
01332     param_names(pos_c) = "Class";
01333     param_names(pos_e) = "Elements";
01334     param_names(pos_n) = "Name";
01335     param_names(pos_s) = "Size";
01336     param_names(pos_t) = "Type";
01337 
01338     for (size_t i = 0; i < param_string.length (); i++)
01339       param_length(i) = param_names(i) . length ();
01340 
01341     // The attribute column needs size 5.
01342     param_length(pos_a) = 5;
01343 
01344     // Calculating necessary spacing for name column,
01345     // bytes column, elements column and class column
01346 
01347     for (std::list<symbol_info>::const_iterator p = lst.begin ();
01348          p != lst.end (); p++)
01349       {
01350         std::stringstream ss1, ss2;
01351         std::string str;
01352 
01353         str = p->name;
01354         param_length(pos_n) = ((str.length ()
01355                                 > static_cast<size_t> (param_length(pos_n)))
01356                                ? str.length () : param_length(pos_n));
01357 
01358         octave_value val = p->varval;
01359 
01360         str = val.type_name ();
01361         param_length(pos_t) = ((str.length ()
01362                                 > static_cast<size_t> (param_length(pos_t)))
01363                                ? str.length () : param_length(pos_t));
01364 
01365         elements1 = val.capacity ();
01366         ss1 << elements1;
01367         str = ss1.str ();
01368         param_length(pos_e) = ((str.length ()
01369                                 > static_cast<size_t> (param_length(pos_e)))
01370                                ? str.length () : param_length(pos_e));
01371 
01372         bytes1 = val.byte_size ();
01373         ss2 << bytes1;
01374         str = ss2.str ();
01375         param_length(pos_b) = ((str.length ()
01376                                 > static_cast<size_t> (param_length(pos_b)))
01377                                ? str.length () : param_length (pos_b));
01378       }
01379 
01380     idx = 0;
01381     while (static_cast<size_t> (idx) < format_len)
01382       {
01383         whos_parameter param;
01384         param.command = '\0';
01385 
01386         if (Vwhos_line_format[idx] == '%')
01387           {
01388             bool error_encountered = false;
01389             param.modifier = 'r';
01390             param.parameter_length = 0;
01391 
01392             int a = 0, b = -1, balance = 1;
01393             unsigned int items;
01394             size_t pos;
01395             std::string cmd;
01396 
01397             // Parse one command from whos_line_format
01398             cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
01399             pos = cmd.find (';');
01400             if (pos != std::string::npos)
01401               cmd = cmd.substr (0, pos+1);
01402             else
01403               error ("parameter without ; in whos_line_format");
01404 
01405             idx += cmd.length ();
01406 
01407             // FIXME -- use iostream functions instead of sscanf!
01408 
01409             if (cmd.find_first_of ("crl") != 1)
01410               items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
01411                               &garbage, &param.command, &a, &b, &balance);
01412             else
01413               items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
01414                               &garbage, &param.modifier, &param.command,
01415                               &a, &b, &balance) - 1;
01416 
01417             if (items < 2)
01418               {
01419                 error ("whos_line_format: parameter structure without command in whos_line_format");
01420                 error_encountered = true;
01421               }
01422 
01423             // Insert data into parameter
01424             param.first_parameter_length = 0;
01425             pos = param_string.find (param.command);
01426             if (pos != std::string::npos)
01427               {
01428                 param.parameter_length = param_length(pos);
01429                 param.text = param_names(pos);
01430                 param.line.assign (param_names(pos).length (), '=');
01431 
01432                 param.parameter_length = (a > param.parameter_length
01433                                           ? a : param.parameter_length);
01434                 if (param.command == 's' && param.modifier == 'c' && b > 0)
01435                   param.first_parameter_length = b;
01436               }
01437             else
01438               {
01439                 error ("whos_line_format: '%c' is not a command",
01440                        param.command);
01441                 error_encountered = true;
01442               }
01443 
01444             if (param.command == 's')
01445               {
01446                 // Have to calculate space needed for printing
01447                 // matrix dimensions Space needed for Size column is
01448                 // hard to determine in prior, because it depends on
01449                 // dimensions to be shown. That is why it is
01450                 // recalculated for each Size-command int first,
01451                 // rest = 0, total;
01452                 int rest = 0;
01453                 int first = param.first_parameter_length;
01454                 int total = param.parameter_length;
01455 
01456                 for (std::list<symbol_info>::const_iterator p = lst.begin ();
01457                      p != lst.end (); p++)
01458                   {
01459                     octave_value val = p->varval;
01460                     std::string dims_str = get_dims_str (val);
01461                     int first1 = dims_str.find ('x');
01462                     int total1 = dims_str.length ();
01463                     int rest1 = total1 - first1;
01464                     rest = (rest1 > rest ? rest1 : rest);
01465                     first = (first1 > first ? first1 : first);
01466                     total = (total1 > total ? total1 : total);
01467                   }
01468 
01469                 if (param.modifier == 'c')
01470                   {
01471                     if (first < balance)
01472                       first += balance - first;
01473                     if (rest + balance < param.parameter_length)
01474                       rest += param.parameter_length - rest - balance;
01475 
01476                     param.parameter_length = first + rest;
01477                     param.first_parameter_length = first;
01478                     param.balance = balance;
01479                   }
01480                 else
01481                   {
01482                     param.parameter_length = total;
01483                     param.first_parameter_length = 0;
01484                   }
01485               }
01486             else if (param.modifier == 'c')
01487               {
01488                 error ("whos_line_format: modifier 'c' not available for command '%c'",
01489                        param.command);
01490                 error_encountered = true;
01491               }
01492 
01493             // What happens if whos_line_format contains negative numbers
01494             // at param_length positions?
01495             param.balance = (b < 0 ? 0 : param.balance);
01496             param.first_parameter_length = (b < 0 ? 0 :
01497                                             param.first_parameter_length);
01498             param.parameter_length = (a < 0
01499                                       ? 0
01500                                       : (param.parameter_length
01501                                          < param_length(pos_s)
01502                                          ? param_length(pos_s)
01503                                          : param.parameter_length));
01504 
01505             // Parameter will not be pushed into parameter list if ...
01506             if (! error_encountered)
01507               params.push_back (param);
01508           }
01509         else
01510           {
01511             // Text string, to be printed as it is ...
01512             std::string text;
01513             size_t pos;
01514             text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
01515             pos = text.find ('%');
01516             if (pos != std::string::npos)
01517               text = text.substr (0, pos);
01518 
01519             // Push parameter into list ...
01520             idx += text.length ();
01521             param.text=text;
01522             param.line.assign (text.length(), ' ');
01523             params.push_back (param);
01524           }
01525       }
01526 
01527     return params;
01528   }
01529 
01530 private:
01531   std::list<symbol_info> lst;
01532 
01533 };
01534 
01535 static octave_value
01536 do_who (int argc, const string_vector& argv, bool return_list,
01537         bool verbose = false, std::string msg = std::string ())
01538 {
01539   octave_value retval;
01540 
01541   std::string my_name = argv[0];
01542 
01543   bool global_only = false;
01544   bool have_regexp = false;
01545 
01546   int i;
01547   for (i = 1; i < argc; i++)
01548     {
01549       if (argv[i] == "-file")
01550         {
01551           // FIXME. This is an inefficient manner to implement this as the
01552           // variables are loaded in to a temporary context and then treated.
01553           // It would be better to refecat symbol_info_list to not store the
01554           // symbol records and then use it in load-save.cc (do_load) to
01555           // implement this option there so that the variables are never
01556           // stored at all.
01557           if (i == argc - 1)
01558             error ("whos: -file argument must be followed by a file name");
01559           else
01560             {
01561               std::string nm = argv [i + 1];
01562 
01563               unwind_protect frame;
01564 
01565               // Set up temporary scope.
01566 
01567               symbol_table::scope_id tmp_scope = symbol_table::alloc_scope ();
01568               frame.add_fcn (symbol_table::erase_scope, tmp_scope);
01569 
01570               symbol_table::set_scope (tmp_scope);
01571 
01572               octave_call_stack::push (tmp_scope, 0);
01573               frame.add_fcn (octave_call_stack::pop);
01574 
01575               frame.add_fcn (symbol_table::clear_variables);
01576 
01577               feval ("load", octave_value (nm), 0);
01578 
01579               if (! error_state)
01580                 {
01581                   std::string newmsg = std::string ("Variables in the file ") +
01582                     nm + ":\n\n";
01583 
01584                   retval =  do_who (i, argv, return_list, verbose, newmsg);
01585                 }
01586             }
01587 
01588           return retval;
01589         }
01590       else if (argv[i] == "-regexp")
01591         have_regexp = true;
01592       else if (argv[i] == "global")
01593         global_only = true;
01594       else if (argv[i][0] == '-')
01595         warning ("%s: unrecognized option '%s'", my_name.c_str (),
01596                  argv[i].c_str ());
01597       else
01598         break;
01599     }
01600 
01601   int npats = argc - i;
01602   string_vector pats;
01603   if (npats > 0)
01604     {
01605       pats.resize (npats);
01606       for (int j = 0; j < npats; j++)
01607         pats[j] = argv[i+j];
01608     }
01609   else
01610     {
01611       pats.resize (++npats);
01612       pats[0] = "*";
01613     }
01614 
01615   symbol_info_list symbol_stats;
01616   std::list<std::string> symbol_names;
01617 
01618   for (int j = 0; j < npats; j++)
01619     {
01620       std::string pat = pats[j];
01621 
01622       if (have_regexp)
01623         {
01624           std::list<symbol_table::symbol_record> tmp = global_only
01625             ? symbol_table::regexp_global_variables (pat)
01626             : symbol_table::regexp_variables (pat);
01627 
01628           for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin ();
01629                p != tmp.end (); p++)
01630             {
01631               if (p->is_variable ())
01632                 {
01633                   if (verbose)
01634                     symbol_stats.append (*p);
01635                   else
01636                     symbol_names.push_back (p->name ());
01637                 }
01638             }
01639         }
01640       else
01641         {
01642           size_t pos = pat.find_first_of (".({");
01643 
01644           if (pos != std::string::npos && pos > 0)
01645             {
01646               if (verbose)
01647                 {
01648                   // NOTE: we can only display information for
01649                   // expressions based on global values if the variable is
01650                   // global in the current scope because we currently have
01651                   // no way of looking up the base value in the global
01652                   // scope and then evaluating the arguments in the
01653                   // current scope.
01654 
01655                   std::string base_name = pat.substr (0, pos);
01656 
01657                   if (symbol_table::is_variable (base_name))
01658                     {
01659                       symbol_table::symbol_record sr
01660                         = symbol_table::find_symbol (base_name);
01661 
01662                       if (! global_only || sr.is_global ())
01663                         {
01664                           int parse_status;
01665 
01666                           octave_value expr_val
01667                             = eval_string (pat, true, parse_status);
01668 
01669                           if (! error_state)
01670                             symbol_stats.append (sr, pat, expr_val);
01671                           else
01672                             return retval;
01673                         }
01674                     }
01675                 }
01676             }
01677           else
01678             {
01679               std::list<symbol_table::symbol_record> tmp = global_only
01680                 ? symbol_table::glob_global_variables (pat)
01681                 : symbol_table::glob_variables (pat);
01682 
01683               for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin ();
01684                    p != tmp.end (); p++)
01685                 {
01686                   if (p->is_variable ())
01687                     {
01688                       if (verbose)
01689                         symbol_stats.append (*p);
01690                       else
01691                         symbol_names.push_back (p->name ());
01692                     }
01693                 }
01694             }
01695         }
01696     }
01697 
01698   if (return_list)
01699     {
01700       if (verbose)
01701         {
01702           std::string caller_function_name;
01703           octave_function *caller = octave_call_stack::caller ();
01704           if (caller)
01705             caller_function_name = caller->name ();
01706 
01707           retval = symbol_stats.map_value (caller_function_name, 1);
01708         }
01709       else
01710         retval = Cell (string_vector (symbol_names));
01711     }
01712   else if (! (symbol_stats.empty () && symbol_names.empty ()))
01713     {
01714       if (msg.length () == 0)
01715         if (global_only)
01716           octave_stdout << "Global variables:\n\n";
01717         else
01718           octave_stdout << "Variables in the current scope:\n\n";
01719       else
01720         octave_stdout << msg;
01721 
01722       if (verbose)
01723         symbol_stats.display (octave_stdout);
01724       else
01725         {
01726           string_vector names (symbol_names);
01727 
01728           names.list_in_columns (octave_stdout);
01729         }
01730 
01731       octave_stdout << "\n";
01732     }
01733 
01734   return retval;
01735 }
01736 
01737 DEFUN (who, args, nargout,
01738   "-*- texinfo -*-\n\
01739 @deftypefn  {Command} {} who\n\
01740 @deftypefnx {Command} {} who pattern @dots{}\n\
01741 @deftypefnx {Command} {} who option pattern @dots{}\n\
01742 @deftypefnx {Command} {C =} who (\"pattern\", @dots{})\n\
01743 List currently defined variables matching the given patterns.  Valid\n\
01744 pattern syntax is the same as described for the @code{clear} command.\n\
01745 If no patterns are supplied, all variables are listed.\n\
01746 By default, only variables visible in the local scope are displayed.\n\
01747 \n\
01748 The following are valid options but may not be combined.\n\
01749 \n\
01750 @table @code\n\
01751 @item global\n\
01752 List variables in the global scope rather than the current scope.\n\
01753 \n\
01754 @item -regexp\n\
01755 The patterns are considered to be regular expressions when matching the\n\
01756 variables to display.  The same pattern syntax accepted by\n\
01757 the @code{regexp} function is used.\n\
01758 \n\
01759 @item -file\n\
01760 The next argument is treated as a filename.  All variables found within the\n\
01761 specified file are listed.  No patterns are accepted when reading variables\n\
01762 from a file.\n\
01763 @end table\n\
01764 \n\
01765 If called as a function, return a cell array of defined variable names\n\
01766 matching the given patterns.\n\
01767 @seealso{whos, isglobal, isvarname, exist, regexp}\n\
01768 @end deftypefn")
01769 {
01770   octave_value retval;
01771 
01772   if (nargout < 2)
01773     {
01774       int argc = args.length () + 1;
01775 
01776       string_vector argv = args.make_argv ("who");
01777 
01778       if (! error_state)
01779         retval = do_who (argc, argv, nargout == 1);
01780     }
01781   else
01782     print_usage ();
01783 
01784   return retval;
01785 }
01786 
01787 DEFUN (whos, args, nargout,
01788   "-*- texinfo -*-\n\
01789 @deftypefn  {Command} {} whos\n\
01790 @deftypefnx {Command} {} whos pattern @dots{}\n\
01791 @deftypefnx {Command} {} whos option pattern @dots{}\n\
01792 @deftypefnx {Command} {S =} whos (\"pattern\", @dots{})\n\
01793 Provide detailed information on currently defined variables matching the\n\
01794 given patterns.  Options and pattern syntax are the same as for the\n\
01795 @code{who} command.  Extended information about each variable is\n\
01796 summarized in a table with the following default entries.\n\
01797 \n\
01798 @table @asis\n\
01799 @item Attr\n\
01800 Attributes of the listed variable.  Possible attributes are:\n\
01801 @table @asis\n\
01802 @item blank\n\
01803 Variable in local scope\n\
01804 \n\
01805 @item @code{a}\n\
01806 Automatic variable.  An automatic variable is one created by the\n\
01807 interpreter, for example @code{argn}.\n\
01808 \n\
01809 @item @code{c}\n\
01810 Variable of complex type.\n\
01811 \n\
01812 @item @code{f}\n\
01813 Formal parameter (function argument).\n\
01814 \n\
01815 @item @code{g}\n\
01816 Variable with global scope.\n\
01817 \n\
01818 @item @code{p}\n\
01819 Persistent variable.\n\
01820 @end table\n\
01821 \n\
01822 @item Name\n\
01823 The name of the variable.\n\
01824 \n\
01825 @item Size\n\
01826 The logical size of the variable.  A scalar is 1x1, a vector is\n\
01827 @nospell{1xN} or @nospell{Nx1}, a 2-D matrix is @nospell{MxN}.\n\
01828 \n\
01829 @item Bytes\n\
01830 The amount of memory currently used to store the variable.\n\
01831 \n\
01832 @item Class\n\
01833 The class of the variable.  Examples include double, single, char, uint16,\n\
01834 cell, and struct.\n\
01835 @end table\n\
01836 \n\
01837 The table can be customized to display more or less information through\n\
01838 the function @code{whos_line_format}.\n\
01839 \n\
01840 If @code{whos} is called as a function, return a struct array of defined\n\
01841 variable names matching the given patterns.  Fields in the structure\n\
01842 describing each variable are: name, size, bytes, class, global, sparse,\n\
01843 complex, nesting, persistent.\n\
01844 @seealso{who, whos_line_format}\n\
01845 @end deftypefn")
01846 {
01847   octave_value retval;
01848 
01849   if (nargout < 2)
01850     {
01851       int argc = args.length () + 1;
01852 
01853       string_vector argv = args.make_argv ("whos");
01854 
01855       if (! error_state)
01856         retval = do_who (argc, argv, nargout == 1, true);
01857     }
01858   else
01859     print_usage ();
01860 
01861   return retval;
01862 }
01863 
01864 // Defining variables.
01865 
01866 void
01867 bind_ans (const octave_value& val, bool print)
01868 {
01869   static std::string ans = "ans";
01870 
01871   if (val.is_defined ())
01872     {
01873       if (val.is_cs_list ())
01874         {
01875           octave_value_list lst = val.list_value ();
01876 
01877           for (octave_idx_type i = 0; i < lst.length (); i++)
01878             bind_ans (lst(i), print);
01879         }
01880       else
01881         {
01882           symbol_table::varref (ans) = val;
01883 
01884           if (print)
01885             val.print_with_name (octave_stdout, ans);
01886         }
01887     }
01888 }
01889 
01890 void
01891 bind_internal_variable (const std::string& fname, const octave_value& val)
01892 {
01893   octave_value_list args;
01894 
01895   args(0) = val;
01896 
01897   feval (fname, args, 0);
01898 }
01899 
01900 void
01901 mlock (void)
01902 {
01903   octave_function *fcn = octave_call_stack::current ();
01904 
01905   if (fcn)
01906     fcn->lock ();
01907   else
01908     error ("mlock: invalid use outside a function");
01909 }
01910 
01911 void
01912 munlock (const std::string& nm)
01913 {
01914   octave_value val = symbol_table::find_function (nm);
01915 
01916   if (val.is_defined ())
01917     {
01918       octave_function *fcn = val.function_value ();
01919 
01920       if (fcn)
01921         fcn->unlock ();
01922     }
01923 }
01924 
01925 bool
01926 mislocked (const std::string& nm)
01927 {
01928   bool retval = false;
01929 
01930   octave_value val = symbol_table::find_function (nm);
01931 
01932   if (val.is_defined ())
01933     {
01934       octave_function *fcn = val.function_value ();
01935 
01936       if (fcn)
01937         retval = fcn->islocked ();
01938     }
01939 
01940   return retval;
01941 }
01942 
01943 DEFUN (mlock, args, ,
01944   "-*- texinfo -*-\n\
01945 @deftypefn {Built-in Function} {} mlock ()\n\
01946 Lock the current function into memory so that it can't be cleared.\n\
01947 @seealso{munlock, mislocked, persistent}\n\
01948 @end deftypefn")
01949 {
01950   octave_value_list retval;
01951 
01952   if (args.length () == 0)
01953     {
01954       octave_function *fcn = octave_call_stack::caller ();
01955 
01956       if (fcn)
01957         fcn->lock ();
01958       else
01959         error ("mlock: invalid use outside a function");
01960     }
01961   else
01962     print_usage ();
01963 
01964   return retval;
01965 }
01966 
01967 DEFUN (munlock, args, ,
01968   "-*- texinfo -*-\n\
01969 @deftypefn  {Built-in Function} {} munlock ()\n\
01970 @deftypefnx {Built-in Function} {} munlock (@var{fcn})\n\
01971 Unlock the named function @var{fcn}.  If no function is named\n\
01972 then unlock the current function.\n\
01973 @seealso{mlock, mislocked, persistent}\n\
01974 @end deftypefn")
01975 {
01976   octave_value_list retval;
01977 
01978   if (args.length() == 1)
01979     {
01980       std::string name = args(0).string_value ();
01981 
01982       if (! error_state)
01983         munlock (name);
01984       else
01985         error ("munlock: FCN must be a string");
01986     }
01987   else if (args.length () == 0)
01988     {
01989       octave_function *fcn = octave_call_stack::caller ();
01990 
01991       if (fcn)
01992         fcn->unlock ();
01993       else
01994         error ("munlock: invalid use outside a function");
01995     }
01996   else
01997     print_usage ();
01998 
01999   return retval;
02000 }
02001 
02002 
02003 DEFUN (mislocked, args, ,
02004   "-*- texinfo -*-\n\
02005 @deftypefn  {Built-in Function} {} mislocked ()\n\
02006 @deftypefnx {Built-in Function} {} mislocked (@var{fcn})\n\
02007 Return true if the named function @var{fcn} is locked.  If no function is\n\
02008 named then return true if the current function is locked.\n\
02009 @seealso{mlock, munlock, persistent}\n\
02010 @end deftypefn")
02011 {
02012   octave_value retval;
02013 
02014   if (args.length() == 1)
02015     {
02016       std::string name = args(0).string_value ();
02017 
02018       if (! error_state)
02019         retval = mislocked (name);
02020       else
02021         error ("mislocked: FCN must be a string");
02022     }
02023   else if (args.length () == 0)
02024     {
02025       octave_function *fcn = octave_call_stack::caller ();
02026 
02027       if (fcn)
02028         retval = fcn->islocked ();
02029       else
02030         error ("mislocked: invalid use outside a function");
02031     }
02032   else
02033     print_usage ();
02034 
02035   return retval;
02036 }
02037 
02038 // Deleting names from the symbol tables.
02039 
02040 static inline bool
02041 name_matches_any_pattern (const std::string& nm, const string_vector& argv,
02042                           int argc, int idx, bool have_regexp = false)
02043 {
02044   bool retval = false;
02045 
02046   for (int k = idx; k < argc; k++)
02047     {
02048       std::string patstr = argv[k];
02049       if (! patstr.empty ())
02050         {
02051           if (have_regexp)
02052             {
02053               if (is_regexp_match (patstr, nm))
02054                 {
02055                   retval = true;
02056                   break;
02057                 }
02058             }
02059           else
02060             {
02061               glob_match pattern (patstr);
02062 
02063               if (pattern.match (nm))
02064                 {
02065                   retval = true;
02066                   break;
02067                 }
02068             }
02069         }
02070     }
02071 
02072   return retval;
02073 }
02074 
02075 static inline void
02076 maybe_warn_exclusive (bool exclusive)
02077 {
02078   if (exclusive)
02079     warning ("clear: ignoring --exclusive option");
02080 }
02081 
02082 static void
02083 do_clear_functions (const string_vector& argv, int argc, int idx,
02084                     bool exclusive = false)
02085 {
02086   if (idx == argc)
02087     symbol_table::clear_functions ();
02088   else
02089     {
02090       if (exclusive)
02091         {
02092           string_vector fcns = symbol_table::user_function_names ();
02093 
02094           int fcount = fcns.length ();
02095 
02096           for (int i = 0; i < fcount; i++)
02097             {
02098               std::string nm = fcns[i];
02099 
02100               if (! name_matches_any_pattern (nm, argv, argc, idx))
02101                 symbol_table::clear_function (nm);
02102             }
02103         }
02104       else
02105         {
02106           while (idx < argc)
02107             symbol_table::clear_function_pattern (argv[idx++]);
02108         }
02109     }
02110 }
02111 
02112 static void
02113 do_clear_globals (const string_vector& argv, int argc, int idx,
02114                   bool exclusive = false)
02115 {
02116   if (idx == argc)
02117     {
02118       string_vector gvars = symbol_table::global_variable_names ();
02119 
02120       int gcount = gvars.length ();
02121 
02122       for (int i = 0; i < gcount; i++)
02123         symbol_table::clear_global (gvars[i]);
02124     }
02125   else
02126     {
02127       if (exclusive)
02128         {
02129           string_vector gvars = symbol_table::global_variable_names ();
02130 
02131           int gcount = gvars.length ();
02132 
02133           for (int i = 0; i < gcount; i++)
02134             {
02135               std::string nm = gvars[i];
02136 
02137               if (! name_matches_any_pattern (nm, argv, argc, idx))
02138                 symbol_table::clear_global (nm);
02139             }
02140         }
02141       else
02142         {
02143           while (idx < argc)
02144             symbol_table::clear_global_pattern (argv[idx++]);
02145         }
02146     }
02147 }
02148 
02149 static void
02150 do_clear_variables (const string_vector& argv, int argc, int idx,
02151                     bool exclusive = false, bool have_regexp = false)
02152 {
02153   if (idx == argc)
02154     symbol_table::clear_variables ();
02155   else
02156     {
02157       if (exclusive)
02158         {
02159           string_vector lvars = symbol_table::variable_names ();
02160 
02161           int lcount = lvars.length ();
02162 
02163           for (int i = 0; i < lcount; i++)
02164             {
02165               std::string nm = lvars[i];
02166 
02167               if (! name_matches_any_pattern (nm, argv, argc, idx, have_regexp))
02168                 symbol_table::clear_variable (nm);
02169             }
02170         }
02171       else
02172         {
02173           if (have_regexp)
02174             while (idx < argc)
02175               symbol_table::clear_variable_regexp (argv[idx++]);
02176           else
02177             while (idx < argc)
02178               symbol_table::clear_variable_pattern (argv[idx++]);
02179         }
02180     }
02181 }
02182 
02183 static void
02184 do_clear_symbols (const string_vector& argv, int argc, int idx,
02185                   bool exclusive = false)
02186 {
02187   if (idx == argc)
02188     symbol_table::clear_variables ();
02189   else
02190     {
02191       if (exclusive)
02192         {
02193           // FIXME -- is this really what we want, or do we
02194           // somehow want to only clear the functions that are not
02195           // shadowed by local variables?  It seems that would be a
02196           // bit harder to do.
02197 
02198           do_clear_variables (argv, argc, idx, exclusive);
02199           do_clear_functions (argv, argc, idx, exclusive);
02200         }
02201       else
02202         {
02203           while (idx < argc)
02204             symbol_table::clear_symbol_pattern (argv[idx++]);
02205         }
02206     }
02207 }
02208 
02209 static void
02210 do_matlab_compatible_clear (const string_vector& argv, int argc, int idx)
02211 {
02212   // This is supposed to be mostly Matlab compatible.
02213 
02214   for (; idx < argc; idx++)
02215     {
02216       if (argv[idx] == "all"
02217           && ! symbol_table::is_local_variable ("all"))
02218         {
02219           symbol_table::clear_all ();
02220         }
02221       else if (argv[idx] == "functions"
02222                && ! symbol_table::is_local_variable ("functions"))
02223         {
02224           do_clear_functions (argv, argc, ++idx);
02225         }
02226       else if (argv[idx] == "global"
02227                && ! symbol_table::is_local_variable ("global"))
02228         {
02229           do_clear_globals (argv, argc, ++idx);
02230         }
02231       else if (argv[idx] == "variables"
02232                && ! symbol_table::is_local_variable ("variables"))
02233         {
02234           symbol_table::clear_variables ();
02235         }
02236       else if (argv[idx] == "classes"
02237                && ! symbol_table::is_local_variable ("classes"))
02238         {
02239           symbol_table::clear_objects ();
02240           octave_class::clear_exemplar_map ();
02241         }
02242       else
02243         {
02244           symbol_table::clear_symbol_pattern (argv[idx]);
02245         }
02246     }
02247 }
02248 
02249 #define CLEAR_OPTION_ERROR(cond) \
02250   do \
02251     { \
02252       if (cond) \
02253         { \
02254           print_usage (); \
02255           return retval; \
02256         } \
02257     } \
02258   while (0)
02259 
02260 DEFUN (clear, args, ,
02261   "-*- texinfo -*-\n\
02262 @deftypefn {Command} {} clear [options] pattern @dots{}\n\
02263 Delete the names matching the given patterns from the symbol table.  The\n\
02264 pattern may contain the following special characters:\n\
02265 \n\
02266 @table @code\n\
02267 @item ?\n\
02268 Match any single character.\n\
02269 \n\
02270 @item *\n\
02271 Match zero or more characters.\n\
02272 \n\
02273 @item [ @var{list} ]\n\
02274 Match the list of characters specified by @var{list}.  If the first\n\
02275 character is @code{!} or @code{^}, match all characters except those\n\
02276 specified by @var{list}.  For example, the pattern @samp{[a-zA-Z]} will\n\
02277 match all lowercase and uppercase alphabetic characters.\n\
02278 @end table\n\
02279 \n\
02280 For example, the command\n\
02281 \n\
02282 @example\n\
02283 clear foo b*r\n\
02284 @end example\n\
02285 \n\
02286 @noindent\n\
02287 clears the name @code{foo} and all names that begin with the letter\n\
02288 @code{b} and end with the letter @code{r}.\n\
02289 \n\
02290 If @code{clear} is called without any arguments, all user-defined\n\
02291 variables (local and global) are cleared from the symbol table.  If\n\
02292 @code{clear} is called with at least one argument, only the visible\n\
02293 names matching the arguments are cleared.  For example, suppose you have\n\
02294 defined a function @code{foo}, and then hidden it by performing the\n\
02295 assignment @code{foo = 2}.  Executing the command @kbd{clear foo} once\n\
02296 will clear the variable definition and restore the definition of\n\
02297 @code{foo} as a function.  Executing @kbd{clear foo} a second time will\n\
02298 clear the function definition.\n\
02299 \n\
02300 The following options are available in both long and short form\n\
02301 @table @code\n\
02302 @item -all, -a\n\
02303 Clears all local and global user-defined variables and all functions\n\
02304 from the symbol table.\n\
02305 \n\
02306 @item -exclusive, -x\n\
02307 Clears the variables that don't match the following pattern.\n\
02308 \n\
02309 @item -functions, -f\n\
02310 Clears the function names and the built-in symbols names.\n\
02311 \n\
02312 @item -global, -g\n\
02313 Clears the global symbol names.\n\
02314 \n\
02315 @item -variables, -v\n\
02316 Clears the local variable names.\n\
02317 \n\
02318 @item -classes, -c\n\
02319 Clears the class structure table and clears all objects.\n\
02320 \n\
02321 @item -regexp, -r\n\
02322 The arguments are treated as regular expressions as any variables that\n\
02323 match will be cleared.\n\
02324 @end table\n\
02325 With the exception of @code{exclusive}, all long options can be used\n\
02326 without the dash as well.\n\
02327 @end deftypefn")
02328 {
02329   octave_value_list retval;
02330 
02331   int argc = args.length () + 1;
02332 
02333   string_vector argv = args.make_argv ("clear");
02334 
02335   if (! error_state)
02336     {
02337       if (argc == 1)
02338         {
02339           do_clear_globals (argv, argc, 1);
02340           do_clear_variables (argv, argc, 1);
02341         }
02342       else
02343         {
02344           int idx = 0;
02345 
02346           bool clear_all = false;
02347           bool clear_functions = false;
02348           bool clear_globals = false;
02349           bool clear_variables = false;
02350           bool clear_objects = false;
02351           bool exclusive = false;
02352           bool have_regexp = false;
02353           bool have_dash_option = false;
02354 
02355           while (++idx < argc)
02356             {
02357               if (argv[idx] == "-all" || argv[idx] == "-a")
02358                 {
02359                   CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
02360 
02361                   have_dash_option = true;
02362                   clear_all = true;
02363                 }
02364               else if (argv[idx] == "-exclusive" || argv[idx] == "-x")
02365                 {
02366                   have_dash_option = true;
02367                   exclusive = true;
02368                 }
02369               else if (argv[idx] == "-functions" || argv[idx] == "-f")
02370                 {
02371                   CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
02372 
02373                   have_dash_option = true;
02374                   clear_functions = true;
02375                 }
02376               else if (argv[idx] == "-global" || argv[idx] == "-g")
02377                 {
02378                   CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
02379 
02380                   have_dash_option = true;
02381                   clear_globals = true;
02382                 }
02383               else if (argv[idx] == "-variables" || argv[idx] == "-v")
02384                 {
02385                   CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
02386 
02387                   have_dash_option = true;
02388                   clear_variables = true;
02389                 }
02390               else if (argv[idx] == "-classes" || argv[idx] == "-c")
02391                 {
02392                   CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
02393 
02394                   have_dash_option = true;
02395                   clear_objects = true;
02396                 }
02397               else if (argv[idx] == "-regexp" || argv[idx] == "-r")
02398                 {
02399                   CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
02400 
02401                   have_dash_option = true;
02402                   have_regexp = true;
02403                 }
02404               else
02405                 break;
02406             }
02407 
02408           if (idx <= argc)
02409             {
02410               if (! have_dash_option)
02411                 {
02412                   do_matlab_compatible_clear (argv, argc, idx);
02413                 }
02414               else
02415                 {
02416                   if (clear_all)
02417                     {
02418                       maybe_warn_exclusive (exclusive);
02419 
02420                       if (++idx < argc)
02421                         warning
02422                           ("clear: ignoring extra arguments after -all");
02423 
02424                       symbol_table::clear_all ();
02425                     }
02426                   else if (have_regexp)
02427                     {
02428                       do_clear_variables (argv, argc, idx, exclusive, true);
02429                     }
02430                   else if (clear_functions)
02431                     {
02432                       do_clear_functions (argv, argc, idx, exclusive);
02433                     }
02434                   else if (clear_globals)
02435                     {
02436                       do_clear_globals (argv, argc, idx, exclusive);
02437                     }
02438                   else if (clear_variables)
02439                     {
02440                       do_clear_variables (argv, argc, idx, exclusive);
02441                     }
02442                   else if (clear_objects)
02443                     {
02444                       symbol_table::clear_objects ();
02445                       octave_class::clear_exemplar_map ();
02446                     }
02447                   else
02448                     {
02449                       do_clear_symbols (argv, argc, idx, exclusive);
02450                     }
02451                 }
02452             }
02453         }
02454     }
02455 
02456   return retval;
02457 }
02458 
02459 DEFUN (whos_line_format, args, nargout,
02460   "-*- texinfo -*-\n\
02461 @deftypefn  {Built-in Function} {@var{val} =} whos_line_format ()\n\
02462 @deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\
02463 @deftypefnx {Built-in Function} {} whos_line_format (@var{new_val}, \"local\")\n\
02464 Query or set the format string used by the command @code{whos}.\n\
02465 \n\
02466 A full format string is:\n\
02467 @c Set example in small font to prevent overfull line\n\
02468 \n\
02469 @smallexample\n\
02470 %[modifier]<command>[:width[:left-min[:balance]]];\n\
02471 @end smallexample\n\
02472 \n\
02473 The following command sequences are available:\n\
02474 \n\
02475 @table @code\n\
02476 @item %a\n\
02477 Prints attributes of variables (g=global, p=persistent,\n\
02478 f=formal parameter, a=automatic variable).\n\
02479 \n\
02480 @item %b\n\
02481 Prints number of bytes occupied by variables.\n\
02482 \n\
02483 @item %c\n\
02484 Prints class names of variables.\n\
02485 \n\
02486 @item %e\n\
02487 Prints elements held by variables.\n\
02488 \n\
02489 @item %n\n\
02490 Prints variable names.\n\
02491 \n\
02492 @item %s\n\
02493 Prints dimensions of variables.\n\
02494 \n\
02495 @item %t\n\
02496 Prints type names of variables.\n\
02497 @end table\n\
02498 \n\
02499 Every command may also have an alignment modifier:\n\
02500 \n\
02501 @table @code\n\
02502 @item l\n\
02503 Left alignment.\n\
02504 \n\
02505 @item r\n\
02506 Right alignment (default).\n\
02507 \n\
02508 @item c\n\
02509 Column-aligned (only applicable to command %s).\n\
02510 @end table\n\
02511 \n\
02512 The @code{width} parameter is a positive integer specifying the minimum\n\
02513 number of columns used for printing.  No maximum is needed as the field will\n\
02514 auto-expand as required.\n\
02515 \n\
02516 The parameters @code{left-min} and @code{balance} are only available when the\n\
02517 column-aligned modifier is used with the command @samp{%s}.\n\
02518 @code{balance} specifies the column number within the field width which will\n\
02519 be aligned between entries.  Numbering starts from 0 which indicates the\n\
02520 leftmost column.  @code{left-min} specifies the minimum field width to the\n\
02521 left of the specified balance column.\n\
02522 \n\
02523 The default format is\n\
02524 @code{\"  %a:4; %ln:6; %cs:16:6:1;  %rb:12;  %lc:-1;\\n\"}.\n\
02525 \n\
02526 When called from inside a function with the \"local\" option, the variable is\n\
02527 changed locally for the function and any subroutines it calls.  The original\n\
02528 variable value is restored when exiting the function.\n\
02529 @seealso{whos}\n\
02530 @end deftypefn")
02531 {
02532   return SET_INTERNAL_VARIABLE (whos_line_format);
02533 }
02534 
02535 static std::string Vmissing_function_hook = "unimplemented";
02536 
02537 DEFUN (missing_function_hook, args, nargout,
02538     "-*- texinfo -*-\n\
02539 @deftypefn  {Built-in Function} {@var{val} =} missing_function_hook ()\n\
02540 @deftypefnx {Built-in Function} {@var{old_val} =} missing_function_hook (@var{new_val})\n\
02541 @deftypefnx {Built-in Function} {} missing_function_hook (@var{new_val}, \"local\")\n\
02542 Query or set the internal variable that specifies the function to call when\n\
02543 an unknown identifier is requested.\n\
02544 \n\
02545 When called from inside a function with the \"local\" option, the variable is\n\
02546 changed locally for the function and any subroutines it calls.  The original\n\
02547 variable value is restored when exiting the function.\n\
02548 @end deftypefn")
02549 {
02550   return SET_INTERNAL_VARIABLE (missing_function_hook);
02551 }
02552 
02553 void maybe_missing_function_hook (const std::string& name)
02554 {
02555   // Don't do this if we're handling errors.
02556   if (buffer_error_messages == 0 && ! Vmissing_function_hook.empty ())
02557     {
02558       // Ensure auto-restoration.
02559       unwind_protect frame;
02560       frame.protect_var (Vmissing_function_hook);
02561 
02562       // Clear the variable prior to calling the function.
02563       const std::string func_name = Vmissing_function_hook;
02564       Vmissing_function_hook.clear ();
02565 
02566       // Call.
02567       feval (func_name, octave_value (name));
02568     }
02569 }
02570 
02571 DEFUN (__varval__, args, ,
02572   "-*- texinfo -*-\n\
02573 @deftypefn {Built-in Function} {} __varval__ (@var{name})\n\
02574 Undocumented internal function.\n\
02575 @end deftypefn")
02576 {
02577   octave_value retval;
02578 
02579   if (args.length () == 1)
02580     {
02581       std::string name = args(0).string_value ();
02582 
02583       if (! error_state)
02584         retval = symbol_table::varval (args(0).string_value ());
02585       else
02586         error ("__varval__: expecting argument to be variable name");
02587     }
02588   else
02589     print_usage ();
02590 
02591   return retval;
02592 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines