comparison src/interpfcn/variables.cc @ 15088:60ff2cef569d

maint: Move core interpreter files with DEFUNS to interpfcn/ directory * src/Makefile.am: Adjust build system for new location of files. * interpfcn/module.mk: Add files and rules to build system. * data.cc, data.h, debug.cc, debug.h, defaults.cc, defaults.in.h, defun.cc, defun.h, dirfns.cc, dirfns.h, error.cc, error.h, file-io.cc, file-io.h, graphics.cc, graphics.in.h, help.cc, help.h, input.cc, input.h, load-path.cc, load-path.h, load-save.cc, load-save.h, ls-oct-ascii.cc, ls-oct-ascii.h, oct-hist.cc, oct-hist.h, pager.cc, pager.h, pr-output.cc, pr-output.h, profiler.cc, profiler.h, sighandlers.cc, sighandlers.h, symtab.cc, symtab.h, sysdep.cc, sysdep.h, toplev.cc, toplev.h, utils.cc, utils.h, variables.cc, variables.h: Move files to interpfcn/ directory
author Rik <rik@octave.org>
date Fri, 03 Aug 2012 09:31:37 -0700
parents src/variables.cc@560317fd5977
children
comparison
equal deleted inserted replaced
15087:20b33f227599 15088:60ff2cef569d
1 /*
2
3 Copyright (C) 1993-2012 John W. Eaton
4 Copyright (C) 2009-2010 VZLU Prague
5
6 This file is part of Octave.
7
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <cstdio>
29 #include <cstring>
30
31 #include <iomanip>
32 #include <set>
33 #include <string>
34
35 #include "file-stat.h"
36 #include "oct-env.h"
37 #include "file-ops.h"
38 #include "glob-match.h"
39 #include "regexp.h"
40 #include "str-vec.h"
41
42 #include <defaults.h>
43 #include "Cell.h"
44 #include "defun.h"
45 #include "dirfns.h"
46 #include "error.h"
47 #include "gripes.h"
48 #include "help.h"
49 #include "input.h"
50 #include "lex.h"
51 #include "load-path.h"
52 #include "oct-map.h"
53 #include "oct-obj.h"
54 #include "ov.h"
55 #include "ov-class.h"
56 #include "ov-usr-fcn.h"
57 #include "pager.h"
58 #include "parse.h"
59 #include "symtab.h"
60 #include "toplev.h"
61 #include "unwind-prot.h"
62 #include "utils.h"
63 #include "variables.h"
64
65 // Defines layout for the whos/who -long command
66 static std::string Vwhos_line_format
67 = " %a:4; %ln:6; %cs:16:6:1; %rb:12; %lc:-1;\n";
68
69 void
70 clear_mex_functions (void)
71 {
72 symbol_table::clear_mex_functions ();
73 }
74
75 void
76 clear_function (const std::string& nm)
77 {
78 symbol_table::clear_function (nm);
79 }
80
81 void
82 clear_variable (const std::string& nm)
83 {
84 symbol_table::clear_variable (nm);
85 }
86
87 void
88 clear_symbol (const std::string& nm)
89 {
90 symbol_table::clear_symbol (nm);
91 }
92
93 // Attributes of variables and functions.
94
95 // Is this octave_value a valid function?
96
97 octave_function *
98 is_valid_function (const std::string& fcn_name,
99 const std::string& warn_for, bool warn)
100 {
101 octave_function *ans = 0;
102
103 if (! fcn_name.empty ())
104 {
105 octave_value val = symbol_table::find_function (fcn_name);
106
107 if (val.is_defined ())
108 ans = val.function_value (true);
109 }
110
111 if (! ans && warn)
112 error ("%s: the symbol `%s' is not valid as a function",
113 warn_for.c_str (), fcn_name.c_str ());
114
115 return ans;
116 }
117
118 octave_function *
119 is_valid_function (const octave_value& arg,
120 const std::string& warn_for, bool warn)
121 {
122 octave_function *ans = 0;
123
124 std::string fcn_name;
125
126 if (arg.is_string ())
127 {
128 fcn_name = arg.string_value ();
129
130 if (! error_state)
131 ans = is_valid_function (fcn_name, warn_for, warn);
132 else if (warn)
133 error ("%s: expecting function name as argument", warn_for.c_str ());
134 }
135 else if (warn)
136 error ("%s: expecting function name as argument", warn_for.c_str ());
137
138 return ans;
139 }
140
141 octave_function *
142 extract_function (const octave_value& arg, const std::string& warn_for,
143 const std::string& fname, const std::string& header,
144 const std::string& trailer)
145 {
146 octave_function *retval = 0;
147
148 retval = is_valid_function (arg, warn_for, 0);
149
150 if (! retval)
151 {
152 std::string s = arg.string_value ();
153
154 std::string cmd = header;
155 cmd.append (s);
156 cmd.append (trailer);
157
158 if (! error_state)
159 {
160 int parse_status;
161
162 eval_string (cmd, true, parse_status, 0);
163
164 if (parse_status == 0)
165 {
166 retval = is_valid_function (fname, warn_for, 0);
167
168 if (! retval)
169 {
170 error ("%s: `%s' is not valid as a function",
171 warn_for.c_str (), fname.c_str ());
172 return retval;
173 }
174
175 warning ("%s: passing function body as a string is obsolete; please use anonymous functions",
176 warn_for.c_str ());
177 }
178 else
179 error ("%s: `%s' is not valid as a function",
180 warn_for.c_str (), fname.c_str ());
181 }
182 else
183 error ("%s: expecting first argument to be a string",
184 warn_for.c_str ());
185 }
186
187 return retval;
188 }
189
190 string_vector
191 get_struct_elts (const std::string& text)
192 {
193 int n = 1;
194
195 size_t pos = 0;
196
197 size_t len = text.length ();
198
199 while ((pos = text.find ('.', pos)) != std::string::npos)
200 {
201 if (++pos == len)
202 break;
203
204 n++;
205 }
206
207 string_vector retval (n);
208
209 pos = 0;
210
211 for (int i = 0; i < n; i++)
212 {
213 len = text.find ('.', pos);
214
215 if (len != std::string::npos)
216 len -= pos;
217
218 retval[i] = text.substr (pos, len);
219
220 if (len != std::string::npos)
221 pos += len + 1;
222 }
223
224 return retval;
225 }
226
227 static inline bool
228 is_variable (const std::string& name)
229 {
230 bool retval = false;
231
232 if (! name.empty ())
233 {
234 octave_value val = symbol_table::varval (name);
235
236 retval = val.is_defined ();
237 }
238
239 return retval;
240 }
241
242 string_vector
243 generate_struct_completions (const std::string& text,
244 std::string& prefix, std::string& hint)
245 {
246 string_vector names;
247
248 size_t pos = text.rfind ('.');
249
250 if (pos != std::string::npos)
251 {
252 if (pos == text.length ())
253 hint = "";
254 else
255 hint = text.substr (pos+1);
256
257 prefix = text.substr (0, pos);
258
259 std::string base_name = prefix;
260
261 pos = base_name.find_first_of ("{(.");
262
263 if (pos != std::string::npos)
264 base_name = base_name.substr (0, pos);
265
266 if (is_variable (base_name))
267 {
268 int parse_status;
269
270 unwind_protect frame;
271
272 frame.protect_var (error_state);
273 frame.protect_var (warning_state);
274
275 frame.protect_var (discard_error_messages);
276 frame.protect_var (discard_warning_messages);
277
278 discard_error_messages = true;
279 discard_warning_messages = true;
280
281 octave_value tmp = eval_string (prefix, true, parse_status);
282
283 frame.run ();
284
285 if (tmp.is_defined () && tmp.is_map ())
286 names = tmp.map_keys ();
287 }
288 }
289
290 return names;
291 }
292
293 // FIXME -- this will have to be much smarter to work
294 // "correctly".
295
296 bool
297 looks_like_struct (const std::string& text)
298 {
299 bool retval = (! text.empty ()
300 && text != "."
301 && text.find_first_of (file_ops::dir_sep_chars ()) == std::string::npos
302 && text.find ("..") == std::string::npos
303 && text.rfind ('.') != std::string::npos);
304
305 #if 0
306 symbol_record *sr = curr_sym_tab->lookup (text);
307
308 if (sr && ! sr->is_function ())
309 {
310 int parse_status;
311
312 unwind_protect frame;
313
314 frame.protect_var (discard_error_messages);
315 frame.protect_var (error_state);
316
317 discard_error_messages = true;
318
319 octave_value tmp = eval_string (text, true, parse_status);
320
321 frame.run ();
322
323 retval = (tmp.is_defined () && tmp.is_map ());
324 }
325 #endif
326
327 return retval;
328 }
329
330 static octave_value
331 do_isglobal (const octave_value_list& args)
332 {
333 octave_value retval = false;
334
335 int nargin = args.length ();
336
337 if (nargin != 1)
338 {
339 print_usage ();
340 return retval;
341 }
342
343 std::string name = args(0).string_value ();
344
345 if (error_state)
346 {
347 error ("isglobal: NAME must be a string");
348 return retval;
349 }
350
351 return symbol_table::is_global (name);
352 }
353
354 DEFUN (isglobal, args, ,
355 "-*- texinfo -*-\n\
356 @deftypefn {Built-in Function} {} isglobal (@var{name})\n\
357 Return true if @var{name} is a globally visible variable.\n\
358 For example:\n\
359 \n\
360 @example\n\
361 @group\n\
362 global x\n\
363 isglobal (\"x\")\n\
364 @result{} 1\n\
365 @end group\n\
366 @end example\n\
367 @seealso{isvarname, exist}\n\
368 @end deftypefn")
369 {
370 return do_isglobal (args);
371 }
372
373 static octave_value
374 safe_symbol_lookup (const std::string& symbol_name)
375 {
376 octave_value retval;
377
378 unwind_protect frame;
379 interpreter_try (frame);
380
381 retval = symbol_table::find (symbol_name);
382
383 error_state = 0;
384
385 return retval;
386 }
387
388 int
389 symbol_exist (const std::string& name, const std::string& type)
390 {
391 int retval = 0;
392
393 std::string struct_elts;
394 std::string symbol_name = name;
395
396 size_t pos = name.find ('.');
397
398 if (pos != std::string::npos && pos > 0)
399 {
400 struct_elts = name.substr (pos+1);
401 symbol_name = name.substr (0, pos);
402 }
403
404 // We shouldn't need to look in the global symbol table, since any
405 // name that is visible in the current scope will be in the local
406 // symbol table.
407
408 octave_value val = safe_symbol_lookup (symbol_name);
409
410 if (val.is_defined ())
411 {
412 bool not_a_struct = struct_elts.empty ();
413 bool var_ok = not_a_struct /* || val.is_map_element (struct_elts) */;
414
415 if (! retval
416 && var_ok
417 && (type == "any" || type == "var")
418 && (val.is_constant () || val.is_object ()
419 || val.is_function_handle ()
420 || val.is_anonymous_function ()
421 || val.is_inline_function ()))
422 {
423 retval = 1;
424 }
425
426 if (! retval
427 && (type == "any" || type == "builtin"))
428 {
429 if (not_a_struct && val.is_builtin_function ())
430 {
431 retval = 5;
432 }
433 }
434
435 if (! retval
436 && not_a_struct
437 && (type == "any" || type == "file")
438 && (val.is_user_function () || val.is_dld_function ()))
439 {
440 octave_function *f = val.function_value (true);
441 std::string s = f ? f->fcn_file_name () : std::string ();
442
443 retval = s.empty () ? 103 : (val.is_user_function () ? 2 : 3);
444 }
445 }
446
447 if (! (type == "var" || type == "builtin"))
448 {
449 if (! retval)
450 {
451 std::string file_name = lookup_autoload (name);
452
453 if (file_name.empty ())
454 file_name = load_path::find_fcn (name);
455
456 size_t len = file_name.length ();
457
458 if (len > 0)
459 {
460 if (type == "any" || type == "file")
461 {
462 if (len > 4 && (file_name.substr (len-4) == ".oct"
463 || file_name.substr (len-4) == ".mex"))
464 retval = 3;
465 else
466 retval = 2;
467 }
468 }
469 }
470
471 if (! retval)
472 {
473 std::string file_name = file_in_path (name, "");
474
475 if (file_name.empty ())
476 file_name = name;
477
478 file_stat fs (file_name);
479
480 if (fs)
481 {
482 if (type == "any" || type == "file")
483 retval = fs.is_dir () ? 7 : 2;
484 else if (type == "dir" && fs.is_dir ())
485 retval = 7;
486 }
487 }
488 }
489
490 return retval;
491 }
492
493 #define GET_IDX(LEN) \
494 static_cast<int> ((LEN-1) * static_cast<double> (rand ()) / RAND_MAX)
495
496 std::string
497 unique_symbol_name (const std::string& basename)
498 {
499 static const std::string alpha
500 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
501
502 static size_t len = alpha.length ();
503
504 std::string nm = basename + alpha[GET_IDX (len)];
505
506 size_t pos = nm.length ();
507
508 if (nm.substr (0, 2) == "__")
509 nm.append ("__");
510
511 while (symbol_exist (nm, "any"))
512 nm.insert (pos++, 1, alpha[GET_IDX (len)]);
513
514 return nm;
515 }
516
517 DEFUN (exist, args, ,
518 "-*- texinfo -*-\n\
519 @deftypefn {Built-in Function} {} exist (@var{name}, @var{type})\n\
520 Return 1 if the name exists as a variable, 2 if the name is an\n\
521 absolute file name, an ordinary file in Octave's @code{path}, or (after\n\
522 appending @samp{.m}) a function file in Octave's @code{path}, 3 if the\n\
523 name is a @samp{.oct} or @samp{.mex} file in Octave's @code{path},\n\
524 5 if the name is a built-in function, 7 if the name is a directory, or 103\n\
525 if the name is a function not associated with a file (entered on\n\
526 the command line).\n\
527 \n\
528 Otherwise, return 0.\n\
529 \n\
530 This function also returns 2 if a regular file called @var{name}\n\
531 exists in Octave's search path. If you want information about\n\
532 other types of files, you should use some combination of the functions\n\
533 @code{file_in_path} and @code{stat} instead.\n\
534 \n\
535 If the optional argument @var{type} is supplied, check only for\n\
536 symbols of the specified type. Valid types are\n\
537 \n\
538 @table @asis\n\
539 @item \"var\"\n\
540 Check only for variables.\n\
541 \n\
542 @item \"builtin\"\n\
543 Check only for built-in functions.\n\
544 \n\
545 @item \"file\"\n\
546 Check only for files.\n\
547 \n\
548 @item \"dir\"\n\
549 Check only for directories.\n\
550 @end table\n\
551 \n\
552 @seealso{file_in_loadpath}\n\
553 @end deftypefn")
554 {
555 octave_value retval = false;
556
557 int nargin = args.length ();
558
559 if (nargin == 1 || nargin == 2)
560 {
561 std::string name = args(0).string_value ();
562
563 if (! error_state)
564 {
565 std::string type
566 = (nargin == 2) ? args(1).string_value () : std::string ("any");
567
568 if (! error_state)
569 retval = symbol_exist (name, type);
570 else
571 error ("exist: TYPE must be a string");
572 }
573 else
574 error ("exist: NAME must be a string");
575 }
576 else
577 print_usage ();
578
579 return retval;
580 }
581
582 /*
583 %!test
584 %! if (isunix ())
585 %! assert (exist ("/tmp") == 7);
586 %! assert (exist ("/tmp", "file") == 7);
587 %! assert (exist ("/tmp", "dir") == 7);
588 %! assert (exist ("/bin/sh") == 2);
589 %! assert (exist ("/bin/sh", "file") == 2);
590 %! assert (exist ("/bin/sh", "dir") == 0);
591 %! assert (exist ("/dev/null") == 2);
592 %! assert (exist ("/dev/null", "file") == 2);
593 %! assert (exist ("/dev/null", "dir") == 0);
594 %! endif
595 */
596
597 octave_value
598 lookup_function_handle (const std::string& nm)
599 {
600 octave_value val = symbol_table::varval (nm);
601
602 return val.is_function_handle () ? val : octave_value ();
603 }
604
605 octave_value
606 get_global_value (const std::string& nm, bool silent)
607 {
608 octave_value val = symbol_table::global_varval (nm);
609
610 if (val.is_undefined () && ! silent)
611 error ("get_global_value: undefined symbol `%s'", nm.c_str ());
612
613 return val;
614 }
615
616 void
617 set_global_value (const std::string& nm, const octave_value& val)
618 {
619 symbol_table::global_varref (nm) = val;
620 }
621
622 octave_value
623 get_top_level_value (const std::string& nm, bool silent)
624 {
625 octave_value val = symbol_table::top_level_varval (nm);
626
627 if (val.is_undefined () && ! silent)
628 error ("get_top_level_value: undefined symbol `%s'", nm.c_str ());
629
630 return val;
631 }
632
633 void
634 set_top_level_value (const std::string& nm, const octave_value& val)
635 {
636 symbol_table::top_level_varref (nm) = val;
637 }
638
639 // Variable values.
640
641 static bool
642 wants_local_change (const octave_value_list& args, int& nargin)
643 {
644 bool retval = false;
645
646 if (nargin == 2)
647 {
648 if (args(1).is_string () && args(1).string_value () == "local")
649 {
650 nargin = 1;
651 retval = true;
652 }
653 else
654 {
655 error_with_cfn ("expecting second argument to be \"local\"");
656 nargin = 0;
657 }
658 }
659
660 return retval;
661 }
662
663 template <class T>
664 bool try_local_protect (T& var)
665 {
666 octave_user_code *curr_usr_code = octave_call_stack::caller_user_code ();
667 octave_user_function *curr_usr_fcn = 0;
668 if (curr_usr_code && curr_usr_code->is_user_function ())
669 curr_usr_fcn = dynamic_cast<octave_user_function *> (curr_usr_code);
670
671 if (curr_usr_fcn && curr_usr_fcn->local_protect (var))
672 return true;
673 else
674 return false;
675 }
676
677 octave_value
678 set_internal_variable (bool& var, const octave_value_list& args,
679 int nargout, const char *nm)
680 {
681 octave_value retval;
682
683 int nargin = args.length ();
684
685 if (nargout > 0 || nargin == 0)
686 retval = var;
687
688 if (wants_local_change (args, nargin))
689 {
690 if (! try_local_protect (var))
691 warning ("\"local\" has no effect outside a function");
692 }
693
694 if (nargin == 1)
695 {
696 bool bval = args(0).bool_value ();
697
698 if (! error_state)
699 var = bval;
700 else
701 error ("%s: expecting arg to be a logical value", nm);
702 }
703 else if (nargin > 1)
704 print_usage ();
705
706 return retval;
707 }
708
709 octave_value
710 set_internal_variable (char& var, const octave_value_list& args,
711 int nargout, const char *nm)
712 {
713 octave_value retval;
714
715 int nargin = args.length ();
716
717 if (nargout > 0 || nargin == 0)
718 retval = var;
719
720 if (wants_local_change (args, nargin))
721 {
722 if (! try_local_protect (var))
723 warning ("\"local\" has no effect outside a function");
724 }
725
726 if (nargin == 1)
727 {
728 std::string sval = args(0).string_value ();
729
730 if (! error_state)
731 {
732 switch (sval.length ())
733 {
734 case 1:
735 var = sval[0];
736 break;
737
738 case 0:
739 var = '\0';
740 break;
741
742 default:
743 error ("%s: argument must be a single character", nm);
744 break;
745 }
746 }
747 else
748 error ("%s: argument must be a single character", nm);
749 }
750 else if (nargin > 1)
751 print_usage ();
752
753 return retval;
754 }
755
756 octave_value
757 set_internal_variable (int& var, const octave_value_list& args,
758 int nargout, const char *nm,
759 int minval, int maxval)
760 {
761 octave_value retval;
762
763 int nargin = args.length ();
764
765 if (nargout > 0 || nargin == 0)
766 retval = var;
767
768 if (wants_local_change (args, nargin))
769 {
770 if (! try_local_protect (var))
771 warning ("\"local\" has no effect outside a function");
772 }
773
774 if (nargin == 1)
775 {
776 int ival = args(0).int_value ();
777
778 if (! error_state)
779 {
780 if (ival < minval)
781 error ("%s: expecting arg to be greater than %d", nm, minval);
782 else if (ival > maxval)
783 error ("%s: expecting arg to be less than or equal to %d",
784 nm, maxval);
785 else
786 var = ival;
787 }
788 else
789 error ("%s: expecting arg to be an integer value", nm);
790 }
791 else if (nargin > 1)
792 print_usage ();
793
794 return retval;
795 }
796
797 octave_value
798 set_internal_variable (double& var, const octave_value_list& args,
799 int nargout, const char *nm,
800 double minval, double maxval)
801 {
802 octave_value retval;
803
804 int nargin = args.length ();
805
806 if (nargout > 0 || nargin == 0)
807 retval = var;
808
809 if (wants_local_change (args, nargin))
810 {
811 if (! try_local_protect (var))
812 warning ("\"local\" has no effect outside a function");
813 }
814
815 if (nargin == 1)
816 {
817 double dval = args(0).scalar_value ();
818
819 if (! error_state)
820 {
821 if (dval < minval)
822 error ("%s: expecting arg to be greater than %g", minval);
823 else if (dval > maxval)
824 error ("%s: expecting arg to be less than or equal to %g", maxval);
825 else
826 var = dval;
827 }
828 else
829 error ("%s: expecting arg to be a scalar value", nm);
830 }
831 else if (nargin > 1)
832 print_usage ();
833
834 return retval;
835 }
836
837 octave_value
838 set_internal_variable (std::string& var, const octave_value_list& args,
839 int nargout, const char *nm, bool empty_ok)
840 {
841 octave_value retval;
842
843 int nargin = args.length ();
844
845 if (nargout > 0 || nargin == 0)
846 retval = var;
847
848 if (wants_local_change (args, nargin))
849 {
850 if (! try_local_protect (var))
851 warning ("\"local\" has no effect outside a function");
852 }
853
854 if (nargin == 1)
855 {
856 std::string sval = args(0).string_value ();
857
858 if (! error_state)
859 {
860 if (empty_ok || ! sval.empty ())
861 var = sval;
862 else
863 error ("%s: value must not be empty", nm);
864 }
865 else
866 error ("%s: expecting arg to be a character string", nm);
867 }
868 else if (nargin > 1)
869 print_usage ();
870
871 return retval;
872 }
873
874 octave_value
875 set_internal_variable (int& var, const octave_value_list& args,
876 int nargout, const char *nm, const char **choices)
877 {
878 octave_value retval;
879 int nchoices = 0;
880 while (choices[nchoices] != 0)
881 nchoices++;
882
883 int nargin = args.length ();
884 assert (var < nchoices);
885
886 if (nargout > 0 || nargin == 0)
887 retval = choices[var];
888
889 if (wants_local_change (args, nargin))
890 {
891 if (! try_local_protect (var))
892 warning ("\"local\" has no effect outside a function");
893 }
894
895 if (nargin == 1)
896 {
897 std::string sval = args(0).string_value ();
898
899 if (! error_state)
900 {
901 int i = 0;
902 for (; i < nchoices; i++)
903 {
904 if (sval == choices[i])
905 {
906 var = i;
907 break;
908 }
909 }
910 if (i == nchoices)
911 error ("%s: value not allowed (\"%s\")", nm, sval.c_str ());
912 }
913 else
914 error ("%s: expecting arg to be a character string", nm);
915 }
916 else if (nargin > 1)
917 print_usage ();
918
919 return retval;
920 }
921
922 struct
923 whos_parameter
924 {
925 char command;
926 char modifier;
927 int parameter_length;
928 int first_parameter_length;
929 int balance;
930 std::string text;
931 std::string line;
932 };
933
934 static void
935 print_descriptor (std::ostream& os, std::list<whos_parameter> params)
936 {
937 // This method prints a line of information on a given symbol
938 std::list<whos_parameter>::iterator i = params.begin ();
939 std::ostringstream param_buf;
940
941 while (i != params.end ())
942 {
943 whos_parameter param = *i;
944
945 if (param.command != '\0')
946 {
947 // Do the actual printing
948 switch (param.modifier)
949 {
950 case 'l':
951 os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
952 param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
953 break;
954
955 case 'r':
956 os << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
957 param_buf << std::setiosflags (std::ios::right) << std::setw (param.parameter_length);
958 break;
959
960 case 'c':
961 if (param.command != 's')
962 {
963 os << std::setiosflags (std::ios::left)
964 << std::setw (param.parameter_length);
965 param_buf << std::setiosflags (std::ios::left)
966 << std::setw (param.parameter_length);
967 }
968 break;
969
970 default:
971 os << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
972 param_buf << std::setiosflags (std::ios::left) << std::setw (param.parameter_length);
973 }
974
975 if (param.command == 's' && param.modifier == 'c')
976 {
977 int a, b;
978
979 if (param.modifier == 'c')
980 {
981 a = param.first_parameter_length - param.balance;
982 a = (a < 0 ? 0 : a);
983 b = param.parameter_length - a - param.text . length ();
984 b = (b < 0 ? 0 : b);
985 os << std::setiosflags (std::ios::left) << std::setw (a)
986 << "" << std::resetiosflags (std::ios::left) << param.text
987 << std::setiosflags (std::ios::left)
988 << std::setw (b) << ""
989 << std::resetiosflags (std::ios::left);
990 param_buf << std::setiosflags (std::ios::left) << std::setw (a)
991 << "" << std::resetiosflags (std::ios::left) << param.line
992 << std::setiosflags (std::ios::left)
993 << std::setw (b) << ""
994 << std::resetiosflags (std::ios::left);
995 }
996 }
997 else
998 {
999 os << param.text;
1000 param_buf << param.line;
1001 }
1002 os << std::resetiosflags (std::ios::left)
1003 << std::resetiosflags (std::ios::right);
1004 param_buf << std::resetiosflags (std::ios::left)
1005 << std::resetiosflags (std::ios::right);
1006 i++;
1007 }
1008 else
1009 {
1010 os << param.text;
1011 param_buf << param.line;
1012 i++;
1013 }
1014 }
1015
1016 os << param_buf.str ();
1017 }
1018
1019 // FIXME -- This is a bit of a kluge. We'd like to just use val.dims()
1020 // and if val is an object, expect that dims will call size if it is
1021 // overloaded by a user-defined method. But there are currently some
1022 // unresolved const issues that prevent that solution from working.
1023
1024 std::string
1025 get_dims_str (const octave_value& val)
1026 {
1027 octave_value tmp = val;
1028
1029 Matrix sz = tmp.size ();
1030
1031 dim_vector dv = dim_vector::alloc (sz.numel ());
1032
1033 for (octave_idx_type i = 0; i < dv.length (); i++)
1034 dv(i) = sz(i);
1035
1036 return dv.str ();
1037 }
1038
1039 class
1040 symbol_info_list
1041 {
1042 private:
1043 struct symbol_info
1044 {
1045 symbol_info (const symbol_table::symbol_record& sr,
1046 const std::string& expr_str = std::string (),
1047 const octave_value& expr_val = octave_value ())
1048 : name (expr_str.empty () ? sr.name () : expr_str),
1049 varval (expr_val.is_undefined () ? sr.varval () : expr_val),
1050 is_automatic (sr.is_automatic ()),
1051 is_complex (varval.is_complex_type ()),
1052 is_formal (sr.is_formal ()),
1053 is_global (sr.is_global ()),
1054 is_persistent (sr.is_persistent ())
1055 { }
1056
1057 void display_line (std::ostream& os,
1058 const std::list<whos_parameter>& params) const
1059 {
1060 std::string dims_str = get_dims_str (varval);
1061
1062 std::list<whos_parameter>::const_iterator i = params.begin ();
1063
1064 while (i != params.end ())
1065 {
1066 whos_parameter param = *i;
1067
1068 if (param.command != '\0')
1069 {
1070 // Do the actual printing.
1071
1072 switch (param.modifier)
1073 {
1074 case 'l':
1075 os << std::setiosflags (std::ios::left)
1076 << std::setw (param.parameter_length);
1077 break;
1078
1079 case 'r':
1080 os << std::setiosflags (std::ios::right)
1081 << std::setw (param.parameter_length);
1082 break;
1083
1084 case 'c':
1085 if (param.command == 's')
1086 {
1087 int front = param.first_parameter_length
1088 - dims_str.find ('x');
1089 int back = param.parameter_length
1090 - dims_str.length ()
1091 - front;
1092 front = (front > 0) ? front : 0;
1093 back = (back > 0) ? back : 0;
1094
1095 os << std::setiosflags (std::ios::left)
1096 << std::setw (front)
1097 << ""
1098 << std::resetiosflags (std::ios::left)
1099 << dims_str
1100 << std::setiosflags (std::ios::left)
1101 << std::setw (back)
1102 << ""
1103 << std::resetiosflags (std::ios::left);
1104 }
1105 else
1106 {
1107 os << std::setiosflags (std::ios::left)
1108 << std::setw (param.parameter_length);
1109 }
1110 break;
1111
1112 default:
1113 error ("whos_line_format: modifier `%c' unknown",
1114 param.modifier);
1115
1116 os << std::setiosflags (std::ios::right)
1117 << std::setw (param.parameter_length);
1118 }
1119
1120 switch (param.command)
1121 {
1122 case 'a':
1123 {
1124 char tmp[6];
1125
1126 tmp[0] = (is_automatic ? 'a' : ' ');
1127 tmp[1] = (is_complex ? 'c' : ' ');
1128 tmp[2] = (is_formal ? 'f' : ' ');
1129 tmp[3] = (is_global ? 'g' : ' ');
1130 tmp[4] = (is_persistent ? 'p' : ' ');
1131 tmp[5] = 0;
1132
1133 os << tmp;
1134 }
1135 break;
1136
1137 case 'b':
1138 os << varval.byte_size ();
1139 break;
1140
1141 case 'c':
1142 os << varval.class_name ();
1143 break;
1144
1145 case 'e':
1146 os << varval.capacity ();
1147 break;
1148
1149 case 'n':
1150 os << name;
1151 break;
1152
1153 case 's':
1154 if (param.modifier != 'c')
1155 os << dims_str;
1156 break;
1157
1158 case 't':
1159 os << varval.type_name ();
1160 break;
1161
1162 default:
1163 error ("whos_line_format: command `%c' unknown",
1164 param.command);
1165 }
1166
1167 os << std::resetiosflags (std::ios::left)
1168 << std::resetiosflags (std::ios::right);
1169 i++;
1170 }
1171 else
1172 {
1173 os << param.text;
1174 i++;
1175 }
1176 }
1177 }
1178
1179 std::string name;
1180 octave_value varval;
1181 bool is_automatic;
1182 bool is_complex;
1183 bool is_formal;
1184 bool is_global;
1185 bool is_persistent;
1186 };
1187
1188 public:
1189 symbol_info_list (void) : lst () { }
1190
1191 symbol_info_list (const symbol_info_list& sil) : lst (sil.lst) { }
1192
1193 symbol_info_list& operator = (const symbol_info_list& sil)
1194 {
1195 if (this != &sil)
1196 lst = sil.lst;
1197
1198 return *this;
1199 }
1200
1201 ~symbol_info_list (void) { }
1202
1203 void append (const symbol_table::symbol_record& sr)
1204 {
1205 lst.push_back (symbol_info (sr));
1206 }
1207
1208 void append (const symbol_table::symbol_record& sr,
1209 const std::string& expr_str,
1210 const octave_value& expr_val)
1211 {
1212 lst.push_back (symbol_info (sr, expr_str, expr_val));
1213 }
1214
1215 size_t size (void) const { return lst.size (); }
1216
1217 bool empty (void) const { return lst.empty (); }
1218
1219 octave_map
1220 map_value (const std::string& caller_function_name, int nesting_level) const
1221 {
1222 size_t len = lst.size ();
1223
1224 Cell name_info (len, 1);
1225 Cell size_info (len, 1);
1226 Cell bytes_info (len, 1);
1227 Cell class_info (len, 1);
1228 Cell global_info (len, 1);
1229 Cell sparse_info (len, 1);
1230 Cell complex_info (len, 1);
1231 Cell nesting_info (len, 1);
1232 Cell persistent_info (len, 1);
1233
1234 std::list<symbol_info>::const_iterator p = lst.begin ();
1235
1236 for (size_t j = 0; j < len; j++)
1237 {
1238 const symbol_info& si = *p++;
1239
1240 octave_scalar_map ni;
1241
1242 ni.assign ("function", caller_function_name);
1243 ni.assign ("level", nesting_level);
1244
1245 name_info(j) = si.name;
1246 global_info(j) = si.is_global;
1247 persistent_info(j) = si.is_persistent;
1248
1249 octave_value val = si.varval;
1250
1251 size_info(j) = val.size ();
1252 bytes_info(j) = val.byte_size ();
1253 class_info(j) = val.class_name ();
1254 sparse_info(j) = val.is_sparse_type ();
1255 complex_info(j) = val.is_complex_type ();
1256 nesting_info(j) = ni;
1257 }
1258
1259 octave_map info;
1260
1261 info.assign ("name", name_info);
1262 info.assign ("size", size_info);
1263 info.assign ("bytes", bytes_info);
1264 info.assign ("class", class_info);
1265 info.assign ("global", global_info);
1266 info.assign ("sparse", sparse_info);
1267 info.assign ("complex", complex_info);
1268 info.assign ("nesting", nesting_info);
1269 info.assign ("persistent", persistent_info);
1270
1271 return info;
1272 }
1273
1274 void display (std::ostream& os)
1275 {
1276 if (! lst.empty ())
1277 {
1278 size_t bytes = 0;
1279 size_t elements = 0;
1280
1281 std::list<whos_parameter> params = parse_whos_line_format ();
1282
1283 print_descriptor (os, params);
1284
1285 octave_stdout << "\n";
1286
1287 for (std::list<symbol_info>::const_iterator p = lst.begin ();
1288 p != lst.end (); p++)
1289 {
1290 p->display_line (os, params);
1291
1292 octave_value val = p->varval;
1293
1294 elements += val.capacity ();
1295 bytes += val.byte_size ();
1296 }
1297
1298 os << "\nTotal is " << elements
1299 << (elements == 1 ? " element" : " elements")
1300 << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
1301 << "\n";
1302 }
1303 }
1304
1305 // Parse the string whos_line_format, and return a parameter list,
1306 // containing all information needed to print the given
1307 // attributtes of the symbols.
1308 std::list<whos_parameter> parse_whos_line_format (void)
1309 {
1310 int idx;
1311 size_t format_len = Vwhos_line_format.length ();
1312 char garbage;
1313 std::list<whos_parameter> params;
1314
1315 size_t bytes1;
1316 int elements1;
1317
1318 std::string param_string = "abcenst";
1319 Array<int> param_length (dim_vector (param_string.length (), 1));
1320 Array<std::string> param_names (dim_vector (param_string.length (), 1));
1321 size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
1322
1323 pos_a = param_string.find ('a'); // Attributes
1324 pos_b = param_string.find ('b'); // Bytes
1325 pos_c = param_string.find ('c'); // Class
1326 pos_e = param_string.find ('e'); // Elements
1327 pos_n = param_string.find ('n'); // Name
1328 pos_s = param_string.find ('s'); // Size
1329 pos_t = param_string.find ('t'); // Type
1330
1331 param_names(pos_a) = "Attr";
1332 param_names(pos_b) = "Bytes";
1333 param_names(pos_c) = "Class";
1334 param_names(pos_e) = "Elements";
1335 param_names(pos_n) = "Name";
1336 param_names(pos_s) = "Size";
1337 param_names(pos_t) = "Type";
1338
1339 for (size_t i = 0; i < param_string.length (); i++)
1340 param_length(i) = param_names(i).length ();
1341
1342 // The attribute column needs size 5.
1343 param_length(pos_a) = 5;
1344
1345 // Calculating necessary spacing for name column,
1346 // bytes column, elements column and class column
1347
1348 for (std::list<symbol_info>::const_iterator p = lst.begin ();
1349 p != lst.end (); p++)
1350 {
1351 std::stringstream ss1, ss2;
1352 std::string str;
1353
1354 str = p->name;
1355 param_length(pos_n) = ((str.length ()
1356 > static_cast<size_t> (param_length(pos_n)))
1357 ? str.length () : param_length(pos_n));
1358
1359 octave_value val = p->varval;
1360
1361 str = val.type_name ();
1362 param_length(pos_t) = ((str.length ()
1363 > static_cast<size_t> (param_length(pos_t)))
1364 ? str.length () : param_length(pos_t));
1365
1366 elements1 = val.capacity ();
1367 ss1 << elements1;
1368 str = ss1.str ();
1369 param_length(pos_e) = ((str.length ()
1370 > static_cast<size_t> (param_length(pos_e)))
1371 ? str.length () : param_length(pos_e));
1372
1373 bytes1 = val.byte_size ();
1374 ss2 << bytes1;
1375 str = ss2.str ();
1376 param_length(pos_b) = ((str.length ()
1377 > static_cast<size_t> (param_length(pos_b)))
1378 ? str.length () : param_length (pos_b));
1379 }
1380
1381 idx = 0;
1382 while (static_cast<size_t> (idx) < format_len)
1383 {
1384 whos_parameter param;
1385 param.command = '\0';
1386
1387 if (Vwhos_line_format[idx] == '%')
1388 {
1389 bool error_encountered = false;
1390 param.modifier = 'r';
1391 param.parameter_length = 0;
1392
1393 int a = 0, b = -1, balance = 1;
1394 unsigned int items;
1395 size_t pos;
1396 std::string cmd;
1397
1398 // Parse one command from whos_line_format
1399 cmd = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
1400 pos = cmd.find (';');
1401 if (pos != std::string::npos)
1402 cmd = cmd.substr (0, pos+1);
1403 else
1404 error ("parameter without ; in whos_line_format");
1405
1406 idx += cmd.length ();
1407
1408 // FIXME -- use iostream functions instead of sscanf!
1409
1410 if (cmd.find_first_of ("crl") != 1)
1411 items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
1412 &garbage, &param.command, &a, &b, &balance);
1413 else
1414 items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
1415 &garbage, &param.modifier, &param.command,
1416 &a, &b, &balance) - 1;
1417
1418 if (items < 2)
1419 {
1420 error ("whos_line_format: parameter structure without command in whos_line_format");
1421 error_encountered = true;
1422 }
1423
1424 // Insert data into parameter
1425 param.first_parameter_length = 0;
1426 pos = param_string.find (param.command);
1427 if (pos != std::string::npos)
1428 {
1429 param.parameter_length = param_length(pos);
1430 param.text = param_names(pos);
1431 param.line.assign (param_names(pos).length (), '=');
1432
1433 param.parameter_length = (a > param.parameter_length
1434 ? a : param.parameter_length);
1435 if (param.command == 's' && param.modifier == 'c' && b > 0)
1436 param.first_parameter_length = b;
1437 }
1438 else
1439 {
1440 error ("whos_line_format: '%c' is not a command",
1441 param.command);
1442 error_encountered = true;
1443 }
1444
1445 if (param.command == 's')
1446 {
1447 // Have to calculate space needed for printing
1448 // matrix dimensions Space needed for Size column is
1449 // hard to determine in prior, because it depends on
1450 // dimensions to be shown. That is why it is
1451 // recalculated for each Size-command int first,
1452 // rest = 0, total;
1453 int rest = 0;
1454 int first = param.first_parameter_length;
1455 int total = param.parameter_length;
1456
1457 for (std::list<symbol_info>::const_iterator p = lst.begin ();
1458 p != lst.end (); p++)
1459 {
1460 octave_value val = p->varval;
1461 std::string dims_str = get_dims_str (val);
1462 int first1 = dims_str.find ('x');
1463 int total1 = dims_str.length ();
1464 int rest1 = total1 - first1;
1465 rest = (rest1 > rest ? rest1 : rest);
1466 first = (first1 > first ? first1 : first);
1467 total = (total1 > total ? total1 : total);
1468 }
1469
1470 if (param.modifier == 'c')
1471 {
1472 if (first < balance)
1473 first += balance - first;
1474 if (rest + balance < param.parameter_length)
1475 rest += param.parameter_length - rest - balance;
1476
1477 param.parameter_length = first + rest;
1478 param.first_parameter_length = first;
1479 param.balance = balance;
1480 }
1481 else
1482 {
1483 param.parameter_length = total;
1484 param.first_parameter_length = 0;
1485 }
1486 }
1487 else if (param.modifier == 'c')
1488 {
1489 error ("whos_line_format: modifier 'c' not available for command '%c'",
1490 param.command);
1491 error_encountered = true;
1492 }
1493
1494 // What happens if whos_line_format contains negative numbers
1495 // at param_length positions?
1496 param.balance = (b < 0 ? 0 : param.balance);
1497 param.first_parameter_length = (b < 0 ? 0 :
1498 param.first_parameter_length);
1499 param.parameter_length = (a < 0
1500 ? 0
1501 : (param.parameter_length
1502 < param_length(pos_s)
1503 ? param_length(pos_s)
1504 : param.parameter_length));
1505
1506 // Parameter will not be pushed into parameter list if ...
1507 if (! error_encountered)
1508 params.push_back (param);
1509 }
1510 else
1511 {
1512 // Text string, to be printed as it is ...
1513 std::string text;
1514 size_t pos;
1515 text = Vwhos_line_format.substr (idx, Vwhos_line_format.length ());
1516 pos = text.find ('%');
1517 if (pos != std::string::npos)
1518 text = text.substr (0, pos);
1519
1520 // Push parameter into list ...
1521 idx += text.length ();
1522 param.text=text;
1523 param.line.assign (text.length (), ' ');
1524 params.push_back (param);
1525 }
1526 }
1527
1528 return params;
1529 }
1530
1531 private:
1532 std::list<symbol_info> lst;
1533
1534 };
1535
1536 static octave_value
1537 do_who (int argc, const string_vector& argv, bool return_list,
1538 bool verbose = false, std::string msg = std::string ())
1539 {
1540 octave_value retval;
1541
1542 std::string my_name = argv[0];
1543
1544 bool global_only = false;
1545 bool have_regexp = false;
1546
1547 int i;
1548 for (i = 1; i < argc; i++)
1549 {
1550 if (argv[i] == "-file")
1551 {
1552 // FIXME. This is an inefficient manner to implement this as the
1553 // variables are loaded in to a temporary context and then treated.
1554 // It would be better to refecat symbol_info_list to not store the
1555 // symbol records and then use it in load-save.cc (do_load) to
1556 // implement this option there so that the variables are never
1557 // stored at all.
1558 if (i == argc - 1)
1559 error ("whos: -file argument must be followed by a file name");
1560 else
1561 {
1562 std::string nm = argv[i + 1];
1563
1564 unwind_protect frame;
1565
1566 // Set up temporary scope.
1567
1568 symbol_table::scope_id tmp_scope = symbol_table::alloc_scope ();
1569 frame.add_fcn (symbol_table::erase_scope, tmp_scope);
1570
1571 symbol_table::set_scope (tmp_scope);
1572
1573 octave_call_stack::push (tmp_scope, 0);
1574 frame.add_fcn (octave_call_stack::pop);
1575
1576 frame.add_fcn (symbol_table::clear_variables);
1577
1578 feval ("load", octave_value (nm), 0);
1579
1580 if (! error_state)
1581 {
1582 std::string newmsg = std::string ("Variables in the file ") +
1583 nm + ":\n\n";
1584
1585 retval = do_who (i, argv, return_list, verbose, newmsg);
1586 }
1587 }
1588
1589 return retval;
1590 }
1591 else if (argv[i] == "-regexp")
1592 have_regexp = true;
1593 else if (argv[i] == "global")
1594 global_only = true;
1595 else if (argv[i][0] == '-')
1596 warning ("%s: unrecognized option `%s'", my_name.c_str (),
1597 argv[i].c_str ());
1598 else
1599 break;
1600 }
1601
1602 int npats = argc - i;
1603 string_vector pats;
1604 if (npats > 0)
1605 {
1606 pats.resize (npats);
1607 for (int j = 0; j < npats; j++)
1608 pats[j] = argv[i+j];
1609 }
1610 else
1611 {
1612 pats.resize (++npats);
1613 pats[0] = "*";
1614 }
1615
1616 symbol_info_list symbol_stats;
1617 std::list<std::string> symbol_names;
1618
1619 for (int j = 0; j < npats; j++)
1620 {
1621 std::string pat = pats[j];
1622
1623 if (have_regexp)
1624 {
1625 std::list<symbol_table::symbol_record> tmp = global_only
1626 ? symbol_table::regexp_global_variables (pat)
1627 : symbol_table::regexp_variables (pat);
1628
1629 for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin ();
1630 p != tmp.end (); p++)
1631 {
1632 if (p->is_variable ())
1633 {
1634 if (verbose)
1635 symbol_stats.append (*p);
1636 else
1637 symbol_names.push_back (p->name ());
1638 }
1639 }
1640 }
1641 else
1642 {
1643 size_t pos = pat.find_first_of (".({");
1644
1645 if (pos != std::string::npos && pos > 0)
1646 {
1647 if (verbose)
1648 {
1649 // NOTE: we can only display information for
1650 // expressions based on global values if the variable is
1651 // global in the current scope because we currently have
1652 // no way of looking up the base value in the global
1653 // scope and then evaluating the arguments in the
1654 // current scope.
1655
1656 std::string base_name = pat.substr (0, pos);
1657
1658 if (symbol_table::is_variable (base_name))
1659 {
1660 symbol_table::symbol_record sr
1661 = symbol_table::find_symbol (base_name);
1662
1663 if (! global_only || sr.is_global ())
1664 {
1665 int parse_status;
1666
1667 octave_value expr_val
1668 = eval_string (pat, true, parse_status);
1669
1670 if (! error_state)
1671 symbol_stats.append (sr, pat, expr_val);
1672 else
1673 return retval;
1674 }
1675 }
1676 }
1677 }
1678 else
1679 {
1680 std::list<symbol_table::symbol_record> tmp = global_only
1681 ? symbol_table::glob_global_variables (pat)
1682 : symbol_table::glob_variables (pat);
1683
1684 for (std::list<symbol_table::symbol_record>::const_iterator p = tmp.begin ();
1685 p != tmp.end (); p++)
1686 {
1687 if (p->is_variable ())
1688 {
1689 if (verbose)
1690 symbol_stats.append (*p);
1691 else
1692 symbol_names.push_back (p->name ());
1693 }
1694 }
1695 }
1696 }
1697 }
1698
1699 if (return_list)
1700 {
1701 if (verbose)
1702 {
1703 std::string caller_function_name;
1704 octave_function *caller = octave_call_stack::caller ();
1705 if (caller)
1706 caller_function_name = caller->name ();
1707
1708 retval = symbol_stats.map_value (caller_function_name, 1);
1709 }
1710 else
1711 retval = Cell (string_vector (symbol_names));
1712 }
1713 else if (! (symbol_stats.empty () && symbol_names.empty ()))
1714 {
1715 if (msg.length () == 0)
1716 if (global_only)
1717 octave_stdout << "Global variables:\n\n";
1718 else
1719 octave_stdout << "Variables in the current scope:\n\n";
1720 else
1721 octave_stdout << msg;
1722
1723 if (verbose)
1724 symbol_stats.display (octave_stdout);
1725 else
1726 {
1727 string_vector names (symbol_names);
1728
1729 names.list_in_columns (octave_stdout);
1730 }
1731
1732 octave_stdout << "\n";
1733 }
1734
1735 return retval;
1736 }
1737
1738 DEFUN (who, args, nargout,
1739 "-*- texinfo -*-\n\
1740 @deftypefn {Command} {} who\n\
1741 @deftypefnx {Command} {} who pattern @dots{}\n\
1742 @deftypefnx {Command} {} who option pattern @dots{}\n\
1743 @deftypefnx {Command} {C =} who (\"pattern\", @dots{})\n\
1744 List currently defined variables matching the given patterns. Valid\n\
1745 pattern syntax is the same as described for the @code{clear} command.\n\
1746 If no patterns are supplied, all variables are listed.\n\
1747 By default, only variables visible in the local scope are displayed.\n\
1748 \n\
1749 The following are valid options but may not be combined.\n\
1750 \n\
1751 @table @code\n\
1752 @item global\n\
1753 List variables in the global scope rather than the current scope.\n\
1754 \n\
1755 @item -regexp\n\
1756 The patterns are considered to be regular expressions when matching the\n\
1757 variables to display. The same pattern syntax accepted by\n\
1758 the @code{regexp} function is used.\n\
1759 \n\
1760 @item -file\n\
1761 The next argument is treated as a filename. All variables found within the\n\
1762 specified file are listed. No patterns are accepted when reading variables\n\
1763 from a file.\n\
1764 @end table\n\
1765 \n\
1766 If called as a function, return a cell array of defined variable names\n\
1767 matching the given patterns.\n\
1768 @seealso{whos, isglobal, isvarname, exist, regexp}\n\
1769 @end deftypefn")
1770 {
1771 octave_value retval;
1772
1773 if (nargout < 2)
1774 {
1775 int argc = args.length () + 1;
1776
1777 string_vector argv = args.make_argv ("who");
1778
1779 if (! error_state)
1780 retval = do_who (argc, argv, nargout == 1);
1781 }
1782 else
1783 print_usage ();
1784
1785 return retval;
1786 }
1787
1788 DEFUN (whos, args, nargout,
1789 "-*- texinfo -*-\n\
1790 @deftypefn {Command} {} whos\n\
1791 @deftypefnx {Command} {} whos pattern @dots{}\n\
1792 @deftypefnx {Command} {} whos option pattern @dots{}\n\
1793 @deftypefnx {Command} {S =} whos (\"pattern\", @dots{})\n\
1794 Provide detailed information on currently defined variables matching the\n\
1795 given patterns. Options and pattern syntax are the same as for the\n\
1796 @code{who} command. Extended information about each variable is\n\
1797 summarized in a table with the following default entries.\n\
1798 \n\
1799 @table @asis\n\
1800 @item Attr\n\
1801 Attributes of the listed variable. Possible attributes are:\n\
1802 \n\
1803 @table @asis\n\
1804 @item blank\n\
1805 Variable in local scope\n\
1806 \n\
1807 @item @code{a}\n\
1808 Automatic variable. An automatic variable is one created by the\n\
1809 interpreter, for example @code{argn}.\n\
1810 \n\
1811 @item @code{c}\n\
1812 Variable of complex type.\n\
1813 \n\
1814 @item @code{f}\n\
1815 Formal parameter (function argument).\n\
1816 \n\
1817 @item @code{g}\n\
1818 Variable with global scope.\n\
1819 \n\
1820 @item @code{p}\n\
1821 Persistent variable.\n\
1822 @end table\n\
1823 \n\
1824 @item Name\n\
1825 The name of the variable.\n\
1826 \n\
1827 @item Size\n\
1828 The logical size of the variable. A scalar is 1x1, a vector is\n\
1829 @nospell{1xN} or @nospell{Nx1}, a 2-D matrix is @nospell{MxN}.\n\
1830 \n\
1831 @item Bytes\n\
1832 The amount of memory currently used to store the variable.\n\
1833 \n\
1834 @item Class\n\
1835 The class of the variable. Examples include double, single, char, uint16,\n\
1836 cell, and struct.\n\
1837 @end table\n\
1838 \n\
1839 The table can be customized to display more or less information through\n\
1840 the function @code{whos_line_format}.\n\
1841 \n\
1842 If @code{whos} is called as a function, return a struct array of defined\n\
1843 variable names matching the given patterns. Fields in the structure\n\
1844 describing each variable are: name, size, bytes, class, global, sparse,\n\
1845 complex, nesting, persistent.\n\
1846 @seealso{who, whos_line_format}\n\
1847 @end deftypefn")
1848 {
1849 octave_value retval;
1850
1851 if (nargout < 2)
1852 {
1853 int argc = args.length () + 1;
1854
1855 string_vector argv = args.make_argv ("whos");
1856
1857 if (! error_state)
1858 retval = do_who (argc, argv, nargout == 1, true);
1859 }
1860 else
1861 print_usage ();
1862
1863 return retval;
1864 }
1865
1866 // Defining variables.
1867
1868 void
1869 bind_ans (const octave_value& val, bool print)
1870 {
1871 static std::string ans = "ans";
1872
1873 if (val.is_defined ())
1874 {
1875 if (val.is_cs_list ())
1876 {
1877 octave_value_list lst = val.list_value ();
1878
1879 for (octave_idx_type i = 0; i < lst.length (); i++)
1880 bind_ans (lst(i), print);
1881 }
1882 else
1883 {
1884 symbol_table::varref (ans) = val;
1885
1886 if (print)
1887 val.print_with_name (octave_stdout, ans);
1888 }
1889 }
1890 }
1891
1892 void
1893 bind_internal_variable (const std::string& fname, const octave_value& val)
1894 {
1895 octave_value_list args;
1896
1897 args(0) = val;
1898
1899 feval (fname, args, 0);
1900 }
1901
1902 void
1903 mlock (void)
1904 {
1905 octave_function *fcn = octave_call_stack::current ();
1906
1907 if (fcn)
1908 fcn->lock ();
1909 else
1910 error ("mlock: invalid use outside a function");
1911 }
1912
1913 void
1914 munlock (const std::string& nm)
1915 {
1916 octave_value val = symbol_table::find_function (nm);
1917
1918 if (val.is_defined ())
1919 {
1920 octave_function *fcn = val.function_value ();
1921
1922 if (fcn)
1923 fcn->unlock ();
1924 }
1925 }
1926
1927 bool
1928 mislocked (const std::string& nm)
1929 {
1930 bool retval = false;
1931
1932 octave_value val = symbol_table::find_function (nm);
1933
1934 if (val.is_defined ())
1935 {
1936 octave_function *fcn = val.function_value ();
1937
1938 if (fcn)
1939 retval = fcn->islocked ();
1940 }
1941
1942 return retval;
1943 }
1944
1945 DEFUN (mlock, args, ,
1946 "-*- texinfo -*-\n\
1947 @deftypefn {Built-in Function} {} mlock ()\n\
1948 Lock the current function into memory so that it can't be cleared.\n\
1949 @seealso{munlock, mislocked, persistent}\n\
1950 @end deftypefn")
1951 {
1952 octave_value_list retval;
1953
1954 if (args.length () == 0)
1955 {
1956 octave_function *fcn = octave_call_stack::caller ();
1957
1958 if (fcn)
1959 fcn->lock ();
1960 else
1961 error ("mlock: invalid use outside a function");
1962 }
1963 else
1964 print_usage ();
1965
1966 return retval;
1967 }
1968
1969 DEFUN (munlock, args, ,
1970 "-*- texinfo -*-\n\
1971 @deftypefn {Built-in Function} {} munlock ()\n\
1972 @deftypefnx {Built-in Function} {} munlock (@var{fcn})\n\
1973 Unlock the named function @var{fcn}. If no function is named\n\
1974 then unlock the current function.\n\
1975 @seealso{mlock, mislocked, persistent}\n\
1976 @end deftypefn")
1977 {
1978 octave_value_list retval;
1979
1980 if (args.length () == 1)
1981 {
1982 std::string name = args(0).string_value ();
1983
1984 if (! error_state)
1985 munlock (name);
1986 else
1987 error ("munlock: FCN must be a string");
1988 }
1989 else if (args.length () == 0)
1990 {
1991 octave_function *fcn = octave_call_stack::caller ();
1992
1993 if (fcn)
1994 fcn->unlock ();
1995 else
1996 error ("munlock: invalid use outside a function");
1997 }
1998 else
1999 print_usage ();
2000
2001 return retval;
2002 }
2003
2004
2005 DEFUN (mislocked, args, ,
2006 "-*- texinfo -*-\n\
2007 @deftypefn {Built-in Function} {} mislocked ()\n\
2008 @deftypefnx {Built-in Function} {} mislocked (@var{fcn})\n\
2009 Return true if the named function @var{fcn} is locked. If no function is\n\
2010 named then return true if the current function is locked.\n\
2011 @seealso{mlock, munlock, persistent}\n\
2012 @end deftypefn")
2013 {
2014 octave_value retval;
2015
2016 if (args.length () == 1)
2017 {
2018 std::string name = args(0).string_value ();
2019
2020 if (! error_state)
2021 retval = mislocked (name);
2022 else
2023 error ("mislocked: FCN must be a string");
2024 }
2025 else if (args.length () == 0)
2026 {
2027 octave_function *fcn = octave_call_stack::caller ();
2028
2029 if (fcn)
2030 retval = fcn->islocked ();
2031 else
2032 error ("mislocked: invalid use outside a function");
2033 }
2034 else
2035 print_usage ();
2036
2037 return retval;
2038 }
2039
2040 // Deleting names from the symbol tables.
2041
2042 static inline bool
2043 name_matches_any_pattern (const std::string& nm, const string_vector& argv,
2044 int argc, int idx, bool have_regexp = false)
2045 {
2046 bool retval = false;
2047
2048 for (int k = idx; k < argc; k++)
2049 {
2050 std::string patstr = argv[k];
2051 if (! patstr.empty ())
2052 {
2053 if (have_regexp)
2054 {
2055 if (is_regexp_match (patstr, nm))
2056 {
2057 retval = true;
2058 break;
2059 }
2060 }
2061 else
2062 {
2063 glob_match pattern (patstr);
2064
2065 if (pattern.match (nm))
2066 {
2067 retval = true;
2068 break;
2069 }
2070 }
2071 }
2072 }
2073
2074 return retval;
2075 }
2076
2077 static inline void
2078 maybe_warn_exclusive (bool exclusive)
2079 {
2080 if (exclusive)
2081 warning ("clear: ignoring --exclusive option");
2082 }
2083
2084 static void
2085 do_clear_functions (const string_vector& argv, int argc, int idx,
2086 bool exclusive = false)
2087 {
2088 if (idx == argc)
2089 symbol_table::clear_functions ();
2090 else
2091 {
2092 if (exclusive)
2093 {
2094 string_vector fcns = symbol_table::user_function_names ();
2095
2096 int fcount = fcns.length ();
2097
2098 for (int i = 0; i < fcount; i++)
2099 {
2100 std::string nm = fcns[i];
2101
2102 if (! name_matches_any_pattern (nm, argv, argc, idx))
2103 symbol_table::clear_function (nm);
2104 }
2105 }
2106 else
2107 {
2108 while (idx < argc)
2109 symbol_table::clear_function_pattern (argv[idx++]);
2110 }
2111 }
2112 }
2113
2114 static void
2115 do_clear_globals (const string_vector& argv, int argc, int idx,
2116 bool exclusive = false)
2117 {
2118 if (idx == argc)
2119 {
2120 string_vector gvars = symbol_table::global_variable_names ();
2121
2122 int gcount = gvars.length ();
2123
2124 for (int i = 0; i < gcount; i++)
2125 symbol_table::clear_global (gvars[i]);
2126 }
2127 else
2128 {
2129 if (exclusive)
2130 {
2131 string_vector gvars = symbol_table::global_variable_names ();
2132
2133 int gcount = gvars.length ();
2134
2135 for (int i = 0; i < gcount; i++)
2136 {
2137 std::string nm = gvars[i];
2138
2139 if (! name_matches_any_pattern (nm, argv, argc, idx))
2140 symbol_table::clear_global (nm);
2141 }
2142 }
2143 else
2144 {
2145 while (idx < argc)
2146 symbol_table::clear_global_pattern (argv[idx++]);
2147 }
2148 }
2149 }
2150
2151 static void
2152 do_clear_variables (const string_vector& argv, int argc, int idx,
2153 bool exclusive = false, bool have_regexp = false)
2154 {
2155 if (idx == argc)
2156 symbol_table::clear_variables ();
2157 else
2158 {
2159 if (exclusive)
2160 {
2161 string_vector lvars = symbol_table::variable_names ();
2162
2163 int lcount = lvars.length ();
2164
2165 for (int i = 0; i < lcount; i++)
2166 {
2167 std::string nm = lvars[i];
2168
2169 if (! name_matches_any_pattern (nm, argv, argc, idx, have_regexp))
2170 symbol_table::clear_variable (nm);
2171 }
2172 }
2173 else
2174 {
2175 if (have_regexp)
2176 while (idx < argc)
2177 symbol_table::clear_variable_regexp (argv[idx++]);
2178 else
2179 while (idx < argc)
2180 symbol_table::clear_variable_pattern (argv[idx++]);
2181 }
2182 }
2183 }
2184
2185 static void
2186 do_clear_symbols (const string_vector& argv, int argc, int idx,
2187 bool exclusive = false)
2188 {
2189 if (idx == argc)
2190 symbol_table::clear_variables ();
2191 else
2192 {
2193 if (exclusive)
2194 {
2195 // FIXME -- is this really what we want, or do we
2196 // somehow want to only clear the functions that are not
2197 // shadowed by local variables? It seems that would be a
2198 // bit harder to do.
2199
2200 do_clear_variables (argv, argc, idx, exclusive);
2201 do_clear_functions (argv, argc, idx, exclusive);
2202 }
2203 else
2204 {
2205 while (idx < argc)
2206 symbol_table::clear_symbol_pattern (argv[idx++]);
2207 }
2208 }
2209 }
2210
2211 static void
2212 do_matlab_compatible_clear (const string_vector& argv, int argc, int idx)
2213 {
2214 // This is supposed to be mostly Matlab compatible.
2215
2216 for (; idx < argc; idx++)
2217 {
2218 if (argv[idx] == "all"
2219 && ! symbol_table::is_local_variable ("all"))
2220 {
2221 symbol_table::clear_all ();
2222 }
2223 else if (argv[idx] == "functions"
2224 && ! symbol_table::is_local_variable ("functions"))
2225 {
2226 do_clear_functions (argv, argc, ++idx);
2227 }
2228 else if (argv[idx] == "global"
2229 && ! symbol_table::is_local_variable ("global"))
2230 {
2231 do_clear_globals (argv, argc, ++idx);
2232 }
2233 else if (argv[idx] == "variables"
2234 && ! symbol_table::is_local_variable ("variables"))
2235 {
2236 symbol_table::clear_variables ();
2237 }
2238 else if (argv[idx] == "classes"
2239 && ! symbol_table::is_local_variable ("classes"))
2240 {
2241 symbol_table::clear_objects ();
2242 octave_class::clear_exemplar_map ();
2243 }
2244 else
2245 {
2246 symbol_table::clear_symbol_pattern (argv[idx]);
2247 }
2248 }
2249 }
2250
2251 #define CLEAR_OPTION_ERROR(cond) \
2252 do \
2253 { \
2254 if (cond) \
2255 { \
2256 print_usage (); \
2257 return retval; \
2258 } \
2259 } \
2260 while (0)
2261
2262 DEFUN (clear, args, ,
2263 "-*- texinfo -*-\n\
2264 @deftypefn {Command} {} clear [options] pattern @dots{}\n\
2265 Delete the names matching the given patterns from the symbol table. The\n\
2266 pattern may contain the following special characters:\n\
2267 \n\
2268 @table @code\n\
2269 @item ?\n\
2270 Match any single character.\n\
2271 \n\
2272 @item *\n\
2273 Match zero or more characters.\n\
2274 \n\
2275 @item [ @var{list} ]\n\
2276 Match the list of characters specified by @var{list}. If the first\n\
2277 character is @code{!} or @code{^}, match all characters except those\n\
2278 specified by @var{list}. For example, the pattern @samp{[a-zA-Z]} will\n\
2279 match all lowercase and uppercase alphabetic characters.\n\
2280 @end table\n\
2281 \n\
2282 For example, the command\n\
2283 \n\
2284 @example\n\
2285 clear foo b*r\n\
2286 @end example\n\
2287 \n\
2288 @noindent\n\
2289 clears the name @code{foo} and all names that begin with the letter\n\
2290 @code{b} and end with the letter @code{r}.\n\
2291 \n\
2292 If @code{clear} is called without any arguments, all user-defined\n\
2293 variables (local and global) are cleared from the symbol table. If\n\
2294 @code{clear} is called with at least one argument, only the visible\n\
2295 names matching the arguments are cleared. For example, suppose you have\n\
2296 defined a function @code{foo}, and then hidden it by performing the\n\
2297 assignment @code{foo = 2}. Executing the command @kbd{clear foo} once\n\
2298 will clear the variable definition and restore the definition of\n\
2299 @code{foo} as a function. Executing @kbd{clear foo} a second time will\n\
2300 clear the function definition.\n\
2301 \n\
2302 The following options are available in both long and short form\n\
2303 \n\
2304 @table @code\n\
2305 @item -all, -a\n\
2306 Clears all local and global user-defined variables and all functions\n\
2307 from the symbol table.\n\
2308 \n\
2309 @item -exclusive, -x\n\
2310 Clears the variables that don't match the following pattern.\n\
2311 \n\
2312 @item -functions, -f\n\
2313 Clears the function names and the built-in symbols names.\n\
2314 \n\
2315 @item -global, -g\n\
2316 Clears the global symbol names.\n\
2317 \n\
2318 @item -variables, -v\n\
2319 Clears the local variable names.\n\
2320 \n\
2321 @item -classes, -c\n\
2322 Clears the class structure table and clears all objects.\n\
2323 \n\
2324 @item -regexp, -r\n\
2325 The arguments are treated as regular expressions as any variables that\n\
2326 match will be cleared.\n\
2327 @end table\n\
2328 \n\
2329 With the exception of @code{exclusive}, all long options can be used\n\
2330 without the dash as well.\n\
2331 @end deftypefn")
2332 {
2333 octave_value_list retval;
2334
2335 int argc = args.length () + 1;
2336
2337 string_vector argv = args.make_argv ("clear");
2338
2339 if (! error_state)
2340 {
2341 if (argc == 1)
2342 {
2343 do_clear_globals (argv, argc, 1);
2344 do_clear_variables (argv, argc, 1);
2345 }
2346 else
2347 {
2348 int idx = 0;
2349
2350 bool clear_all = false;
2351 bool clear_functions = false;
2352 bool clear_globals = false;
2353 bool clear_variables = false;
2354 bool clear_objects = false;
2355 bool exclusive = false;
2356 bool have_regexp = false;
2357 bool have_dash_option = false;
2358
2359 while (++idx < argc)
2360 {
2361 if (argv[idx] == "-all" || argv[idx] == "-a")
2362 {
2363 CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
2364
2365 have_dash_option = true;
2366 clear_all = true;
2367 }
2368 else if (argv[idx] == "-exclusive" || argv[idx] == "-x")
2369 {
2370 have_dash_option = true;
2371 exclusive = true;
2372 }
2373 else if (argv[idx] == "-functions" || argv[idx] == "-f")
2374 {
2375 CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
2376
2377 have_dash_option = true;
2378 clear_functions = true;
2379 }
2380 else if (argv[idx] == "-global" || argv[idx] == "-g")
2381 {
2382 CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
2383
2384 have_dash_option = true;
2385 clear_globals = true;
2386 }
2387 else if (argv[idx] == "-variables" || argv[idx] == "-v")
2388 {
2389 CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
2390
2391 have_dash_option = true;
2392 clear_variables = true;
2393 }
2394 else if (argv[idx] == "-classes" || argv[idx] == "-c")
2395 {
2396 CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
2397
2398 have_dash_option = true;
2399 clear_objects = true;
2400 }
2401 else if (argv[idx] == "-regexp" || argv[idx] == "-r")
2402 {
2403 CLEAR_OPTION_ERROR (have_dash_option && ! exclusive);
2404
2405 have_dash_option = true;
2406 have_regexp = true;
2407 }
2408 else
2409 break;
2410 }
2411
2412 if (idx <= argc)
2413 {
2414 if (! have_dash_option)
2415 {
2416 do_matlab_compatible_clear (argv, argc, idx);
2417 }
2418 else
2419 {
2420 if (clear_all)
2421 {
2422 maybe_warn_exclusive (exclusive);
2423
2424 if (++idx < argc)
2425 warning
2426 ("clear: ignoring extra arguments after -all");
2427
2428 symbol_table::clear_all ();
2429 }
2430 else if (have_regexp)
2431 {
2432 do_clear_variables (argv, argc, idx, exclusive, true);
2433 }
2434 else if (clear_functions)
2435 {
2436 do_clear_functions (argv, argc, idx, exclusive);
2437 }
2438 else if (clear_globals)
2439 {
2440 do_clear_globals (argv, argc, idx, exclusive);
2441 }
2442 else if (clear_variables)
2443 {
2444 do_clear_variables (argv, argc, idx, exclusive);
2445 }
2446 else if (clear_objects)
2447 {
2448 symbol_table::clear_objects ();
2449 octave_class::clear_exemplar_map ();
2450 }
2451 else
2452 {
2453 do_clear_symbols (argv, argc, idx, exclusive);
2454 }
2455 }
2456 }
2457 }
2458 }
2459
2460 return retval;
2461 }
2462
2463 DEFUN (whos_line_format, args, nargout,
2464 "-*- texinfo -*-\n\
2465 @deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\
2466 @deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\
2467 @deftypefnx {Built-in Function} {} whos_line_format (@var{new_val}, \"local\")\n\
2468 Query or set the format string used by the command @code{whos}.\n\
2469 \n\
2470 A full format string is:\n\
2471 @c Set example in small font to prevent overfull line\n\
2472 \n\
2473 @smallexample\n\
2474 %[modifier]<command>[:width[:left-min[:balance]]];\n\
2475 @end smallexample\n\
2476 \n\
2477 The following command sequences are available:\n\
2478 \n\
2479 @table @code\n\
2480 @item %a\n\
2481 Prints attributes of variables (g=global, p=persistent,\n\
2482 f=formal parameter, a=automatic variable).\n\
2483 \n\
2484 @item %b\n\
2485 Prints number of bytes occupied by variables.\n\
2486 \n\
2487 @item %c\n\
2488 Prints class names of variables.\n\
2489 \n\
2490 @item %e\n\
2491 Prints elements held by variables.\n\
2492 \n\
2493 @item %n\n\
2494 Prints variable names.\n\
2495 \n\
2496 @item %s\n\
2497 Prints dimensions of variables.\n\
2498 \n\
2499 @item %t\n\
2500 Prints type names of variables.\n\
2501 @end table\n\
2502 \n\
2503 Every command may also have an alignment modifier:\n\
2504 \n\
2505 @table @code\n\
2506 @item l\n\
2507 Left alignment.\n\
2508 \n\
2509 @item r\n\
2510 Right alignment (default).\n\
2511 \n\
2512 @item c\n\
2513 Column-aligned (only applicable to command %s).\n\
2514 @end table\n\
2515 \n\
2516 The @code{width} parameter is a positive integer specifying the minimum\n\
2517 number of columns used for printing. No maximum is needed as the field will\n\
2518 auto-expand as required.\n\
2519 \n\
2520 The parameters @code{left-min} and @code{balance} are only available when the\n\
2521 column-aligned modifier is used with the command @samp{%s}.\n\
2522 @code{balance} specifies the column number within the field width which will\n\
2523 be aligned between entries. Numbering starts from 0 which indicates the\n\
2524 leftmost column. @code{left-min} specifies the minimum field width to the\n\
2525 left of the specified balance column.\n\
2526 \n\
2527 The default format is\n\
2528 @code{\" %a:4; %ln:6; %cs:16:6:1; %rb:12; %lc:-1;\\n\"}.\n\
2529 \n\
2530 When called from inside a function with the \"local\" option, the variable is\n\
2531 changed locally for the function and any subroutines it calls. The original\n\
2532 variable value is restored when exiting the function.\n\
2533 @seealso{whos}\n\
2534 @end deftypefn")
2535 {
2536 return SET_INTERNAL_VARIABLE (whos_line_format);
2537 }
2538
2539 static std::string Vmissing_function_hook = "unimplemented";
2540
2541 DEFUN (missing_function_hook, args, nargout,
2542 "-*- texinfo -*-\n\
2543 @deftypefn {Built-in Function} {@var{val} =} missing_function_hook ()\n\
2544 @deftypefnx {Built-in Function} {@var{old_val} =} missing_function_hook (@var{new_val})\n\
2545 @deftypefnx {Built-in Function} {} missing_function_hook (@var{new_val}, \"local\")\n\
2546 Query or set the internal variable that specifies the function to call when\n\
2547 an unknown identifier is requested.\n\
2548 \n\
2549 When called from inside a function with the \"local\" option, the variable is\n\
2550 changed locally for the function and any subroutines it calls. The original\n\
2551 variable value is restored when exiting the function.\n\
2552 @end deftypefn")
2553 {
2554 return SET_INTERNAL_VARIABLE (missing_function_hook);
2555 }
2556
2557 void maybe_missing_function_hook (const std::string& name)
2558 {
2559 // Don't do this if we're handling errors.
2560 if (buffer_error_messages == 0 && ! Vmissing_function_hook.empty ())
2561 {
2562 // Ensure auto-restoration.
2563 unwind_protect frame;
2564 frame.protect_var (Vmissing_function_hook);
2565
2566 // Clear the variable prior to calling the function.
2567 const std::string func_name = Vmissing_function_hook;
2568 Vmissing_function_hook.clear ();
2569
2570 // Call.
2571 feval (func_name, octave_value (name));
2572 }
2573 }
2574
2575 DEFUN (__varval__, args, ,
2576 "-*- texinfo -*-\n\
2577 @deftypefn {Built-in Function} {} __varval__ (@var{name})\n\
2578 Undocumented internal function.\n\
2579 @end deftypefn")
2580 {
2581 octave_value retval;
2582
2583 if (args.length () == 1)
2584 {
2585 std::string name = args(0).string_value ();
2586
2587 if (! error_state)
2588 retval = symbol_table::varval (args(0).string_value ());
2589 else
2590 error ("__varval__: expecting argument to be variable name");
2591 }
2592 else
2593 print_usage ();
2594
2595 return retval;
2596 }