1 // Copyright (C) 2009 VZLU Prague 2 // Copyright (C) 2018 John Donoghue <john.donogue@ieee.org> 3 // 4 // This program is free software; you can redistribute it and/or modify it under 5 // the terms of the GNU General Public License as published by the Free Software 6 // Foundation; either version 3 of the License, or (at your option) any later 7 // version. 8 // 9 // This program is distributed in the hope that it will be useful, but WITHOUT 10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 12 // details. 13 // 14 // You should have received a copy of the GNU General Public License along with 15 // this program; if not, see <http://www.gnu.org/licenses/>. 16 17 #include <octave/oct.h> 18 19 #ifdef HAVE_CONFIG_H 20 #include "config.h" 21 #endif 22 23 #include <octave/utils.h> 24 #ifdef HAVE_OCTAVE_INTERPRETER_H 25 # include <octave/interpreter.h> 26 #endif 27 #include <octave/symtab.h> 28 #include <octave/oct-map.h> 29 30 #ifdef DEFMETHOD_DLD 31 DEFMETHOD_DLD (unpackfields, interp, args, , 32 #else 33 DEFUN_DLD (unpackfields, args, , 34 #endif 35 "-*- texinfo -*-\n\ 36 @deftypefn {Loadable Function} {} unpackfields (@var{s_name}, @var{fld1}, @var{fld2}, @dots{})\n\ 37 Create variables from fields of a struct.\n\ 38 \n\ 39 Inserts the named fields @var{fld1}, @var{fld2}, @dots{}, from the struct\n\ 40 named @var{s_name}, into the current scope. Note that @var{s_name} is the\n\ 41 name of the struct in the current scope, not the struct itself.\n\ 42 \n\ 43 @example\n\ 44 @group\n\ 45 unpackfields (\"struct\", \"var1\", \"var2\")\n\ 46 @end group\n\ 47 @end example\n\ 48 \n\ 49 is equivalent to the code:\n\ 50 @example\n\ 51 @group\n\ 52 var1 = struct.var1;\n\ 53 var2 = struct.var2;\n\ 54 : \n\ 55 @end group\n\ 56 @end example\n\ 57 but more efficient and more concise.\n\ 58 \n\ 59 @seealso{getfield, getfields, packfields, struct}\n\ 60 @end deftypefn") 61 { 62 int nargin = args.length (); 63 64 if (nargin > 0) 65 { 66 #ifdef DEFMETHOD_DLD 67 #ifndef OCTAVE_HAVE_INTERPRETER_VARVAL 68 octave::symbol_table::scope curr_scope 69 = interp.require_current_scope ("unpackfields"); 70 #endif 71 #endif 72 if (! args (0).is_string ()) 73 { 74 error ("unpackfields: expected variable name"); 75 return octave_value (); 76 } 77 78 std::string struct_name = args (0).string_value (); 79 string_vector fld_names(nargin-1); 80 81 if (! OCTAVE__VALID_IDENTIFIER (struct_name)) 82 { 83 error ("unpackfields: invalid variable name: %s", 84 struct_name.c_str ()); 85 return octave_value (); 86 } 87 88 for (octave_idx_type i = 0; i < nargin-1; i++) 89 { 90 if (! args (i+1).is_string ()) 91 { 92 error ("unpackfields: expected variable name for input %d", (int)i+1); 93 return octave_value (); 94 } 95 96 std::string fld_name = args(i+1).string_value (); 97 98 if (OCTAVE__VALID_IDENTIFIER (fld_name)) 99 fld_names(i) = fld_name; 100 else 101 { 102 error ("unpackfields: invalid field name: %s", fld_name.c_str ()); 103 return octave_value (); 104 } 105 } 106 107 // Force the symbol to be inserted in caller's scope. 108 #ifdef DEFMETHOD_DLD 109 #ifdef OCTAVE_HAVE_INTERPRETER_VARVAL 110 octave_value struct_val = interp.varval (struct_name); 111 #else 112 octave_value struct_val = curr_scope.varval (struct_name); 113 #endif 114 #else 115 octave_value struct_val = symbol_table::varval (struct_name); 116 #endif 117 if (struct_val.OV_ISMAP ()) 118 { 119 if (struct_val.ndims () == 2) 120 { 121 // Fast code for a built-in struct. 122 const octave_scalar_map map = struct_val.scalar_map_value (); 123 124 // Do the actual work. 125 for (octave_idx_type i = 0; i < nargin-1; i++) 126 { 127 octave_scalar_map::const_iterator iter = map.seek (fld_names(i)); 128 if (iter != map.end ()) 129 #ifdef DEFMETHOD_DLD 130 #ifdef OCTAVE_HAVE_INTERPRETER_ASSIGN 131 interp.assign (fld_names(i), map.contents (iter)); 132 #else 133 curr_scope.assign (fld_names(i), map.contents (iter)); 134 #endif 135 #else 136 symbol_table::assign (fld_names(i), map.contents (iter)); 137 #endif 138 else 139 { 140 error ("unpackfields: field %s does not exist", fld_names(i).c_str ()); 141 break; 142 } 143 } 144 } 145 else 146 { 147 error ("unpackfields: structure must have singleton dimensions"); 148 return octave_value (); 149 } 150 } 151 else if (struct_val.is_defined ()) 152 { 153 // General case. 154 std::list<octave_value_list> idx (1); 155 156 for (octave_idx_type i = 0; i < nargin-1; i++) 157 { 158 idx.front () = args(i+1); // Save one string->octave_value conversion. 159 octave_value val = struct_val.subsref (".", idx); 160 161 if (val.is_defined ()) 162 #ifdef DEFMETHOD_DLD 163 #ifdef OCTAVE_HAVE_INTERPRETER_ASSIGN 164 interp.assign (fld_names(i), val); 165 #else 166 curr_scope.assign (fld_names(i), val); 167 #endif 168 #else 169 symbol_table::assign (fld_names(i), val); 170 #endif 171 } 172 } 173 } 174 else 175 print_usage (); 176 177 return octave_value_list (); 178 } 179 180 /* 181 %!test 182 %! s.foo = "hello"; 183 %! s.bar = 42; 184 %! unpackfields ("s", "foo", "bar"); 185 %! assert (foo, "hello"); 186 %! assert (bar, 42); 187 */ 188