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