changelog shortlog tags changeset files revisions annotate raw

src/variables.cc

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