src/ov-fcn-inline.cc
author Benjamin Lindner <lindnerb@users.sourceforge.net>
Wed Mar 18 15:23:14 2009 +0100 (2009-03-18)
changeset 7685 34b75a47e712
parent 7509 ad9e3e3293ba
permissions -rw-r--r--
fix leaving stray '\r' in stream when reading from CRLF data file
* * *
fix CRLF issues with text-mode reading in windows when loading ascii data
     1 /*
     2 
     3 Copyright (C) 2004, 2005, 2006, 2007 David Bateman
     4 
     5 This file is part of Octave.
     6 
     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.
    11 
    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
    15 for more details.
    16 
    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/>.
    20 
    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)
    24 
    25 */
    26 
    27 #ifdef HAVE_CONFIG_H
    28 #include <config.h>
    29 #endif
    30 
    31 #include <istream>
    32 #include <iostream>
    33 #include <sstream>
    34 #include <vector>
    35 
    36 #include "defun.h"
    37 #include "error.h"
    38 #include "gripes.h"
    39 #include "oct-map.h"
    40 #include "ov-base.h"
    41 #include "ov-fcn-inline.h"
    42 #include "pr-output.h"
    43 #include "variables.h"
    44 #include "parse.h"
    45 
    46 #include "byte-swap.h"
    47 #include "ls-oct-ascii.h"
    48 #include "ls-hdf5.h"
    49 #include "ls-utils.h"
    50 #include "ls-ascii-helper.h"
    51 
    52 DEFINE_OCTAVE_ALLOCATOR (octave_fcn_inline);
    53 
    54 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_fcn_inline,
    55 				     "inline function",
    56 				     "function_handle");
    57 
    58 octave_fcn_inline::octave_fcn_inline (const std::string& f,
    59 				      const string_vector& a,
    60 				      const std::string& n)
    61   : octave_fcn_handle (n), iftext (f), ifargs (a)
    62 {
    63   // Form a string representing the function.
    64 
    65   std::ostringstream buf;
    66 
    67   buf << "@(";
    68 
    69   for (int i = 0; i < ifargs.length (); i++)
    70     {
    71       if (i > 0)
    72 	buf << ", ";
    73 
    74       buf << ifargs(i);
    75     }
    76 
    77   buf << ") " << iftext;
    78 
    79   int parse_status;
    80   octave_value anon_fcn_handle = eval_string (buf.str (), true, parse_status);
    81 
    82   if (parse_status == 0)
    83     {
    84       octave_fcn_handle *fh = anon_fcn_handle.fcn_handle_value ();
    85 
    86       if (fh)
    87 	fcn = fh->fcn_val ();
    88     }
    89 
    90   if (fcn.is_undefined ())
    91     error ("inline: unable to define function");
    92 }
    93 
    94 // This function is supplied to allow a Matlab style class structure
    95 // to be returned..
    96 Octave_map
    97 octave_fcn_inline::map_value (void) const
    98 {
    99   Octave_map m;
   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 ()));
   110 
   111   return m;
   112 }
   113 
   114 bool
   115 octave_fcn_inline::save_ascii (std::ostream& os)
   116 {
   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.
   122     os << "0\n";
   123   else
   124     os << nm << "\n";
   125   os << iftext << "\n";
   126   return true;
   127 }
   128 
   129 bool
   130 octave_fcn_inline::load_ascii (std::istream& is)
   131 {
   132   int nargs;
   133   if (extract_keyword (is, "nargs", nargs, true))
   134     {
   135       ifargs.resize (nargs);
   136       for (int i = 0; i < nargs; i++)
   137 	is >> ifargs(i);
   138       is >> nm;
   139       if (nm == "0")
   140 	nm = "";
   141 
   142       char c;
   143       std::string buf;
   144 
   145       // Skip preceeding newline(s)
   146       skip_preceeding_newline (is);
   147 
   148       if (is)
   149 	{
   150 
   151 	  // Get a line of text whitespace characters included, leaving
   152 	  // newline in the stream
   153 	  buf = read_until_newline (is, true);
   154 	}
   155 
   156       iftext = buf;
   157 
   158       octave_fcn_inline tmp (iftext, ifargs, nm);
   159       fcn = tmp.fcn;
   160 
   161       return true;
   162     }
   163   else
   164     return false;
   165 }
   166 
   167 bool
   168 octave_fcn_inline::save_binary (std::ostream& os, bool&)
   169 {
   170   int32_t tmp = ifargs.length ();
   171   os.write (reinterpret_cast<char *> (&tmp), 4);
   172   for (int i = 0; i < ifargs.length (); i++)
   173     {
   174       tmp = ifargs(i).length ();
   175       os.write (reinterpret_cast<char *> (&tmp), 4);
   176       os.write (ifargs(i).c_str (), ifargs(i).length ());
   177     }
   178   tmp = nm.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 ());
   184   return true;
   185 }
   186 
   187 bool
   188 octave_fcn_inline::load_binary (std::istream& is, bool swap,
   189 				oct_mach_info::float_format)
   190 {
   191   int32_t nargs;
   192   if (! is.read (reinterpret_cast<char *> (&nargs), 4))
   193     return false;
   194   if (swap)
   195     swap_bytes<4> (&nargs);
   196 
   197   if (nargs < 1)
   198     return false;
   199   else
   200     {
   201       int32_t tmp;
   202       ifargs.resize (nargs);
   203       for (int i = 0; i < nargs; i++)
   204 	{
   205 	  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
   206 	    return false;
   207 	  if (swap)
   208 	    swap_bytes<4> (&tmp);
   209 
   210 	  OCTAVE_LOCAL_BUFFER (char, ctmp, tmp+1);
   211 	  is.read (ctmp, tmp);
   212 	  ifargs(i) = std::string (ctmp);
   213 
   214 	  if (! is)
   215 	    return false;
   216 	}
   217 
   218       if (! is.read (reinterpret_cast<char *> (&tmp), 4))
   219 	return false;
   220       if (swap)
   221 	swap_bytes<4> (&tmp);
   222 
   223       OCTAVE_LOCAL_BUFFER (char, ctmp1, tmp+1);
   224       is.read (ctmp1, tmp);
   225       nm = std::string (ctmp1);
   226 
   227       if (! is)
   228 	return false;
   229 
   230       if (! is.read (reinterpret_cast<char *> (&tmp), 4))
   231 	return false;
   232       if (swap)
   233 	swap_bytes<4> (&tmp);
   234 
   235       OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
   236       is.read (ctmp2, tmp);
   237       iftext = std::string (ctmp2);
   238 
   239       if (! is)
   240 	return false;
   241 
   242       octave_fcn_inline ftmp (iftext, ifargs, nm);
   243       fcn = ftmp.fcn;
   244     }
   245   return true;
   246 }
   247 
   248 #if defined (HAVE_HDF5)
   249 bool
   250 octave_fcn_inline::save_hdf5 (hid_t loc_id, const char *name,
   251 			      bool /* save_as_floats */)
   252 {
   253   hid_t group_hid = -1;
   254   group_hid = H5Gcreate (loc_id, name, 0);
   255   if (group_hid < 0 ) return false;
   256 
   257   size_t len = 0;
   258   for (int i = 0; i < ifargs.length (); i++)
   259     if (len < ifargs(i).length ())
   260       len = ifargs(i).length ();
   261 
   262   hid_t space_hid = -1, data_hid = -1, type_hid = -1;;
   263   bool retval = true;
   264 
   265   // FIXME Is there a better way of saving string vectors, than a
   266   // null padded matrix?
   267 
   268   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
   269 
   270   // Octave uses column-major, while HDF5 uses row-major ordering
   271   hdims[1] = ifargs.length ();
   272   hdims[0] = len + 1;
   273 
   274   space_hid = H5Screate_simple (2, hdims, 0);
   275   if (space_hid < 0)
   276     {
   277       H5Gclose (group_hid);
   278       return false;
   279     }
   280 
   281   data_hid = H5Dcreate (group_hid, "args", H5T_NATIVE_CHAR, space_hid,
   282 			H5P_DEFAULT);
   283   if (data_hid < 0)
   284     {
   285       H5Sclose (space_hid);
   286       H5Gclose (group_hid);
   287       return false;
   288     }
   289 
   290   OCTAVE_LOCAL_BUFFER (char, s, ifargs.length () * (len + 1));
   291 
   292   // Save the args as a null teminated list
   293   for (int i = 0; i < ifargs.length (); i++)
   294     {
   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';
   299     }
   300 
   301   retval = H5Dwrite (data_hid, H5T_NATIVE_CHAR, H5S_ALL, H5S_ALL,
   302 		     H5P_DEFAULT, s) >= 0;
   303 
   304   H5Dclose (data_hid);
   305   H5Sclose (space_hid);
   306 
   307   if (!retval)
   308     {
   309       H5Gclose (group_hid);
   310       return false;
   311     }
   312 
   313   // attach the type of the variable
   314   type_hid = H5Tcopy (H5T_C_S1);
   315   H5Tset_size (type_hid, nm.length () + 1);
   316   if (type_hid < 0)
   317     {
   318       H5Gclose (group_hid);
   319       return false;
   320     }
   321 
   322   hdims[0] = 0;
   323   space_hid = H5Screate_simple (0 , hdims, 0);
   324   if (space_hid < 0)
   325     {
   326       H5Tclose (type_hid);
   327       H5Gclose (group_hid);
   328       return false;
   329     }
   330 
   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)
   334     {
   335       H5Sclose (space_hid);
   336       H5Tclose (type_hid);
   337       H5Gclose (group_hid);
   338       return false;
   339     }
   340   H5Dclose (data_hid);
   341 
   342   // attach the type of the variable
   343   H5Tset_size (type_hid, iftext.length () + 1);
   344   if (type_hid < 0)
   345     {
   346       H5Gclose (group_hid);
   347       return false;
   348     }
   349 
   350   data_hid = H5Dcreate (group_hid, "iftext",  type_hid, space_hid,
   351 			H5P_DEFAULT);
   352   if (data_hid < 0 || H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL,
   353 				H5P_DEFAULT, iftext.c_str ()) < 0)
   354     {
   355       H5Sclose (space_hid);
   356       H5Tclose (type_hid);
   357       H5Gclose (group_hid);
   358       return false;
   359     }
   360 
   361   H5Dclose (data_hid);
   362   H5Sclose (space_hid);
   363   H5Tclose (type_hid);
   364   H5Gclose (group_hid);
   365 
   366   return retval;
   367 }
   368 
   369 bool
   370 octave_fcn_inline::load_hdf5 (hid_t loc_id, const char *name,
   371 			      bool /* have_h5giterate_bug */)
   372 {
   373   hid_t group_hid, data_hid, space_hid, type_hid, type_class_hid, st_id;
   374   hsize_t rank;
   375   int slen;
   376 
   377   group_hid = H5Gopen (loc_id, name);
   378   if (group_hid < 0 ) return false;
   379 
   380   data_hid = H5Dopen (group_hid, "args");
   381   space_hid = H5Dget_space (data_hid);
   382   rank = H5Sget_simple_extent_ndims (space_hid);
   383 
   384   if (rank != 2)
   385     {
   386       H5Dclose (data_hid);
   387       H5Sclose (space_hid);
   388       H5Gclose (group_hid);
   389       return false;
   390     }
   391 
   392   OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
   393   OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
   394 
   395   H5Sget_simple_extent_dims (space_hid, hdims, maxdims);
   396 
   397   ifargs.resize (hdims[1]);
   398 
   399   OCTAVE_LOCAL_BUFFER (char, s1, hdims[0] * hdims[1]);
   400 
   401   if (H5Dread (data_hid, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL,
   402 	       H5P_DEFAULT, s1) < 0)
   403     {
   404       H5Dclose (data_hid);
   405       H5Sclose (space_hid);
   406       H5Gclose (group_hid);
   407       return false;
   408     }
   409 
   410   H5Dclose (data_hid);
   411   H5Sclose (space_hid);
   412 
   413   for (size_t i = 0; i < hdims[1]; i++)
   414     ifargs(i) = std::string (s1 + i*hdims[0]);
   415 
   416   data_hid = H5Dopen (group_hid, "nm");
   417 
   418   if (data_hid < 0)
   419     {
   420       H5Gclose (group_hid);
   421       return false;
   422     }
   423 
   424   type_hid = H5Dget_type (data_hid);
   425   type_class_hid = H5Tget_class (type_hid);
   426 
   427   if (type_class_hid != H5T_STRING)
   428     {
   429       H5Tclose (type_hid);
   430       H5Dclose (data_hid);
   431       H5Gclose (group_hid);
   432       return false;
   433     }
   434 
   435   space_hid = H5Dget_space (data_hid);
   436   rank = H5Sget_simple_extent_ndims (space_hid);
   437 
   438   if (rank != 0)
   439     {
   440       H5Sclose (space_hid);
   441       H5Tclose (type_hid);
   442       H5Dclose (data_hid);
   443       H5Gclose (group_hid);
   444       return false;
   445     }
   446 
   447   slen = H5Tget_size (type_hid);
   448   if (slen < 0)
   449     {
   450       H5Sclose (space_hid);
   451       H5Tclose (type_hid);
   452       H5Dclose (data_hid);
   453       H5Gclose (group_hid);
   454       return false;
   455     }
   456 
   457   OCTAVE_LOCAL_BUFFER (char, nm_tmp, slen);
   458 
   459   // create datatype for (null-terminated) string to read into:
   460   st_id = H5Tcopy (H5T_C_S1);
   461   H5Tset_size (st_id, slen);
   462 
   463   if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, nm_tmp) < 0)
   464     {
   465       H5Sclose (space_hid);
   466       H5Tclose (type_hid);
   467       H5Gclose (group_hid);
   468       return false;
   469     }
   470   H5Tclose (st_id);
   471   H5Dclose (data_hid);
   472   nm = nm_tmp;
   473 
   474   data_hid = H5Dopen (group_hid, "iftext");
   475 
   476   if (data_hid < 0)
   477     {
   478       H5Gclose (group_hid);
   479       return false;
   480     }
   481 
   482   type_hid = H5Dget_type (data_hid);
   483   type_class_hid = H5Tget_class (type_hid);
   484 
   485   if (type_class_hid != H5T_STRING)
   486     {
   487       H5Tclose (type_hid);
   488       H5Dclose (data_hid);
   489       H5Gclose (group_hid);
   490       return false;
   491     }
   492 
   493   space_hid = H5Dget_space (data_hid);
   494   rank = H5Sget_simple_extent_ndims (space_hid);
   495 
   496   if (rank != 0)
   497     {
   498       H5Sclose (space_hid);
   499       H5Tclose (type_hid);
   500       H5Dclose (data_hid);
   501       H5Gclose (group_hid);
   502       return false;
   503     }
   504 
   505   slen = H5Tget_size (type_hid);
   506   if (slen < 0)
   507     {
   508       H5Sclose (space_hid);
   509       H5Tclose (type_hid);
   510       H5Dclose (data_hid);
   511       H5Gclose (group_hid);
   512       return false;
   513     }
   514 
   515   OCTAVE_LOCAL_BUFFER (char, iftext_tmp, slen);
   516 
   517   // create datatype for (null-terminated) string to read into:
   518   st_id = H5Tcopy (H5T_C_S1);
   519   H5Tset_size (st_id, slen);
   520 
   521   if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, iftext_tmp) < 0)
   522     {
   523       H5Sclose (space_hid);
   524       H5Tclose (type_hid);
   525       H5Gclose (group_hid);
   526       return false;
   527     }
   528   H5Tclose (st_id);
   529   H5Dclose (data_hid);
   530   iftext = iftext_tmp;
   531 
   532   octave_fcn_inline ftmp (iftext, ifargs, nm);
   533   fcn = ftmp.fcn;
   534 
   535   return true;
   536 }
   537 #endif
   538 
   539 void
   540 octave_fcn_inline::print (std::ostream& os, bool pr_as_read_syntax) const
   541 {
   542   print_raw (os, pr_as_read_syntax);
   543   newline (os);
   544 }
   545 
   546 void
   547 octave_fcn_inline::print_raw (std::ostream& os, bool pr_as_read_syntax) const
   548 {
   549   std::ostringstream buf;
   550 
   551   if (nm.empty ())
   552     buf << "f(";
   553   else
   554     buf << nm << "(";
   555 
   556   for (int i = 0; i < ifargs.length (); i++)
   557     {
   558       if (i)
   559 	buf << ", ";
   560 
   561       buf << ifargs(i);
   562     }
   563 
   564   buf << ") = " << iftext;
   565 
   566   octave_print_internal (os, buf.str (), pr_as_read_syntax,
   567 			 current_print_indent_level ());
   568 }
   569 
   570 octave_value
   571 octave_fcn_inline::convert_to_str_internal (bool, bool, char type) const
   572 {
   573   return octave_value (fcn_text (), type);
   574 }
   575 
   576 DEFUNX ("inline", Finline, args, ,
   577   "-*- texinfo -*-\n\
   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\
   588 to be functions.\n\
   589 \n\
   590 If the second and subsequent arguments are character strings,\n\
   591 they are the names of the arguments of the function.\n\
   592 \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\
   596 @end deftypefn")
   597 {
   598   octave_value retval;
   599 
   600   int nargin = args.length ();
   601 
   602   if (nargin > 0)
   603     {
   604       std::string fun = args(0).string_value ();
   605 
   606       if (! error_state)
   607 	{
   608 	  string_vector fargs;
   609 
   610 	  if (nargin == 1)
   611 	    {
   612 	      bool is_arg = false;
   613 	      bool in_string = false;
   614 	      std::string tmp_arg;
   615 	      size_t i = 0;
   616 	      
   617 	      while (i < fun.length ())
   618 		{
   619 		  bool terminate_arg = false;
   620 		  char c = fun[i++];
   621 
   622 		  if (in_string)
   623 		    {
   624 		      if (c == '\'' || c == '\"')
   625 			in_string = false;
   626 		    }
   627 		  else if (c == '\'' || c == '\"')
   628 		    {
   629 		      in_string = true;
   630 		      if (is_arg)
   631 			terminate_arg = true;
   632 		    }
   633 		  else if (! isalpha (c) && c != '_')
   634 		    if (! is_arg)
   635 		      continue;
   636 		    else if (isdigit (c))
   637 		      tmp_arg.append (1, c);
   638 		    else
   639 		      {
   640 			// Before we do anything remove trailing whitespaces.
   641 			while (i < fun.length () && isspace (c))
   642 			  c = fun[i++];
   643 			
   644 			// Do we have a variable or a function?
   645 			if (c != '(')
   646 			  terminate_arg = true;
   647 			else
   648 			  {
   649 			    tmp_arg = std::string ();
   650 			    is_arg = false;
   651 			  }
   652 		      }
   653 		  else
   654 		    {
   655 		      tmp_arg.append (1, c);
   656 		      is_arg = true;
   657 		    }
   658 
   659 		  if (terminate_arg || (i == fun.length () && is_arg))
   660 		    {
   661 		      bool have_arg = false;
   662 		      
   663 		      for (int j = 0; j < fargs.length (); j++)
   664 			if (tmp_arg == fargs (j))
   665 			  {
   666 			    have_arg = true;
   667 			    break;
   668 			  }
   669 			  
   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" &&
   674 			  tmp_arg != "eps")
   675 			fargs.append (tmp_arg);
   676 
   677 		      tmp_arg = std::string ();
   678 		      is_arg = false;
   679 		    }
   680 		}
   681 
   682 	      // Sort the arguments into ascii order.
   683 	      fargs.qsort ();
   684 	    }
   685 	  else if (nargin == 2 && args(1).is_numeric_type ())
   686 	    {
   687 	      int n = args(1).int_value ();
   688 
   689 	      if (! error_state)
   690 		{
   691 		  if (n >= 0)
   692 		    {
   693 		      fargs.resize (n+1);
   694 
   695 		      fargs(0) = "x";
   696 
   697 		      for (int i = 1; i < n+1; i++)
   698 			{
   699 			  std::ostringstream buf;
   700 			  buf << "P" << i;
   701 			  fargs(i) = buf.str ();
   702 			}
   703 		    }
   704 		  else
   705 		    {
   706 		      error ("inline: numeric argument must be nonnegative");
   707 		      return retval;
   708 		    }
   709 		}
   710 	      else
   711 		{
   712 		  error ("inline: expecting second argument to be an integer");
   713 		  return retval;
   714 		}
   715 	    }
   716 	  else
   717 	    {
   718 	      fargs.resize (nargin - 1);
   719 
   720 	      for (int i = 1; i < nargin; i++)
   721 		{
   722 		  std::string s = args(i).string_value ();
   723 
   724 		  if (! error_state)
   725 		    fargs(i-1) = s;
   726 		  else
   727 		    {
   728 		      error ("inline: expecting string arguments");
   729 		      return retval;
   730 		    }
   731 		}
   732 	    }
   733 
   734 	  retval = octave_value (new octave_fcn_inline (fun, fargs));
   735 	}
   736       else
   737 	error ("inline: first argument must be a string");
   738     }
   739   else
   740     print_usage ();
   741 
   742   return retval;
   743 }
   744 
   745 DEFUN (formula, args, ,
   746   "-*- texinfo -*-\n\
   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\
   752 @end deftypefn")
   753 {
   754   octave_value retval;
   755 
   756   int nargin = args.length ();
   757 
   758   if (nargin == 1)
   759     {
   760       octave_fcn_inline* fn = args(0).fcn_inline_value (true);
   761 
   762       if (fn)
   763 	retval = octave_value (fn->fcn_text ());
   764       else
   765 	error ("formula: must be an inline function");
   766     }
   767   else
   768     print_usage ();
   769 
   770   return retval;
   771 }
   772 
   773 DEFUN (argnames, args, ,
   774   "-*- texinfo -*-\n\
   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\
   779 @end deftypefn")
   780 {
   781   octave_value retval;
   782 
   783   int nargin = args.length ();
   784 
   785   if (nargin == 1)
   786     {
   787       octave_fcn_inline *fn = args(0).fcn_inline_value (true);
   788 
   789       if (fn)
   790 	{
   791 	  string_vector t1 = fn->fcn_arg_names ();
   792 
   793 	  Cell t2 (dim_vector (t1.length (), 1));
   794 
   795 	  for (int i = 0; i < t1.length (); i++)
   796 	    t2(i) = t1(i);
   797 
   798 	  retval = t2;
   799 	}
   800       else
   801 	error ("argnames: argument must be an inline function");
   802     }
   803   else
   804     print_usage ();
   805 
   806   return retval;
   807 }
   808 
   809 DEFUN (vectorize, args, ,
   810   "-*- texinfo -*-\n\
   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\
   815 @end deftypefn")
   816 {
   817   octave_value retval;
   818 
   819   int nargin = args.length ();
   820 
   821   if (nargin == 1)
   822     {
   823       std::string old_func;
   824       octave_fcn_inline* old = 0;
   825       bool func_is_string = true;
   826 
   827       if (args(0).is_string ())
   828 	old_func = args(0).string_value ();
   829       else
   830 	{
   831 	  old = args(0).fcn_inline_value (true);
   832 	  func_is_string = false;
   833 
   834 	  if (old)
   835 	    old_func = old->fcn_text ();
   836 	  else
   837 	    error ("vectorize: must be a string or inline function");
   838 	}
   839 
   840       if (! error_state)
   841 	{
   842 	  std::string new_func;
   843 	  size_t i = 0;
   844 
   845 	  while (i < old_func.length ())
   846 	    {
   847 	      std::string t1 = old_func.substr (i, 1);
   848 
   849 	      if (t1 == "*" || t1 == "/" || t1 == "\\" || t1 == "^")
   850 		{
   851 		  if (i && old_func.substr (i-1, 1) != ".")
   852 		    new_func.append (".");
   853 
   854 		  // Special case for ** operator.
   855 		  if (t1 == "*" && i < (old_func.length () - 1)
   856 		      && old_func.substr (i+1, 1) == "*")
   857 		    {
   858 		      new_func.append ("*");
   859 		      i++;
   860 		    }
   861 		}
   862 	      new_func.append (t1);
   863 	      i++;
   864 	    }
   865 
   866 	  if (func_is_string)
   867 	    retval = octave_value (new_func);
   868 	  else
   869 	    retval = octave_value (new octave_fcn_inline 
   870 				   (new_func, old->fcn_arg_names ()));
   871 	}
   872     }
   873   else
   874     print_usage ();
   875 
   876   return retval;
   877 }
   878 
   879 /*
   880 ;;; Local Variables: ***
   881 ;;; mode: C++ ***
   882 ;;; End: ***
   883 */