3 Copyright (C) 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007 John W. Eaton
6 This file is part of Octave.
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.
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
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/>.
31 #include "data-conv.h"
33 #include "mach-info.h"
37 #include "byte-swap.h"
39 #include "ls-oct-ascii.h"
43 #include "oct-stream.h"
45 #include "ov-scalar.h"
46 #include "ov-re-mat.h"
47 #include "ov-str-mat.h"
48 #include "pr-output.h"
51 #include "ls-ascii-helper.h"
53 DEFINE_OCTAVE_ALLOCATOR (octave_char_matrix_str);
54 DEFINE_OCTAVE_ALLOCATOR (octave_char_matrix_sq_str);
56 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_char_matrix_str, "string", "char");
57 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_char_matrix_sq_str, "sq_string", "char");
59 static octave_base_value *
60 default_numeric_conversion_function (const octave_base_value& a)
62 octave_base_value *retval = 0;
64 CAST_CONV_ARG (const octave_char_matrix_str&);
66 NDArray nda = v.array_value (true);
70 if (nda.numel () == 1)
71 retval = new octave_scalar (nda(0));
73 retval = new octave_matrix (nda);
79 octave_base_value::type_conv_fcn
80 octave_char_matrix_str::numeric_conversion_function (void) const
82 return default_numeric_conversion_function;
86 octave_char_matrix_str::do_index_op_internal (const octave_value_list& idx,
87 bool resize_ok, char type)
91 octave_idx_type len = idx.length ();
96 retval = octave_value (matrix, true, type);
101 idx_vector i = idx (0).index_vector ();
104 retval = octave_value (charNDArray (matrix.index (i, resize_ok)),
111 idx_vector i = idx (0).index_vector ();
112 idx_vector j = idx (1).index_vector ();
115 retval = octave_value (charNDArray (matrix.index (i, j, resize_ok)),
122 Array<idx_vector> idx_vec (len);
124 for (octave_idx_type i = 0; i < len; i++)
125 idx_vec(i) = idx(i).index_vector ();
128 retval = octave_value (charNDArray (matrix.index (idx_vec, resize_ok)),
138 octave_char_matrix_str::assign (const octave_value_list& idx,
139 const charMatrix& rhs)
141 octave_idx_type len = idx.length ();
144 charMatrix tmp = rhs;
145 if (tmp.rows () == 1 && tmp.columns () == 0)
148 for (octave_idx_type i = 0; i < len; i++)
149 matrix.set_index (idx(i).index_vector ());
151 ::assign (matrix, tmp, Vstring_fill_char);
155 octave_char_matrix_str::resize (const dim_vector& dv, bool fill) const
157 charNDArray retval (matrix);
159 retval.resize (dv, charNDArray::resize_fill_value());
162 return octave_value (retval, true);
166 octave_char_matrix_str::valid_as_scalar_index (void) const
169 error ("octave_char_matrix_str::valid_as_scalar_index(): not implemented");
173 #define CHAR_MATRIX_CONV(T, INIT, TNAME, FCN) \
176 if (! force_string_conv) \
177 gripe_invalid_conversion ("string", TNAME); \
180 warning_with_id ("Octave:str-to-num", \
181 "implicit conversion from %s to %s", \
184 retval = octave_char_matrix::FCN (); \
190 octave_char_matrix_str::double_value (bool force_string_conv) const
192 CHAR_MATRIX_CONV (double, = 0, "real scalar", double_value);
196 octave_char_matrix_str::complex_value (bool force_string_conv) const
198 CHAR_MATRIX_CONV (Complex, = 0, "complex scalar", complex_value);
202 octave_char_matrix_str::matrix_value (bool force_string_conv) const
204 CHAR_MATRIX_CONV (Matrix, , "real matrix", matrix_value);
208 octave_char_matrix_str::complex_matrix_value (bool force_string_conv) const
210 CHAR_MATRIX_CONV (ComplexMatrix, , "complex matrix", complex_matrix_value);
214 octave_char_matrix_str::array_value (bool force_string_conv) const
216 CHAR_MATRIX_CONV (NDArray, , "real N-d array", array_value);
220 octave_char_matrix_str::complex_array_value (bool force_string_conv) const
222 CHAR_MATRIX_CONV (ComplexNDArray, , "complex N-d array",
223 complex_array_value);
227 octave_char_matrix_str::all_strings (bool) const
229 string_vector retval;
231 if (matrix.ndims () == 2)
233 charMatrix chm = matrix.matrix_value ();
235 octave_idx_type n = chm.rows ();
239 for (octave_idx_type i = 0; i < n; i++)
240 retval[i] = chm.row_as_string (i);
243 error ("invalid conversion of charNDArray to string_vector");
249 octave_char_matrix_str::string_value (bool) const
253 if (matrix.ndims () == 2)
255 charMatrix chm = matrix.matrix_value ();
257 retval = chm.row_as_string (0); // FIXME???
260 error ("invalid conversion of charNDArray to string");
266 octave_char_matrix_str::print_raw (std::ostream& os, bool pr_as_read_syntax) const
268 octave_print_internal (os, matrix, pr_as_read_syntax,
269 current_print_indent_level (), true);
273 octave_char_matrix_str::save_ascii (std::ostream& os)
275 dim_vector d = dims ();
278 charNDArray tmp = char_array_value ();
279 os << "# ndims: " << d.length () << "\n";
280 for (int i=0; i < d.length (); i++)
283 os.write (tmp.fortran_vec (), d.numel ());
288 // Keep this case, rather than use generic code above for
289 // backward compatiability. Makes load_ascii much more complex!!
290 charMatrix chm = char_matrix_value ();
291 octave_idx_type elements = chm.rows ();
292 os << "# elements: " << elements << "\n";
293 for (octave_idx_type i = 0; i < elements; i++)
295 unsigned len = chm.cols ();
296 os << "# length: " << len << "\n";
297 std::string tstr = chm.row_as_string (i, false, true);
298 const char *tmp = tstr.data ();
299 if (tstr.length () > len)
310 octave_char_matrix_str::load_ascii (std::istream& is)
314 string_vector keywords(3);
316 keywords[0] = "ndims";
317 keywords[1] = "elements";
318 keywords[2] = "length";
323 if (extract_keyword (is, keywords, kw, val, true))
334 for (int i = 0; i < mdims; i++)
345 char *ftmp = tmp.fortran_vec ();
347 // Skip the return line
348 skip_preceeding_newline (is);
350 if (! is.read (ftmp, dv.numel ()) || !is)
352 error ("load: failed to load string constant");
361 error ("load: failed to read dimensions");
367 error ("load: failed to extract matrix size");
371 else if (kw == "elements")
377 // FIXME -- need to be able to get max length
378 // before doing anything.
380 charMatrix chm (elements, 0);
382 for (int i = 0; i < elements; i++)
385 if (extract_keyword (is, "length", len) && len >= 0)
387 // Use this instead of a C-style character
388 // buffer so that we can properly handle
389 // embedded NUL characters.
390 charMatrix tmp (1, len);
391 char *ptmp = tmp.fortran_vec ();
393 if (len > 0 && ! is.read (ptmp, len))
395 error ("load: failed to load string constant");
404 chm.resize (elements, max_len, 0);
407 chm.insert (tmp, i, 0);
412 error ("load: failed to extract string length for element %d",
423 error ("load: failed to extract number of string elements");
427 else if (kw == "length")
433 // This is cruft for backward compatiability,
434 // but relatively harmless.
436 // Use this instead of a C-style character buffer so
437 // that we can properly handle embedded NUL characters.
438 charMatrix tmp (1, len);
439 char *ptmp = tmp.fortran_vec ();
441 if (len > 0 && ! is.read (ptmp, len))
443 error ("load: failed to load string constant");
450 error ("load: failed to load string constant");
459 error ("load: failed to extract number of rows and columns");
467 octave_char_matrix_str::save_binary (std::ostream& os,
468 bool& /* save_as_floats */)
470 dim_vector d = dims ();
474 // Use negative value for ndims to differentiate with old format!!
475 int32_t tmp = - d.length();
476 os.write (reinterpret_cast<char *> (&tmp), 4);
477 for (int i=0; i < d.length (); i++)
480 os.write (reinterpret_cast<char *> (&tmp), 4);
483 charNDArray m = char_array_value ();
484 os.write (m.fortran_vec (), d.numel ());
489 octave_char_matrix_str::load_binary (std::istream& is, bool swap,
490 oct_mach_info::float_format /* fmt */)
493 if (! is.read (reinterpret_cast<char *> (&elements), 4))
496 swap_bytes<4> (&elements);
500 int32_t mdims = - elements;
505 for (int i = 0; i < mdims; i++)
507 if (! is.read (reinterpret_cast<char *> (&di), 4))
514 // Convert an array with a single dimension to be a row vector.
515 // Octave should never write files like this, other software
527 char *tmp = m.fortran_vec ();
528 is.read (tmp, dv.numel ());
530 if (error_state || ! is)
536 charMatrix chm (elements, 0);
538 for (int i = 0; i < elements; i++)
541 if (! is.read (reinterpret_cast<char *> (&len), 4))
544 swap_bytes<4> (&len);
545 charMatrix btmp (1, len);
546 char *pbtmp = btmp.fortran_vec ();
547 if (! is.read (pbtmp, len))
552 chm.resize (elements, max_len, 0);
554 chm.insert (btmp, i, 0);
561 #if defined (HAVE_HDF5)
564 octave_char_matrix_str::save_hdf5 (hid_t loc_id, const char *name,
565 bool /* save_as_floats */)
567 dim_vector dv = dims ();
568 int empty = save_hdf5_empty (loc_id, name, dv);
572 int rank = dv.length ();
573 hid_t space_hid = -1, data_hid = -1;
575 charNDArray m = char_array_value ();
577 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
579 // Octave uses column-major, while HDF5 uses row-major ordering
580 for (int i = 0; i < rank; i++)
581 hdims[i] = dv (rank-i-1);
583 space_hid = H5Screate_simple (rank, hdims, 0);
587 data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_CHAR, space_hid,
591 H5Sclose (space_hid);
595 OCTAVE_LOCAL_BUFFER (char, s, dv.numel ());
597 for (int i = 0; i < dv.numel (); ++i)
600 retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
601 H5P_DEFAULT, s) >= 0;
604 H5Sclose (space_hid);
610 octave_char_matrix_str::load_hdf5 (hid_t loc_id, const char *name,
611 bool /* have_h5giterate_bug */)
616 int empty = load_hdf5_empty (loc_id, name, dv);
622 hid_t data_hid = H5Dopen (loc_id, name);
623 hid_t space_hid = H5Dget_space (data_hid);
624 hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
625 hid_t type_hid = H5Dget_type (data_hid);
626 hid_t type_class_hid = H5Tget_class (type_hid);
628 if (type_class_hid == H5T_INTEGER)
633 H5Sclose (space_hid);
638 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
639 OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
641 H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
643 // Octave uses column-major, while HDF5 uses row-major ordering
653 for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
658 char *str = m.fortran_vec ();
659 if (H5Dread (data_hid, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
660 H5P_DEFAULT, str) >= 0)
667 H5Sclose (space_hid);
673 // This is cruft for backward compatiability and easy data
678 int slen = H5Tget_size (type_hid);
682 H5Sclose (space_hid);
688 OCTAVE_LOCAL_BUFFER (char, s, slen);
689 // create datatype for (null-terminated) string
691 hid_t st_id = H5Tcopy (H5T_C_S1);
692 H5Tset_size (st_id, slen);
693 if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, s) < 0)
697 H5Sclose (space_hid);
702 matrix = charMatrix (s);
706 H5Sclose (space_hid);
714 hsize_t elements, maxdim;
715 H5Sget_simple_extent_dims (space_hid, &elements, &maxdim);
716 int slen = H5Tget_size (type_hid);
720 H5Sclose (space_hid);
726 // hdf5 string arrays store strings of all the
727 // same physical length (I think), which is
728 // slightly wasteful, but oh well.
730 OCTAVE_LOCAL_BUFFER (char, s, elements * slen);
732 // create datatype for (null-terminated) string
734 hid_t st_id = H5Tcopy (H5T_C_S1);
735 H5Tset_size (st_id, slen);
737 if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, s) < 0)
741 H5Sclose (space_hid);
746 charMatrix chm (elements, slen - 1);
747 for (hsize_t i = 0; i < elements; ++i)
749 chm.insert (s + i*slen, i, 0);
756 H5Sclose (space_hid);
764 H5Sclose (space_hid);
776 ;;; Local Variables: ***