3 Copyright (C) 2004, 2005, 2006, 2007 David Bateman
5 This file is part of Octave.
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
21 In addition to the terms of the GPL, you are permitted to link
22 this program with any Open Source program, as defined by the
23 Open Source Initiative (www.opensource.org)
41 #include "ov-fcn-inline.h"
42 #include "pr-output.h"
43 #include "variables.h"
46 #include "byte-swap.h"
47 #include "ls-oct-ascii.h"
50 #include "ls-ascii-helper.h"
52 DEFINE_OCTAVE_ALLOCATOR (octave_fcn_inline);
54 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_fcn_inline,
58 octave_fcn_inline::octave_fcn_inline (const std::string& f,
59 const string_vector& a,
61 : octave_fcn_handle (n), iftext (f), ifargs (a)
63 // Form a string representing the function.
65 std::ostringstream buf;
69 for (int i = 0; i < ifargs.length (); i++)
77 buf << ") " << iftext;
80 octave_value anon_fcn_handle = eval_string (buf.str (), true, parse_status);
82 if (parse_status == 0)
84 octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
90 if (fcn.is_undefined ())
91 error ("inline: unable to define function");
94 // This function is supplied to allow a Matlab style class structure
97 octave_fcn_inline::map_value (void) const
100 string_vector args = fcn_arg_names ();
101 m.assign ("version", octave_value (1.0));
102 m.assign ("isEmpty", octave_value (0.0));
103 m.assign ("expr", octave_value (fcn_text ()));
104 m.assign ("numArgs", octave_value (args.length ()));
105 m.assign ("args", octave_value (args));
106 std::ostringstream buf;
107 for (int i = 0; i < args.length (); i++)
108 buf << args(i) << " = INLINE_INPUTS_{" << i + 1 << "}; ";
109 m.assign ("inputExpr", octave_value (buf.str ()));
115 octave_fcn_inline::save_ascii (std::ostream& os)
117 os << "# nargs: " << ifargs.length () << "\n";
118 for (int i = 0; i < ifargs.length (); i++)
119 os << ifargs(i) << "\n";
120 if (nm.length () < 1)
121 // Write an invalid value to flag empty fcn handle name.
125 os << iftext << "\n";
130 octave_fcn_inline::load_ascii (std::istream& is)
133 if (extract_keyword (is, "nargs", nargs, true))
135 ifargs.resize (nargs);
136 for (int i = 0; i < nargs; i++)
145 // Skip preceeding newline(s)
146 skip_preceeding_newline (is);
151 // Get a line of text whitespace characters included, leaving
152 // newline in the stream
153 buf = read_until_newline (is, true);
158 octave_fcn_inline tmp (iftext, ifargs, nm);
168 octave_fcn_inline::save_binary (std::ostream& os, bool&)
170 int32_t tmp = ifargs.length ();
171 os.write (reinterpret_cast<char *> (&tmp), 4);
172 for (int i = 0; i < ifargs.length (); i++)
174 tmp = ifargs(i).length ();
175 os.write (reinterpret_cast<char *> (&tmp), 4);
176 os.write (ifargs(i).c_str (), ifargs(i).length ());
179 os.write (reinterpret_cast<char *> (&tmp), 4);
180 os.write (nm.c_str (), nm.length ());
181 tmp = iftext.length ();
182 os.write (reinterpret_cast<char *> (&tmp), 4);
183 os.write (iftext.c_str (), iftext.length ());
188 octave_fcn_inline::load_binary (std::istream& is, bool swap,
189 oct_mach_info::float_format)
192 if (! is.read (reinterpret_cast<char *> (&nargs), 4))
195 swap_bytes<4> (&nargs);
202 ifargs.resize (nargs);
203 for (int i = 0; i < nargs; i++)
205 if (! is.read (reinterpret_cast<char *> (&tmp), 4))
208 swap_bytes<4> (&tmp);
210 OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1);
212 ifargs(i) = std::string (ctmp);
218 if (! is.read (reinterpret_cast<char *> (&tmp), 4))
221 swap_bytes<4> (&tmp);
223 OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
224 is.read (ctmp1, tmp);
225 nm = std::string (ctmp1);
230 if (! is.read (reinterpret_cast<char *> (&tmp), 4))
233 swap_bytes<4> (&tmp);
235 OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
236 is.read (ctmp2, tmp);
237 iftext = std::string (ctmp2);
242 octave_fcn_inline ftmp (iftext, ifargs, nm);
248 #if defined (HAVE_HDF5)
250 octave_fcn_inline::save_hdf5 (hid_t loc_id, const char *name,
251 bool /* save_as_floats */)
253 hid_t group_hid = -1;
254 group_hid = H5Gcreate (loc_id, name, 0);
255 if (group_hid < 0 ) return false;
258 for (int i = 0; i < ifargs.length (); i++)
259 if (len < ifargs(i).length ())
260 len = ifargs(i).length ();
262 hid_t space_hid = -1, data_hid = -1, type_hid = -1;;
265 // FIXME Is there a better way of saving string vectors, than a
266 // null padded matrix?
268 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
270 // Octave uses column-major, while HDF5 uses row-major ordering
271 hdims[1] = ifargs.length ();
274 space_hid = H5Screate_simple (2, hdims, 0);
277 H5Gclose (group_hid);
281 data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
285 H5Sclose (space_hid);
286 H5Gclose (group_hid);
290 OCTAVE_LOCAL_BUFFER (char, s, ifargs.length () * (len + 1));
292 // Save the args as a null teminated list
293 for (int i = 0; i < ifargs.length (); i++)
295 const char * cptr = ifargs(i).c_str ();
296 for (size_t j = 0; j < ifargs(i).length (); j++)
297 s[i*(len+1)+j] = *cptr++;
298 s[ifargs(i).length ()] = '\0';
301 retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
302 H5P_DEFAULT, s) >= 0;
305 H5Sclose (space_hid);
309 H5Gclose (group_hid);
313 // attach the type of the variable
314 type_hid = H5Tcopy (H5T_C_S1);
315 H5Tset_size (type_hid, nm.length () + 1);
318 H5Gclose (group_hid);
323 space_hid = H5Screate_simple (0 , hdims, 0);
327 H5Gclose (group_hid);
331 data_hid = H5Dcreate (group_hid, "nm", type_hid, space_hid, H5P_DEFAULT);
332 if (data_hid < 0 || H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL,
333 H5P_DEFAULT, nm.c_str ()) < 0)
335 H5Sclose (space_hid);
337 H5Gclose (group_hid);
342 // attach the type of the variable
343 H5Tset_size (type_hid, iftext.length () + 1);
346 H5Gclose (group_hid);
350 data_hid = H5Dcreate (group_hid, "iftext", type_hid, space_hid,
352 if (data_hid < 0 || H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL,
353 H5P_DEFAULT, iftext.c_str ()) < 0)
355 H5Sclose (space_hid);
357 H5Gclose (group_hid);
362 H5Sclose (space_hid);
364 H5Gclose (group_hid);
370 octave_fcn_inline::load_hdf5 (hid_t loc_id, const char *name,
371 bool /* have_h5giterate_bug */)
373 hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
377 group_hid = H5Gopen (loc_id, name);
378 if (group_hid < 0 ) return false;
380 data_hid = H5Dopen (group_hid, "args");
381 space_hid = H5Dget_space (data_hid);
382 rank = H5Sget_simple_extent_ndims (space_hid);
387 H5Sclose (space_hid);
388 H5Gclose (group_hid);
392 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
393 OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
395 H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
397 ifargs.resize (hdims[1]);
399 OCTAVE_LOCAL_BUFFER (char, s1, hdims[0] * hdims[1]);
401 if (H5Dread (data_hid, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL,
402 H5P_DEFAULT, s1) < 0)
405 H5Sclose (space_hid);
406 H5Gclose (group_hid);
411 H5Sclose (space_hid);
413 for (size_t i = 0; i < hdims[1]; i++)
414 ifargs(i) = std::string (s1 + i*hdims[0]);
416 data_hid = H5Dopen (group_hid, "nm");
420 H5Gclose (group_hid);
424 type_hid = H5Dget_type (data_hid);
425 type_class_hid = H5Tget_class (type_hid);
427 if (type_class_hid != H5T_STRING)
431 H5Gclose (group_hid);
435 space_hid = H5Dget_space (data_hid);
436 rank = H5Sget_simple_extent_ndims (space_hid);
440 H5Sclose (space_hid);
443 H5Gclose (group_hid);
447 slen = H5Tget_size (type_hid);
450 H5Sclose (space_hid);
453 H5Gclose (group_hid);
457 OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
459 // create datatype for (null-terminated) string to read into:
460 st_id = H5Tcopy (H5T_C_S1);
461 H5Tset_size (st_id, slen);
463 if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, nm_tmp) < 0)
465 H5Sclose (space_hid);
467 H5Gclose (group_hid);
474 data_hid = H5Dopen (group_hid, "iftext");
478 H5Gclose (group_hid);
482 type_hid = H5Dget_type (data_hid);
483 type_class_hid = H5Tget_class (type_hid);
485 if (type_class_hid != H5T_STRING)
489 H5Gclose (group_hid);
493 space_hid = H5Dget_space (data_hid);
494 rank = H5Sget_simple_extent_ndims (space_hid);
498 H5Sclose (space_hid);
501 H5Gclose (group_hid);
505 slen = H5Tget_size (type_hid);
508 H5Sclose (space_hid);
511 H5Gclose (group_hid);
515 OCTAVE_LOCAL_BUFFER (char, iftext_tmp, slen);
517 // create datatype for (null-terminated) string to read into:
518 st_id = H5Tcopy (H5T_C_S1);
519 H5Tset_size (st_id, slen);
521 if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, iftext_tmp) < 0)
523 H5Sclose (space_hid);
525 H5Gclose (group_hid);
532 octave_fcn_inline ftmp (iftext, ifargs, nm);
540 octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax) const
542 print_raw (os, pr_as_read_syntax);
547 octave_fcn_inline::print_raw (std::ostream& os, bool pr_as_read_syntax) const
549 std::ostringstream buf;
556 for (int i = 0; i < ifargs.length (); i++)
564 buf << ") = " << iftext;
566 octave_print_internal (os, buf.str (), pr_as_read_syntax,
567 current_print_indent_level ());
571 octave_fcn_inline::convert_to_str_internal (bool, bool, char type) const
573 return octave_value (fcn_text (), type);
576 DEFUNX ("inline", Finline, args, ,
578 @deftypefn {Built-in Function} {} inline (@var{str})\n\
579 @deftypefnx {Built-in Function} {} inline (@var{str}, @var{arg1}, @dots{})\n\
580 @deftypefnx {Built-in Function} {} inline (@var{str}, @var{n})\n\
581 Create an inline function from the character string @var{str}.\n\
582 If called with a single argument, the arguments of the generated\n\
583 function are extracted from the function itself. The generated\n\
584 function arguments will then be in alphabetical order. It should\n\
585 be noted that i, and j are ignored as arguments due to the\n\
586 ambiguity between their use as a variable or their use as an inbuilt\n\
587 constant. All arguments followed by a parenthesis are considered\n\
590 If the second and subsequent arguments are character strings,\n\
591 they are the names of the arguments of the function.\n\
593 If the second argument is an integer @var{n}, the arguments are\n\
594 @code{\"x\"}, @code{\"P1\"}, @dots{}, @code{\"P@var{N}\"}.\n\
595 @seealso{argnames, formula, vectorize}\n\
600 int nargin = args.length ();
604 std::string fun = args(0).string_value ();
613 bool in_string = false;
617 while (i < fun.length ())
619 bool terminate_arg = false;
624 if (c == '\'' || c == '\"')
627 else if (c == '\'' || c == '\"')
631 terminate_arg = true;
633 else if (! isalpha (c) && c != '_')
636 else if (isdigit (c))
637 tmp_arg.append (1, c);
640 // Before we do anything remove trailing whitespaces.
641 while (i < fun.length () && isspace (c))
644 // Do we have a variable or a function?
646 terminate_arg = true;
649 tmp_arg = std::string ();
655 tmp_arg.append (1, c);
659 if (terminate_arg || (i == fun.length () && is_arg))
661 bool have_arg = false;
663 for (int j = 0; j < fargs.length (); j++)
664 if (tmp_arg == fargs (j))
670 if (! have_arg && tmp_arg != "i" && tmp_arg != "j" &&
671 tmp_arg != "NaN" && tmp_arg != "nan" &&
672 tmp_arg != "Inf" && tmp_arg != "inf" &&
673 tmp_arg != "NA" && tmp_arg != "pi" &&
675 fargs.append (tmp_arg);
677 tmp_arg = std::string ();
682 // Sort the arguments into ascii order.
685 else if (nargin == 2 && args(1).is_numeric_type ())
687 int n = args(1).int_value ();
697 for (int i = 1; i < n+1; i++)
699 std::ostringstream buf;
701 fargs(i) = buf.str ();
706 error ("inline: numeric argument must be nonnegative");
712 error ("inline: expecting second argument to be an integer");
718 fargs.resize (nargin - 1);
720 for (int i = 1; i < nargin; i++)
722 std::string s = args(i).string_value ();
728 error ("inline: expecting string arguments");
734 retval = octave_value (new octave_fcn_inline (fun, fargs));
737 error ("inline: first argument must be a string");
745 DEFUN (formula, args, ,
747 @deftypefn {Built-in Function} {} formula (@var{fun})\n\
748 Return a character string representing the inline function @var{fun}.\n\
749 Note that @code{char (@var{fun})} is equivalent to\n\
750 @code{formula (@var{fun})}.\n\
751 @seealso{argnames, inline, vectorize}\n\
756 int nargin = args.length ();
760 octave_fcn_inline* fn = args(0).fcn_inline_value (true);
763 retval = octave_value (fn->fcn_text ());
765 error ("formula: must be an inline function");
773 DEFUN (argnames, args, ,
775 @deftypefn {Built-in Function} {} argnames (@var{fun})\n\
776 Return a cell array of character strings containing the names of\n\
777 the arguments of the inline function @var{fun}.\n\
778 @seealso{inline, formula, vectorize}\n\
783 int nargin = args.length ();
787 octave_fcn_inline *fn = args(0).fcn_inline_value (true);
791 string_vector t1 = fn->fcn_arg_names ();
793 Cell t2 (dim_vector (t1.length (), 1));
795 for (int i = 0; i < t1.length (); i++)
801 error ("argnames: argument must be an inline function");
809 DEFUN (vectorize, args, ,
811 @deftypefn {Built-in Function} {} vectorize (@var{fun})\n\
812 Create a vectorized version of the inline function @var{fun}\n\
813 by replacing all occurrences of @code{*}, @code{/}, etc., with\n\
814 @code{.*}, @code{./}, etc.\n\
819 int nargin = args.length ();
823 std::string old_func;
824 octave_fcn_inline* old = 0;
825 bool func_is_string = true;
827 if (args(0).is_string ())
828 old_func = args(0).string_value ();
831 old = args(0).fcn_inline_value (true);
832 func_is_string = false;
835 old_func = old->fcn_text ();
837 error ("vectorize: must be a string or inline function");
842 std::string new_func;
845 while (i < old_func.length ())
847 std::string t1 = old_func.substr (i, 1);
849 if (t1 == "*" || t1 == "/" || t1 == "\\" || t1 == "^")
851 if (i && old_func.substr (i-1, 1) != ".")
852 new_func.append (".");
854 // Special case for ** operator.
855 if (t1 == "*" && i < (old_func.length () - 1)
856 && old_func.substr (i+1, 1) == "*")
858 new_func.append ("*");
862 new_func.append (t1);
867 retval = octave_value (new_func);
869 retval = octave_value (new octave_fcn_inline
870 (new_func, old->fcn_arg_names ()));
880 ;;; Local Variables: ***