GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
syminfo.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2018-2022 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <iomanip>
31#include <list>
32#include <ostream>
33#include <sstream>
34
35#include "Cell.h"
36#include "error.h"
38#include "ov.h"
39#include "oct-map.h"
40#include "pager.h"
41#include "syminfo.h"
42
43namespace octave
44{
45 void
46 symbol_info::display_line (std::ostream& os,
47 const std::list<whos_parameter>& params) const
48 {
49 std::string dims_str = m_value.get_dims_str ();
50
51 auto i = params.begin ();
52
53 preserve_stream_state stream_state (os);
54
55 while (i != params.end ())
56 {
57 whos_parameter param = *i;
58
59 if (param.command != '\0')
60 {
61 // Do the actual printing.
62
63 switch (param.modifier)
64 {
65 case 'l':
66 os << std::setiosflags (std::ios::left)
67 << std::setw (param.parameter_length);
68 break;
69
70 case 'r':
71 os << std::setiosflags (std::ios::right)
72 << std::setw (param.parameter_length);
73 break;
74
75 case 'c':
76 if (param.command == 's')
77 {
78 int front = param.first_parameter_length
79 - dims_str.find ('x');
80 int back = param.parameter_length
81 - dims_str.length ()
82 - front;
83 front = (front > 0) ? front : 0;
84 back = (back > 0) ? back : 0;
85
86 os << std::setiosflags (std::ios::left)
87 << std::setw (front)
88 << ""
89 << std::resetiosflags (std::ios::left)
90 << dims_str
91 << std::setiosflags (std::ios::left)
92 << std::setw (back)
93 << ""
94 << std::resetiosflags (std::ios::left);
95 }
96 else
97 {
98 os << std::setiosflags (std::ios::left)
99 << std::setw (param.parameter_length);
100 }
101 break;
102
103 default:
104 error ("whos_line_format: modifier '%c' unknown",
105 param.modifier);
106 }
107
108 switch (param.command)
109 {
110 case 'a':
111 {
112 char tmp[6];
113
114 tmp[0] = (m_is_complex ? 'c' : ' ');
115 tmp[1] = (m_is_sparse ? 's' : ' ');
116 tmp[2] = (m_is_formal ? 'f' : ' ');
117 tmp[3] = (m_is_global ? 'g' : ' ');
118 tmp[4] = (m_is_persistent ? 'p' : ' ');
119 tmp[5] = 0;
120
121 os << tmp;
122 }
123 break;
124
125 case 'b':
126 os << m_value.byte_size ();
127 break;
128
129 case 'c':
130 os << m_value.class_name ();
131 break;
132
133 case 'e':
134 os << m_value.numel ();
135 break;
136
137 case 'n':
138 os << m_name;
139 break;
140
141 case 's':
142 if (param.modifier != 'c')
143 os << dims_str;
144 break;
145
146 case 't':
147 os << m_value.type_name ();
148 break;
149
150 default:
151 error ("whos_line_format: command '%c' unknown",
152 param.command);
153 }
154
155 os << std::resetiosflags (std::ios::left)
156 << std::resetiosflags (std::ios::right);
157 i++;
158 }
159 else
160 {
161 os << param.text;
162 i++;
163 }
164 }
165 }
166
167 // FIXME: should we be using std::map<symbol_info> instead of a list?
168
169 octave_value symbol_info_list::varval (const std::string& name) const
170 {
171 for (const auto& syminfo : m_lst)
172 {
173 if (name == syminfo.name ())
174 return syminfo.value ();
175 }
176
177 return octave_value ();
178 }
179
180 std::list<std::string> symbol_info_list::names (void) const
181 {
182 std::list<std::string> retval;
183
184 for (const auto& syminfo : m_lst)
185 retval.push_back (syminfo.name ());
186
187 return retval;
188 }
189
191 symbol_info_list::map_value (const std::string& caller_function_name,
192 int nesting_level) const
193 {
194 std::size_t len = m_lst.size ();
195
196 Cell name_info (len, 1);
197 Cell size_info (len, 1);
198 Cell bytes_info (len, 1);
199 Cell class_info (len, 1);
200 Cell global_info (len, 1);
201 Cell sparse_info (len, 1);
202 Cell complex_info (len, 1);
203 Cell nesting_info (len, 1);
204 Cell persistent_info (len, 1);
205
206 std::size_t j = 0;
207
208 for (const auto& syminfo : m_lst)
209 {
211
212 ni.assign ("function", caller_function_name);
213 ni.assign ("level", nesting_level);
214
215 name_info(j) = syminfo.name ();
216 global_info(j) = syminfo.is_global ();
217 persistent_info(j) = syminfo.is_persistent ();
218
219 octave_value val = syminfo.value ();
220
221 size_info(j) = val.size ();
222 bytes_info(j) = val.byte_size ();
223 class_info(j) = val.class_name ();
224 sparse_info(j) = val.issparse ();
225 complex_info(j) = val.iscomplex ();
226 nesting_info(j) = ni;
227
228 j++;
229 }
230
231 octave_map info;
232
233 info.assign ("name", name_info);
234 info.assign ("size", size_info);
235 info.assign ("bytes", bytes_info);
236 info.assign ("class", class_info);
237 info.assign ("global", global_info);
238 info.assign ("sparse", sparse_info);
239 info.assign ("complex", complex_info);
240 info.assign ("nesting", nesting_info);
241 info.assign ("persistent", persistent_info);
242
243 return info;
244 }
245
246 void
248 const std::list<whos_parameter> params) const
249 {
250 std::ostringstream param_buf;
251
252 preserve_stream_state stream_state (os);
253
254 for (const auto& param : params)
255 {
256 if (param.command != '\0')
257 {
258 // Do the actual printing
259 switch (param.modifier)
260 {
261 case 'l':
262 os << std::setiosflags (std::ios::left)
263 << std::setw (param.parameter_length);
264 param_buf << std::setiosflags (std::ios::left)
265 << std::setw (param.parameter_length);
266 break;
267
268 case 'r':
269 os << std::setiosflags (std::ios::right)
270 << std::setw (param.parameter_length);
271 param_buf << std::setiosflags (std::ios::right)
272 << std::setw (param.parameter_length);
273 break;
274
275 case 'c':
276 if (param.command != 's')
277 {
278 os << std::setiosflags (std::ios::left)
279 << std::setw (param.parameter_length);
280 param_buf << std::setiosflags (std::ios::left)
281 << std::setw (param.parameter_length);
282 }
283 break;
284
285 default:
286 os << std::setiosflags (std::ios::left)
287 << std::setw (param.parameter_length);
288 param_buf << std::setiosflags (std::ios::left)
289 << std::setw (param.parameter_length);
290 }
291
292 if (param.command == 's' && param.modifier == 'c')
293 {
294 int a = param.first_parameter_length - param.balance;
295 a = (a < 0 ? 0 : a);
296 int b = param.parameter_length - a - param.text.length ();
297 b = (b < 0 ? 0 : b);
298 os << std::setiosflags (std::ios::left) << std::setw (a)
299 << "" << std::resetiosflags (std::ios::left) << param.text
300 << std::setiosflags (std::ios::left)
301 << std::setw (b) << ""
302 << std::resetiosflags (std::ios::left);
303 param_buf << std::setiosflags (std::ios::left)
304 << std::setw (a)
305 << "" << std::resetiosflags (std::ios::left)
306 << param.line
307 << std::setiosflags (std::ios::left)
308 << std::setw (b) << ""
309 << std::resetiosflags (std::ios::left);
310 }
311 else
312 {
313 os << param.text;
314 param_buf << param.line;
315 }
316 os << std::resetiosflags (std::ios::left)
317 << std::resetiosflags (std::ios::right);
318 param_buf << std::resetiosflags (std::ios::left)
319 << std::resetiosflags (std::ios::right);
320 }
321 else
322 {
323 os << param.text;
324 param_buf << param.line;
325 }
326 }
327
328 os << param_buf.str ();
329 }
330
331 void symbol_info_list::display (std::ostream& os,
332 const std::string& format) const
333 {
334 if (! m_lst.empty ())
335 {
336 std::size_t bytes = 0;
337 std::size_t elements = 0;
338
339 std::list<whos_parameter> params = parse_whos_line_format (format);
340
341 print_descriptor (os, params);
342
343 octave_stdout << "\n";
344
345 for (const auto& syminfo : m_lst)
346 {
347 syminfo.display_line (os, params);
348
349 octave_value val = syminfo.value ();
350
351 elements += val.numel ();
352 bytes += val.byte_size ();
353 }
354
355 os << "\nTotal is " << elements
356 << (elements == 1 ? " element" : " elements")
357 << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
358 << "\n";
359 }
360 }
361
362 std::list<whos_parameter>
364 {
365 int idx;
366 std::size_t format_len = format.length ();
367 char garbage;
368 std::list<whos_parameter> params;
369
370 std::size_t bytes1;
371 int elements1;
372
373 std::string param_string = "abcenst";
374 Array<int> param_length (dim_vector (param_string.length (), 1));
375 Array<std::string> param_names (dim_vector (param_string.length (), 1));
376 std::size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
377
378 pos_a = param_string.find ('a'); // Attributes
379 pos_b = param_string.find ('b'); // Bytes
380 pos_c = param_string.find ('c'); // Class
381 pos_e = param_string.find ('e'); // Elements
382 pos_n = param_string.find ('n'); // Name
383 pos_s = param_string.find ('s'); // Size
384 pos_t = param_string.find ('t'); // Type
385
386 param_names(pos_a) = "Attr";
387 param_names(pos_b) = "Bytes";
388 param_names(pos_c) = "Class";
389 param_names(pos_e) = "Elements";
390 param_names(pos_n) = "Name";
391 param_names(pos_s) = "Size";
392 param_names(pos_t) = "Type";
393
394 for (std::size_t i = 0; i < param_string.length (); i++)
395 param_length(i) = param_names(i).length ();
396
397 // The attribute column needs size 6.
398 param_length(pos_a) = 6;
399
400 // Calculating necessary spacing for name column,
401 // bytes column, elements column and class column
402
403 for (const auto& syminfo : m_lst)
404 {
405 std::stringstream ss1, ss2;
406 std::string str;
407
408 str = syminfo.name ();
409 param_length(pos_n) = ((str.length ()
410 > static_cast<std::size_t> (param_length(pos_n)))
411 ? str.length () : param_length(pos_n));
412
413 octave_value val = syminfo.value ();
414
415 str = val.type_name ();
416 param_length(pos_t) = ((str.length ()
417 > static_cast<std::size_t> (param_length(pos_t)))
418 ? str.length () : param_length(pos_t));
419
420 elements1 = val.numel ();
421 ss1 << elements1;
422 str = ss1.str ();
423 param_length(pos_e) = ((str.length ()
424 > static_cast<std::size_t> (param_length(pos_e)))
425 ? str.length () : param_length(pos_e));
426
427 bytes1 = val.byte_size ();
428 ss2 << bytes1;
429 str = ss2.str ();
430 param_length(pos_b) = ((str.length ()
431 > static_cast<std::size_t> (param_length(pos_b)))
432 ? str.length () : param_length (pos_b));
433 }
434
435 idx = 0;
436 while (static_cast<std::size_t> (idx) < format_len)
437 {
438 whos_parameter param;
439 param.command = '\0';
440
441 if (format[idx] == '%')
442 {
443 param.modifier = 'r';
444 param.parameter_length = 0;
445
446 int a = 0;
447 int b = -1;
448 int balance = 1;
449 unsigned int items;
450 std::size_t pos;
451 std::string cmd;
452
453 // Parse one command from format
454 cmd = format.substr (idx, format.length ());
455 pos = cmd.find (';');
456 if (pos == std::string::npos)
457 error ("parameter without ; in format");
458
459 cmd = cmd.substr (0, pos+1);
460
461 idx += cmd.length ();
462
463 // FIXME: use iostream functions instead of sscanf!
464
465 if (cmd.find_first_of ("crl") != 1)
466 items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
467 &garbage, &param.command, &a, &b, &balance);
468 else
469 items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
470 &garbage, &param.modifier, &param.command,
471 &a, &b, &balance) - 1;
472
473 if (items < 2)
474 error ("whos_line_format: found parameter structure without command");
475
476 // Exception case of bare class command 'c' without modifier 'l/r'
477 if (param.modifier == 'c'
478 && param_string.find (param.command) == std::string::npos)
479 {
480 param.modifier = 'r';
481 param.command = 'c';
482 }
483
484 // Insert data into parameter
485 param.first_parameter_length = 0;
486 pos = param_string.find (param.command);
487 if (pos == std::string::npos)
488 error ("whos_line_format: '%c' is not a command", param.command);
489
490 param.parameter_length = param_length(pos);
491 param.text = param_names(pos);
492 param.line.assign (param_names(pos).length (), '=');
493
494 param.parameter_length = (a > param.parameter_length
495 ? a : param.parameter_length);
496 if (param.command == 's' && param.modifier == 'c' && b > 0)
497 param.first_parameter_length = b;
498
499 if (param.command == 's')
500 {
501 // Have to calculate space needed for printing
502 // matrix dimensions Space needed for Size column is
503 // hard to determine in prior, because it depends on
504 // dimensions to be shown. That is why it is
505 // recalculated for each Size-command int first,
506 // rest = 0, total;
507 int rest = 0;
508 int first = param.first_parameter_length;
509 int total = param.parameter_length;
510
511 for (const auto& syminfo : m_lst)
512 {
513 octave_value val = syminfo.value ();
514 std::string dims_str = val.get_dims_str ();
515 int first1 = dims_str.find ('x');
516 int total1 = dims_str.length ();
517 int rest1 = total1 - first1;
518 rest = (rest1 > rest ? rest1 : rest);
519 first = (first1 > first ? first1 : first);
520 total = (total1 > total ? total1 : total);
521 }
522
523 if (param.modifier == 'c')
524 {
525 if (first < balance)
526 first += balance - first;
527 if (rest + balance < param.parameter_length)
528 rest += param.parameter_length - rest - balance;
529
530 param.parameter_length = first + rest;
531 param.first_parameter_length = first;
532 param.balance = balance;
533 }
534 else
535 {
536 param.parameter_length = total;
537 param.first_parameter_length = 0;
538 }
539 }
540 else if (param.modifier == 'c')
541 error ("whos_line_format: modifier 'c' not available for command '%c'",
542 param.command);
543
544 // What happens if format contains negative numbers
545 // at param_length positions?
546 param.balance = (b < 0 ? 0 : param.balance);
547 param.first_parameter_length = (b < 0
548 ? 0
549 : param.first_parameter_length);
550 param.parameter_length = (a < 0
551 ? 0
552 : (param.parameter_length
553 < param_length(pos_s)
554 ? param_length(pos_s)
555 : param.parameter_length));
556
557 params.push_back (param);
558 }
559 else
560 {
561 // Text string, to be printed as it is ...
562 std::string text;
563 std::size_t pos;
564 text = format.substr (idx, format.length ());
565 pos = text.find ('%');
566 if (pos != std::string::npos)
567 text = text.substr (0, pos);
568
569 // Push parameter into list ...
570 idx += text.length ();
571 param.text=text;
572 param.line.assign (text.length (), ' ');
573 params.push_back (param);
574 }
575 }
576
577 return params;
578 }
579}
Definition: Cell.h:43
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
std::list< symbol_info > m_lst
Definition: base-list.h:106
std::size_t length(void) const
Definition: base-list.h:53
octave_map map_value(const std::string &caller_function_name, int nesting_level) const
Definition: syminfo.cc:191
std::list< whos_parameter > parse_whos_line_format(const std::string &format) const
Definition: syminfo.cc:363
octave_value varval(const std::string &name) const
Definition: syminfo.cc:169
void print_descriptor(std::ostream &os, const std::list< whos_parameter > params) const
Definition: syminfo.cc:247
void display(std::ostream &os, const std::string &format) const
Definition: syminfo.cc:331
std::list< std::string > names(void) const
Definition: syminfo.cc:180
octave_value m_value
Definition: syminfo.h:85
std::string m_name
Definition: syminfo.h:84
bool m_is_persistent
Definition: syminfo.h:90
void display_line(std::ostream &os, const std::list< whos_parameter > &params) const
Definition: syminfo.cc:46
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:365
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:238
bool issparse(void) const
Definition: ov.h:798
octave_idx_type numel(void) const
Definition: ov.h:604
Matrix size(void)
Definition: ov.h:511
std::string class_name(void) const
Definition: ov.h:1451
std::size_t byte_size(void) const
Definition: ov.h:607
OCTINTERP_API std::string get_dims_str(void) const
bool iscomplex(void) const
Definition: ov.h:786
std::string type_name(void) const
Definition: ov.h:1449
void error(const char *fmt,...)
Definition: error.cc:980
QString name
static int left
Definition: randmtzig.cc:193
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define octave_stdout
Definition: pager.h:314
std::string text
Definition: syminfo.h:49
std::string line
Definition: syminfo.h:50
std::size_t format(std::ostream &os, const char *fmt,...)
Definition: utils.cc:1471
F77_RET_T len
Definition: xerbla.cc:61