GNU Octave  9.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-2024 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 
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 
170 symbol_info_list::varval (const std::string& name) const
171 {
172  for (const auto& syminfo : m_lst)
173  {
174  if (name == syminfo.name ())
175  return syminfo.value ();
176  }
177 
178  return octave_value ();
179 }
180 
181 std::list<std::string>
183 {
184  std::list<std::string> retval;
185 
186  for (const auto& syminfo : m_lst)
187  retval.push_back (syminfo.name ());
188 
189  return retval;
190 }
191 
193 symbol_info_list::map_value (const std::string& caller_function_name,
194  int nesting_level) const
195 {
196  std::size_t len = m_lst.size ();
197 
198  Cell name_info (len, 1);
199  Cell size_info (len, 1);
200  Cell bytes_info (len, 1);
201  Cell class_info (len, 1);
202  Cell global_info (len, 1);
203  Cell sparse_info (len, 1);
204  Cell complex_info (len, 1);
205  Cell nesting_info (len, 1);
206  Cell persistent_info (len, 1);
207 
208  std::size_t j = 0;
209 
210  for (const auto& syminfo : m_lst)
211  {
213 
214  ni.assign ("function", caller_function_name);
215  ni.assign ("level", nesting_level);
216 
217  name_info(j) = syminfo.name ();
218  global_info(j) = syminfo.is_global ();
219  persistent_info(j) = syminfo.is_persistent ();
220 
221  octave_value val = syminfo.value ();
222 
223  size_info(j) = val.size ();
224  bytes_info(j) = val.byte_size ();
225  class_info(j) = val.class_name ();
226  sparse_info(j) = val.issparse ();
227  complex_info(j) = val.iscomplex ();
228  nesting_info(j) = ni;
229 
230  j++;
231  }
232 
233  octave_map info;
234 
235  info.assign ("name", name_info);
236  info.assign ("size", size_info);
237  info.assign ("bytes", bytes_info);
238  info.assign ("class", class_info);
239  info.assign ("global", global_info);
240  info.assign ("sparse", sparse_info);
241  info.assign ("complex", complex_info);
242  info.assign ("nesting", nesting_info);
243  info.assign ("persistent", persistent_info);
244 
245  return info;
246 }
247 
248 void
250  const std::list<whos_parameter> params) const
251 {
252  std::ostringstream param_buf;
253 
254  preserve_stream_state stream_state (os);
255 
256  for (const auto& param : params)
257  {
258  if (param.command != '\0')
259  {
260  // Do the actual printing
261  switch (param.modifier)
262  {
263  case 'l':
264  os << std::setiosflags (std::ios::left)
265  << std::setw (param.parameter_length);
266  param_buf << std::setiosflags (std::ios::left)
267  << std::setw (param.parameter_length);
268  break;
269 
270  case 'r':
271  os << std::setiosflags (std::ios::right)
272  << std::setw (param.parameter_length);
273  param_buf << std::setiosflags (std::ios::right)
274  << std::setw (param.parameter_length);
275  break;
276 
277  case 'c':
278  if (param.command != 's')
279  {
280  os << std::setiosflags (std::ios::left)
281  << std::setw (param.parameter_length);
282  param_buf << std::setiosflags (std::ios::left)
283  << std::setw (param.parameter_length);
284  }
285  break;
286 
287  default:
288  os << std::setiosflags (std::ios::left)
289  << std::setw (param.parameter_length);
290  param_buf << std::setiosflags (std::ios::left)
291  << std::setw (param.parameter_length);
292  }
293 
294  if (param.command == 's' && param.modifier == 'c')
295  {
296  int a = param.first_parameter_length - param.balance;
297  a = (a < 0 ? 0 : a);
298  int b = param.parameter_length - a - param.text.length ();
299  b = (b < 0 ? 0 : b);
300  os << std::setiosflags (std::ios::left) << std::setw (a)
301  << "" << std::resetiosflags (std::ios::left) << param.text
302  << std::setiosflags (std::ios::left)
303  << std::setw (b) << ""
304  << std::resetiosflags (std::ios::left);
305  param_buf << std::setiosflags (std::ios::left)
306  << std::setw (a)
307  << "" << std::resetiosflags (std::ios::left)
308  << param.line
309  << std::setiosflags (std::ios::left)
310  << std::setw (b) << ""
311  << std::resetiosflags (std::ios::left);
312  }
313  else
314  {
315  os << param.text;
316  param_buf << param.line;
317  }
318  os << std::resetiosflags (std::ios::left)
319  << std::resetiosflags (std::ios::right);
320  param_buf << std::resetiosflags (std::ios::left)
321  << std::resetiosflags (std::ios::right);
322  }
323  else
324  {
325  os << param.text;
326  param_buf << param.line;
327  }
328  }
329 
330  os << param_buf.str ();
331 }
332 
333 void
334 symbol_info_list::display (std::ostream& os,
335  const std::string& format) const
336 {
337  if (! m_lst.empty ())
338  {
339  std::size_t bytes = 0;
340  std::size_t elements = 0;
341 
342  std::list<whos_parameter> params = parse_whos_line_format (format);
343 
344  print_descriptor (os, params);
345 
346  octave_stdout << "\n";
347 
348  for (const auto& syminfo : m_lst)
349  {
350  syminfo.display_line (os, params);
351 
352  octave_value val = syminfo.value ();
353 
354  elements += val.numel ();
355  bytes += val.byte_size ();
356  }
357 
358  os << "\nTotal is " << elements
359  << (elements == 1 ? " element" : " elements")
360  << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
361  << "\n";
362  }
363 }
364 
365 std::list<whos_parameter>
367 {
368  int idx;
369  std::size_t format_len = format.length ();
370  char garbage;
371  std::list<whos_parameter> params;
372 
373  std::size_t bytes1;
374  int elements1;
375 
376  std::string param_string = "abcenst";
377  Array<int> param_length (dim_vector (param_string.length (), 1));
378  Array<std::string> param_names (dim_vector (param_string.length (), 1));
379  std::size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
380 
381  pos_a = param_string.find ('a'); // Attributes
382  pos_b = param_string.find ('b'); // Bytes
383  pos_c = param_string.find ('c'); // Class
384  pos_e = param_string.find ('e'); // Elements
385  pos_n = param_string.find ('n'); // Name
386  pos_s = param_string.find ('s'); // Size
387  pos_t = param_string.find ('t'); // Type
388 
389  param_names(pos_a) = "Attr";
390  param_names(pos_b) = "Bytes";
391  param_names(pos_c) = "Class";
392  param_names(pos_e) = "Elements";
393  param_names(pos_n) = "Name";
394  param_names(pos_s) = "Size";
395  param_names(pos_t) = "Type";
396 
397  for (std::size_t i = 0; i < param_string.length (); i++)
398  param_length(i) = param_names(i).length ();
399 
400  // The attribute column needs size 6.
401  param_length(pos_a) = 6;
402 
403  // Calculating necessary spacing for name column,
404  // bytes column, elements column and class column
405 
406  for (const auto& syminfo : m_lst)
407  {
408  std::stringstream ss1, ss2;
409  std::string str;
410 
411  str = syminfo.name ();
412  param_length(pos_n) = ((str.length ()
413  > static_cast<std::size_t> (param_length(pos_n)))
414  ? str.length () : param_length(pos_n));
415 
416  octave_value val = syminfo.value ();
417 
418  str = val.type_name ();
419  param_length(pos_t) = ((str.length ()
420  > static_cast<std::size_t> (param_length(pos_t)))
421  ? str.length () : param_length(pos_t));
422 
423  elements1 = val.numel ();
424  ss1 << elements1;
425  str = ss1.str ();
426  param_length(pos_e) = ((str.length ()
427  > static_cast<std::size_t> (param_length(pos_e)))
428  ? str.length () : param_length(pos_e));
429 
430  bytes1 = val.byte_size ();
431  ss2 << bytes1;
432  str = ss2.str ();
433  param_length(pos_b) = ((str.length ()
434  > static_cast<std::size_t> (param_length(pos_b)))
435  ? str.length () : param_length (pos_b));
436  }
437 
438  idx = 0;
439  while (static_cast<std::size_t> (idx) < format_len)
440  {
441  whos_parameter param;
442  param.command = '\0';
443 
444  if (format[idx] == '%')
445  {
446  param.modifier = 'r';
447  param.parameter_length = 0;
448 
449  int a = 0;
450  int b = -1;
451  int balance = 1;
452  unsigned int items;
453  std::size_t pos;
454  std::string cmd;
455 
456  // Parse one command from format
457  cmd = format.substr (idx, format.length ());
458  pos = cmd.find (';');
459  if (pos == std::string::npos)
460  error ("parameter without ; in format");
461 
462  cmd = cmd.substr (0, pos+1);
463 
464  idx += cmd.length ();
465 
466  // FIXME: use iostream functions instead of sscanf!
467 
468  if (cmd.find_first_of ("crl") != 1)
469  items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
470  &garbage, &param.command, &a, &b, &balance);
471  else
472  items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
473  &garbage, &param.modifier, &param.command,
474  &a, &b, &balance) - 1;
475 
476  if (items < 2)
477  error ("whos_line_format: found parameter structure without command");
478 
479  // Exception case of bare class command 'c' without modifier 'l/r'
480  if (param.modifier == 'c'
481  && param_string.find (param.command) == std::string::npos)
482  {
483  param.modifier = 'r';
484  param.command = 'c';
485  }
486 
487  // Insert data into parameter
488  param.first_parameter_length = 0;
489  pos = param_string.find (param.command);
490  if (pos == std::string::npos)
491  error ("whos_line_format: '%c' is not a command", param.command);
492 
493  param.parameter_length = param_length(pos);
494  param.text = param_names(pos);
495  param.line.assign (param_names(pos).length (), '=');
496 
497  param.parameter_length = (a > param.parameter_length
498  ? a : param.parameter_length);
499  if (param.command == 's' && param.modifier == 'c' && b > 0)
500  param.first_parameter_length = b;
501 
502  if (param.command == 's')
503  {
504  // Have to calculate space needed for printing
505  // matrix dimensions Space needed for Size column is
506  // hard to determine in prior, because it depends on
507  // dimensions to be shown. That is why it is
508  // recalculated for each Size-command int first,
509  // rest = 0, total;
510  int rest = 0;
511  int first = param.first_parameter_length;
512  int total = param.parameter_length;
513 
514  for (const auto& syminfo : m_lst)
515  {
516  octave_value val = syminfo.value ();
517  std::string dims_str = val.get_dims_str ();
518  int first1 = dims_str.find ('x');
519  int total1 = dims_str.length ();
520  int rest1 = total1 - first1;
521  rest = (rest1 > rest ? rest1 : rest);
522  first = (first1 > first ? first1 : first);
523  total = (total1 > total ? total1 : total);
524  }
525 
526  if (param.modifier == 'c')
527  {
528  if (first < balance)
529  first += balance - first;
530  if (rest + balance < param.parameter_length)
531  rest += param.parameter_length - rest - balance;
532 
533  param.parameter_length = first + rest;
534  param.first_parameter_length = first;
535  param.balance = balance;
536  }
537  else
538  {
539  param.parameter_length = total;
540  param.first_parameter_length = 0;
541  }
542  }
543  else if (param.modifier == 'c')
544  error ("whos_line_format: modifier 'c' not available for command '%c'",
545  param.command);
546 
547  // What happens if format contains negative numbers
548  // at param_length positions?
549  param.balance = (b < 0 ? 0 : param.balance);
550  param.first_parameter_length = (b < 0
551  ? 0
552  : param.first_parameter_length);
553  param.parameter_length = (a < 0
554  ? 0
555  : (param.parameter_length
556  < param_length(pos_s)
557  ? param_length(pos_s)
558  : param.parameter_length));
559 
560  params.push_back (param);
561  }
562  else
563  {
564  // Text string, to be printed as it is ...
565  std::string text;
566  std::size_t pos;
567  text = format.substr (idx, format.length ());
568  pos = text.find ('%');
569  if (pos != std::string::npos)
570  text = text.substr (0, pos);
571 
572  // Push parameter into list ...
573  idx += text.length ();
574  param.text=text;
575  param.line.assign (text.length (), ' ');
576  params.push_back (param);
577  }
578  }
579 
580  return params;
581 }
582 
583 OCTAVE_END_NAMESPACE(octave)
Definition: Cell.h:43
std::size_t length() const
Definition: base-list.h:53
std::list< symbol_info > m_lst
Definition: base-list.h:106
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:344
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:230
std::string class_name() const
Definition: ov.h:1347
std::string get_dims_str() const
Matrix size()
Definition: ov.h:462
bool issparse() const
Definition: ov.h:753
octave_idx_type numel() const
Definition: ov.h:559
bool iscomplex() const
Definition: ov.h:741
std::string type_name() const
Definition: ov.h:1345
std::size_t byte_size() const
Definition: ov.h:562
void print_descriptor(std::ostream &os, const std::list< whos_parameter > params) const
Definition: syminfo.cc:249
std::list< std::string > names() const
Definition: syminfo.cc:182
void display(std::ostream &os, const std::string &format) const
Definition: syminfo.cc:334
std::list< whos_parameter > parse_whos_line_format(const std::string &format) const
Definition: syminfo.cc:366
octave_value varval(const std::string &name) const
Definition: syminfo.cc:170
octave_map map_value(const std::string &caller_function_name, int nesting_level) const
Definition: syminfo.cc:193
void display_line(std::ostream &os, const std::list< whos_parameter > &params) const
Definition: syminfo.cc:46
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void() error(const char *fmt,...)
Definition: error.cc:988
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:309
char modifier
Definition: syminfo.h:45
int parameter_length
Definition: syminfo.h:46
std::string line
Definition: syminfo.h:50
std::string text
Definition: syminfo.h:49
int first_parameter_length
Definition: syminfo.h:47
char command
Definition: syminfo.h:44
std::size_t format(std::ostream &os, const char *fmt,...)
F77_RET_T len
Definition: xerbla.cc:61