changeset 5476:941f0fc6b596

[project @ 2005-09-29 22:46:07 by jwe]
author jwe
date Thu, 29 Sep 2005 22:49:43 +0000
parents 04fa51cb7e90
children 9e59c91ddc99
files liboctave/ChangeLog liboctave/file-ops.cc liboctave/file-ops.h liboctave/file-stat.cc liboctave/file-stat.h scripts/ChangeLog scripts/miscellaneous/single.m src/ChangeLog src/data.cc src/dirfns.cc src/oct-stream.cc src/ov-type-conv.h src/syscalls.cc test/octave.test/string/split-4.m
diffstat 14 files changed, 581 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,17 @@
+2005-09-29  John W. Eaton  <jwe@octave.org>
+
+	* file-stat.h (file_stat::mode): New function.
+
+	* file-stat.cc (file_stat::is_blk, file_stat::is_chr,
+	file_stat::is_dir, file_stat::is_fifo, file_stat::is_lnk,
+	file_stat::is_reg, file_stat::is_sock): New static functions.
+	* file-stat.h: Provide decls.
+
+2005-09-28  John W. Eaton  <jwe@octave.org>
+
+	* file-ops.cc (file_ops::recursive_rmdir): New function.
+	* file-ops.h: Provide decl.
+
 2005-09-19  David Bateman  <dbateman@free.fr>
 
 	* oct-env.cc (octave_env::do_get_home_directory):
--- a/liboctave/file-ops.cc
+++ b/liboctave/file-ops.cc
@@ -41,10 +41,13 @@
 #include <unistd.h>
 #endif
 
+#include "dir-ops.h"
 #include "file-ops.h"
+#include "file-stat.h"
 #include "oct-env.h"
 #include "oct-passwd.h"
 #include "pathlen.h"
+#include "quit.h"
 #include "statdefs.h"
 #include "str-vec.h"
 
@@ -312,6 +315,80 @@
   return status;
 }
 
