ov-fcn-inline.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2004-2012 David Bateman
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 In addition to the terms of the GPL, you are permitted to link
00022 this program with any Open Source program, as defined by the
00023 Open Source Initiative (www.opensource.org)
00024 
00025 */
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030 
00031 #include <istream>
00032 #include <iostream>
00033 #include <sstream>
00034 #include <vector>
00035 
00036 #include "oct-locbuf.h"
00037 
00038 #include "defun.h"
00039 #include "error.h"
00040 #include "gripes.h"
00041 #include "oct-map.h"
00042 #include "ov-base.h"
00043 #include "ov-fcn-inline.h"
00044 #include "ov-usr-fcn.h"
00045 #include "pr-output.h"
00046 #include "variables.h"
00047 #include "parse.h"
00048 #include "toplev.h"
00049 
00050 #include "byte-swap.h"
00051 #include "ls-ascii-helper.h"
00052 #include "ls-oct-ascii.h"
00053 #include "ls-hdf5.h"
00054 #include "ls-utils.h"
00055 
00056 DEFINE_OCTAVE_ALLOCATOR (octave_fcn_inline);
00057 
00058 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_fcn_inline,
00059                                      "inline function",
00060                                      "function_handle");
00061 
00062 octave_fcn_inline::octave_fcn_inline (const std::string& f,
00063                                       const string_vector& a,
00064                                       const std::string& n)
00065   : octave_fcn_handle (n), iftext (f), ifargs (a)
00066 {
00067   // Form a string representing the function.
00068 
00069   std::ostringstream buf;
00070 
00071   buf << "@(";
00072 
00073   for (int i = 0; i < ifargs.length (); i++)
00074     {
00075       if (i > 0)
00076         buf << ", ";
00077 
00078       buf << ifargs(i);
00079     }
00080 
00081   buf << ") " << iftext;
00082 
00083   int parse_status;
00084   octave_value anon_fcn_handle = eval_string (buf.str (), true, parse_status);
00085 
00086   if (parse_status == 0)
00087     {
00088       octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
00089 
00090       if (fh)
00091         {
00092           fcn = fh->fcn_val ();
00093 
00094           octave_user_function *uf = fcn.user_function_value ();
00095 
00096           if (uf)
00097             {
00098               octave_function *curr_fcn = octave_call_stack::current ();
00099 
00100               if (curr_fcn)
00101                 {
00102                   symbol_table::scope_id parent_scope
00103                     = curr_fcn->parent_fcn_scope ();
00104 
00105                   if (parent_scope < 0)
00106                     parent_scope = curr_fcn->scope ();
00107 
00108                   uf->stash_parent_fcn_scope (parent_scope);
00109                 }
00110             }
00111         }
00112     }
00113 
00114   if (fcn.is_undefined ())
00115     error ("inline: unable to define function");
00116 }
00117 
00118 // This function is supplied to allow a Matlab style class structure
00119 // to be returned..
00120 octave_map
00121 octave_fcn_inline::map_value (void) const
00122 {
00123   octave_scalar_map m;
00124 
00125   m.assign ("version", 1.0);
00126   m.assign ("isEmpty", 0.0);
00127   m.assign ("expr", fcn_text ());
00128 
00129   string_vector args = fcn_arg_names ();
00130 
00131   m.assign ("numArgs", args.length ());
00132   m.assign ("args", args);
00133 
00134   std::ostringstream buf;
00135 
00136   for (int i = 0; i < args.length (); i++)
00137     buf << args(i) << " = INLINE_INPUTS_{" << i + 1 << "}; ";
00138 
00139   m.assign ("inputExpr", buf.str ());
00140 
00141   return m;
00142 }
00143 
00144 bool
00145 octave_fcn_inline::save_ascii (std::ostream& os)
00146 {
00147   os << "# nargs: " <<  ifargs.length () << "\n";
00148   for (int i = 0; i < ifargs.length (); i++)
00149     os << ifargs(i) << "\n";
00150   if (nm.length () < 1)
00151     // Write an invalid value to flag empty fcn handle name.
00152     os << "0\n";
00153   else
00154     os << nm << "\n";
00155   os << iftext << "\n";
00156   return true;
00157 }
00158 
00159 bool
00160 octave_fcn_inline::load_ascii (std::istream& is)
00161 {
00162   int nargs;
00163   if (extract_keyword (is, "nargs", nargs, true))
00164     {
00165       ifargs.resize (nargs);
00166       for (int i = 0; i < nargs; i++)
00167         is >> ifargs(i);
00168       is >> nm;
00169       if (nm == "0")
00170         nm = "";
00171 
00172       skip_preceeding_newline (is);
00173 
00174       std::string buf;
00175 
00176       if (is)
00177         {
00178 
00179           // Get a line of text whitespace characters included,
00180           // leaving newline in the stream.
00181           buf = read_until_newline (is, true);
00182         }
00183 
00184       iftext = buf;
00185 
00186       octave_fcn_inline tmp (iftext, ifargs, nm);
00187       fcn = tmp.fcn;
00188 
00189       return true;
00190     }
00191   else
00192     return false;
00193 }
00194 
00195 bool
00196 octave_fcn_inline::save_binary (std::ostream& os, bool&)
00197 {
00198   int32_t tmp = ifargs.length ();
00199   os.write (reinterpret_cast<char *> (&tmp), 4);
00200   for (int i = 0; i < ifargs.length (); i++)
00201     {
00202       tmp = ifargs(i).length ();
00203       os.write (reinterpret_cast<char *> (&tmp), 4);
00204       os.write (ifargs(i).c_str (), ifargs(i).length ());
00205     }
00206   tmp = nm.length ();
00207   os.write (reinterpret_cast<char *> (&tmp), 4);
00208   os.write (nm.c_str (), nm.length ());
00209   tmp = iftext.length ();
00210   os.write (reinterpret_cast<char *> (&tmp), 4);
00211   os.write (iftext.c_str (), iftext.length ());
00212   return true;
00213 }
00214 
00215 bool
00216 octave_fcn_inline::load_binary (std::istream& is, bool swap,
00217                                 oct_mach_info::float_format)
00218 {
00219   int32_t nargs;
00220   if (! is.read (reinterpret_cast<char *> (&nargs), 4))
00221     return false;
00222   if (swap)
00223     swap_bytes<4> (&nargs);
00224 
00225   if (nargs < 1)
00226     return false;
00227   else
00228     {
00229       int32_t tmp;
00230       ifargs.resize (nargs);
00231       for (int i = 0; i < nargs; i++)
00232         {
00233           if (! is.read (reinterpret_cast<char *> (&tmp), 4))
00234             return false;
00235           if (swap)
00236             swap_bytes<4> (&tmp);
00237 
00238           OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1);
00239           is.read (ctmp, tmp);
00240           ifargs(i) = std::string (ctmp);
00241 
00242           if (! is)
00243             return false;
00244         }
00245 
00246       if (! is.read (reinterpret_cast<char *> (&tmp), 4))
00247         return false;
00248       if (swap)
00249         swap_bytes<4> (&tmp);
00250 
00251       OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
00252       is.read (ctmp1, tmp);
00253       nm = std::string (ctmp1);
00254 
00255       if (! is)
00256         return false;
00257 
00258       if (! is.read (reinterpret_cast<char *> (&tmp), 4))
00259         return false;
00260       if (swap)
00261         swap_bytes<4> (&tmp);
00262 
00263       OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
00264       is.read (ctmp2, tmp);
00265       iftext = std::string (ctmp2);
00266 
00267       if (! is)
00268         return false;
00269 
00270       octave_fcn_inline ftmp (iftext, ifargs, nm);
00271       fcn = ftmp.fcn;
00272     }
00273   return true;
00274 }
00275 
00276 #if defined (HAVE_HDF5)
00277 bool
00278 octave_fcn_inline::save_hdf5 (hid_t loc_id, const char *name,
00279                               bool /* save_as_floats */)
00280 {
00281   hid_t group_hid = -1;
00282 #if HAVE_HDF5_18
00283   group_hid = H5Gcreate (loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00284 #else
00285   group_hid = H5Gcreate (loc_id, name, 0);
00286 #endif
00287   if (group_hid < 0 ) return false;
00288 
00289   size_t len = 0;
00290   for (int i = 0; i < ifargs.length (); i++)
00291     if (len < ifargs(i).length ())
00292       len = ifargs(i).length ();
00293 
00294   hid_t space_hid = -1, data_hid = -1, type_hid = -1;;
00295   bool retval = true;
00296 
00297   // FIXME Is there a better way of saving string vectors, than a
00298   // null padded matrix?
00299 
00300   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
00301 
00302   // Octave uses column-major, while HDF5 uses row-major ordering
00303   hdims[1] = ifargs.length ();
00304   hdims[0] = len + 1;
00305 
00306   space_hid = H5Screate_simple (2, hdims, 0);
00307   if (space_hid < 0)
00308     {
00309       H5Gclose (group_hid);
00310       return false;
00311     }
00312 #if HAVE_HDF5_18
00313   data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
00314                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00315 #else
00316   data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
00317                         H5P_DEFAULT);
00318 #endif
00319   if (data_hid < 0)
00320     {
00321       H5Sclose (space_hid);
00322       H5Gclose (group_hid);
00323       return false;
00324     }
00325 
00326   OCTAVE_LOCAL_BUFFER (char, s, ifargs.length () * (len + 1));
00327 
00328   // Save the args as a null teminated list
00329   for (int i = 0; i < ifargs.length (); i++)
00330     {
00331       const char * cptr = ifargs(i).c_str ();
00332       for (size_t j = 0; j < ifargs(i).length (); j++)
00333         s[i*(len+1)+j] = *cptr++;
00334       s[ifargs(i).length ()] = '\0';
00335     }
00336 
00337   retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
00338                      H5P_DEFAULT, s) >= 0;
00339 
00340   H5Dclose (data_hid);
00341   H5Sclose (space_hid);
00342 
00343   if (!retval)
00344     {
00345       H5Gclose (group_hid);
00346       return false;
00347     }
00348 
00349   // attach the type of the variable
00350   type_hid = H5Tcopy (H5T_C_S1);
00351   H5Tset_size (type_hid, nm.length () + 1);
00352   if (type_hid < 0)
00353     {
00354       H5Gclose (group_hid);
00355       return false;
00356     }
00357 
00358   hdims[0] = 0;
00359   space_hid = H5Screate_simple (0 , hdims, 0);
00360   if (space_hid < 0)
00361     {
00362       H5Tclose (type_hid);
00363       H5Gclose (group_hid);
00364       return false;
00365     }
00366 #if HAVE_HDF5_18
00367   data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
00368                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00369 #else
00370   data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid, H5P_DEFAULT);
00371 #endif
00372   if (data_hid < 0 || H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL,
00373                                 H5P_DEFAULT, nm.c_str ()) < 0)
00374     {
00375       H5Sclose (space_hid);
00376       H5Tclose (type_hid);
00377       H5Gclose (group_hid);
00378       return false;
00379     }
00380   H5Dclose (data_hid);
00381 
00382   // attach the type of the variable
00383   H5Tset_size (type_hid, iftext.length () + 1);
00384   if (type_hid < 0)
00385     {
00386       H5Gclose (group_hid);
00387       return false;
00388     }
00389 
00390 #if HAVE_HDF5_18
00391   data_hid = H5Dcreate (group_hid, "iftext",  type_hid, space_hid,
00392                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00393 #else
00394   data_hid = H5Dcreate (group_hid, "iftext",  type_hid, space_hid,
00395                         H5P_DEFAULT);
00396 #endif
00397   if (data_hid < 0 || H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL,
00398                                 H5P_DEFAULT, iftext.c_str ()) < 0)
00399     {
00400       H5Sclose (space_hid);
00401       H5Tclose (type_hid);
00402       H5Gclose (group_hid);
00403       return false;
00404     }
00405 
00406   H5Dclose (data_hid);
00407   H5Sclose (space_hid);
00408   H5Tclose (type_hid);
00409   H5Gclose (group_hid);
00410 
00411   return retval;
00412 }
00413 
00414 bool
00415 octave_fcn_inline::load_hdf5 (hid_t loc_id, const char *name)
00416 {
00417   hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
00418   hsize_t rank;
00419   int slen;
00420 
00421 #if HAVE_HDF5_18
00422   group_hid = H5Gopen (loc_id, name, H5P_DEFAULT);
00423 #else
00424   group_hid = H5Gopen (loc_id, name);
00425 #endif
00426   if (group_hid < 0 ) return false;
00427 
00428 #if HAVE_HDF5_18
00429   data_hid = H5Dopen (group_hid, "args", H5P_DEFAULT);
00430 #else
00431   data_hid = H5Dopen (group_hid, "args");
00432 #endif
00433   space_hid = H5Dget_space (data_hid);
00434   rank = H5Sget_simple_extent_ndims (space_hid);
00435 
00436   if (rank != 2)
00437     {
00438       H5Dclose (data_hid);
00439       H5Sclose (space_hid);
00440       H5Gclose (group_hid);
00441       return false;
00442     }
00443 
00444   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
00445   OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
00446 
00447   H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
00448 
00449   ifargs.resize (hdims[1]);
00450 
00451   OCTAVE_LOCAL_BUFFER (char, s1, hdims[0] * hdims[1]);
00452 
00453   if (H5Dread (data_hid, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL,
00454                H5P_DEFAULT, s1) < 0)
00455     {
00456       H5Dclose (data_hid);
00457       H5Sclose (space_hid);
00458       H5Gclose (group_hid);
00459       return false;
00460     }
00461 
00462   H5Dclose (data_hid);
00463   H5Sclose (space_hid);
00464 
00465   for (size_t i = 0; i < hdims[1]; i++)
00466     ifargs(i) = std::string (s1 + i*hdims[0]);
00467 
00468 #if HAVE_HDF5_18
00469   data_hid = H5Dopen (group_hid, "nm", H5P_DEFAULT);
00470 #else
00471   data_hid = H5Dopen (group_hid, "nm");
00472 #endif
00473 
00474   if (data_hid < 0)
00475     {
00476       H5Gclose (group_hid);
00477       return false;
00478     }
00479 
00480   type_hid = H5Dget_type (data_hid);
00481   type_class_hid = H5Tget_class (type_hid);
00482 
00483   if (type_class_hid != H5T_STRING)
00484     {
00485       H5Tclose (type_hid);
00486       H5Dclose (data_hid);
00487       H5Gclose (group_hid);
00488       return false;
00489     }
00490 
00491   space_hid = H5Dget_space (data_hid);
00492   rank = H5Sget_simple_extent_ndims (space_hid);
00493 
00494   if (rank != 0)
00495     {
00496       H5Sclose (space_hid);
00497       H5Tclose (type_hid);
00498       H5Dclose (data_hid);
00499       H5Gclose (group_hid);
00500       return false;
00501     }
00502 
00503   slen = H5Tget_size (type_hid);
00504   if (slen < 0)
00505     {
00506       H5Sclose (space_hid);
00507       H5Tclose (type_hid);
00508       H5Dclose (data_hid);
00509       H5Gclose (group_hid);
00510       return false;
00511     }
00512 
00513   OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
00514 
00515   // create datatype for (null-terminated) string to read into:
00516   st_id = H5Tcopy (H5T_C_S1);
00517   H5Tset_size (st_id, slen);
00518 
00519   if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, nm_tmp) < 0)
00520     {
00521       H5Sclose (space_hid);
00522       H5Tclose (type_hid);
00523       H5Gclose (group_hid);
00524       return false;
00525     }
00526   H5Tclose (st_id);
00527   H5Dclose (data_hid);
00528   nm = nm_tmp;
00529 
00530 #if HAVE_HDF5_18
00531   data_hid = H5Dopen (group_hid, "iftext", H5P_DEFAULT);
00532 #else
00533   data_hid = H5Dopen (group_hid, "iftext");
00534 #endif
00535 
00536   if (data_hid < 0)
00537     {
00538       H5Gclose (group_hid);
00539       return false;
00540     }
00541 
00542   type_hid = H5Dget_type (data_hid);
00543   type_class_hid = H5Tget_class (type_hid);
00544 
00545   if (type_class_hid != H5T_STRING)
00546     {
00547       H5Tclose (type_hid);
00548       H5Dclose (data_hid);
00549       H5Gclose (group_hid);
00550       return false;
00551     }
00552 
00553   space_hid = H5Dget_space (data_hid);
00554   rank = H5Sget_simple_extent_ndims (space_hid);
00555 
00556   if (rank != 0)
00557     {
00558       H5Sclose (space_hid);
00559       H5Tclose (type_hid);
00560       H5Dclose (data_hid);
00561       H5Gclose (group_hid);
00562       return false;
00563     }
00564 
00565   slen = H5Tget_size (type_hid);
00566   if (slen < 0)
00567     {
00568       H5Sclose (space_hid);
00569       H5Tclose (type_hid);
00570       H5Dclose (data_hid);
00571       H5Gclose (group_hid);
00572       return false;
00573     }
00574 
00575   OCTAVE_LOCAL_BUFFER (char, iftext_tmp, slen);
00576 
00577   // create datatype for (null-terminated) string to read into:
00578   st_id = H5Tcopy (H5T_C_S1);
00579   H5Tset_size (st_id, slen);
00580 
00581   if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, iftext_tmp) < 0)
00582     {
00583       H5Sclose (space_hid);
00584       H5Tclose (type_hid);
00585       H5Gclose (group_hid);
00586       return false;
00587     }
00588   H5Tclose (st_id);
00589   H5Dclose (data_hid);
00590   iftext = iftext_tmp;
00591 
00592   octave_fcn_inline ftmp (iftext, ifargs, nm);
00593   fcn = ftmp.fcn;
00594 
00595   return true;
00596 }
00597 #endif
00598 
00599 void
00600 octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax) const
00601 {
00602   print_raw (os, pr_as_read_syntax);
00603   newline (os);
00604 }
00605 
00606 void
00607 octave_fcn_inline::print_raw (std::ostream& os, bool pr_as_read_syntax) const
00608 {
00609   std::ostringstream buf;
00610 
00611   if (nm.empty ())
00612     buf << "f(";
00613   else
00614     buf << nm << "(";
00615 
00616   for (int i = 0; i < ifargs.length (); i++)
00617     {
00618       if (i)
00619         buf << ", ";
00620 
00621       buf << ifargs(i);
00622     }
00623 
00624   buf << ") = " << iftext;
00625 
00626   octave_print_internal (os, buf.str (), pr_as_read_syntax,
00627                          current_print_indent_level ());
00628 }
00629 
00630 octave_value
00631 octave_fcn_inline::convert_to_str_internal (bool, bool, char type) const
00632 {
00633   return octave_value (fcn_text (), type);
00634 }
00635 
00636 DEFUNX ("inline", Finline, args, ,
00637   "-*- texinfo -*-\n\
00638 @deftypefn  {Built-in Function} {} inline (@var{str})\n\
00639 @deftypefnx {Built-in Function} {} inline (@var{str}, @var{arg1}, @dots{})\n\
00640 @deftypefnx {Built-in Function} {} inline (@var{str}, @var{n})\n\
00641 Create an inline function from the character string @var{str}.\n\
00642 If called with a single argument, the arguments of the generated\n\
00643 function are extracted from the function itself.  The generated\n\
00644 function arguments will then be in alphabetical order.  It should\n\
00645 be noted that i, and j are ignored as arguments due to the\n\
00646 ambiguity between their use as a variable or their use as an inbuilt\n\
00647 constant.  All arguments followed by a parenthesis are considered\n\
00648 to be functions.\n\
00649 \n\
00650 If the second and subsequent arguments are character strings,\n\
00651 they are the names of the arguments of the function.\n\
00652 \n\
00653 If the second argument is an integer @var{n}, the arguments are\n\
00654 @code{\"x\"}, @code{\"P1\"}, @dots{}, @code{\"P@var{N}\"}.\n\
00655 @seealso{argnames, formula, vectorize}\n\
00656 @end deftypefn")
00657 {
00658   octave_value retval;
00659 
00660   int nargin = args.length ();
00661 
00662   if (nargin > 0)
00663     {
00664       if (args(0).is_string ())
00665         {
00666           std::string fun = args(0).string_value ();
00667           string_vector fargs;
00668 
00669           if (nargin == 1)
00670             {
00671               bool is_arg = false;
00672               bool in_string = false;
00673               std::string tmp_arg;
00674               size_t i = 0;
00675               size_t fun_length = fun.length ();
00676 
00677               while (i < fun_length)
00678                 {
00679                   bool terminate_arg = false;
00680                   char c = fun[i++];
00681 
00682                   if (in_string)
00683                     {
00684                       if (c == '\'' || c == '\"')
00685                         in_string = false;
00686                     }
00687                   else if (c == '\'' || c == '\"')
00688                     {
00689                       in_string = true;
00690                       if (is_arg)
00691                         terminate_arg = true;
00692                     }
00693                   else if (! isalpha (c) && c != '_')
00694                     if (! is_arg)
00695                       continue;
00696                     else if (isdigit (c))
00697                       tmp_arg.append (1, c);
00698                     else
00699                       {
00700                         // Before we do anything remove trailing whitespaces.
00701                         while (i < fun_length && isspace (c))
00702                           c = fun[i++];
00703 
00704                         // Do we have a variable or a function?
00705                         if (c != '(')
00706                           terminate_arg = true;
00707                         else
00708                           {
00709                             tmp_arg = std::string ();
00710                             is_arg = false;
00711                           }
00712                       }
00713                   else if (! is_arg)
00714                     {
00715                       if (c == 'e' || c == 'E')
00716                         {
00717                           // possible number in exponent form, not arg
00718                           if (isdigit (fun[i])
00719                               || fun[i] == '-' || fun[i] == '+')
00720                             continue;
00721                         }
00722                       is_arg = true;
00723                       tmp_arg.append (1, c);
00724                     }
00725                   else
00726                     {
00727                       tmp_arg.append (1, c);
00728                     }
00729 
00730                   if (terminate_arg || (i == fun_length && is_arg))
00731                     {
00732                       bool have_arg = false;
00733 
00734                       for (int j = 0; j < fargs.length (); j++)
00735                         if (tmp_arg == fargs (j))
00736                           {
00737                             have_arg = true;
00738                             break;
00739                           }
00740 
00741                       if (! have_arg && tmp_arg != "i" && tmp_arg != "j" &&
00742                           tmp_arg != "NaN" && tmp_arg != "nan" &&
00743                           tmp_arg != "Inf" && tmp_arg != "inf" &&
00744                           tmp_arg != "NA" && tmp_arg != "pi" &&
00745                           tmp_arg != "e" && tmp_arg != "eps")
00746                         fargs.append (tmp_arg);
00747 
00748                       tmp_arg = std::string ();
00749                       is_arg = false;
00750                     }
00751                 }
00752 
00753               // Sort the arguments into ascii order.
00754               fargs.sort ();
00755             }
00756           else if (nargin == 2 && args(1).is_numeric_type ())
00757             {
00758               if (! args(1).is_scalar_type ()) 
00759                 {
00760                   error ("inline: N must be an integer");
00761                   return retval;
00762                 }
00763               
00764               int n = args(1).int_value ();
00765 
00766               if (! error_state)
00767                 {
00768                   if (n >= 0)
00769                     {
00770                       fargs.resize (n+1);
00771 
00772                       fargs(0) = "x";
00773 
00774                       for (int i = 1; i < n+1; i++)
00775                         {
00776                           std::ostringstream buf;
00777                           buf << "P" << i;
00778                           fargs(i) = buf.str ();
00779                         }
00780                     }
00781                   else
00782                     {
00783                       error ("inline: N must be a positive integer or zero");
00784                       return retval;
00785                     }
00786                 }
00787               else
00788                 {
00789                   error ("inline: N must be an integer");
00790                   return retval;
00791                 }
00792             }
00793           else
00794             {
00795               fargs.resize (nargin - 1);
00796 
00797               for (int i = 1; i < nargin; i++)
00798                 {
00799                   if (args(i).is_string ())
00800                     {
00801                       std::string s = args(i).string_value ();
00802                       fargs(i-1) = s;
00803                     }
00804                     else
00805                     {
00806                       error ("inline: expecting string arguments");
00807                       return retval;
00808                     }
00809                 }
00810             }
00811 
00812           retval = octave_value (new octave_fcn_inline (fun, fargs));
00813         }
00814       else
00815         error ("inline: STR argument must be a string");
00816     }
00817   else
00818     print_usage ();
00819 
00820   return retval;
00821 }
00822 
00823 /*
00824 %!shared fn
00825 %! fn = inline ("x.^2 + 1");
00826 %!assert (feval (fn, 6), 37)
00827 %!assert (fn (6), 37)
00828 %% FIXME: Need tests for other 2 calling forms of inline()
00829 
00830 %% Test input validation 
00831 %!error inline ()
00832 %!error <STR argument must be a string> inline (1)
00833 %!error <N must be an integer> inline ("2", ones (2,2))
00834 %!error <N must be a positive integer> inline ("2", -1)
00835 %!error <expecting string arguments> inline ("2", "x", -1, "y")
00836 */
00837 
00838 DEFUN (formula, args, ,
00839   "-*- texinfo -*-\n\
00840 @deftypefn {Built-in Function} {} formula (@var{fun})\n\
00841 Return a character string representing the inline function @var{fun}.\n\
00842 Note that @code{char (@var{fun})} is equivalent to\n\
00843 @code{formula (@var{fun})}.\n\
00844 @seealso{argnames, inline, vectorize}\n\
00845 @end deftypefn")
00846 {
00847   octave_value retval;
00848 
00849   int nargin = args.length ();
00850 
00851   if (nargin == 1)
00852     {
00853       octave_fcn_inline* fn = args(0).fcn_inline_value (true);
00854 
00855       if (fn)
00856         retval = octave_value (fn->fcn_text ());
00857       else
00858         error ("formula: FUN must be an inline function");
00859     }
00860   else
00861     print_usage ();
00862 
00863   return retval;
00864 }
00865 
00866 /*
00867 %!assert (formula (fn), "x.^2 + 1")
00868 %!assert (formula (fn), char (fn))
00869 
00870 %% Test input validation
00871 %!error formula ()
00872 %!error formula (1, 2)
00873 %!error <FUN must be an inline function> formula (1)
00874 */
00875 
00876 DEFUN (argnames, args, ,
00877   "-*- texinfo -*-\n\
00878 @deftypefn {Built-in Function} {} argnames (@var{fun})\n\
00879 Return a cell array of character strings containing the names of\n\
00880 the arguments of the inline function @var{fun}.\n\
00881 @seealso{inline, formula, vectorize}\n\
00882 @end deftypefn")
00883 {
00884   octave_value retval;
00885 
00886   int nargin = args.length ();
00887 
00888   if (nargin == 1)
00889     {
00890       octave_fcn_inline *fn = args(0).fcn_inline_value (true);
00891 
00892       if (fn)
00893         {
00894           string_vector t1 = fn->fcn_arg_names ();
00895 
00896           Cell t2 (dim_vector (t1.length (), 1));
00897 
00898           for (int i = 0; i < t1.length (); i++)
00899             t2(i) = t1(i);
00900 
00901           retval = t2;
00902         }
00903       else
00904         error ("argnames: FUN must be an inline function");
00905     }
00906   else
00907     print_usage ();
00908 
00909   return retval;
00910 }
00911 
00912 /*
00913 %!assert (argnames (fn), {"x"})
00914 %!assert (argnames (inline ("1e-3*y + 2e4*z")), {"y"; "z"})
00915 %!assert (argnames (inline ("2", 2)), {"x"; "P1"; "P2"})
00916 
00917 %% Test input validation
00918 %!error argnames ()
00919 %!error argnames (1, 2)
00920 %!error <FUN must be an inline function> argnames (1)
00921 */
00922 
00923 DEFUN (vectorize, args, ,
00924   "-*- texinfo -*-\n\
00925 @deftypefn {Built-in Function} {} vectorize (@var{fun})\n\
00926 Create a vectorized version of the inline function @var{fun}\n\
00927 by replacing all occurrences of @code{*}, @code{/}, etc., with\n\
00928 @code{.*}, @code{./}, etc.\n\
00929 \n\
00930 This may be useful, for example, when using inline functions with\n\
00931 numerical integration or optimization where a vector-valued function\n\
00932 is expected.\n\
00933 \n\
00934 @example\n\
00935 @group\n\
00936 fcn = vectorize (inline (\"x^2 - 1\"))\n\
00937    @result{} fcn = f(x) = x.^2 - 1\n\
00938 quadv (fcn, 0, 3)\n\
00939    @result{} 6\n\
00940 @end group\n\
00941 @end example\n\
00942 @seealso{inline, formula, argnames}\n\
00943 @end deftypefn")
00944 {
00945   octave_value retval;
00946 
00947   int nargin = args.length ();
00948 
00949   if (nargin == 1)
00950     {
00951       std::string old_func;
00952       octave_fcn_inline* old = 0;
00953       bool func_is_string = true;
00954 
00955       if (args(0).is_string ())
00956         old_func = args(0).string_value ();
00957       else
00958         {
00959           old = args(0).fcn_inline_value (true);
00960           func_is_string = false;
00961 
00962           if (old)
00963             old_func = old->fcn_text ();
00964           else
00965             error ("vectorize: FUN must be a string or inline function");
00966         }
00967 
00968       if (! error_state)
00969         {
00970           std::string new_func;
00971           size_t i = 0;
00972 
00973           while (i < old_func.length ())
00974             {
00975               std::string t1 = old_func.substr (i, 1);
00976 
00977               if (t1 == "*" || t1 == "/" || t1 == "\\" || t1 == "^")
00978                 {
00979                   if (i && old_func.substr (i-1, 1) != ".")
00980                     new_func.append (".");
00981 
00982                   // Special case for ** operator.
00983                   if (t1 == "*" && i < (old_func.length () - 1)
00984                       && old_func.substr (i+1, 1) == "*")
00985                     {
00986                       new_func.append ("*");
00987                       i++;
00988                     }
00989                 }
00990               new_func.append (t1);
00991               i++;
00992             }
00993 
00994           if (func_is_string)
00995             retval = octave_value (new_func);
00996           else
00997             retval = octave_value (new octave_fcn_inline
00998                                    (new_func, old->fcn_arg_names ()));
00999         }
01000     }
01001   else
01002     print_usage ();
01003 
01004   return retval;
01005 }
01006 
01007 /*
01008 %!assert (char (vectorize (fn)), "x.^2 + 1")
01009 %!assert (char (vectorize (inline ("1e-3*y + 2e4*z"))), "1e-3.*y + 2e4.*z")
01010 %!assert (char (vectorize (inline ("2**x^5"))), "2.**x.^5")
01011 %!assert (vectorize ("x.^2 + 1"), "x.^2 + 1")
01012 %!assert (vectorize ("1e-3*y + 2e4*z"), "1e-3.*y + 2e4.*z")
01013 %!assert (vectorize ("2**x^5"), "2.**x.^5")
01014 
01015 %% Test input validation
01016 %!error vectorize ()
01017 %!error vectorize (1, 2)
01018 %!error <FUN must be a string or inline function> vectorize (1)
01019 */
01020 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines