GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ov-str-mat.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 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 <cctype>
29 
30 #include <iostream>
31 #include <vector>
32 
33 #include "data-conv.h"
34 #include "lo-ieee.h"
35 #include "mach-info.h"
36 #include "mx-base.h"
37 #include "oct-locbuf.h"
38 
39 #include "byte-swap.h"
40 #include "defun.h"
41 #include "gripes.h"
42 #include "ls-ascii-helper.h"
43 #include "ls-hdf5.h"
44 #include "ls-oct-ascii.h"
45 #include "ls-utils.h"
46 #include "oct-obj.h"
47 #include "oct-stream.h"
48 #include "ops.h"
49 #include "ov-scalar.h"
50 #include "ov-re-mat.h"
51 #include "ov-str-mat.h"
52 #include "pr-output.h"
53 #include "pt-mat.h"
54 #include "utils.h"
55 
58 
61  "char");
62 
63 static octave_base_value *
65 {
66  octave_base_value *retval = 0;
67 
69 
70  NDArray nda = v.array_value (true);
71 
72  if (! error_state)
73  {
74  if (nda.numel () == 1)
75  retval = new octave_scalar (nda(0));
76  else
77  retval = new octave_matrix (nda);
78  }
79 
80  return retval;
81 }
82 
85 {
88 }
89 
92  bool resize_ok, char type)
93 {
94  octave_value retval;
95 
96  octave_idx_type len = idx.length ();
97 
98  switch (len)
99  {
100  case 0:
101  retval = octave_value (matrix, type);
102  break;
103 
104  case 1:
105  {
106  idx_vector i = idx (0).index_vector ();
107 
108  if (! error_state)
109  retval = octave_value (charNDArray (matrix.index (i, resize_ok)),
110  type);
111  }
112  break;
113 
114  case 2:
115  {
116  idx_vector i = idx (0).index_vector ();
117  idx_vector j = idx (1).index_vector ();
118 
119  if (! error_state)
120  retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)),
121  type);
122  }
123  break;
124 
125  default:
126  {
127  Array<idx_vector> idx_vec (dim_vector (len, 1));
128 
129  for (octave_idx_type i = 0; i < len; i++)
130  idx_vec(i) = idx(i).index_vector ();
131 
132  if (! error_state)
133  retval =
134  octave_value (charNDArray (matrix.index (idx_vec, resize_ok)),
135  type);
136  }
137  break;
138  }
139 
140  return retval;
141 }
142 
144 octave_char_matrix_str::resize (const dim_vector& dv, bool fill) const
145 {
146  charNDArray retval (matrix);
147  if (fill)
148  retval.resize (dv, 0);
149  else
150  retval.resize (dv);
151  return octave_value (retval, is_sq_string () ? '\'' : '"');
152 }
153 
154 #define CHAR_MATRIX_CONV(T, INIT, TNAME, FCN) \
155  T retval INIT; \
156  \
157  if (! force_string_conv) \
158  gripe_invalid_conversion ("string", TNAME); \
159  else \
160  { \
161  warning_with_id ("Octave:str-to-num", \
162  "implicit conversion from %s to %s", \
163  "string", TNAME); \
164  \
165  retval = octave_char_matrix::FCN (); \
166  } \
167  \
168  return retval
169 
170 double
171 octave_char_matrix_str::double_value (bool force_string_conv) const
172 {
173  CHAR_MATRIX_CONV (double, = 0, "real scalar", double_value);
174 }
175 
176 Complex
177 octave_char_matrix_str::complex_value (bool force_string_conv) const
178 {
179  CHAR_MATRIX_CONV (Complex, = 0, "complex scalar", complex_value);
180 }
181 
182 Matrix
183 octave_char_matrix_str::matrix_value (bool force_string_conv) const
184 {
185  CHAR_MATRIX_CONV (Matrix, , "real matrix", matrix_value);
186 }
187 
189 octave_char_matrix_str::complex_matrix_value (bool force_string_conv) const
190 {
191  CHAR_MATRIX_CONV (ComplexMatrix, , "complex matrix", complex_matrix_value);
192 }
193 
194 NDArray
195 octave_char_matrix_str::array_value (bool force_string_conv) const
196 {
197  CHAR_MATRIX_CONV (NDArray, , "real N-d array", array_value);
198 }
199 
201 octave_char_matrix_str::complex_array_value (bool force_string_conv) const
202 {
203  CHAR_MATRIX_CONV (ComplexNDArray, , "complex N-d array",
205 }
206 
209 {
210  string_vector retval;
211 
212  if (matrix.ndims () == 2)
213  {
214  charMatrix chm = matrix.matrix_value ();
215 
216  octave_idx_type n = chm.rows ();
217 
218  retval.resize (n);
219 
220  for (octave_idx_type i = 0; i < n; i++)
221  retval[i] = chm.row_as_string (i);
222  }
223  else
224  error ("invalid conversion of charNDArray to string_vector");
225 
226  return retval;
227 }
228 
229 std::string
231 {
232  std::string retval;
233 
234  if (matrix.ndims () == 2)
235  {
236  charMatrix chm = matrix.matrix_value ();
237 
238  retval = chm.row_as_string (0); // FIXME?
239  }
240  else
241  error ("invalid conversion of charNDArray to string");
242 
243  return retval;
244 }
245 
248 {
249  Array<std::string> retval;
250 
251  if (matrix.ndims () == 2)
252  {
253  const charMatrix chm = matrix.matrix_value ();
254  octave_idx_type nr = chm.rows ();
255  retval.clear (nr, 1);
256  for (octave_idx_type i = 0; i < nr; i++)
257  retval.xelem (i) = chm.row_as_string (i);
258  }
259  else
260  error ("cellstr: cannot convert multidimensional arrays");
261 
262  return retval;
263 }
264 
265 void
267  bool pr_as_read_syntax) const
268 {
269  octave_print_internal (os, matrix, pr_as_read_syntax,
270  current_print_indent_level (), true);
271 }
272 
273 void
274 octave_char_matrix_str::short_disp (std::ostream& os) const
275 {
276  if (matrix.ndims () == 2 && numel () > 0)
277  {
278  std::string tmp = string_value ();
279 
280  // FIXME: should this be configurable?
281  size_t max_len = 100;
282 
283  os << (tmp.length () > max_len ? tmp.substr (0, 100) : tmp);
284  }
285 }
286 
287 bool
289 {
290  dim_vector d = dims ();
291  if (d.length () > 2)
292  {
293  charNDArray tmp = char_array_value ();
294  os << "# ndims: " << d.length () << "\n";
295  for (int i=0; i < d.length (); i++)
296  os << " " << d (i);
297  os << "\n";
298  os.write (tmp.fortran_vec (), d.numel ());
299  os << "\n";
300  }
301  else
302  {
303  // Keep this case, rather than use generic code above for
304  // backward compatiability. Makes load_ascii much more complex!!
305  charMatrix chm = char_matrix_value ();
306  octave_idx_type elements = chm.rows ();
307  os << "# elements: " << elements << "\n";
308  for (octave_idx_type i = 0; i < elements; i++)
309  {
310  unsigned len = chm.cols ();
311  os << "# length: " << len << "\n";
312  std::string tstr = chm.row_as_string (i);
313  const char *tmp = tstr.data ();
314  if (tstr.length () > len)
315  panic_impossible ();
316  os.write (tmp, len);
317  os << "\n";
318  }
319  }
320 
321  return true;
322 }
323 
324 bool
326 {
327  bool success = true;
328 
330 
331  keywords[0] = "ndims";
332  keywords[1] = "elements";
333  keywords[2] = "length";
334 
335  std::string kw;
336  int val = 0;
337 
338  if (extract_keyword (is, keywords, kw, val, true))
339  {
340  if (kw == "ndims")
341  {
342  int mdims = val;
343 
344  if (mdims >= 0)
345  {
346  dim_vector dv;
347  dv.resize (mdims);
348 
349  for (int i = 0; i < mdims; i++)
350  is >> dv(i);
351 
352  if (is)
353  {
354  charNDArray tmp(dv);
355 
356  if (tmp.is_empty ())
357  matrix = tmp;
358  else
359  {
360  char *ftmp = tmp.fortran_vec ();
361 
363 
364  if (! is.read (ftmp, dv.numel ()) || !is)
365  {
366  error ("load: failed to load string constant");
367  success = false;
368  }
369  else
370  matrix = tmp;
371  }
372  }
373  else
374  {
375  error ("load: failed to read dimensions");
376  success = false;
377  }
378  }
379  else
380  {
381  error ("load: failed to extract matrix size");
382  success = false;
383  }
384  }
385  else if (kw == "elements")
386  {
387  int elements = val;
388 
389  if (elements >= 0)
390  {
391  // FIXME: need to be able to get max length before doing anything.
392 
393  charMatrix chm (elements, 0);
394  int max_len = 0;
395  for (int i = 0; i < elements; i++)
396  {
397  int len;
398  if (extract_keyword (is, "length", len) && len >= 0)
399  {
400  // Use this instead of a C-style character
401  // buffer so that we can properly handle
402  // embedded NUL characters.
403  charMatrix tmp (1, len);
404  char *ptmp = tmp.fortran_vec ();
405 
406  if (len > 0 && ! is.read (ptmp, len))
407  {
408  error ("load: failed to load string constant");
409  success = false;
410  break;
411  }
412  else
413  {
414  if (len > max_len)
415  {
416  max_len = len;
417  chm.resize (elements, max_len, 0);
418  }
419 
420  chm.insert (tmp, i, 0);
421  }
422  }
423  else
424  {
425  error ("load: failed to extract string length for element %d",
426  i+1);
427  success = false;
428  }
429  }
430 
431  if (! error_state)
432  matrix = chm;
433  }
434  else
435  {
436  error ("load: failed to extract number of string elements");
437  success = false;
438  }
439  }
440  else if (kw == "length")
441  {
442  int len = val;
443 
444  if (len >= 0)
445  {
446  // This is cruft for backward compatiability,
447  // but relatively harmless.
448 
449  // Use this instead of a C-style character buffer so
450  // that we can properly handle embedded NUL characters.
451  charMatrix tmp (1, len);
452  char *ptmp = tmp.fortran_vec ();
453 
454  if (len > 0 && ! is.read (ptmp, len))
455  {
456  error ("load: failed to load string constant");
457  }
458  else
459  {
460  if (is)
461  matrix = tmp;
462  else
463  error ("load: failed to load string constant");
464  }
465  }
466  }
467  else
468  panic_impossible ();
469  }
470  else
471  {
472  error ("load: failed to extract number of rows and columns");
473  success = false;
474  }
475 
476  return success;
477 }
478 
479 bool
481  bool& /* save_as_floats */)
482 {
483  dim_vector d = dims ();
484  if (d.length () < 1)
485  return false;
486 
487  // Use negative value for ndims to differentiate with old format!!
488  int32_t tmp = - d.length ();
489  os.write (reinterpret_cast<char *> (&tmp), 4);
490  for (int i=0; i < d.length (); i++)
491  {
492  tmp = d(i);
493  os.write (reinterpret_cast<char *> (&tmp), 4);
494  }
495 
497  os.write (m.fortran_vec (), d.numel ());
498  return true;
499 }
500 
501 bool
502 octave_char_matrix_str::load_binary (std::istream& is, bool swap,
503  oct_mach_info::float_format /* fmt */)
504 {
505  int32_t elements;
506  if (! is.read (reinterpret_cast<char *> (&elements), 4))
507  return false;
508  if (swap)
509  swap_bytes<4> (&elements);
510 
511  if (elements < 0)
512  {
513  int32_t mdims = - elements;
514  int32_t di;
515  dim_vector dv;
516  dv.resize (mdims);
517 
518  for (int i = 0; i < mdims; i++)
519  {
520  if (! is.read (reinterpret_cast<char *> (&di), 4))
521  return false;
522  if (swap)
523  swap_bytes<4> (&di);
524  dv(i) = di;
525  }
526 
527  // Convert an array with a single dimension to be a row vector.
528  // Octave should never write files like this, other software
529  // might.
530 
531  if (mdims == 1)
532  {
533  mdims = 2;
534  dv.resize (mdims);
535  dv(1) = dv(0);
536  dv(0) = 1;
537  }
538 
539  charNDArray m(dv);
540  char *tmp = m.fortran_vec ();
541  is.read (tmp, dv.numel ());
542 
543  if (error_state || ! is)
544  return false;
545  matrix = m;
546  }
547  else
548  {
549  charMatrix chm (elements, 0);
550  int max_len = 0;
551  for (int i = 0; i < elements; i++)
552  {
553  int32_t len;
554  if (! is.read (reinterpret_cast<char *> (&len), 4))
555  return false;
556  if (swap)
557  swap_bytes<4> (&len);
558  charMatrix btmp (1, len);
559  char *pbtmp = btmp.fortran_vec ();
560  if (! is.read (pbtmp, len))
561  return false;
562  if (len > max_len)
563  {
564  max_len = len;
565  chm.resize (elements, max_len, 0);
566  }
567  chm.insert (btmp, i, 0);
568  }
569  matrix = chm;
570  }
571  return true;
572 }
573 
574 #if defined (HAVE_HDF5)
575 
576 bool
577 octave_char_matrix_str::save_hdf5 (hid_t loc_id, const char *name,
578  bool /* save_as_floats */)
579 {
580  dim_vector dv = dims ();
581  int empty = save_hdf5_empty (loc_id, name, dv);
582  if (empty)
583  return (empty > 0);
584 
585  int rank = dv.length ();
586  hid_t space_hid = -1, data_hid = -1;
587  bool retval = true;
589 
590  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
591 
592  // Octave uses column-major, while HDF5 uses row-major ordering
593  for (int i = 0; i < rank; i++)
594  hdims[i] = dv (rank-i-1);
595 
596  space_hid = H5Screate_simple (rank, hdims, 0);
597  if (space_hid < 0)
598  return false;
599 #if HAVE_HDF5_18
600  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_CHAR, space_hid,
601  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
602 #else
603  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_CHAR, space_hid,
604  H5P_DEFAULT);
605 #endif
606  if (data_hid < 0)
607  {
608  H5Sclose (space_hid);
609  return false;
610  }
611 
612  OCTAVE_LOCAL_BUFFER (char, s, dv.numel ());
613 
614  for (int i = 0; i < dv.numel (); ++i)
615  s[i] = m(i);
616 
617  retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
618  H5P_DEFAULT, s) >= 0;
619 
620  H5Dclose (data_hid);
621  H5Sclose (space_hid);
622 
623  return retval;
624 }
625 
626 bool
627 octave_char_matrix_str::load_hdf5 (hid_t loc_id, const char *name)
628 {
629  bool retval = false;
630 
631  dim_vector dv;
632  int empty = load_hdf5_empty (loc_id, name, dv);
633  if (empty > 0)
634  matrix.resize (dv);
635  if (empty)
636  return (empty > 0);
637 
638 #if HAVE_HDF5_18
639  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
640 #else
641  hid_t data_hid = H5Dopen (loc_id, name);
642 #endif
643  hid_t space_hid = H5Dget_space (data_hid);
644  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
645  hid_t type_hid = H5Dget_type (data_hid);
646  hid_t type_class_hid = H5Tget_class (type_hid);
647 
648  if (type_class_hid == H5T_INTEGER)
649  {
650  if (rank < 1)
651  {
652  H5Tclose (type_hid);
653  H5Sclose (space_hid);
654  H5Dclose (data_hid);
655  return false;
656  }
657 
658  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
659  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
660 
661  H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
662 
663  // Octave uses column-major, while HDF5 uses row-major ordering
664  if (rank == 1)
665  {
666  dv.resize (2);
667  dv(0) = 1;
668  dv(1) = hdims[0];
669  }
670  else
671  {
672  dv.resize (rank);
673  for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
674  dv(j) = hdims[i];
675  }
676 
677  charNDArray m (dv);
678  char *str = m.fortran_vec ();
679  if (H5Dread (data_hid, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
680  H5P_DEFAULT, str) >= 0)
681  {
682  retval = true;
683  matrix = m;
684  }
685 
686  H5Tclose (type_hid);
687  H5Sclose (space_hid);
688  H5Dclose (data_hid);
689  return true;
690  }
691  else
692  {
693  // This is cruft for backward compatiability and easy data
694  // importation
695  if (rank == 0) //FIXME: Does rank==0 even exist for strings in HDF5?
696  {
697  // a single string:
698  int slen = H5Tget_size (type_hid);
699  if (slen < 0)
700  {
701  H5Tclose (type_hid);
702  H5Sclose (space_hid);
703  H5Dclose (data_hid);
704  return false;
705  }
706  else
707  {
708  OCTAVE_LOCAL_BUFFER (char, s, slen);
709  // create datatype for (null-terminated) string
710  // to read into:
711  hid_t st_id = H5Tcopy (H5T_C_S1);
712  H5Tset_size (st_id, slen+1);
713  if (H5Dread (data_hid, st_id, H5S_ALL,
714  H5S_ALL, H5P_DEFAULT, s) < 0)
715  {
716  H5Tclose (st_id);
717  H5Tclose (type_hid);
718  H5Sclose (space_hid);
719  H5Dclose (data_hid);
720  return false;
721  }
722 
723  matrix = charMatrix (s);
724 
725  H5Tclose (st_id);
726  H5Tclose (type_hid);
727  H5Sclose (space_hid);
728  H5Dclose (data_hid);
729  return true;
730  }
731  }
732  else if (rank == 1)
733  {
734  // string vector
735  hsize_t elements, maxdim;
736  H5Sget_simple_extent_dims (space_hid, &elements, &maxdim);
737  int slen = H5Tget_size (type_hid);
738  if (slen < 0)
739  {
740  H5Tclose (type_hid);
741  H5Sclose (space_hid);
742  H5Dclose (data_hid);
743  return false;
744  }
745  else
746  {
747  // hdf5 string arrays store strings of all the
748  // same physical length (I think), which is
749  // slightly wasteful, but oh well.
750 
751  OCTAVE_LOCAL_BUFFER (char, s, elements * (slen+1));
752 
753  // create datatype for (null-terminated) string
754  // to read into:
755  hid_t st_id = H5Tcopy (H5T_C_S1);
756  H5Tset_size (st_id, slen+1);
757 
758  if (H5Dread (data_hid, st_id, H5S_ALL,
759  H5S_ALL, H5P_DEFAULT, s) < 0)
760  {
761  H5Tclose (st_id);
762  H5Tclose (type_hid);
763  H5Sclose (space_hid);
764  H5Dclose (data_hid);
765  return false;
766  }
767 
768  charMatrix chm (elements, slen, ' ');
769  for (hsize_t i = 0; i < elements; ++i)
770  {
771  chm.insert (s + i*(slen+1), i, 0);
772  }
773 
774  matrix = chm;
775 
776  H5Tclose (st_id);
777  H5Tclose (type_hid);
778  H5Sclose (space_hid);
779  H5Dclose (data_hid);
780  return true;
781  }
782  }
783  else
784  {
785  H5Tclose (type_hid);
786  H5Sclose (space_hid);
787  H5Dclose (data_hid);
788  return false;
789  }
790  }
791 
792  return retval;
793 }
794 
795 #endif