+// And a version that works recursively.
+
+int
+file_ops::recursive_rmdir (const std::string& name)
+{
+  std::string msg;
+  return recursive_rmdir (name, msg);
+}
+
+int
+file_ops::recursive_rmdir (const std::string& name, std::string& msg)
+{
+  msg = std::string ();
+
+  int status = 0;
+
+  dir_entry dir (name);
+
+  if (dir)
+    {
+      string_vector dirlist = dir.read ();
+
+      for (octave_idx_type i = 0; i < dirlist.length (); i++)
+	{
+	  OCTAVE_QUIT;
+
+	  std::string nm = dirlist[i];
+
+	  // Skip current directory and parent.
+	  if (nm == "." || nm == "..")
+	    continue;
+
+	  std::string fullnm = name + file_ops::dir_sep_str + nm;
+
+	  // Get info about the file.  Don't follow links.
+	  file_stat fs (fullnm, false);
+
+	  if (fs)
+	    {
+	      if (fs.is_dir ())
+		{
+		  status = recursive_rmdir (fullnm, msg);
+
+		  if (status < 0)
+		    break;
+		}
+	      else
+		{
+		  status = unlink (fullnm, msg);
+
+		  if (status < 0)
+		    break;
+		}
+	    }
+	  else
+	    {
+	      msg = fs.error ();
+	      break;
+	    }
+	}
+
+      if (status >= 0)
+	status = file_ops::rmdir (name, msg);
+    }
+  else
+    {
+      status = -1;
+
+      msg = dir.error ();
+    }
+
+  return status;
+}
+
 std::string
 file_ops::canonicalize_file_name (const std::string& name)
 {
--- a/liboctave/file-ops.h
+++ b/liboctave/file-ops.h
@@ -56,6 +56,9 @@
   static int rmdir (const std::string&);
   static int rmdir (const std::string&, std::string&);
 
+  static int recursive_rmdir (const std::string&);
+  static int recursive_rmdir (const std::string&, std::string&);
+
   static std::string canonicalize_file_name (const std::string&);
   static std::string canonicalize_file_name (const std::string&, std::string&);
 
--- a/liboctave/file-stat.cc
+++ b/liboctave/file-stat.cc
@@ -53,68 +53,110 @@
 bool
 file_stat::is_blk (void) const
 {
-#ifdef S_ISBLK
-  return S_ISBLK (fs_mode);
-#else
-  return false;
-#endif
+  return is_blk (fs_mode);
 }
 
 bool
 file_stat::is_chr (void) const
 {
-#ifdef S_ISCHR
-  return S_ISCHR (fs_mode);
-#else
-  return false;
-#endif
+  return is_chr (fs_mode);
 }
 
 bool
 file_stat::is_dir (void) const
 { 
-#ifdef S_ISDIR
-  return S_ISDIR (fs_mode);
+  return is_dir (fs_mode);
+}
+
+bool
+file_stat::is_fifo (void) const
+{ 
+  return is_fifo (fs_mode);
+}
+
+bool
+file_stat::is_lnk (void) const
+{ 
+  return is_lnk (fs_mode);
+}
+
+bool
+file_stat::is_reg (void) const
+{ 
+  return is_reg (fs_mode);
+}
+
+bool
+file_stat::is_sock (void) const
+{ 
+  return is_sock (fs_mode);
+}
+
+bool
+file_stat::is_blk (mode_t mode)
+{
+#ifdef S_ISBLK
+  return S_ISBLK (mode);
 #else
   return false;
 #endif
 }
 
 bool
-file_stat::is_fifo (void) const
+file_stat::is_chr (mode_t mode)
+{
+#ifdef S_ISCHR
+  return S_ISCHR (mode);
+#else
+  return false;
+#endif
+}
+
+bool
+file_stat::is_dir (mode_t mode)
 { 
-#ifdef S_ISFIFO
-  return S_ISFIFO (fs_mode);
+#ifdef S_ISDIR
+  return S_ISDIR (mode);
 #else
   return false;
 #endif
 }
 
 bool
-file_stat::is_lnk (void) const
+file_stat::is_fifo (mode_t mode)
 { 
-#ifdef S_ISLNK
-  return S_ISLNK (fs_mode);
+#ifdef S_ISFIFO
+  return S_ISFIFO (mode);
 #else
   return false;
 #endif
 }
 
 bool
-file_stat::is_reg (void) const
+file_stat::is_lnk (mode_t mode)
 { 
-#ifdef S_ISREG
-  return S_ISREG (fs_mode);
+#ifdef S_ISLNK
+  return S_ISLNK (mode);
 #else
   return false;
 #endif
 }
 
 bool
-file_stat::is_sock (void) const
+file_stat::is_reg (mode_t mode)
+{ 
+#ifdef S_ISREG
+  return S_ISREG (mode);
+#else
+  return false;
+#endif
+}
+
+bool
+file_stat::is_sock (mode_t mode)
 { 
 #ifdef S_ISSOCK
-  return S_ISSOCK (fs_mode);
+  return S_ISSOCK (mode);
 #else
   return false;
 #endif
--- a/liboctave/file-stat.h
+++ b/liboctave/file-stat.h
@@ -85,6 +85,14 @@
   bool is_reg (void) const;
   bool is_sock (void) const;
 
+  static bool is_blk (mode_t mode);
+  static bool is_chr (mode_t mode);
+  static bool is_dir (mode_t mode);
+  static bool is_fifo (mode_t mode);
+  static bool is_lnk (mode_t mode);
+  static bool is_reg (mode_t mode);
+  static bool is_sock (mode_t mode);
+
   ino_t ino (void) const { return fs_ino; }
   dev_t dev (void) const { return fs_dev; }
 
@@ -111,6 +119,8 @@
   long blocks (void) const { return fs_blocks; }
 #endif
 
+  mode_t mode (void) const { return fs_mode; }
+
   std::string mode_as_string (void) const;
 
   bool ok (void) const { return initialized && ! fail; }
--- a/scripts/ChangeLog
+++ b/scripts/ChangeLog
@@ -1,5 +1,7 @@
 2005-09-28  John W. Eaton  <jwe@octave.org>
 
+	* miscellaneous/single.m: New function.
+
 	* statistics/base/unidrnd.m: New function.
 
 2005-09-27  John W. Eaton  <jwe@octave.org>
new file mode 100644
--- /dev/null
+++ b/scripts/miscellaneous/single.m
@@ -0,0 +1,37 @@
+## Copyright (C) 2005 John W. Eaton
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, write to the Free
+## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+## 02110-1301, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} single (@var{val})
+## Convert the numeric value @var{val} to single precision.
+##
+## @strong{Note}: this function currently returns its argument unchanged
+## because Octave does not yet have a single-precision numeric data
+## type.
+## @end deftypefn
+
+function retval = single (val)
+
+  if (nargin == 1 && isnumeric (val))
+    retval = val;
+  else
+    usage ("single (val)");
+  endif
+
+endfunction
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,24 @@
+2005-09-29  John W. Eaton  <jwe@octave.org>
+
+	* syscalls.cc (mk_stat_map): Store mode too.
+	(FS_ISREG, FS_ISDIR, FS_ISCHR, FS_ISBLK, FS_ISFIFO, FS_ISLNK,
+	FS_ISSOCK): New functions.
+	(Fstat): Fix docstring.
+
+2005-09-28  John W. Eaton  <jwe@octave.org>
+
+	* oct-stream.cc (printf_value_cache::double_value): Force
+	character strings to be converted to ASCII equivalents.
+
+	* data.cc (Fcomplex): New function.
+
+	* ov-type-conv.h (OCTAVE_TYPE_CONV_BODY3): Return arg unchanged if
+	class name is same as name of conversion.
+
+	* dirfns.cc (Frmdir, Fmkdir): For compatibility, return true for
+	success and false for failure.  Return third value, msgid.
+	(Frmdir): Handle second arg for recursive behavior.
+
 2005-09-23  John W. Eaton  <jwe@octave.org>
 
 	* parse.y (load_fcn_from_file): Don't look in path if file is
--- a/src/data.cc
+++ b/src/data.cc
@@ -38,6 +38,8 @@
 #include "error.h"
 #include "gripes.h"
 #include "ov.h"
+#include "ov-complex.h"
+#include "ov-cx-mat.h"
 #include "variables.h"
 #include "oct-obj.h"
 #include "utils.h"
@@ -1149,6 +1151,127 @@
   return retval;
 }
 
+// XXX FIXME XXX -- perhaps this should be implemented with an
+// octave_value member function?
+
+DEFUN (complex, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} complex (@var{val})\n\
+@deftypefnx {Built-in Function} {} complex (@var{re}, @var{im})\n\
+Convert @var{x} to a complex value.\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1)
+    {
+      octave_value arg = args(0);
+
+      if (arg.is_complex_type ())
+	retval = arg;
+      else
+	{
+	  if (arg.numel () == 1)
+	    {
+	      Complex val = arg.complex_value ();
+
+	      if (! error_state)
+		retval = octave_value (new octave_complex (val));
+	    }
+	  else
+	    {
+	      ComplexNDArray val = arg.complex_array_value ();
+
+	      if (! error_state)
+		retval = octave_value (new octave_complex_matrix (val));
+	    }
+
+	  if (error_state)
+	    error ("complex: invalid conversion");
+	}
+    }
+  else if (nargin == 2)
+    {
+      octave_value re = args(0);
+      octave_value im = args(1);
+
+      if (re.numel () == 1)
+	{
+	  double re_val = re.double_value ();
+
+	  if (im.numel () == 1)
+	    {
+	      double im_val = im.double_value ();
+
+	      if (! error_state)
+		retval = octave_value (new octave_complex (Complex (re_val, im_val)));
+	    }
+	  else
+	    {
+	      const NDArray im_val = im.array_value ();
+
+	      if (! error_state)
+		{
+		  ComplexNDArray result (im_val.dims (), Complex ());
+
+		  for (octave_idx_type i = 0; i < im_val.numel (); i++)
+		    result.xelem (i) = Complex (re_val, im_val(i));
+
+		  retval = octave_value (new octave_complex_matrix (result));
+		}
+	    }
+	}
+      else
+	{
+	  const NDArray re_val = re.array_value ();
+
+	  if (im.numel () == 1)
+	    {
+	      double im_val = im.double_value ();
+
+	      if (! error_state)
+		{
+		  ComplexNDArray result (re_val.dims (), Complex ());
+
+		  for (octave_idx_type i = 0; i < re_val.numel (); i++)
+		    result.xelem (i) = Complex (re_val(i), im_val);
+
+		  retval = octave_value (new octave_complex_matrix (result));
+		}
+	    }
+	  else
+	    {
+	      const NDArray im_val = im.array_value ();
+
+	      if (! error_state)
+		{
+		  if (re_val.dims () == im_val.dims ())
+		    {
+		      ComplexNDArray result (re_val.dims (), Complex ());
+
+		      for (octave_idx_type i = 0; i < re_val.numel (); i++)
+			result.xelem (i) = Complex (re_val(i), im_val(i));
+
+		      retval = octave_value (new octave_complex_matrix (result));
+		    }
+		  else
+		    error ("complex: dimension mismatch");
+		}
+	    }
+	}
+
+      if (error_state)
+	error ("complex: invalid conversion");
+    }
+  else
+    print_usage ("complex");
+
+  return retval;
+}
+
+
 DEFUN (isreal, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} isreal (@var{x})\n\
