changeset 28695:b3770a5f210d

improve validation of cell2struct fields argument (bug #58617) * ov-struct.cc (invalid_cell2struct_fields_error): New function. (get_cell2struct_fields): New function. (Fcell2struct): Use get_cell2struct_fields to extract field names. New tests for cell2struct.
author John W. Eaton <jwe@octave.org>
date Tue, 08 Sep 2020 13:42:23 -0400
parents d91935bd879c
children 8d04d7c58d49
files libinterp/octave-value/ov-struct.cc
diffstat 1 files changed, 50 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-struct.cc	Tue Sep 08 08:41:57 2020 -0700
+++ b/libinterp/octave-value/ov-struct.cc	Tue Sep 08 13:42:23 2020 -0400
@@ -1991,6 +1991,46 @@
 %!assert (isfield (struct ("a", 1, "b", 2), {"a", "c"}), [true, false])
 */
 
+OCTAVE_NORETURN
+static void
+invalid_cell2struct_fields_error (void)
+{
+  error ("cell2struct: FIELDS must be a cell array of strings or a scalar string");
+}
+
+static Array<std::string>
+get_cell2struct_fields (const octave_value& arg)
+{
+  if (arg.is_string ())
+    {
+      if (arg.rows () != 1)
+        invalid_cell2struct_fields_error ();
+
+      return Array<std::string> (dim_vector (1, 1), arg.string_value ());
+    }
+
+  if (arg.iscell ())
+    {
+      const Cell c = arg.cell_value ();
+
+      Array<std::string> retval (c.dims ());
+
+      for (octave_idx_type i = 0; i < c.numel (); i++)
+        {
+          const octave_value val = c(i);
+
+          if (! val.is_string () || val.rows () != 1)
+            invalid_cell2struct_fields_error ();
+
+          retval(i) = c(i).string_value ();
+        }
+
+      return retval;
+    }
+
+  invalid_cell2struct_fields_error ();
+}
+
 DEFUN (cell2struct, args, ,
        doc: /* -*- texinfo -*-
 @deftypefn  {} {} cell2struct (@var{cell}, @var{fields})
@@ -2024,11 +2064,10 @@
   if (nargin < 2 || nargin > 3)
     print_usage ();
 
-  if (! args(0).iscell ())
-    error ("cell2struct: argument CELL must be of type cell");
-
-  if (! (args(1).iscellstr () || args(1).is_char_matrix ()))
-    error ("cell2struct: FIELDS must be a cell array of strings or a character matrix");
+  const Cell vals
+    = args(0).xcell_value ("cell2struct: argument CELL must be of type cell");
+
+  const Array<std::string> fields = get_cell2struct_fields (args(1));
 
   int dim = 0;
 
@@ -2043,9 +2082,6 @@
   if (dim < 0)
     error ("cell2struct: DIM must be a valid dimension");
 
-  const Cell vals = args(0).cell_value ();
-  const Array<std::string> fields = args(1).cellstr_value ();
-
   octave_idx_type ext = (vals.ndims () > dim ? vals.dims ()(dim) : 1);
 
   if (ext != fields.numel ())
@@ -2095,6 +2131,12 @@
 %!assert (cell2struct ({1; 2}, {"a"; "b"}), struct ("a", 1, "b", 2))
 
 %!assert (cell2struct ({}, {"f"}, 3), struct ("f", {}))
+
+%!assert (cell2struct ({1; 2; 3; 4}, {'a', 'b'; 'c', 'd'}),
+%!        struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
+%!assert (cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'}, 2),
+%!        struct ('a', 1, 'c', 2, 'b', 3, 'd', 4));
+%!error cell2struct ({1, 2, 3, 4}, {'a', 'b'; 'c', 'd'})
 */
 
 DEFUN (rmfield, args, ,