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