--- a/src/dirfns.cc
+++ b/src/dirfns.cc
@@ -284,23 +284,25 @@
   return retval;
 }
 
-// XXX FIXME XXX -- should probably also allow second arg to specify
-// mode.
+// XXX FIXME XXX -- should maybe also allow second arg to specify
+// mode?  OTOH, that might cause trouble with compatibility later...
 
 DEFUN (mkdir, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} mkdir (@var{dir})\n\
+@deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} mkdir (@var{dir})\n\
 Create a directory named @var{dir}.\n\
 \n\
-If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
-Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
-system-dependent error message.\n\
+If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
+character strings.  Otherwise, @var{status} is 0, @var{msg} contains a\n\
+system-dependent error message, and @var{msgid} contains a unique\n\
+message identifier.\n\
 @end deftypefn")
 {
   octave_value_list retval;
 
+  retval(2) = std::string ();
   retval(1) = std::string ();
-  retval(0) = -1.0;
+  retval(0) = false;
 
   if (args.length () == 1)
     {
@@ -315,10 +317,13 @@
 	  int status = file_ops::mkdir (file_ops::tilde_expand (dirname),
 					0777, msg);
 
-	  retval(0) = status;
-
 	  if (status < 0)
-	    retval(1) = msg;
+	    {
+	      retval(2) = "mkdir";
+	      retval(1) = msg;
+	    }
+	  else
+	    retval(0) = true;
 	}
     }
   else
