changelog shortlog tags changeset files revisions annotate raw

src/variables.cc

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