@@ -329,20 +334,28 @@
 
 DEFUN (rmdir, args, ,
   "-*- texinfo -*-\n\
-@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} rmdir (@var{dir})\n\
+@deftypefn {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir})\n\
+@deftypefnx {Built-in Function} {[@var{status}, @var{msg}, @var{msgid}] =} rmdir (@var{dir}, @code{\"s\"})\n\
 Remove the directory named @var{dir}.\n\
 \n\
-If successful, @var{err} is 0 and @var{msg} is an empty string.\n\
-Otherwise, @var{err} is nonzero and @var{msg} contains a\n\
-system-dependent error message.\n\
+If successful, @var{status} is 1, with @var{msg} and @var{msgid} empty\n\
+character strings.  Otherwise, @var{status} is 0, @var{msg} contains a\n\
+system-dependent error message, and @var{msgid} contains a unique\n\
+message identifier.\n\
+\n\
+If the optional second parameter is suplied, recursively remove all\n\
+subdirectories as well.\n\
 @end deftypefn")
 {
   octave_value_list retval;
 
+  retval(2) = std::string ();
   retval(1) = std::string ();
-  retval(0) = -1.0;
+  retval(0) = false;
 
-  if (args.length () == 1)
+  int nargin = args.length ();
+
+  if (nargin == 1 || nargin == 2)
     {
       std::string dirname = args(0).string_value ();
 
@@ -352,12 +365,19 @@
 	{
 	  std::string msg;
 
-	  int status = file_ops::rmdir (file_ops::tilde_expand (dirname), msg);
+	  std::string fulldir = file_ops::tilde_expand (dirname);
 
-	  retval(0) = status;
+	  int status = (nargin == 1)
+	    ? file_ops::rmdir (fulldir, msg)
+	    : file_ops::recursive_rmdir (fulldir, msg);
 
 	  if (status < 0)
-	    retval(1) = msg;
+	    {
+	      retval(2) = "rmdir";
+	      retval(1) = msg;
+	    }
+	  else
+	    retval(0) = true;
 	}
     }
   else
--- a/src/oct-stream.cc
+++ b/src/oct-stream.cc
@@ -2323,7 +2323,9 @@
 	{
 	  octave_value tmp_val = values (val_idx);
 
-	  curr_val = tmp_val.array_value ();
+	  // Force string conversion here for compatibility.
+
+	  curr_val = tmp_val.array_value (true);
 
 	  if (! error_state)
 	    {
--- a/src/ov-type-conv.h
+++ b/src/ov-type-conv.h
@@ -35,7 +35,11 @@
  \
       int t_result = MATRIX_RESULT_T::static_type_id (); \
  \
-      if (t_arg != t_result) \
+      if (t_arg == t_result || arg.class_name () == #NAME) \
+	{ \
+	  retval = arg; \
+	} \
+      else \
         { \
           type_conv_fcn cf \
 	    = octave_value_typeinfo::lookup_type_conv_op (t_arg, t_result); \
@@ -62,8 +66,6 @@
 	      gripe_invalid_conversion (arg_tname, result_tname); \
 	    } \
 	} \
-      else \
-        retval = arg; \
     } \
   else \
     print_usage (#NAME); \
--- a/src/syscalls.cc
+++ b/src/syscalls.cc
@@ -67,6 +67,7 @@
 
   m.assign ("dev", static_cast<double> (fs.dev ()));
   m.assign ("ino", fs.ino ());
+  m.assign ("mode", fs.mode ());
   m.assign ("modestr", fs.mode_as_string ());
   m.assign ("nlink", fs.nlink ());
   m.assign ("uid", fs.uid ());
@@ -711,6 +712,12 @@
 @item ino\n\
 File number of the file.\n\
 \n\
+@item mode\n\
+File mode, as an integer.  Use the functions @code{S_ISREG},\n\
+@code{S_ISDIR}, @code{S_ISCHR}, @code{S_ISBLK}, @code{S_ISFIFO},\n\
+@code{S_ISLNK}, or @code{S_ISSOCK} to extract information from this\n\
+value.\n\
+\n\
 @item modestr\n\
 File mode, as a string of ten letters or dashes as would be returned by\n\
 @kbd{ls -l}.\n\
@@ -775,6 +782,7 @@
           gid = 6\n\
           nlink = 1\n\
           blocks = 768\n\
+          mode = -rw-r--r--\n\
           modestr = -rw-r--r--\n\
           ino = 9316\n\
           dev = 2049\n\
@@ -815,6 +823,179 @@
   return retval;
 }
 
+DEFUNX ("S_ISREG", FS_ISREG, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} S_ISREG (@var{mode})\n\
+Return true if @var{mode} corresponds to a regular file.  The value\n\
+of @var{mode} is assumed to be returned from a call to @code{stat}.\n\
+@seealso{stat, lstat}\n\
+@end deftypefn")
+{
+  octave_value retval = false;
+
+  if (args.length () == 1)
+    {
+      double mode = args(0).double_value ();
+
+      if (! error_state)
+	retval = file_stat::is_reg (static_cast<mode_t> (mode));
+      else
+	error ("S_ISREG: invalid mode value");
+    }
+  else
+    print_usage ("S_ISREG");
+
+  return retval;
+}
+
+DEFUNX ("S_ISDIR", FS_ISDIR, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} S_ISDIR (@var{mode})\n\
+Return true if @var{mode} corresponds to a directory.  The value\n\
+of @var{mode} is assumed to be returned from a call to @code{stat}.\n\
+@seealso{stat, lstat}\n\
+@end deftypefn")
+{
+  octave_value retval = false;
+
+  if (args.length () == 1)
+    {
+      double mode = args(0).double_value ();
+
+      if (! error_state)
+	retval = file_stat::is_dir (static_cast<mode_t> (mode));
+      else
+	error ("S_ISDIR: invalid mode value");
+    }
+  else
+    print_usage ("S_ISDIR");
+
+  return retval;
+}
+
+DEFUNX ("S_ISCHR", FS_ISCHR, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} S_ISCHR (@var{mode})\n\
+Return true if @var{mode} corresponds to a character devicey.  The value\n\
+of @var{mode} is assumed to be returned from a call to @code{stat}.\n\
+@seealso{stat, lstat}\n\
+@end deftypefn")
+{
+  octave_value retval = false;
+
+  if (args.length () == 1)
+    {
+      double mode = args(0).double_value ();
+
+      if (! error_state)
+	retval = file_stat::is_chr (static_cast<mode_t> (mode));
+      else
+	error ("S_ISCHR: invalid mode value");
+    }
+  else
+    print_usage ("S_ISCHR");
+
+  return retval;
+}
+
+DEFUNX ("S_ISBLK", FS_ISBLK, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} S_ISBLK (@var{mode})\n\
+Return true if @var{mode} corresponds to a block device.  The value\n\
+of @var{mode} is assumed to be returned from a call to @code{stat}.\n\
+@seealso{stat, lstat}\n\
+@end deftypefn")
+{
+  octave_value retval = false;
+
+  if (args.length () == 1)
+    {
+      double mode = args(0).double_value ();
+
+      if (! error_state)
+	retval = file_stat::is_blk (static_cast<mode_t> (mode));
+      else
+	error ("S_ISBLK: invalid mode value");
+    }
+  else
+    print_usage ("S_ISBLK");
+
+  return retval;
+}
+
+DEFUNX ("S_ISFIFO", FS_ISFIFO, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} S_ISFIFO (@var{mode})\n\
+Return true if @var{mode} corresponds to a fifo.  The value\n\
+of @var{mode} is assumed to be returned from a call to @code{stat}.\n\
+@seealso{stat, lstat}\n\
+@end deftypefn")
+{
+  octave_value retval = false;
+
+  if (args.length () == 1)
+    {
+      double mode = args(0).double_value ();
+
+      if (! error_state)
+	retval = file_stat::is_fifo (static_cast<mode_t> (mode));
+      else
+	error ("S_ISFIFO: invalid mode value");
+    }
+  else
+    print_usage ("S_ISFIFO");
+
+  return retval;
+}
+
+DEFUNX ("S_ISLNK", FS_ISLNK, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} S_ISLNK (@var{mode})\n\
+Return true if @var{mode} corresponds to a symbolic link.  The value\n\
+of @var{mode} is assumed to be returned from a call to @code{stat}.\n\
+@seealso{stat, lstat}\n\
+@end deftypefn")
+{
+  octave_value retval = false;
+
+  if (args.length () == 1)
+    {
+      double mode = args(0).double_value ();
+
+      if (! error_state)
+	retval = file_stat::is_lnk (static_cast<mode_t> (mode));
+      else
+	error ("S_ISLNK: invalid mode value");
+    }
+  else
+    print_usage ("S_ISLNK");
+
+  return retval;
+}
+
+DEFUNX ("S_ISSOCK", FS_ISSOCK, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} S_ISSOCK (@var{mode})\n\
+@seealso{stat, lstat}\n\
+@end deftypefn")
+{
+  octave_value retval = false;
+
+  if (args.length () == 1)
+    {
+      double mode = args(0).double_value ();
+
+      if (! error_state)
+	retval = file_stat::is_sock (static_cast<mode_t> (mode));
+      else
+	error ("S_ISSOCK: invalid mode value");
+    }
+  else
+    print_usage ("S_ISSOCK");
+
+  return retval;
+}
+
 DEFUN (unlink, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} unlink (@var{file})\n\
new file mode 100644
--- /dev/null
+++ b/test/octave.test/string/split-4.m
@@ -0,0 +1,1 @@
+split ("foo", "bar", 3, 4)