changeset 5900:c20eb7330d13

[project @ 2006-07-22 08:31:16 by jwe]
author jwe
date Sat, 22 Jul 2006 08:31:17 +0000
parents 82c38ce145a7
children 5610a3fdeca6
files liboctave/Array.h liboctave/ChangeLog liboctave/Sparse.h liboctave/oct-inttypes.h src/ChangeLog src/Makefile.in src/ls-mat5.cc src/mex.cc src/mex.h src/mexproto.h src/mxarray.h src/oct-map.cc src/ov-base-mat.h src/ov-base-scalar.h src/ov-base-sparse.h src/ov-base.cc src/ov-base.h src/ov-bool-mat.cc src/ov-bool-mat.h src/ov-bool-sparse.cc src/ov-bool-sparse.h src/ov-bool.cc src/ov-bool.h src/ov-cell.cc src/ov-cell.h src/ov-ch-mat.cc src/ov-ch-mat.h src/ov-complex.cc src/ov-complex.h src/ov-cx-mat.cc src/ov-cx-mat.h src/ov-cx-sparse.cc src/ov-cx-sparse.h src/ov-int16.h src/ov-int32.h src/ov-int64.h src/ov-int8.h src/ov-intx.h src/ov-range.cc src/ov-range.h src/ov-re-mat.cc src/ov-re-mat.h src/ov-re-sparse.cc src/ov-re-sparse.h src/ov-scalar.cc src/ov-scalar.h src/ov-struct.cc src/ov-struct.h src/ov-uint16.h src/ov-uint32.h src/ov-uint64.h src/ov-uint8.h src/ov.h
diffstat 53 files changed, 3806 insertions(+), 1266 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array.h
+++ b/liboctave/Array.h
@@ -132,6 +132,8 @@
 
 public:
 
+  typedef T element_type;
+
   // !!! WARNING !!! -- these should be protected, not public.  You
   // should not access these data members directly!
 
@@ -534,6 +536,10 @@
   //  static T resize_fill_value (void) { return T (); }
 
   void print_info (std::ostream& os, const std::string& prefix) const;
+
+  // Unsafe.  This function exists to support the MEX interface.
+  // You should not use it anywhere else.
+  void *mex_get_data (void) const { return const_cast<T *> (data ()); }
 };
 
 // NOTE: these functions should be friends of the Array<T> class and
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,13 @@
+2006-07-22  John W. Eaton  <jwe@octave.org>
+
+	* Sparse.h (Sparse<T>::mex_get_data, Sparse<T>::mex_get_ir,
+	Sparse<T>::mex_get_jc): New functions.
+
+2006-07-21  John W. Eaton  <jwe@octave.org>
+
+	* oct-inttypes.h (octave_int<T>::mex_get_data): New function.
+	* Array.h (Array<T>::mex_get_data): New function.
+
 2006-07-19  John W. Eaton  <jwe@octave.org>
 
 	* oct-inttypes.h (octave_int::operator bool (void)): New function.
--- a/liboctave/Sparse.h
+++ b/liboctave/Sparse.h
@@ -460,6 +460,7 @@
   T& xdata (octave_idx_type i) { return rep->data (i); }
 
   T data (octave_idx_type i) const { return rep->data (i); }
+  // FIXME -- shouldn't this be returning const T*?
   T* data (void) const { return rep->d; }
 
   octave_idx_type* ridx (void) { make_unique (); return rep->r; }
@@ -468,6 +469,7 @@
   octave_idx_type& xridx (octave_idx_type i) { return rep->ridx (i); }
 
   octave_idx_type ridx (octave_idx_type i) const { return rep->cridx (i); }
+  // FIXME -- shouldn't this be returning const octave_idx_type*?
   octave_idx_type* ridx (void) const { return rep->r; }
 
   octave_idx_type* cidx (void) { make_unique (); return rep->c; }
@@ -476,6 +478,7 @@
   octave_idx_type& xcidx (octave_idx_type i) { return rep->cidx (i); }
 
   octave_idx_type cidx (octave_idx_type i) const { return rep->ccidx (i); }
+  // FIXME -- shouldn't this be returning const octave_idx_type*?
   octave_idx_type* cidx (void) const { return rep->c; }
 
   octave_idx_type ndims (void) const { return dimensions.length (); }
@@ -504,6 +507,13 @@
 
   void print_info (std::ostream& os, const std::string& prefix) const;
 
+  // Unsafe.  These functions exist to support the MEX interface.
+  // You should not use them anywhere else.
+  void *mex_get_data (void) const { return const_cast<T *> (data ()); }
+
+  octave_idx_type *mex_get_ir (void) const { return const_cast<octave_idx_type *> (ridx ()); }
+
+  octave_idx_type *mex_get_jc (void) const { return const_cast<octave_idx_type *> (cidx ()); }
 };
 
 // NOTE: these functions should be friends of the Sparse<T> class and
--- a/liboctave/oct-inttypes.h
+++ b/liboctave/oct-inttypes.h
@@ -309,6 +309,10 @@
 
   static int byte_size (void) { return sizeof(T); }
 
+  // Unsafe.  This function exists to support the MEX interface.
+  // You should not use it anywhere else.
+  void *mex_get_data (void) const { return const_cast<T *> (&ival); }
+
 private:
 
   T ival;
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,58 @@
+2006-07-22  John W. Eaton  <jwe@octave.org>
+
+	* mxarray.h: New file.
+	* mex.h, mexproto.h, mex.cc: New implementation of mxArray and MEX
+	interface.
+
+	* ov.h (octave_value::mex_get_ir, octave_value::mex_get_jc):
+	New functions.
+	* ov-base.h (octave_base_value::mex_get_ir,
+	octave_base_value::mex_get_jc): New virtual functions.
+	* ov-base-sparse.h (octave_base_sparse<T>::mex_get_ir,
+	octave_base_sparse<T>::mex_get_jc): New functions.
+
+	* ov-intx.h (OCTAVE_VALUE_INT_SCALAR_T::as_mxArray,
+	OCTAVE_VALUE_INT_MATRIX_T::as_mxArray): New functions.
+	* ov-int8.h, ov-int16.h, ov-int32.h, ov-int64.h, ov-uint8.h,
+	ov-uint16.h, ov-uint32.h, ov-uint64.h: Define OCTAVE_INT_MX_CLASS
+	before including ov-intx.h.  Undef it after.
+	* ov-range.cc (octave_range::as_mxArray): New function.
+	* ov-range.h: Provide decl.
+	* ov-scalar.cc (octave_scalar::as_mxArray): New function.
+	* ov-scalar.h: Provide decl.
+	* ov-complex.cc (octave_complex::as_mxArray): New function.
+	* ov-complex.h: Provide decl.
+	* ov-re-mat.cc (octave_matrix::as_mxArray): New function.
+	* ov-re-mat.h: Provide decl.
+	* ov-cx-mat.cc (octave_complex_matrix::as_mxArray): New function.
+	* ov-cx-mat.h: Provide decl.
+	* ov-ch-mat.cc (octave_char_matrix::as_mxArray): New function.
+	* ov-ch-mat.h: Provide decl.
+	* ov-bool-mat.cc (octave_bool_matrix::as_mxArray): New function.
+	* ov-bool-mat.h: Provide decl.
+	* ov-bool.cc (octave_bool::as_mxArray): New function.
+	* ov-bool.h: Provide decl.
+
+	* ov-struct.h (octave_struct::numel): New function.
+
+	* ls-mat5.cc (arrayclasstype): Use "MAT_FILE_" instead of "mx" as
+	prefix for element names.
+
+	* ov.h (octave_value::as_mxArray): New function.
+	* ov-base.cc (octave_base_value::as_mxArray): New function.
+	* ov-base.h: Provide decl.
+
+	* ov.h (octave_value::mex_get_data): New function.
+	* ov-base.h (octave_base_value::mex_get_data): New function.
+	* ov-base-scalar.h (octave_base_scalar<ST>::mex_get_data): New function.
+	* ov-base-matrix.h (octave_base_matrix<MT>::mex_get_data): New function.
+	* ov-intx.h (OCTAVE_VALUE_INT_SCALAR_T::mex_get_data): New function.
+
+	* ov.h (octave_value::nfields): New function.
+	* ov-base.cc (octave_base_value::nfields): New virtual function.
+	* ov-base.h: Provide decl.
+	* ov-struct.h (octave_struct::nfields): New function.
+
 2006-07-19  John W. Eaton  <jwe@octave.org>
 
 	* OPERATORS/op-bm-bm.cc (oct_assignop_conv_and_assign): New function.
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -98,7 +98,7 @@
 	error.h file-io.h gripes.h help.h input.h \
 	lex.h load-path.h load-save.h ls-hdf5.h ls-mat-ascii.h ls-mat4.h \
 	ls-mat5.h ls-oct-ascii.h ls-oct-binary.h ls-utils.h \
-	matrix.h mex.h mexproto.h \
+	matrix.h mex.h mexproto.h mxarray.h \
 	oct-errno.h oct-fstrm.h oct-hist.h oct-iostrm.h oct-map.h oct-obj.h \
 	oct-prcstrm.h oct-procbuf.h oct-stdstrm.h oct-stream.h zfstream.h \
 	oct-strstrm.h oct-lvalue.h oct.h octave.h ops.h pager.h \
--- a/src/ls-mat5.cc
+++ b/src/ls-mat5.cc
@@ -77,24 +77,31 @@
 #define PAD(l) (((l)<=4)?4:(((l)+7)/8)*8)
 #define TAGLENGTH(l) ((l)<=4?4:8)
 
+// FIXME -- the following enum values should be the same as the
+// mxClassID values in mexproto.h, but it seems they have also changed
+// over time.  What is the correct way to handle this and maintain
+// backward compatibility with old MAT files?  For now, use
+// "MAT_FILE_" instead of "mx" as the prefix for these names to avoid
+// conflict with the mxClassID enum in mexproto.h.
+
 enum arrayclasstype
   {
-    mxCELL_CLASS=1,		// cell array
-    mxSTRUCT_CLASS,		// structure
-    mxOBJECT_CLASS,		// object
-    mxCHAR_CLASS,		// character array
-    mxSPARSE_CLASS,		// sparse array
-    mxDOUBLE_CLASS,		// double precision array
-    mxSINGLE_CLASS,		// single precision floating point
-    mxINT8_CLASS,		// 8 bit signed integer
-    mxUINT8_CLASS,		// 8 bit unsigned integer
-    mxINT16_CLASS,		// 16 bit signed integer
-    mxUINT16_CLASS,		// 16 bit unsigned integer
-    mxINT32_CLASS,		// 32 bit signed integer
-    mxUINT32_CLASS,		// 32 bit unsigned integer
-    mxINT64_CLASS,		// 64 bit signed integer
-    mxUINT64_CLASS,		// 64 bit unsigned integer
-    mxFUNCTION_CLASS            // Function handle
+    MAT_FILE_CELL_CLASS=1,		// cell array
+    MAT_FILE_STRUCT_CLASS,		// structure
+    MAT_FILE_OBJECT_CLASS,		// object
+    MAT_FILE_CHAR_CLASS,		// character array
+    MAT_FILE_SPARSE_CLASS,		// sparse array
+    MAT_FILE_DOUBLE_CLASS,		// double precision array
+    MAT_FILE_SINGLE_CLASS,		// single precision floating point
+    MAT_FILE_INT8_CLASS,		// 8 bit signed integer
+    MAT_FILE_UINT8_CLASS,		// 8 bit unsigned integer
+    MAT_FILE_INT16_CLASS,		// 16 bit signed integer
+    MAT_FILE_UINT16_CLASS,		// 16 bit unsigned integer
+    MAT_FILE_INT32_CLASS,		// 32 bit signed integer
+    MAT_FILE_UINT32_CLASS,		// 32 bit unsigned integer
+    MAT_FILE_INT64_CLASS,		// 64 bit signed integer
+    MAT_FILE_UINT64_CLASS,		// 64 bit unsigned integer
+    MAT_FILE_FUNCTION_CLASS            // Function handle
   };
 
 // Read COUNT elements of data from IS in the format specified by TYPE,
@@ -546,7 +553,7 @@
 
   switch (arrayclass)
     {
-    case mxCELL_CLASS:
+    case MAT_FILE_CELL_CLASS:
       {
 	Cell cell_array (dims);
 
@@ -572,11 +579,11 @@
       }
       break;
 
-    case mxOBJECT_CLASS:
+    case MAT_FILE_OBJECT_CLASS:
       warning ("load: objects are not implemented");
       goto skip_ahead;
 
-    case mxSPARSE_CLASS:
+    case MAT_FILE_SPARSE_CLASS:
 #if SIZEOF_INT != SIZEOF_OCTAVE_IDX_TYPE
       warning ("load: sparse objects are not implemented");
       goto skip_ahead;
@@ -711,11 +718,11 @@
       break;
 #endif
 
-    case mxFUNCTION_CLASS:
+    case MAT_FILE_FUNCTION_CLASS:
       warning ("load: function handles are not implemented");
       goto skip_ahead;
 
-    case mxSTRUCT_CLASS:
+    case MAT_FILE_STRUCT_CLASS:
       {
 	Octave_map m;
 	int32_t fn_type;
@@ -786,16 +793,17 @@
       }
       break;
 
-    case mxINT8_CLASS:
+    case MAT_FILE_INT8_CLASS:
       OCTAVE_MAT5_INTEGER_READ (int8NDArray);
       break;
 
-    case mxUINT8_CLASS:
+    case MAT_FILE_UINT8_CLASS:
       {
 	OCTAVE_MAT5_INTEGER_READ (uint8NDArray);
 
-	// logical variables can either be mxUINT8_CLASS or mxDOUBLE_CLASS,
-	// so chek if we have a logical variable and convert it
+	// Logical variables can either be MAT_FILE_UINT8_CLASS or
+	// MAT_FILE_DOUBLE_CLASS, so check if we have a logical
+	// variable and convert it.
 
 	if (logicalvar)
 	  {
@@ -811,35 +819,35 @@
       }
       break;
 
-    case mxINT16_CLASS:
+    case MAT_FILE_INT16_CLASS:
       OCTAVE_MAT5_INTEGER_READ (int16NDArray);
       break;
 
-    case mxUINT16_CLASS:
+    case MAT_FILE_UINT16_CLASS:
       OCTAVE_MAT5_INTEGER_READ (uint16NDArray);
       break;
 
-    case mxINT32_CLASS:
+    case MAT_FILE_INT32_CLASS:
       OCTAVE_MAT5_INTEGER_READ (int32NDArray);
       break;
 
-    case mxUINT32_CLASS:
+    case MAT_FILE_UINT32_CLASS:
       OCTAVE_MAT5_INTEGER_READ (uint32NDArray);
       break;
 
-    case mxINT64_CLASS:
+    case MAT_FILE_INT64_CLASS:
       OCTAVE_MAT5_INTEGER_READ (int64NDArray);
       break;
 
-    case mxUINT64_CLASS:
+    case MAT_FILE_UINT64_CLASS:
       OCTAVE_MAT5_INTEGER_READ (uint64NDArray);
       break;
 
-    case mxCHAR_CLASS:
+    case MAT_FILE_CHAR_CLASS:
       // handle as a numerical array to start with
 
-    case mxDOUBLE_CLASS:
-    case mxSINGLE_CLASS:
+    case MAT_FILE_DOUBLE_CLASS:
+    case MAT_FILE_SINGLE_CLASS:
     default:
       {
 	NDArray re (dims);
@@ -869,8 +877,9 @@
 
 	if (logicalvar)
 	  {
-	    // logical variables can either be mxUINT8_CLASS or mxDOUBLE_CLASS,
-	    // so chek if we have a logical variable and convert it
+	    // Logical variables can either be MAT_FILE_UINT8_CLASS or
+	    // MAT_FILE_DOUBLE_CLASS, so check if we have a logical
+	    // variable and convert it.
 
 	    boolNDArray out (dims);
 	    
@@ -911,7 +920,7 @@
 	  }
 	else
 	  {
-	    if (arrayclass == mxCHAR_CLASS)
+	    if (arrayclass == MAT_FILE_CHAR_CLASS)
 	      {
 		if (type == miUTF16 || type == miUTF32)
 		  {
@@ -1518,26 +1527,26 @@
     flags |= 0x0800;
 
   if (tc.is_string ())
-    flags |= mxCHAR_CLASS;
+    flags |= MAT_FILE_CHAR_CLASS;
   else if (cname == "int8")
-    flags |= mxINT8_CLASS;
+    flags |= MAT_FILE_INT8_CLASS;
   else if (cname == "int16")
-    flags |= mxINT16_CLASS;
+    flags |= MAT_FILE_INT16_CLASS;
   else if (cname == "int32")
-    flags |= mxINT32_CLASS;
+    flags |= MAT_FILE_INT32_CLASS;
   else if (cname == "int64")
-    flags |= mxINT64_CLASS;
+    flags |= MAT_FILE_INT64_CLASS;
   else if (cname == "uint8" || tc.is_bool_type ())
-    flags |= mxUINT8_CLASS;
+    flags |= MAT_FILE_UINT8_CLASS;
   else if (cname == "uint16")
-    flags |= mxUINT16_CLASS;
+    flags |= MAT_FILE_UINT16_CLASS;
   else if (cname == "uint32")
-    flags |= mxUINT32_CLASS;
+    flags |= MAT_FILE_UINT32_CLASS;
   else if (cname == "uint64")
-    flags |= mxUINT64_CLASS;
+    flags |= MAT_FILE_UINT64_CLASS;
   else if (cname == "sparse")
     {
-      flags |= mxSPARSE_CLASS;
+      flags |= MAT_FILE_SPARSE_CLASS;
       if (tc.is_complex_type ())
 	{
 	  SparseComplexMatrix scm = tc.sparse_complex_matrix_value ();
@@ -1550,17 +1559,17 @@
 	}
     }
   else if (tc.is_real_scalar ())
-    flags |= mxDOUBLE_CLASS;
+    flags |= MAT_FILE_DOUBLE_CLASS;
   else if (tc.is_real_matrix () || tc.is_range ())
-    flags |= mxDOUBLE_CLASS;
+    flags |= MAT_FILE_DOUBLE_CLASS;
   else if (tc.is_complex_scalar ())
-    flags |= mxDOUBLE_CLASS;
+    flags |= MAT_FILE_DOUBLE_CLASS;
   else if (tc.is_complex_matrix ())
-    flags |= mxDOUBLE_CLASS;
+    flags |= MAT_FILE_DOUBLE_CLASS;
   else if (tc.is_map ()) 
-    flags |= mxSTRUCT_CLASS;
+    flags |= MAT_FILE_STRUCT_CLASS;
   else if (tc.is_cell ())
-    flags |= mxCELL_CLASS;
+    flags |= MAT_FILE_CELL_CLASS;
   else
     {
       gripe_wrong_type_arg ("save", tc, false);
--- a/src/mex.cc
+++ b/src/mex.cc
@@ -1,631 +1,2639 @@
-/*
-
-Copyright (C) 2001, 2006 Paul Kienzle
-
-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.
-
-*/
-
-// This code was originally distributed as part of Octave Forge under
-// the following terms:
-//
-// Author: Paul Kienzle
-// I grant this code to the public domain.
-// 2001-03-22
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-// PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
-// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-// SUCH DAMAGE.
+#include <config.h>
 
 #include <cfloat>
 #include <csetjmp>
+#include <cstdarg>
 #include <cstdlib>
-
-#include <iomanip>
+#include <cstring>
+#include <cctype>
+
 #include <set>
-#include <string>
-
-typedef void *Pix;
-typedef std::set<Pix> MemSet;
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "oct.h"
+
+#include "f77-fcn.h"
+#include "lo-ieee.h"
+
+// mxArray must be declared as a class before including mexproto.h.
+class mxArray;
+#include "Cell.h"
+#include "mexproto.h"
+#include "oct-map.h"
+#include "oct-obj.h"
+#include "ov.h"
+#include "ov-usr-fcn.h"
 #include "pager.h"
-#include "f77-fcn.h"
-#include "unwind-prot.h"
-#include "lo-mappers.h"
-#include "lo-ieee.h"
 #include "parse.h"
 #include "toplev.h"
+#include "unwind-prot.h"
+#include "utils.h"
 #include "variables.h"
-#include "oct-map.h"
-#include "str-vec.h"
-
-// mex file context
-//
-// Class mex keeps track of all memory allocated and frees anything
-// not explicitly marked persistent when the it is destroyed.  It also
-// maintains the setjump/longjump buffer required for non-local exit
-// from the mex file, and any other state local to this instance of
-// the mex function invocation.
-class mxArray;
-
-// Prototypes for external functions.  Must declare mxArray as a class
-// before including this file.
-#include "mexproto.h"
+
+// #define DEBUG 1
+
+static int
+max_str_len (int m, const char **str)
+{
+  int max_len = 0;
+
+  for (int i = 0; i < m; i++)
+    {
+      int tmp = strlen (str[i]);
+
+      if (tmp > max_len)
+	max_len = tmp;
+    }
+
+  return max_len;
+}
+
+static int
+valid_key (const char *key)
+{
+  int retval = 0;
+
+  int nel = strlen (key);
+
+  if (nel > 0)
+    {
+      if (isalpha (key[0]))
+	{
+	  for (int i = 1; i < nel; i++)
+	    {
+	      if (! (isalnum (key[i]) || key[i] == '_'))
+		goto done;
+	    }
+
+	  retval = 1;
+	}
+    }
+
+ done:
+
+  return retval;
+}
+
+// ------------------------------------------------------------------
+
+// A class to provide the default implemenation of some of the virtual
+// functions declared in the mxArray class.
+
+class mxArray_base : public mxArray
+{
+protected:
+
+  mxArray_base (void) : mxArray (xmxArray ()) { }
+
+public:
+
+  mxArray *clone (void) const = 0;
+
+  ~mxArray_base (void) { }
+
+  octave_value as_octave_value (void) const = 0;
+
+  bool is_octave_value (void) const { return false; }
+
+  int is_cell (void) const = 0;
+
+  int is_char (void) const = 0;
+
+  int is_class (const char *name_arg) const
+  {
+    int retval = 0;
+
+    const char *cname = get_class_name ();
+
+    if (cname && name_arg)
+      retval = ! strcmp (cname, name_arg);
+
+    return retval;
+  }
+
+  int is_complex (void) const = 0;
+
+  int is_double (void) const = 0;
+
+  int is_int16 (void) const = 0;
+
+  int is_int32 (void) const = 0;
+
+  int is_int64 (void) const = 0;
+
+  int is_int8 (void) const = 0;
+
+  int is_logical (void) const = 0;
+
+  int is_numeric (void) const = 0;
+
+  int is_single (void) const = 0;
+
+  int is_sparse (void) const = 0;
+
+  int is_struct (void) const = 0;
+
+  int is_uint16 (void) const = 0;
+
+  int is_uint32 (void) const = 0;
+
+  int is_uint64 (void) const = 0;
+
+  int is_uint8 (void) const = 0;
+
+  int is_logical_scalar (void) const
+  {
+    return is_logical () && get_number_of_elements () == 1;
+  }
+
+  int is_logical_scalar_true (void) const = 0;
+
+  int get_m (void) const = 0;
+
+  int get_n (void) const = 0;
+
+  int *get_dimensions (void) const = 0;
+
+  int get_number_of_dimensions (void) const = 0;
+
+  void set_m (int m) = 0;
+
+  void set_n (int n) = 0;
+
+  void set_dimensions (int *dims_arg, int ndims_arg) = 0;
+
+  int get_number_of_elements (void) const = 0;
+
+  int is_empty (void) const = 0;
+
+  mxClassID get_class_id (void) const = 0;
+
+  const char *get_class_name (void) const = 0;
+
+  void set_class_name (const char *name_arg) = 0;
+
+  mxArray *get_cell (int /*idx*/) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  void set_cell (int idx, mxArray *val) = 0;
+
+  void *get_data (void) const = 0;
+
+  void *get_imag_data (void) const = 0;
+
+  void set_data (void *pr) = 0;
+
+  void set_imag_data (void *pi) = 0;
+
+  int *get_ir (void) const = 0;
+
+  int *get_jc (void) const = 0;
+
+  int get_nzmax (void) const = 0;
+
+  void set_ir (int *ir) = 0;
+
+  void set_jc (int *jc) = 0;
+
+  void set_nzmax (int nzmax) = 0;
+
+  int add_field (const char *key) = 0;
+
+  void remove_field (int key_num) = 0;
+
+  mxArray *get_field_by_number (int index, int key_num) const = 0;
+
+  void set_field_by_number (int index, int key_num, mxArray *val) = 0;
+
+  int get_number_of_fields (void) const = 0;
+
+  const char *get_field_name_by_number (int key_num) const = 0;
+
+  int get_field_number (const char *key) const = 0;
+
+  int get_string (char *buf, int buflen) const = 0;
+
+  char *array_to_string (void) const = 0;
+
+  int calc_single_subscript (int nsubs, int *subs) const = 0;
+
+  int get_element_size (void) const = 0;
+
+  bool mutation_needed (void) const { return false; }
+
+  mxArray *mutate (void) const { return 0; }
+
+protected:
+
+  mxArray_base (const mxArray_base&) : mxArray (xmxArray ()) { }
+
+  void invalid_type_error (void) const
+  {
+    error ("invalid type for operation");
+  }
+
+  void error (const char *msg) const
+  {
+    // FIXME
+    ::error ("%s", msg);
+  }
+};
+
+// The object that handles values pass to MEX files from Octave.  Some
+// methods in this class may set mutate_flag to TRUE to tell the
+// mxArray class to convert to the Matlab-style representation and
+// then invoke the method on that object instead (for example, getting
+// a pointer to real or imaginary data from a complex object requires
+// a mutation but getting a pointer to real data from a real object
+// does not).  Changing the representation causes a copy so we try to
+// avoid it unless it is really necessary.  Once the conversion
+// happens, we delete this representation, so the conversion can only
+// happen once per call to a MEX file.
+
+class mxArray_octave_value : public mxArray_base
+{
+public:
+
+  mxArray_octave_value (const octave_value& ov)
+    : mxArray_base (), val (ov), mutate_flag (false),
+      id (mxUNKNOWN_CLASS), class_name (0), ndims (-1), dims (0) { }
+
+  mxArray *clone (void) const { return new mxArray_octave_value (*this); }
+
+  ~mxArray_octave_value (void)
+  {
+    mxFree (class_name);
+    mxFree (dims);
+  }
+
+  octave_value as_octave_value (void) const { return val; }
+
+  bool is_octave_value (void) const { return true; }
+
+  int is_cell (void) const { return val.is_cell (); }
+
+  int is_char (void) const { return val.is_string (); }
+
+  int is_complex (void) const { return val.is_complex_type (); }
+
+  int is_double (void) const { return val.is_double_type (); }
+
+  int is_int16 (void) const { return val.is_int16_type (); }
+
+  int is_int32 (void) const { return val.is_int32_type (); }
+
+  int is_int64 (void) const { return val.is_int64_type (); }
+
+  int is_int8 (void) const { return val.is_int8_type (); }
+
+  int is_logical (void) const { return val.is_bool_type (); }
+
+  int is_numeric (void) const { return val.is_numeric_type (); }
+
+  int is_single (void) const { return val.is_single_type (); }
+
+  int is_sparse (void) const { return val.is_sparse_type (); }
+
+  int is_struct (void) const { return val.is_map (); }
+
+  int is_uint16 (void) const { return val.is_uint16_type (); }
+
+  int is_uint32 (void) const { return val.is_int32_type (); }
+
+  int is_uint64 (void) const { return val.is_int64_type (); }
+
+  int is_uint8 (void) const { return val.is_int8_type (); }
+
+  int is_range (void) const { return val.is_range (); }
+
+  int is_real_type (void) const { return val.is_real_type (); }
+
+  int is_logical_scalar_true (void) const
+  {
+    return (is_logical_scalar () && val.is_true ());
+  }
+
+  int get_m (void) const { return val.rows (); }
+
+  int get_n (void) const { return val.columns (); }
+
+  int *get_dimensions (void) const
+  {
+    if (! dims)
+      {
+	// Force ndims to be cached.
+	get_number_of_dimensions ();
+
+	dims = static_cast<int *> (malloc (ndims * sizeof (int)));
+
+	dim_vector dv = val.dims ();
+
+	for (int i = 0; i < ndims; i++)
+	  dims[i] = dv(i);
+      }
+
+    return dims;
+  }
+
+  int get_number_of_dimensions (void) const
+  {
+    if (ndims < 0)
+      ndims = val.ndims ();
+
+    return ndims;
+  }
+
+  void set_m (int /*m*/) { panic_impossible (); }
+
+  void set_n (int /*n*/) { panic_impossible (); }
+
+  void set_dimensions (int */*dims_arg*/, int /*ndims_arg*/)
+  {
+    panic_impossible ();
+  }
+
+  int get_number_of_elements (void) const { return val.numel (); }
+
+  int is_empty (void) const { return val.is_empty (); }
+
+  mxClassID get_class_id (void) const
+  {
+    id = mxUNKNOWN_CLASS;
+
+    std::string cn = val.class_name ();
+
+    if (cn == "cell")
+      id = mxCELL_CLASS;
+    else if (cn == "struct")
+      id = mxSTRUCT_CLASS;
+    else if (cn == "logical")
+      id = mxLOGICAL_CLASS;
+    else if (cn == "char")
+      id = mxCHAR_CLASS;
+    else if (cn == "double")
+      id = mxDOUBLE_CLASS;
+    else if (cn == "single")
+      id = mxSINGLE_CLASS;
+    else if (cn == "int8")
+      id = mxINT8_CLASS;
+    else if (cn == "uint8")
+      id = mxUINT8_CLASS;
+    else if (cn == "int16")
+      id = mxINT16_CLASS;
+    else if (cn == "uint16")
+      id = mxUINT16_CLASS;
+    else if (cn == "int32")
+      id = mxINT32_CLASS;
+    else if (cn == "uint32")
+      id = mxUINT32_CLASS;
+    else if (cn == "int64")
+      id = mxINT64_CLASS;
+    else if (cn == "uint64")
+      id = mxUINT64_CLASS;
+    else if (cn == "function handle")
+      id = mxFUNCTION_CLASS;
+
+    return id;
+  }
+
+  const char *get_class_name (void) const
+  {
+    if (! class_name)
+      {
+	std::string s = val.class_name ();
+	class_name = strsave (s.c_str ());
+      }
+
+    return class_name;
+  }
+
+  // Not allowed.
+  void set_class_name (const char */*name_arg*/) { panic_impossible (); }
+
+  mxArray *get_cell (int /*idx*/) const
+  {
+    request_mutation ();
+    return 0;
+  }
+
+  // Not allowed.
+  void set_cell (int /*idx*/, mxArray */*val*/) { panic_impossible (); }
+
+  void *get_data (void) const
+  {
+    void *retval = 0;
+
+    if (is_char ()
+	|| (is_numeric () && is_real_type () && ! is_range ()))
+      retval = val.mex_get_data ();
+    else
+      request_mutation ();
+
+    return retval;
+  }
+
+  void *get_imag_data (void) const
+  {
+    void *retval = 0;
+
+    if (is_numeric () && is_real_type ())
+      retval = 0;
+    else
+      request_mutation ();
+
+    return retval;
+  }
+
+  // Not allowed.
+  void set_data (void */*pr*/) { panic_impossible (); }
+
+  // Not allowed.
+  void set_imag_data (void */*pi*/) { panic_impossible (); }
+
+  int *get_ir (void) const
+  {
+#if SIZEOF_OCTAVE_IDX_TYPE == SIZEOF_INT
+    return val.mex_get_jc ();
+#else
+    request_mutation ();
+    return 0;
+#endif
+  }
+
+  int *get_jc (void) const
+  {
+#if SIZEOF_OCTAVE_IDX_TYPE == SIZEOF_INT
+    return val.mex_get_jc ();
+#else
+    request_mutation ();
+    return 0;
+#endif
+  }
+
+  int get_nzmax (void) const { return val.nzmax (); }
+
+  // Not allowed.
+  void set_ir (int */*ir*/) { panic_impossible (); }
+
+  // Not allowed.
+  void set_jc (int */*jc*/) { panic_impossible (); }
+
+  // Not allowed.
+  void set_nzmax (int /*nzmax*/) { panic_impossible (); }
+
+  // Not allowed.
+  int add_field (const char */*key*/)
+  {
+    panic_impossible ();
+    return -1;
+  }
+
+  // Not allowed.
+  void remove_field (int /*key_num*/) { panic_impossible (); }
+
+  mxArray *get_field_by_number (int /*index*/, int /*key_num*/) const
+  {
+    request_mutation ();
+    return 0;
+  }
+
+  // Not allowed.
+  void set_field_by_number (int /*index*/, int /*key_num*/, mxArray */*val*/)
+  {
+    panic_impossible ();
+  }
+
+  int get_number_of_fields (void) const { return val.nfields (); }
+
+  const char *get_field_name_by_number (int /*key_num*/) const
+  {
+    request_mutation ();
+    return 0;
+  }
+
+  int get_field_number (const char */*key*/) const
+  {
+    request_mutation ();
+    return 0;
+  }
+
+  int get_string (char *buf, int buflen) const
+  {
+    int retval = 1;
+
+    int nel = get_number_of_elements ();
+
+    if (val.is_string () && nel < buflen)
+      {
+	charNDArray tmp = val.char_array_value ();
+
+	const char *p = tmp.data ();
+
+	for (int i = 0; i < buflen; i++)
+	  buf[i] = p[i];
+
+	buf[nel] = 0;
+
+	retval = 0;
+      }
+
+    return retval;
+  }
+
+  char *array_to_string (void) const
+  {
+    // FIXME -- this is suposed to handle multi-byte character
+    // strings.
+
+    char *buf = 0;
+
+    if (val.is_string ())
+      {
+	int nel = get_number_of_elements ();
+
+	buf = static_cast<char *> (malloc (nel + 1));
+
+	if (buf)
+	  {
+	    charNDArray tmp = val.char_array_value ();
+
+	    const char *p = tmp.data ();
+
+	    for (int i = 0; i < nel; i++)
+	      buf[i] = p[i];
+
+	    buf[nel] = '\0';
+	  }
+      }
+
+    return buf;
+  }
+
+  int calc_single_subscript (int nsubs, int *subs) const
+  {
+    int retval = 0;
+
+    // Force ndims, dims to be cached.
+    get_dimensions ();
+
+    int n = nsubs <= ndims ? nsubs : ndims;
+
+    while (--n > 0)
+      retval = retval * dims[n] + subs[n];
+
+    return retval;
+  }
+
+  int get_element_size (void) const
+  {
+    // Force id to be cached.
+    get_class_id ();
+
+    switch (id)
+      {
+      case mxCELL_CLASS: return sizeof (mxArray *);
+      case mxSTRUCT_CLASS: return sizeof (mxArray *);
+      case mxLOGICAL_CLASS: return sizeof (mxLogical);
+      case mxCHAR_CLASS: return sizeof (mxChar);
+      case mxDOUBLE_CLASS: return sizeof (double);
+      case mxSINGLE_CLASS: return sizeof (float);
+      case mxINT8_CLASS: return 1;
+      case mxUINT8_CLASS: return 1;
+      case mxINT16_CLASS: return 2;
+      case mxUINT16_CLASS: return 2;
+      case mxINT32_CLASS: return 4;
+      case mxUINT32_CLASS: return 4;
+      case mxINT64_CLASS: return 8;
+      case mxUINT64_CLASS: return 8;
+      case mxFUNCTION_CLASS: return 0;
+      default: return 0;
+      }    
+  }
+
+  bool mutation_needed (void) const { return mutate_flag; }
+
+  void request_mutation (void) const
+  {
+    if (mutate_flag)
+      panic_impossible ();
+
+    mutate_flag = true;
+  }
+
+  mxArray *mutate (void) const { return val.as_mxArray (); }
+
+protected:
+
+  mxArray_octave_value (const mxArray_octave_value& arg)
+    : mxArray_base (arg), val (arg.val), mutate_flag (arg.mutate_flag),
+      id (arg.id), class_name (strsave (arg.class_name)), ndims (arg.ndims),
+      dims (ndims > 0 ? static_cast<int *> (malloc (ndims * sizeof (int))) : 0)
+  {
+    if (dims)
+      {
+	for (int i = 0; i < ndims; i++)
+	  dims[i] = arg.dims[i];
+      }
+  }
+
+private:
+
+  octave_value val;
+
+  mutable bool mutate_flag;
+
+  // Caching these does not cost much or lead to much duplicated
+  // code.  For other things, we just request mutation to a
+  // Matlab-style mxArray object.
+
+  mutable mxClassID id;
+  mutable char *class_name;
+  mutable int ndims;
+  mutable int *dims;
+};
+
+// The base class for the Matlab-style representation, used to handle
+// things that are common to all Matlab-style objects.
+
+class mxArray_matlab : public mxArray_base
+{
+protected:
+
+  mxArray_matlab (mxClassID id_arg = mxUNKNOWN_CLASS)
+    : mxArray_base (), class_name (0), id (id_arg), ndims (0), dims (0) { }
+
+  mxArray_matlab (mxClassID id_arg, int ndims_arg, const int *dims_arg)
+    : mxArray_base (), class_name (0), id (id_arg),
+      ndims (ndims_arg < 2 ? 2 : ndims_arg),
+      dims (static_cast<int *> (malloc (ndims * sizeof (int))))
+  {
+    if (ndims_arg < 2)
+      {
+	dims[0] = 1;
+	dims[1] = 1;
+      }
+
+    for (int i = 0; i < ndims_arg; i++)
+      dims[i] = dims_arg[i];
+
+    for (int i = ndims - 1; i > 1; i--)
+      {
+	if (dims[i] == 1)
+	  ndims--;
+	else
+	  break;
+      }
+  }
+
+  mxArray_matlab (mxClassID id_arg, const dim_vector& dv)
+    : mxArray_base (), class_name (0), id (id_arg),
+      ndims (dv.length ()),
+      dims (static_cast<int *> (malloc (ndims * sizeof (int))))
+  {
+    for (int i = 0; i < ndims; i++)
+      dims[i] = dv(i);
+
+    for (int i = ndims - 1; i > 1; i--)
+      {
+	if (dims[i] == 1)
+	  ndims--;
+	else
+	  break;
+      }
+  }
+
+  mxArray_matlab (mxClassID id_arg, int m, int n)
+    : mxArray_base (), class_name (0), id (id_arg), ndims (2),
+      dims (static_cast<int *> (malloc (ndims * sizeof (int))))
+  {
+    dims[0] = m;
+    dims[1] = n;
+  }
+
+public:
+
+  ~mxArray_matlab (void)
+  {
+    mxFree (class_name);
+    mxFree (dims);
+  }
+
+  int is_cell (void) const { return id == mxCELL_CLASS; }
+
+  int is_char (void) const { return id == mxCHAR_CLASS; }
+
+  int is_complex (void) const { return 0; }
+
+  int is_double (void) const { return id == mxDOUBLE_CLASS; }
+
+  int is_int16 (void) const { return id == mxINT16_CLASS; }
+
+  int is_int32 (void) const { return id == mxINT32_CLASS; }
+
+  int is_int64 (void) const { return id == mxINT64_CLASS; }
+
+  int is_int8 (void) const { return id == mxINT8_CLASS; }
+
+  int is_logical (void) const { return id == mxLOGICAL_CLASS; }
+
+  int is_numeric (void) const
+  {
+    return (id == mxDOUBLE_CLASS || id == mxSINGLE_CLASS
+	    || id == mxINT8_CLASS || id == mxUINT8_CLASS
+	    || id == mxINT16_CLASS || id == mxUINT16_CLASS
+	    || id == mxINT32_CLASS || id == mxUINT32_CLASS
+	    || id == mxINT64_CLASS || id == mxUINT64_CLASS);
+  }
+
+  int is_single (void) const { return id == mxSINGLE_CLASS; }
+
+  int is_sparse (void) const { return 0; }
+
+  int is_struct (void) const { return id == mxSTRUCT_CLASS; }
+
+  int is_uint16 (void) const { return id == mxUINT16_CLASS; }
+
+  int is_uint32 (void) const { return id == mxUINT32_CLASS; }
+
+  int is_uint64 (void) const { return id == mxUINT64_CLASS; }
+
+  int is_uint8 (void) const { return id == mxUINT8_CLASS; }
+
+  int is_logical_scalar_true (void) const
+  {
+    return (is_logical_scalar ()
+	    && static_cast<mxLogical *> (get_data ())[0] != 0);
+  }
+
+  int get_m (void) const { return dims[0]; }
+
+  int get_n (void) const { return dims[1]; }
+
+  int *get_dimensions (void) const { return dims; }
+
+  int get_number_of_dimensions (void) const { return ndims; }
+
+  void set_m (int m) { dims[0] = m; }
+
+  void set_n (int n) { dims[1] = n; }
+
+  void set_dimensions (int *dims_arg, int ndims_arg)
+  {
+    dims = dims_arg;
+    ndims = ndims_arg;
+  }
+
+  int get_number_of_elements (void) const
+  {
+    int retval = dims[0];
+
+    for (int i = 1; i < ndims; i++)
+      retval *= dims[i];
+
+    return retval;
+  }
+
+  int is_empty (void) const { return get_number_of_elements () == 0; }
+
+  mxClassID get_class_id (void) const { return id; }
+
+  const char *get_class_name (void) const
+  {
+    switch (id)
+      {
+      case mxCELL_CLASS: return "cell";
+      case mxSTRUCT_CLASS: return "struct";
+      case mxLOGICAL_CLASS: return "logical";
+      case mxCHAR_CLASS: return "char";
+      case mxDOUBLE_CLASS: return "double";
+      case mxSINGLE_CLASS: return "single";
+      case mxINT8_CLASS: return "int8";
+      case mxUINT8_CLASS: return "uint8";
+      case mxINT16_CLASS: return "int16";
+      case mxUINT16_CLASS: return "uint16";
+      case mxINT32_CLASS: return "int32";
+      case mxUINT32_CLASS: return "uint32";
+      case mxINT64_CLASS: return "int64";
+      case mxUINT64_CLASS: return "uint64";
+      case mxFUNCTION_CLASS: return "function handle";
+      default: return "unknown";
+      }
+  }
+
+  void set_class_name (const char *name_arg)
+  {
+    mxFree (class_name);
+    class_name = static_cast<char *> (malloc (strlen (name_arg) + 1));
+    strcpy (class_name, name_arg);
+  }
+
+  mxArray *get_cell (int /*idx*/) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  void set_cell (int /*idx*/, mxArray */*val*/)
+  {
+    invalid_type_error ();
+  }
+
+  void *get_data (void) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  void *get_imag_data (void) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  void set_data (void */*pr*/)
+  {
+    invalid_type_error ();
+  }
+
+  void set_imag_data (void */*pi*/)
+  {
+    invalid_type_error ();
+  }
+
+  int *get_ir (void) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  int *get_jc (void) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  int get_nzmax (void) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  void set_ir (int */*ir*/)
+  {
+    invalid_type_error ();
+  }
+
+  void set_jc (int */*jc*/)
+  {
+    invalid_type_error ();
+  }
+
+  void set_nzmax (int /*nzmax*/)
+  {
+    invalid_type_error ();
+  }
+
+  int add_field (const char */*key*/)
+  {
+    invalid_type_error ();
+    return -1;
+  }
+
+  void remove_field (int /*key_num*/)
+  {
+    invalid_type_error ();
+  }
+
+  mxArray *get_field_by_number (int /*index*/, int /*key_num*/) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  void set_field_by_number (int /*index*/, int /*key_num*/, mxArray */*val*/)
+  {
+    invalid_type_error ();
+  }
+
+  int get_number_of_fields (void) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  const char *get_field_name_by_number (int /*key_num*/) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  int get_field_number (const char */*key*/) const
+  {
+    return -1;
+  }
+
+  int get_string (char */*buf*/, int /*buflen*/) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  char *array_to_string (void) const
+  {
+    invalid_type_error ();
+    return 0;
+  }
+
+  int calc_single_subscript (int nsubs, int *subs) const
+  {
+    int retval = 0;
+
+    int n = nsubs <= ndims ? nsubs : ndims;
+
+    while (--n > 0)
+      retval = retval * dims[n] + subs[n];
+
+    return retval;
+  }
+
+  int get_element_size (void) const
+  {
+    switch (id)
+      {
+      case mxCELL_CLASS: return sizeof (mxArray *);
+      case mxSTRUCT_CLASS: return sizeof (mxArray *);
+      case mxLOGICAL_CLASS: return sizeof (mxLogical);
+      case mxCHAR_CLASS: return sizeof (mxChar);
+      case mxDOUBLE_CLASS: return sizeof (double);
+      case mxSINGLE_CLASS: return sizeof (float);
+      case mxINT8_CLASS: return 1;
+      case mxUINT8_CLASS: return 1;
+      case mxINT16_CLASS: return 2;
+      case mxUINT16_CLASS: return 2;
+      case mxINT32_CLASS: return 4;
+      case mxUINT32_CLASS: return 4;
+      case mxINT64_CLASS: return 8;
+      case mxUINT64_CLASS: return 8;
+      case mxFUNCTION_CLASS: return 0;
+      default: return 0;
+      }    
+  }
+
+protected:
+
+  mxArray_matlab (const mxArray_matlab& val)
+    : mxArray_base (val), class_name (strsave (val.class_name)),
+      id (val.id), ndims (val.ndims),
+      dims (static_cast<int *> (malloc (ndims * sizeof (int))))
+  {
+    for (int i = 0; i < ndims; i++)
+      dims[i] = val.dims[i];
+  }
+
+  dim_vector
+  dims_to_dim_vector (void) const
+  {
+    int nd = get_number_of_dimensions ();
+
+    int *d = get_dimensions ();
+
+    dim_vector dv;
+    dv.resize (nd);
+
+    for (int i = 0; i < nd; i++)
+      dv(i) = d[i];
+
+    return dv;
+  }
+
+private:
+
+  char *class_name;
+
+  mxClassID id;
+
+  int ndims;
+  int *dims;
+
+  void invalid_type_error (void) const
+  {
+    error ("invalid type for operation");
+  }
+};
+
+// Matlab-style numeric, character, and logical data.
+
+class mxArray_number : public mxArray_matlab
+{
+public:
+
+  mxArray_number (mxClassID id_arg, int ndims_arg, const int *dims_arg,
+		  mxComplexity flag = mxREAL)
+    : mxArray_matlab (id_arg, ndims_arg, dims_arg),
+      pr (calloc (get_number_of_elements (), get_element_size ())),
+      pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { }
+
+  mxArray_number (mxClassID id_arg, const dim_vector& dv,
+		  mxComplexity flag = mxREAL)
+    : mxArray_matlab (id_arg, dv),
+      pr (calloc (get_number_of_elements (), get_element_size ())),
+      pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { }
+
+  mxArray_number (mxClassID id_arg, int m, int n, mxComplexity flag = mxREAL)
+    : mxArray_matlab (id_arg, m, n),
+      pr (calloc (get_number_of_elements (), get_element_size ())),
+      pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { }
+
+  mxArray_number (mxClassID id_arg, double val)
+    : mxArray_matlab (id_arg, 1, 1),
+      pr (calloc (get_number_of_elements (), get_element_size ())),
+      pi (0)
+  {
+    double *dpr = static_cast<double *> (pr);
+    dpr[0] = val;
+  }
+
+  mxArray_number (mxClassID id_arg, mxLogical val)
+    : mxArray_matlab (id_arg, 1, 1),
+      pr (calloc (get_number_of_elements (), get_element_size ())),
+      pi (0)
+  {
+    mxLogical *lpr = static_cast<mxLogical *> (pr);
+    lpr[0] = val;
+  }
+
+  mxArray_number (const char *str)
+    : mxArray_matlab (mxCHAR_CLASS, 1, strlen (str)),
+      pr (calloc (get_number_of_elements (), get_element_size ())),
+      pi (0)
+  {
+    mxChar *cpr = static_cast<mxChar *> (pr);
+    int nel = get_number_of_elements ();
+    for (int i = 0; i < nel; i++)
+      cpr[i] = str[i];
+  }
+
+  mxArray_number (int m, const char **str)
+    : mxArray_matlab (mxCHAR_CLASS, m, max_str_len (m, str)),
+      pr (calloc (get_number_of_elements (), get_element_size ())),
+      pi (0)
+  {
+    mxChar *cpr = static_cast<mxChar *> (pr);
+    
+    int *dv = get_dimensions ();
+
+    int nc = dv[1];
+
+    for (int j = 0; j < m; j++)
+      {
+	const char *ptr = str[j];
+
+	int tmp_len = strlen (ptr);
+
+	for (int i = 0; i < tmp_len; i++)
+	  cpr[i] = static_cast<mxChar> (ptr[i]);
+
+	for (int i = tmp_len; i < nc; i++)
+	  cpr[i] = static_cast<mxChar> (' ');
+      }	
+  }
+
+  mxArray_number *clone (void) const { return new mxArray_number (*this); }
+
+  ~mxArray_number (void)
+  {
+    mxFree (pr);
+    mxFree (pi);
+  }
+
+  template <typename ELT_T, typename ARRAY_T, typename ARRAY_ELT_T>
+  octave_value
+  int_to_ov (const dim_vector& dv) const
+  {
+    octave_value retval;
+
+    int nel = get_number_of_elements ();
+
+    ELT_T *ppr = static_cast<ELT_T *> (pr);
+
+    if (pi)
+      error ("complex integer types are not supported");
+    else
+      {
+	ARRAY_T val (dv);
+
+	ARRAY_ELT_T *ptr = val.fortran_vec ();
+
+	for (int i = 0; i < nel; i++)
+	  ptr[i] = ppr[i];
+
+	retval = val;
+      }
+
+    return retval;
+  }
+
+  octave_value as_octave_value (void) const
+  {
+    octave_value retval;
+
+    dim_vector dv = dims_to_dim_vector ();
+
+    switch (get_class_id ())
+      {
+      case mxLOGICAL_CLASS:
+	retval = int_to_ov<bool, boolNDArray, bool> (dv);
+	break;
+
+      case mxCHAR_CLASS:
+	{
+	  int nel = get_number_of_elements ();
+
+	  mxChar *ppr = static_cast<mxChar *> (pr);
+
+	  charNDArray val (dv);
+
+	  char *ptr = val.fortran_vec ();
+
+	  for (int i = 0; i < nel; i++)
+	    ptr[i] = static_cast<char> (ppr[i]);
+
+	  retval = octave_value (val, true, '\'');
+	}
+	break;
+
+      case mxSINGLE_CLASS:
+	error ("single precision data type not supported");
+	break;
+
+      case mxDOUBLE_CLASS:
+	{
+	  int nel = get_number_of_elements ();
+
+	  double *ppr = static_cast<double *> (pr);
+
+	  if (pi)
+	    {
+	      ComplexNDArray val (dv);
+
+	      Complex *ptr = val.fortran_vec ();
+
+	      double *ppi = static_cast<double *> (pi);
+
+	      for (int i = 0; i < nel; i++)
+		ptr[i] = Complex (ppr[i], ppi[i]);
+
+	      retval = val;
+	    }
+	  else
+	    {
+	      NDArray val (dv);
+
+	      double *ptr = val.fortran_vec ();
+
+	      for (int i = 0; i < nel; i++)
+		ptr[i] = ppr[i];
+
+	      retval = val;
+	    }
+	}
+	break;
+
+      case mxINT8_CLASS:
+	retval = int_to_ov<int8_t, int8NDArray, octave_int8> (dv);
+	break;
+
+      case mxUINT8_CLASS:
+	retval = int_to_ov<uint8_t, uint8NDArray, octave_uint8> (dv);
+	break;
+
+      case mxINT16_CLASS:
+	retval = int_to_ov<int16_t, int16NDArray, octave_int16> (dv);
+	break;
+
+      case mxUINT16_CLASS:
+	retval = int_to_ov<uint16_t, uint16NDArray, octave_uint16> (dv);
+	break;
+
+      case mxINT32_CLASS:
+	retval = int_to_ov<int32_t, int32NDArray, octave_int32> (dv);
+	break;
+
+      case mxUINT32_CLASS:
+	retval = int_to_ov<uint32_t, uint32NDArray, octave_uint32> (dv);
+	break;
+
+      case mxINT64_CLASS:
+	retval = int_to_ov<int64_t, int64NDArray, octave_int64> (dv);
+	break;
+
+      case mxUINT64_CLASS:
+	retval = int_to_ov<uint64_t, uint64NDArray, octave_uint64> (dv);
+	break;
+
+      default:
+	panic_impossible ();
+      }    
+
+    return retval;
+  }
+
+  int is_complex (void) const { return pi != 0; }
+
+  void *get_data (void) const { return pr; }
+
+  void *get_imag_data (void) const { return pi; }
+
+  void set_data (void *pr_arg) { pr = pr_arg; }
+
+  void set_imag_data (void *pi_arg) { pi = pi_arg; }
+
+  int get_string (char *buf, int buflen) const
+  {
+    int retval = 1;
+
+    int n = get_number_of_elements ();
+
+    if (n < buflen)
+      {
+	mxChar *ptr = static_cast<mxChar *> (pr);
+
+	for (int i = 0; i < n; i++)
+	  buf[i] = static_cast<char> (ptr[i]);
+
+	buf[n] = 0;
+      }
+
+    return retval;
+  }
+
+  char *array_to_string (void) const
+  {
+    // FIXME -- this is suposed to handle multi-byte character
+    // strings.
+
+    int nel = get_number_of_elements ();
+
+    char *buf = static_cast<char *> (malloc (nel + 1));
+
+    if (buf)
+      {
+	mxChar *ptr = static_cast<mxChar *> (pr);
+
+	for (int i = 0; i < nel; i++)
+	  buf[i] = static_cast<char> (ptr[i]);
+
+	buf[nel] = '\0';
+      }
+
+    return buf;
+  }
+
+protected:
+
+  mxArray_number (const mxArray_number& val)
+    : mxArray_matlab (val),
+      pr (malloc (get_number_of_elements () * get_element_size ())),
+      pi (val.pi ? malloc (get_number_of_elements () * get_element_size ()) : 0)
+  {
+    int ntot = get_number_of_elements () * get_element_size ();
+
+    memcpy (pr, val.pr, ntot);
+
+    if (pi)
+      memcpy (pi, val.pi, ntot);
+  }
+
+private:
+
+  void *pr;
+  void *pi;
+};
+
+// Matlab-style sparse arrays.
+
+class mxArray_sparse : public mxArray_number
+{
+public:
+
+  mxArray_sparse (mxClassID id_arg, int m, int n, int nzmax_arg,
+		  mxComplexity flag = mxREAL)
+    : mxArray_number (id_arg, m, n, flag), nzmax (nzmax_arg)
+  {
+    ir = static_cast<int *> (calloc (nzmax, sizeof (int)));
+    jc = static_cast<int *> (calloc (nzmax, sizeof (int)));
+  }
+
+  mxArray_sparse *clone (void) const { return new mxArray_sparse (*this); }
+
+  ~mxArray_sparse (void)
+  {
+    mxFree (ir);
+    mxFree (jc);
+  }
+
+  octave_value as_octave_value (void) const
+  {
+    // FIXME
+    abort ();
+    return octave_value ();
+  }
+
+  int is_sparse (void) const { return 1; }
+
+  int *get_ir (void) const { return ir; }
+
+  int *get_jc (void) const { return jc; }
+
+  int get_nzmax (void) const { return nzmax; }
+
+  void set_ir (int *ir_arg) { ir = ir_arg; }
+
+  void set_jc (int *jc_arg) { jc = jc_arg; }
+
+  void set_nzmax (int nzmax_arg) { nzmax = nzmax_arg; }
+
+private:
+
+  int nzmax;
+
+  int *ir;
+  int *jc;
+
+  mxArray_sparse (const mxArray_sparse& val)
+    : mxArray_number (val), nzmax (val.nzmax),
+      ir (static_cast<int *> (malloc (nzmax * sizeof (int)))),
+      jc (static_cast<int *> (malloc (nzmax * sizeof (int))))
+  {
+    for (int i = 0; i < nzmax; i++)
+      {
+	ir[i] = val.ir[i];
+	jc[i] = val.jc[i];
+      }
+  }
+};
+
+// Matlab-style struct arrays.
+
+class mxArray_struct : public mxArray_matlab
+{
+public:
+
+  mxArray_struct (int ndims_arg, const int *dims_arg, int num_keys_arg,
+		  const char **keys)
+    : mxArray_matlab (mxSTRUCT_CLASS, ndims_arg, dims_arg), nfields (num_keys_arg),
+      fields (static_cast<char **> (calloc (nfields, sizeof (char *)))),
+      data (static_cast<mxArray **> (calloc (nfields * get_number_of_elements (), sizeof (mxArray *))))
+  {
+    init (keys);
+  }
+
+  mxArray_struct (const dim_vector& dv, int num_keys_arg, const char **keys)
+    : mxArray_matlab (mxSTRUCT_CLASS, dv), nfields (num_keys_arg),
+      fields (static_cast<char **> (calloc (nfields, sizeof (char *)))),
+      data (static_cast<mxArray **> (calloc (nfields * get_number_of_elements (), sizeof (mxArray *))))
+  {
+    init (keys);
+  }
+
+  mxArray_struct (int m, int n, int num_keys_arg, const char **keys)
+    : mxArray_matlab (mxSTRUCT_CLASS, m, n), nfields (num_keys_arg),
+      fields (static_cast<char **> (calloc (nfields, sizeof (char *)))),
+      data (static_cast<mxArray **> (calloc (nfields * get_number_of_elements (), sizeof (mxArray *))))
+  {
+    init (keys);
+  }
+
+  void init (const char **keys)
+  {
+    for (int i = 0; i < nfields; i++)
+      fields[i] = strsave (keys[i]);
+  }
+
+  mxArray_struct *clone (void) const { return new mxArray_struct (*this); }
+
+  ~mxArray_struct (void)
+  {
+    for (int i = 0; i < nfields; i++)
+      mxFree (fields[i]);
+
+    mxFree (fields);
+
+    int ntot = nfields * get_number_of_elements ();
+
+    for  (int i = 0; i < ntot; i++)
+      mxDestroyArray (data[i]);
+
+    mxFree (data);
+  }
+
+  octave_value as_octave_value (void) const
+  {
+    dim_vector dv = dims_to_dim_vector ();
+
+    string_vector keys (fields, nfields);
+
+    Octave_map m;
+
+    int ntot = nfields * get_number_of_elements ();
+
+    for (int i = 0; i < nfields; i++)
+      {
+	Cell c (dv);
+
+	octave_value *p = c.fortran_vec ();
+
+	int k = 0;
+	for (int j = i; j < ntot; j += nfields)
+	  p[k++] = data[j]->as_octave_value ();
+
+	m.assign (keys[i], c);
+      }
+
+    return m;
+  }
+
+  int add_field (const char *key)
+  {
+    int retval = -1;
+
+    if (valid_key (key))
+      {
+	nfields++;
+
+	fields = static_cast<char **> (mxRealloc (fields, nfields * sizeof (char *)));
+
+	if (fields)
+	  {
+	    fields[nfields-1] = strsave (key);
+
+	    int nel = get_number_of_elements ();
+
+	    int ntot = nfields * nel;
+
+	    mxArray **new_data = static_cast<mxArray **> (malloc (ntot * sizeof (mxArray *)));
+
+	    if (new_data)
+	      {
+		int j = 0;
+		int k = 0;
+		int n = 0;
+
+		for (int i = 0; i < ntot; i++)
+		  {
+		    if (++n == nfields)
+		      {
+			new_data[j++] = 0;
+			n = 0;
+		      }
+		    else
+		      new_data[j++] = data[k++];
+		  }
+
+		mxFree (data);
+
+		data = new_data;
+
+		retval = nfields - 1;
+	      }
+	  }
+      }
+
+    return retval;
+  }
+
+  void remove_field (int key_num)
+  {
+    if (key_num >= 0 && key_num < nfields)
+      {
+	int nel = get_number_of_elements ();
+
+	int ntot = nfields * nel;
+
+	int new_nfields = nfields - 1;
+
+	char **new_fields = static_cast<char **> (malloc (new_nfields * sizeof (char *)));
+
+	mxArray **new_data = static_cast<mxArray **> (malloc (new_nfields * nel * sizeof (mxArray *)));
+
+	for (int i = 0; i < key_num; i++)
+	  new_fields[i] = fields[i];
+
+	for (int i = key_num + 1; i < nfields; i++)
+	  new_fields[i-1] = fields[i];
+
+	if (new_nfields > 0)
+	  {
+	    int j = 0;
+	    int k = 0;
+	    int n = 0;
+
+	    for (int i = 0; i < ntot; i++)
+	      {
+		if (n == key_num)
+		  k++;
+		else
+		  new_data[j++] = data[k++];
+
+		if (++n == nfields)
+		  n = 0;
+	      }
+	  }
+
+	nfields = new_nfields;
+
+	mxFree (fields);
+	mxFree (data);
+
+	fields = new_fields;
+	data = new_data;
+      }
+  }
+
+  mxArray *get_field_by_number (int index, int key_num) const
+  {
+    int idx = nfields * index + key_num;
+
+    return data[idx];
+  }
+
+  void set_field_by_number (int index, int key_num, mxArray *val)
+  {
+    int idx = nfields * index + key_num;
+
+    data[idx] = val;
+  }
+
+  int get_number_of_fields (void) const { return nfields; }
+
+  const char *get_field_name_by_number (int key_num) const
+  {
+    return key_num >= 0 && key_num < nfields ? fields[key_num] : 0;
+  }
+
+  int get_field_number (const char *key) const
+  {
+    int retval = -1;
+
+    for (int i = 0; i < nfields; i++)
+      {
+	if (! strcmp (key, fields[i]))
+	  {
+	    retval = i;
+	    break;
+	  }
+      }
+
+    return retval;
+  }
+
+  void *get_data (void) const { return data; }
+
+  void set_data (void *data_arg) { data = static_cast<mxArray **> (data_arg); }
+
+private:
+
+  int nfields;
+
+  char **fields;
+
+  mxArray **data;
+
+  mxArray_struct (const mxArray_struct& val)
+    : mxArray_matlab (val), nfields (val.nfields),
+      fields (static_cast<char **> (malloc (nfields * sizeof (char *)))),
+      data (static_cast<mxArray **> (malloc (nfields * get_number_of_elements () * sizeof (mxArray *))))
+  {
+    for (int i = 0; i < nfields; i++)
+      fields[i] = strsave (val.fields[i]);
+
+    int nel = get_number_of_elements ();
+
+    for (int i = 0; i < nel * nfields; i++)
+      data[i] = val.data[i]->clone ();
+  }
+};
+
+// Matlab-style cell arrays.
+
+class mxArray_cell : public mxArray_matlab
+{
+public:
+
+  mxArray_cell (int ndims_arg, const int *dims_arg)
+    : mxArray_matlab (mxCELL_CLASS, ndims_arg, dims_arg),
+      data (static_cast<mxArray **> (calloc (get_number_of_elements (), sizeof (mxArray *)))) { }
+
+  mxArray_cell (const dim_vector& dv)
+    : mxArray_matlab (mxCELL_CLASS, dv),
+      data (static_cast<mxArray **> (calloc (get_number_of_elements (), sizeof (mxArray *)))) { }
+
+  mxArray_cell (int m, int n)
+    : mxArray_matlab (mxCELL_CLASS, m, n),
+      data (static_cast<mxArray **> (calloc (get_number_of_elements (), sizeof (mxArray *)))) { }
+
+  mxArray_cell *clone (void) const { return new mxArray_cell (*this); }
+
+  ~mxArray_cell (void)
+  {
+    int nel = get_number_of_elements ();
+
+    for  (int i = 0; i < nel; i++)
+      mxDestroyArray (data[i]);
+
+    mxFree (data);
+  }
+
+  octave_value as_octave_value (void) const
+  {
+    dim_vector dv = dims_to_dim_vector ();
+
+    Cell c (dv);
+
+    int nel = get_number_of_elements ();
+
+    octave_value *p = c.fortran_vec ();
+
+    for (int i = 0; i < nel; i++)
+      p[i] = data[i]->as_octave_value ();
+
+    return c;
+  }
+
+  mxArray *get_cell (int idx) const { return data[idx]; }
+
+  void set_cell (int idx, mxArray *val) { data[idx] = val; }
+
+  void *get_data (void) const { return data; }
+
+  void set_data (void *data_arg) { data = static_cast<mxArray **> (data_arg); }
+
+private:
+
+  mxArray **data;
+
+  mxArray_cell (const mxArray_cell& val)
+    : mxArray_matlab (val),
+      data (static_cast<mxArray **> (malloc (get_number_of_elements () * sizeof (mxArray *))))
+  {
+    int nel = get_number_of_elements ();
+
+    for (int i = 0; i < nel; i++)
+      data[i] = val.data[i]->clone ();
+  }
+};
+
+// ------------------------------------------------------------------
+
+mxArray::mxArray (const octave_value& ov)
+  : rep (new mxArray_octave_value (ov)), name (0), persistent (false) { }
+
+mxArray::mxArray (mxClassID id, int ndims, const int *dims, mxComplexity flag)
+  : rep (new mxArray_number (id, ndims, dims, flag)), name (0), persistent (false) { }
+
+mxArray::mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag)
+  : rep (new mxArray_number (id, dv, flag)), name (0), persistent (false) { }
+
+mxArray::mxArray (mxClassID id, int m, int n, mxComplexity flag)
+  : rep (new mxArray_number (id, m, n, flag)), name (0), persistent (false) { }
+
+mxArray::mxArray (mxClassID id, double val)
+  : rep (new mxArray_number (id, val)), name (0), persistent (false) { }
+
+mxArray::mxArray (mxClassID id, mxLogical val)
+  : rep (new mxArray_number (id, val)), name (0), persistent (false) { }
+
+mxArray::mxArray (const char *str)
+  : rep (new mxArray_number (str)), name (0), persistent (false) { }
+
+mxArray::mxArray (int m, const char **str)
+  : rep (new mxArray_number (m, str)), name (0), persistent (false) { }
+
+mxArray::mxArray (mxClassID id, int m, int n, int nzmax, mxComplexity flag)
+  : rep (new mxArray_sparse (id, m, n, nzmax, flag)), name (0), persistent (false) { }
+
+mxArray::mxArray (int ndims, const int *dims, int num_keys, const char **keys)
+  : rep (new mxArray_struct (ndims, dims, num_keys, keys)), name (0), persistent (false) { }
+
+mxArray::mxArray (const dim_vector& dv, int num_keys, const char **keys)
+  : rep (new mxArray_struct (dv, num_keys, keys)), name (0), persistent (false) { }
+
+mxArray::mxArray (int m, int n, int num_keys, const char **keys)
+  : rep (new mxArray_struct (m, n, num_keys, keys)), name (0), persistent (false) { }
+
+mxArray::mxArray (int ndims, const int *dims)
+  : rep (new mxArray_cell (ndims, dims)), name (0), persistent (false) { }
+
+mxArray::mxArray (const dim_vector& dv)
+  : rep (new mxArray_cell (dv)), name (0), persistent (false) { }
+
+mxArray::mxArray (int m, int n)
+  : rep (new mxArray_cell (m, n)), name (0), persistent (false) { }
+
+mxArray::~mxArray (void)
+{
+  mxFree (name);
+
+  delete rep;
+}
+
+octave_value
+mxArray::as_octave_value (void) const
+{
+  return rep->as_octave_value ();
+}
+
+void
+mxArray::set_name (const char *name_arg)
+{
+  mxFree (name);
+  name = strsave (name_arg);
+}
+
+void
+mxArray::maybe_mutate (void) const
+{
+  if (rep->is_octave_value ())
+    {
+      // The mutate function returns a pointer to a complete new
+      // mxArray object (or 0, if no mutation happened).  We just want
+      // to replace the existing rep with the rep from the new object.
+
+      mxArray *new_val = rep->mutate ();
+
+      if (new_val)
+	{
+	  delete rep;
+	  rep = new_val->rep;
+	  new_val->rep = 0;
+	  delete new_val;
+	}
+    }
+}
+
+// ------------------------------------------------------------------
+
+// A clas to manage calls to MEX functions.  Mostly deals with memory
+// management.
 
 class mex
 {
 public:
 
-  mex (void) { }
+  mex (void) : memlist (), arraylist (), fname (0) { }
 
   ~mex (void)
   {
     if (! memlist.empty ())
-      error("mex: no cleanup performed");
+      error ("mex: cleanup failed");
+
+    mxFree (fname);
   }
 
-  // free all unmarked pointers obtained from malloc and calloc
-  static void cleanup (void *context);
+  const char *function_name (void) const
+  {
+    if (! fname)
+      {
+	octave_function *fcn = octave_call_stack::current ();
+
+	if (fcn)
+	  {
+	    std::string nm = fcn->name ();
+	    fname = strsave (nm.c_str ());
+	  }
+	else
+	  fname = strsave ("unknown");
+      }
+
+    return fname;
+  }
+
+  // Free all unmarked pointers obtained from malloc and calloc.
+  static void cleanup (void *ptr)
+  {
+    mex *context = static_cast<mex *> (ptr);
+
+    for (std::set<void *>::iterator p = context->memlist.begin ();
+	 p != context->memlist.end (); p++)
+      context->free (*p);
+
+    for (std::set<mxArray *>::iterator p = context->arraylist.begin ();
+	 p != context->arraylist.end (); p++)
+      context->free_value (*p);
+  }
 
   // allocate a pointer, and mark it to be freed on exit
-  Pix malloc (int n);
-
-  // allocate a pointer to be freed on exit, and initialize to 0
-  Pix calloc (int n, int t);
-
-  // reallocate a pointer obtained from malloc or calloc
-  Pix realloc (Pix ptr, int n);
-
-  // free a pointer obtained from malloc or calloc
-  void free (Pix ptr);
-
-  // mark a pointer so that it will not be freed on exit
-  void persistent (Pix ptr) { unmark (ptr); }
-
-  // make a new array value and initialize it with zeros; it will be
-  // freed on exit unless marked as persistent
-  mxArray *make_value (int nr, int nc, int cmplx);
-
-  // make a new array value and initialize from an octave value; it will be
-  // freed on exit unless marked as persistent
-  mxArray *make_value (const octave_value&);
-
-  // make a new structure value and initialize with empty matrices
-  // FIXME does this leak memory?  Is it persistent?
-  mxArray *make_value (int nr, int nc, const string_vector& keys);
-
-  // free an array and its contents
-  void free_value (mxArray *ptr);
-
-  // mark an array and its contents so it will not be freed on exit
-  void persistent (mxArray *ptr);
-
-  // 1 if error should be returned to MEX file, 0 if abort
+  void *malloc_unmarked (size_t n)
+  {
+    void *ptr = ::malloc (n);
+
+#ifdef DEBUG
+    std::cerr << "malloc " << n << " bytes: " << ptr << std::endl;
+#endif
+
+    if (! ptr)
+      {
+	// FIXME -- could use "octave_new_handler();" instead
+
+	error ("%s: failed to allocate %d bytes of memory",
+	       mexFunctionName (), n);
+
+	abort ();
+      }
+
+    global_mark (ptr);
+
+    return ptr;
+  }
+
+  void *malloc (size_t n)
+  {
+    void *ptr = malloc_unmarked (n);
+
+    mark (ptr);
+
+    return ptr;
+  }
+
+  // Allocate a pointer to be freed on exit, and initialize to 0.
+  void *calloc_unmarked (size_t n, size_t t)
+  {
+    void *ptr = malloc_unmarked (n*t);
+
+    memset (ptr, 0, n*t);
+
+    return ptr;
+  }
+
+  void *calloc (size_t n, size_t t)
+  {
+    void *ptr = calloc_unmarked (n, t);
+
+    mark (ptr);
+
+    return ptr;
+  }
+
+  // Reallocate a pointer obtained from malloc or calloc.  We don't
+  // need an "unmarked" version of this.
+  void *realloc (void *ptr, size_t n)
+  {
+    void *v = ::realloc (ptr, n);
+
+#ifdef DEBUG
+    std::cerr << "realloc: " << n << " bytes: " << ptr << std::endl;
+#endif
+
+    std::set<void *>::iterator p = memlist.find (ptr);
+
+    if (v && p != memlist.end ())
+      {
+	memlist.erase (p);
+	memlist.insert (v);
+      }
+
+    p = global_memlist.find (ptr);
+
+    if (v && p != global_memlist.end ())
+      {
+	global_memlist.erase (p);
+	global_memlist.insert (v);
+      }
+
+    return v;
+  }
+
+  // Free a pointer obtained from malloc or calloc.
+  void free (void *ptr)
+  {
+    if (ptr)
+      {
+	unmark (ptr);
+
+	std::set<void *>::iterator p = global_memlist.find (ptr);
+
+	if (p != global_memlist.end ())
+	  {
+	    global_memlist.erase (p);
+
+#ifdef DEBUG
+	    std::cerr << "free: " << ptr << std::endl;
+#endif
+	    ::free (ptr);
+	  }
+	else
+	  warning ("mxFree: skipping memory not allocated by mxMalloc, mxCalloc, or mxRealloc");
+      }
+  }
+
+  // Mark a pointer so that it will not be freed on exit.
+  void persistent (void *ptr) { unmark (ptr); }
+
+  // Make a new array value and initialize from an octave value; it will be
+  // freed on exit unless marked as persistent.
+  mxArray *make_value (const octave_value& ov)
+  {
+    mxArray *ptr = new mxArray (ov);
+    arraylist.insert (ptr);
+    return ptr;
+  }
+
+  // Free an array and its contents.
+  void free_value (mxArray *ptr)
+  {
+    arraylist.erase (ptr);
+    delete ptr;
+  }
+
+  // Mark an array and its contents so it will not be freed on exit.
+  void persistent (mxArray *ptr)
+  {
+    ptr->mark_persistent ();
+  }
+
+  // 1 if error should be returned to MEX file, 0 if abort.
   int trap_feval_error;
 
-  // longjmp return point if mexErrMsgTxt or error
+  // longjmp return point if mexErrMsgTxt or error.
   jmp_buf jump;
 
-  // trigger a long jump back to the mex calling function
+  // Trigger a long jump back to the mex calling function.
   void abort (void) { longjmp (jump, 1); }
 
 private:
 
-  // list of memory resources that need to be freed upon exit
-  MemSet memlist;
-
-  // mark a pointer to be freed on exit
-  void mark (Pix p);
-
-  // unmark a pointer to be freed on exit, either because it was
-  // made persistent, or because it was already freed
-  void unmark (Pix p);
-};
-
-// Current context
-mex *__mex = 0;
-
-// free all unmarked pointers obtained from malloc and calloc
-void
-mex::cleanup (Pix ptr)
-{
-  mex *context = static_cast<mex *> (ptr);
-
-  for (MemSet::iterator p = context->memlist.begin ();
-	p != context->memlist.end (); p++)
-    ::free (*p);
-
-  context->memlist.clear ();
-}
-
-// mark a pointer to be freed on exit
-void
-mex::mark (Pix p)
-{
+  // List of memory resources that need to be freed upon exit.
+  std::set<void *> memlist;
+
+  std::set<mxArray *> arraylist;
+
+  // The name of the currently executing function.
+  mutable char *fname;
+
+  // Mark a pointer to be freed on exit.
+  void mark (void *p)
+  {
 #ifdef DEBUG
-  if (memlist.find (p) != memlist.end ())
-    warning ("%s: double registration ignored", mexFunctionName ());
+    if (memlist.find (p) != memlist.end ())
+      warning ("%s: double registration ignored", mexFunctionName ());
 #endif
 
-  memlist.insert (p);
-}
-
-// unmark a pointer to be freed on exit, either because it was
-// made persistent, or because it was already freed
-void
-mex::unmark (Pix p)
-{
+    memlist.insert (p);
+  }
+
+  // Unmark a pointer to be freed on exit, either because it was
+  // made persistent, or because it was already freed.
+  void unmark (void *p)
+  {
 #ifdef DEBUG
-  if (memlist.find (p) != memlist.end ())
-    warning ("%s: value not marked", mexFunctionName ());
-#endif
-
-  memlist.erase (p);
-}
-
-// allocate a pointer, and mark it to be freed on exit
-Pix
-mex::malloc (int n)
-{
-  if (n == 0)
-    return 0;
-#if 0
-  // FIXME -- how do you allocate and free aligned, non-typed
-  // memory in C++?
-  Pix ptr = Pix (new double[(n+sizeof(double)-1)/sizeof(double)]);
-#else
-  // FIXME -- can we mix C++ and C-style heap management?
-  Pix ptr = ::malloc (n);
-
-  if (! ptr)
-    {
-      // FIXME -- could use "octave_new_handler();" instead
-      error ("%s: out of memory", mexFunctionName ());
-      abort ();
-    }
+    if (memlist.find (p) != memlist.end ())
+      warning ("%s: value not marked", mexFunctionName ());
 #endif
 
-  mark (ptr);
-
-  return ptr;
-}
-
-// allocate a pointer to be freed on exit, and initialize to 0
-Pix
-mex::calloc (int n, int t)
-{
-  Pix v = malloc (n*t);
-
-  memset (v, 0, n*t);
-
-  return v;
-}
-
-// reallocate a pointer obtained from malloc or calloc
-Pix
-mex::realloc (Pix ptr, int n)
-{
-#if 0
-  error ("%s: cannot reallocate using C++ new/delete operations",
-	 mexFunctionName ());
-  abort ();
-#else
-  Pix v = 0;
-  if (n == 0)
-    free (ptr);
-  else if (! ptr)
-    v = malloc (n);
-  else
-    {
-      v = ::realloc (ptr, n);
-      MemSet::iterator p = memlist.find (ptr);
-      if (v && p != memlist.end ())
-	{
-	  memlist.erase (p);
-	  memlist.insert (v);
-	}
-    }
-#endif
-  return v;
-}
-
-// free a pointer obtained from malloc or calloc
-void
-mex::free (Pix ptr)
-{
-  unmark (ptr);
-#if 0
-  delete [] ptr;
-#else
-  ::free (ptr);
+    memlist.erase (p);
+  }
+
+  // List of memory resources we allocated.
+  static std::set<void *> global_memlist;
+
+  // Mark a pointer as one we allocated.
+  void global_mark (void *p)
+  {
+#ifdef DEBUG
+    if (global_memlist.find (p) != global_memlist.end ())
+      warning ("%s: double registration ignored", mexFunctionName ());
 #endif
-}
-
-// mxArray data type
-//
-// Class mxArray is not much more than a struct for keeping together
-// dimensions and data.  It doesn't even ensure consistency between
-// the dimensions and the data.  Unfortunately you can't do better
-// than this without restricting the operations available in Matlab
-// for directly manipulating its mxArray type.
-
-typedef unsigned short mxChar;
-const int mxMAXNAM=64;
-
-class mxArray
-{
-public:
-
-  mxArray(void)
-  {
-    nr = nc = -1;
-    pr = pi = NULL;
-    keys = NULL;
-    pmap = NULL;
-    isstr = false;
-    aname[0] = '\0';
+
+    global_memlist.insert (p);
   }
 
-  ~mxArray (void)
-  { 
-    if (pmap)
-      {
-      // FIXME why don't string_vectors work?
-	for (int i = 0; i < pmap->length (); i++)
-	  delete [] keys[i];
-
-	delete [] keys;
-      }
-  }
-
-  octave_value as_octave_value (void) const;
-
-  int rows (void) const { return nr; }
-  int columns (void) const { return nc; }
-  void rows (int r) { nr = r; }
-  void columns (int c) { nc = c; }
-  int dims (void) const { return 2; }
-
-  double *imag (void) const { return pi; }
-  double *real (void) const { return pr; }
-  void imag (double *p) { pi = p; }
-  void real (double *p) { pr = p; }
-
-  bool is_empty (void) const { return nr==0 || nc==0; }
-  bool is_numeric (void) const { return ! isstr && (pr || nr == 0 || nc == 0); }
-  bool is_complex (void) const { return pi; }
-  bool is_sparse (void) const { return false; }
-  bool is_struct (void) const { return pmap; }
-
-  bool is_string (void) const { return isstr; }
-  void is_string (bool set) { isstr = set; }
-
-  const char *name (void) const { return aname; }
-  void name (const char *nm)
+  // Unmark a pointer as one we allocated.
+  void global_unmark (void *p)
   {
-    strncpy (aname, nm, mxMAXNAM);
-    aname[mxMAXNAM]='\0';
+#ifdef DEBUG
+    if (global_memlist.find (p) != global_memlist.end ())
+      warning ("%s: value not marked", mexFunctionName ());
+#endif
+
+    global_memlist.erase (p);
   }
-
-  // Structure support functions.  Matlab uses a fixed field order
-  // (the order in which the fields were added?), but Octave uses an
-  // unordered hash for structs.  We can emulate a fixed field order
-  // using pmap->keys(), which returns a string_vector of key names,
-  // but these keys will not be in the same order as the keys given in
-  // mxCreateStruct*.  Within the creating function, we can populate
-  // the key name vector in the order given, so the only problem will
-  // be those functions which assume the key order is maintained
-  // between calls from Matlab.  Unfortunately, these might exist and
-  // I can't detect them :-(
-
-  // Return the map value
-  Octave_map *map (void) const { return pmap; }
-
-  // New structure with the given presumed field order (CreateStruct call)
-  void map (Octave_map *p, const string_vector& mapkeys)
-  {
-    pmap = p;
-    keys = mapkeys.c_str_vec ();
-  }
-
-  // New structure with unknown field order (passed in from Octave)
-  void map (Octave_map *p)
-  { 
-    pmap = p;
-    if (p)
-      keys = p->keys().c_str_vec ();
-  }
-
-  // Get field given field name
-  mxArray *field (const std::string& key_arg, const int index) const
-  {
-    if (pmap && pmap->contains (key_arg))
-      return __mex->make_value (pmap->contents(key_arg)(index));
-    else
-      return 0;
-  }
-
-  // Set field given field name
-  void field (const std::string& key_arg, const int index, mxArray *value)
-  {
-    if (pmap) 
-      pmap->assign (octave_value (index+1), 
-		    key_arg, Cell (value->as_octave_value ()));
-
-    if (error_state)
-      __mex->abort ();
-  }
-
-  // Return number of fields in structure
-  int num_keys(void) const { return pmap ? pmap->length () : 0; } 
-
-  // Return field name from field number
-  const std::string key (const int key_num) const
-  {
-    if (key_num >= 0 && key_num < pmap->length ())
-      return keys[key_num];
-    else
-      return 0;
-  }
-  // Return field number from field name
-  int key (const std::string &key_name) const
-  {
-    for (int i = 0; i < pmap->length (); i++)
-      if (key_name == std::string (keys[i]))
-	return i;
-
-    return -1;
-  }
-
-  // Get field using field number
-  mxArray *field (const int key_num, const int index) const
-  {
-    if (key_num >= 0 && key_num < pmap->length ())
-      return field (keys[key_num], index);
-    else
-      return 0;
-  }
-
-  // Set field using field number
-  void field (const int key_num, const int index , mxArray *value)
-  {
-    if (key_num >= 0 && key_num < pmap->length ())
-      field (keys[key_num], index, value);
-  }
-
-private:
-  int nr;
-  int nc;
-  double *pr;
-  double *pi;
-  // FIXME -- need to have a typeid here instead of complex logic on
-  // isstr, pmap, pr, pi, etc.
-  Octave_map *pmap;
-  // string_vector keys;
-  char **keys;
-  bool isstr;
-  char aname[mxMAXNAM+1];
 };
 
-octave_value
-mxArray::as_octave_value (void) const
+// List of memory resources we allocated.
+std::set<void *> mex::global_memlist;
+
+// Current context.
+mex *mex_context = 0;
+
+void *
+mxArray::malloc (size_t n)
+{
+  return mex_context ? mex_context->malloc_unmarked (n) : malloc (n);
+}
+
+void *
+mxArray::calloc (size_t n, size_t t)
+{
+  return mex_context ? mex_context->calloc_unmarked (n, t) : calloc (n, t);
+}
+
+// ------------------------------------------------------------------
+
+// C interface to mxArray objects:
+
+// Floating point predicates.
+
+int
+mxIsFinite (const double v)
+{
+  return lo_ieee_finite (v) != 0;
+}
+
+int
+mxIsInf (const double v)
+{
+  return lo_ieee_isinf (v) != 0;
+}
+
+int
+mxIsNaN (const double v)
+{
+  return lo_ieee_isnan (v) != 0;
+}
+
+double
+mxGetEps (void)
+{
+  return DBL_EPSILON;
+}
+
+double
+mxGetInf (void)
+{
+  return lo_ieee_inf_value ();
+}
+
+double
+mxGetNaN (void)
+{
+  return lo_ieee_nan_value ();
+}
+
+// Memory management.
+void *
+mxCalloc (size_t n, size_t size)
+{
+  return mex_context ? mex_context->calloc (n, size) : calloc (n, size);
+}
+
+void *
+mxMalloc (size_t n)
+{
+  return mex_context ? mex_context->malloc (n) : malloc (n);
+}
+
+void *
+mxRealloc (void *ptr, size_t size)
+{
+  return mex_context ? mex_context->realloc (ptr, size) : realloc (ptr, size);
+}
+
+void
+mxFree (void *ptr)
 {
-  octave_value ret;
-
-  if (isstr)
-    {
-      charMatrix chm (nr, nc);
-      char *pchm = chm.fortran_vec ();
-      for (int i=0; i < nr*nc; i++)
-	pchm[i] = NINT (pr[i]);
-      ret = octave_value (chm, true);
-    }
-  else if (pmap)
-    {
-      ret = octave_value (*pmap);
-    }
-  else if (pi)
-    {
-      ComplexMatrix cm (nr, nc);
-      Complex *pcm = cm.fortran_vec ();
-      for (int i=0; i < nr*nc; i++)
-	pcm[i] = Complex (pr[i], pi[i]);
-      ret = cm;
-    }
-  else if (pr)
-    {
-      Matrix m (nr, nc);
-      double *pm = m.fortran_vec ();
-      memcpy (pm, pr, nr*nc*sizeof(double));
-      ret = m;
-    }
+  if (mex_context)
+    mex_context->free (ptr);
   else
-    ret = Matrix (0, 0);
-
-  return ret;
+    free (ptr);
+}
+  
+// Constructors.
+mxArray *
+mxCreateCellArray (int ndims, const int *dims)
+{
+  return new mxArray (ndims, dims);
+}
+
+mxArray *
+mxCreateCellMatrix (int m, int n)
+{
+  return new mxArray (m, n);
+}
+
+mxArray *
+mxCreateCharArray (int ndims, const int *dims)
+{
+  return new mxArray (mxCHAR_CLASS, ndims, dims);
 }
 
-
-// mex/mxArray interface
-
-// Make a new array value and initialize from an octave value; it will
-// be freed on exit unless marked as persistent.
-
-mxArray *mex::make_value(const octave_value &ov)
+mxArray *
+mxCreateCharMatrixFromStrings (int m, const char **str)
+{
+  return new mxArray (m, str);
+}
+
+mxArray *
+mxCreateDoubleMatrix (int m, int n, mxComplexity flag)
+{
+  return new mxArray (mxDOUBLE_CLASS, m, n, flag);
+}
+
+mxArray *
+mxCreateDoubleScalar (double val)
+{
+  return new mxArray (mxDOUBLE_CLASS, val);
+}
+
+mxArray *
+mxCreateLogicalArray (int ndims, const int *dims)
 {
-  int nr = -1;
-  int nc = -1;
-  double *pr = 0;
-  double *pi = 0;
-  Octave_map *pmap = 0;
-
-  if (ov.is_numeric_type () || ov.is_string ())
-    {
-      nr = ov.rows ();
-      nc = ov.columns ();
-    }
-  if (ov.is_map ())
-    {
-      pmap = new Octave_map (ov.map_value ());
-      nr = ov.rows ();
-      nc = ov.columns ();
-    }
-  else if (nr > 0 && nc > 0)
-    {
-      if (ov.is_string ())
-	{
-	  // FIXME - must use 16 bit unicode to represent strings.
-	  const Matrix m (ov.matrix_value (1));
-	  pr = static_cast<double *> (malloc(nr*nc*sizeof(double)));
-	  memcpy (pr, m.data (), nr*nc*sizeof(double));
-	}
-      else if (ov.is_complex_type ())
-	{
-	  // FIXME -- may want to consider lazy copying of the
-	  // matrix, but this will only help if the matrix is being
-	  // passed on to octave via callMATLAB later.
-	  const ComplexMatrix cm (ov.complex_matrix_value ());
-	  const Complex *pz = cm.data ();
-	  pr = static_cast<double *> (malloc (nr*nc*sizeof(double)));
-	  pi = static_cast<double *> (malloc (nr*nc*sizeof(double)));
-	  for (int i = 0; i < nr*nc; i++)
-	    {
-	      pr[i] = real (pz[i]);
-	      pi[i] = imag (pz[i]);
-	    }
-	}
-      else
-	{
-	  const Matrix m (ov.matrix_value ());
-	  pr = static_cast<double *> (malloc (nr*nc*sizeof(double)));
-	  memcpy (pr, m.data (), nr*nc*sizeof(double));
-	}
-    }
-
-  mxArray *value = static_cast<mxArray *> (malloc (sizeof(mxArray)));
-
-  value->is_string (ov.is_string ());
-  value->real (pr);
-  value->imag (pi);
-  value->map (pmap);
-  value->rows (nr);
-  value->columns (nc);
-  value->name ("");
-
-  return value;
+  return new mxArray (mxLOGICAL_CLASS, ndims, dims);
+}
+
+mxArray *
+mxCreateLogicalMatrix (int m, int n)
+{
+  return new mxArray (mxLOGICAL_CLASS, m, n);
+}
+
+mxArray *
+mxCreateLogicalScalar (int val)
+{
+  return new mxArray (mxLOGICAL_CLASS, val);
+}
+
+mxArray *
+mxCreateNumericArray (int ndims, const int *dims, mxClassID class_id,
+		      mxComplexity flag)
+{
+  return new mxArray (class_id, ndims, dims, flag);
 }
 
-// Make a new array value and initialize it with zeros; it will be
-// freed on exit unless marked as persistent.
+mxArray *
+mxCreateNumericMatrix (int m, int n, mxClassID class_id, mxComplexity flag)
+{
+  return new mxArray (class_id, m, n, flag);
+}
+
+mxArray *
+mxCreateSparse (int m, int n, int nzmax, mxComplexity flag)
+{
+  return new mxArray (mxDOUBLE_CLASS, m, n, nzmax, flag);
+}
+
+mxArray *
+mxCreateSparseLogicalMatrix (int m, int n, int nzmax)
+{
+  return new mxArray (mxLOGICAL_CLASS, m, n, nzmax);
+}
+
+mxArray *
+mxCreateString (const char *str)
+{
+  return new mxArray (str);
+}
+
+mxArray *
+mxCreateStructArray (int ndims, int *dims, int num_keys, const char **keys)
+{
+  return new mxArray (ndims, dims, num_keys, keys);
+}
 
 mxArray *
-mex::make_value (int nr, int nc, int cmplx)
+mxCreateStructMatrix (int m, int n, int num_keys, const char **keys)
+{
+  return new mxArray (m, n, num_keys, keys);
+}
+
+// Copy constructor.
+mxArray *
+mxDuplicateArray (const mxArray *ptr)
+{
+  return ptr->clone ();
+}
+
+// Destructor.
+void
+mxDestroyArray (mxArray *ptr)
+{
+  if (! ptr->is_persistent ())
+    {
+      if (mex_context)
+	mex_context->free_value (ptr);
+      else
+	delete ptr;
+    }
+}
+
+// Type Predicates.
+int
+mxIsCell (const mxArray *ptr)
+{
+  return ptr->is_cell ();
+}
+
+int
+mxIsChar (const mxArray *ptr)
+{
+  return ptr->is_char ();
+}
+
+int
+mxIsClass (const mxArray *ptr, const char *name)
+{
+  return ptr->is_class (name);
+}
+
+int
+mxIsComplex (const mxArray *ptr)
+{
+  return ptr->is_complex ();
+}
+
+int
+mxIsDouble (const mxArray *ptr)
+{
+  return ptr->is_double ();
+}
+
+int
+mxIsInt16 (const mxArray *ptr)
+{
+  return ptr->is_int16 ();
+}
+
+int
+mxIsInt32 (const mxArray *ptr)
+{
+  return ptr->is_int32 ();
+}
+
+int
+mxIsInt64 (const mxArray *ptr)
+{
+  return ptr->is_int64 ();
+}
+
+int
+mxIsInt8 (const mxArray *ptr)
+{
+  return ptr->is_int8 ();
+}
+
+int
+mxIsLogical (const mxArray *ptr)
+{
+  return ptr->is_logical ();
+}
+
+int
+mxIsNumeric (const mxArray *ptr)
+{
+  return ptr->is_numeric ();
+}
+
+int
+mxIsSingle (const mxArray *ptr)
+{
+  return ptr->is_single ();
+}
+
+int
+mxIsSparse (const mxArray *ptr)
+{
+  return ptr->is_sparse ();
+}
+
+int
+mxIsStruct (const mxArray *ptr)
+{
+  return ptr->is_struct ();
+}
+
+int
+mxIsUint16 (const mxArray *ptr)
+{
+  return ptr->is_uint16 ();
+}
+
+int
+mxIsUint32 (const mxArray *ptr)
+{
+  return ptr->is_uint32 ();
+}
+
+int
+mxIsUint64 (const mxArray *ptr)
+{
+  return ptr->is_uint64 ();
+}
+
+int
+mxIsUint8 (const mxArray *ptr)
+{
+  return ptr->is_uint8 ();
+}
+
+// Odd type+size predicate.
+int
+mxIsLogicalScalar (const mxArray *ptr)
+{
+  return ptr->is_logical_scalar ();
+}
+
+// Odd type+size+value predicate.
+int
+mxIsLogicalScalarTrue (const mxArray *ptr)
+{
+  return ptr->is_logical_scalar_true ();
+}
+
+// Size predicate.
+int
+mxIsEmpty (const mxArray *ptr)
+{
+  return ptr->is_empty ();
+}
+
+// Just plain odd thing to ask of a value.
+int
+mxIsFromGlobalWS (const mxArray */*ptr*/)
+{
+  // FIXME
+  abort ();
+  return 0;
+}
+
+// Dimension extractors.
+int
+mxGetM (const mxArray *ptr)
+{
+  return ptr->get_m ();
+}
+
+int
+mxGetN (const mxArray *ptr)
+{
+  return ptr->get_n ();
+}
+
+int *
+mxGetDimensions (const mxArray *ptr)
 {
-
-  mxArray *value = static_cast<mxArray *> (malloc (sizeof(mxArray)));
-  double *p = static_cast<double *>  (calloc (nr*nc, sizeof(double)));
-
-  value->real (p);
-  if (cmplx)
-    value->imag (static_cast<double *> (calloc (nr*nc, sizeof(double))));
-  else
-    value->imag (static_cast<double *> (Pix (0)));
-  value->rows (nr);
-  value->columns (nc);
-  value->is_string (false);
-  value->map (0);
-  value->name ("");
-
-  return value;
+  return ptr->get_dimensions ();
+}
+
+int
+mxGetNumberOfDimensions (const mxArray *ptr)
+{
+  return ptr->get_number_of_dimensions ();
+}
+
+int
+mxGetNumberOfElements (const mxArray *ptr)
+{
+  return ptr->get_number_of_elements ();
+}
+
+// Dimension setters.
+void
+mxSetM (mxArray *ptr, int m)
+{
+  ptr->set_m (m);
+}
+
+void
+mxSetN (mxArray *ptr, int n)
+{
+  ptr->set_n (n);
+}
+
+void
+mxSetDimensions (mxArray *ptr, int *dims, int ndims)
+{
+  ptr->set_dimensions (dims, ndims);
+}
+  
+// Data extractors.
+double *
+mxGetPr (const mxArray *ptr)
+{
+  return static_cast<double *> (ptr->get_data ());
+}
+
+double *
+mxGetPi (const mxArray *ptr)
+{
+  return static_cast<double *> (ptr->get_imag_data ());
+}
+
+double
+mxGetScalar (const mxArray *ptr)
+{
+  double *d = mxGetPr (ptr);
+  return d[0];
+}
+
+mxChar *
+mxGetChars (const mxArray *ptr)
+{
+  return static_cast<mxChar *> (ptr->get_data ());
+}
+
+mxLogical *
+mxGetLogicals (const mxArray *ptr)
+{
+  return static_cast<mxLogical *> (ptr->get_data ());
+}
+
+void *
+mxGetData (const mxArray *ptr)
+{
+  return ptr->get_data ();
+}
+
+void *
+mxGetImagData (const mxArray *ptr)
+{
+  return ptr->get_imag_data ();
+}
+
+// Data setters.
+void
+mxSetPr (mxArray *ptr, double *pr)
+{
+  ptr->set_data (pr);
+}
+
+void
+mxSetPi (mxArray *ptr, double *pi)
+{
+  ptr->set_imag_data (pi);
 }
 
-// Make a new structure value and initialize with empty matrices
-// FIXME does this leak memory?  Is it persistent?
+void
+mxSetData (mxArray *ptr, void *pr)
+{
+  ptr->set_data (pr);
+}
+
+void
+mxSetImagData (mxArray *ptr, void *pi)
+{
+  ptr->set_imag_data (pi);
+}
+
+// Classes.
+mxClassID
+mxGetClassID (const mxArray *ptr)
+{
+  return ptr->get_class_id ();
+}
+
+const char *
+mxGetClassName (const mxArray *ptr)
+{
+  return ptr->get_class_name ();
+}
+
+void
+mxSetClassName (mxArray *ptr, const char *name)
+{
+  ptr->set_class_name (name);
+}
+
+// Cell support.
+mxArray *
+mxGetCell (const mxArray *ptr, int idx)
+{
+  return ptr->get_cell (idx);
+}
+
+void
+mxSetCell (mxArray *ptr, int idx, mxArray *val)
+{
+  ptr->set_cell (idx, val);
+}
+
+// Sparse support.
+int *
+mxGetIr (const mxArray *ptr)
+{
+  return ptr->get_ir ();
+}
+
+int *
+mxGetJc (const mxArray *ptr)
+{
+  return ptr->get_jc ();
+}
+
+int
+mxGetNzmax (const mxArray *ptr)
+{
+  return ptr->get_nzmax ();
+}
+
+void
+mxSetIr (mxArray *ptr, int *ir)
+{
+  ptr->set_ir (ir);
+}
+
+void
+mxSetJc (mxArray *ptr, int *jc)
+{
+  ptr->set_jc (jc);
+}
+
+void
+mxSetNzmax (mxArray *ptr, int nzmax)
+{
+  ptr->set_nzmax (nzmax);
+}
+
+// Structure support.
+int
+mxAddField (mxArray *ptr, const char *key)
+{
+  return ptr->add_field (key);
+}
+
+void
+mxRemoveField (mxArray *ptr, int key_num)
+{
+  ptr->remove_field (key_num);
+}
 
 mxArray *
-mex::make_value (int nr, int nc, const string_vector& keys)
+mxGetField (const mxArray *ptr, int index, const char *key)
+{
+  int key_num = mxGetFieldNumber (ptr, key);
+  return mxGetFieldByNumber (ptr, index, key_num);
+}
+
+mxArray *
+mxGetFieldByNumber (const mxArray *ptr, int index, int key_num)
 {
-  if (keys.length () == 0)
-    return 0;
-
-  Cell empty (nr, nc);
-  Octave_map *pmap = new Octave_map (keys[0], empty);
-  for (int i=1; i < keys.length (); i++)
-    pmap->assign (keys[i], empty);
-
-  mxArray *value = static_cast<mxArray *> (malloc (sizeof(mxArray)));
-
-  value->rows (nr);
-  value->columns (nc);
-  value->map (pmap, keys);
-
-  return value;
+  return ptr->get_field_by_number (index, key_num);
 }
 
-// free an array and its contents
+void
+mxSetField (mxArray *ptr, int index, const char *key, mxArray *val)
+{
+  int key_num = mxGetFieldNumber (ptr, key);
+  mxSetFieldByNumber (ptr, index, key_num, val);
+}
 
 void
-mex::free_value (mxArray *ptr)
+mxSetFieldByNumber (mxArray *ptr, int index, int key_num, mxArray *val)
 {
-  free (ptr->real ());
-  free (ptr->imag ());
-  free (ptr);
+  ptr->set_field_by_number (index, key_num, val);
+}
+
+int
+mxGetNumberOfFields (const mxArray *ptr)
+{
+  return ptr->get_number_of_fields ();
 }
 
-// mark an array and its contents so it will not be freed on exit
-
-void
-mex::persistent (mxArray *ptr)
+const char *
+mxGetFieldNameByNumber (const mxArray *ptr, int key_num)
 {
-  persistent (Pix (ptr->real ()));
-  persistent (Pix (ptr->imag ()));
-  persistent (Pix (ptr));
+  return ptr->get_field_name_by_number (key_num);
+}
+
+int
+mxGetFieldNumber (const mxArray *ptr, const char *key)
+{
+  return ptr->get_field_number (key);
 }
 
-
-// Octave interface to mex files
-
-#if 0
-// Don't bother trapping stop/exit
-// To trap for STOP in fortran code, this needs to be registered with atexit
-static void mex_exit()
+int
+mxGetString (const mxArray *ptr, char *buf, int buflen)
+{
+  return ptr->get_string (buf, buflen);
+}
+
+char *
+mxArrayToString (const mxArray *ptr)
 {
-  if (__mex)
-    {
-      error ("%s: program aborted", mexFunctionName ());
-      __mex->abort ();
-    }
+  return ptr->array_to_string ();
+}
+  
+int
+mxCalcSingleSubscript (const mxArray *ptr, int nsubs, int *subs)
+{
+  return ptr->calc_single_subscript (nsubs, subs);
 }
-#endif
+
+int
+mxGetElementSize (const mxArray *ptr)
+{
+  return ptr->get_element_size ();
+}
+
+// ------------------------------------------------------------------
 
 typedef void (*cmex_fptr) (int nlhs, mxArray **plhs, int nrhs, mxArray **prhs);
 typedef F77_RET_T (*fmex_fptr) (int& nlhs, mxArray **plhs, int& nrhs, mxArray **prhs);
@@ -642,6 +2650,7 @@
   // the stack handle isn't exported from toplev.cc, so we can't.  mex_exit
   // would have to be declared as DEFUN(mex_exit,,,"") of course.
   static bool unregistered = true;
+
   if (unregistered)
     {
       atexit (mex_exit);
@@ -649,31 +2658,32 @@
     }
 #endif
 
-  // Use nargout+1 since even for zero specified args, still want to
-  // be able to return an ans.
+  // Use at least 1 for nargout since even for zero specified args,
+  // still want to be able to return an ans.
 
   int nargin = args.length ();
-  OCTAVE_LOCAL_BUFFER(mxArray*, argin, nargin);
+  OCTAVE_LOCAL_BUFFER (mxArray *, argin, nargin);
   for (int i = 0; i < nargin; i++)
     argin[i] = 0;
 
   int nout = nargout == 0 ? 1 : nargout;
-  OCTAVE_LOCAL_BUFFER(mxArray*, argout, nout);
+  OCTAVE_LOCAL_BUFFER (mxArray *, argout, nout);
   for (int i = 0; i < nout; i++)
     argout[i] = 0;
 
   mex context;
-  unwind_protect::add (mex::cleanup, Pix (&context));
+
+  unwind_protect::add (mex::cleanup, static_cast<void *> (&context));
 
   for (int i = 0; i < nargin; i++)
     argin[i] = context.make_value (args(i));
 
   // Save old mex pointer.
-  unwind_protect_ptr (__mex);
+  unwind_protect_ptr (mex_context);
 
   if (setjmp (context.jump) == 0)
     {
-      __mex = &context;
+      mex_context = &context;
 
       if (cs == use_fortran)
 	{
@@ -702,14 +2712,21 @@
   if (! error_state)
     {
       if (nargout == 0 && argout[0])
-	retval(0) = argout[0]->as_octave_value ();
-      else
 	{
-	  retval.resize (nargout);
-
-	  for (int i = 0; i < nargout; i++)
-	    if (argout[i])
+	  // We have something for ans.
+	  nargout = 1;
+	}
+
+      retval.resize (nargout);
+
+      for (int i = 0; i < nargout; i++)
+	{
+	  if (argout[i])
+	    {
 	      retval(i) = argout[i]->as_octave_value ();
+
+	      //	      mxDestroyArray (argout[i]);
+	    }
 	}
     }
 
@@ -733,24 +2750,95 @@
 
 // C interface to mex functions:
 
-extern "C" {
-
 const char *
 mexFunctionName (void)
 {
-  static char *retval = 0;
-
-  delete [] retval;
-
-  octave_function *fcn = octave_call_stack::current ();
-
-  if (fcn)
+  return mex_context ? mex_context->function_name () : "unknown";
+}
+
+int
+mexCallMATLAB (int nargout, mxArray *argout[], int nargin, mxArray *argin[],
+	       const char *fname)
+{
+  octave_value_list args;
+
+  // FIXME -- do we need unwind protect to clean up args?  Off hand, I
+  // would say that this problem is endemic to Octave and we will
+  // continue to have memory leaks after Ctrl-C until proper exception
+  // handling is implemented.  longjmp() only clears the stack, so any
+  // class which allocates data on the heap is going to leak.
+
+  args.resize (nargin);
+
+  for (int i = 0; i < nargin; i++)
+    args(i) = argin[i]->as_octave_value ();
+
+  octave_value_list retval = feval (fname, args, nargout);
+
+  if (error_state && mex_context->trap_feval_error == 0)
     {
-      std::string nm = fcn->name ();
-      retval = strsave (nm.c_str ());
+      // FIXME -- is this the correct way to clean up?  abort() is
+      // going to trigger a long jump, so the normal class destructors
+      // will not be called.  Hopefully this will reduce things to a
+      // tiny leak.  Maybe create a new octave memory tracer type
+      // which prints a friendly message every time it is
+      // created/copied/deleted to check this.
+
+      args.resize (0);
+      retval.resize (0);
+      mex_context->abort ();
+    }
+
+  int num_to_copy = retval.length ();
+
+  if (nargout < retval.length ())
+    num_to_copy = nargout;
+
+  for (int i = 0; i < num_to_copy; i++)
+    {
+      // FIXME -- it would be nice to avoid copying the value here,
+      // but there is no way to steal memory from a matrix, never mind
+      // that matrix memory is allocated by new[] and mxArray memory
+      // is allocated by malloc().
+      argout[i] = mex_context->make_value (retval (i));
+    }
+
+  while (num_to_copy < nargout)
+    argout[num_to_copy++] = 0;
+
+  if (error_state)
+    {
+      error_state = 0;
+      return 1;
     }
   else
-    retval = strsave ("unknown");
+    return 0;
+}
+
+void
+mexSetTrapFlag (int flag)
+{
+  if (mex_context)
+    mex_context->trap_feval_error = flag;
+}
+
+int
+mexEvalString (const char *s)
+{
+  int retval = 0;
+
+  int parse_status;
+
+  octave_value_list ret;
+
+  ret = eval_string (s, false, parse_status, 0);
+
+  if (parse_status || error_state)
+    {
+      error_state = 0;
+
+      retval = 1;
+    }
 
   return retval;
 }
@@ -764,7 +2852,7 @@
     // Just set the error state; don't print msg.
     error ("");
 
-  __mex->abort();
+  mex_context->abort ();
 }
 
 void
@@ -776,7 +2864,7 @@
     // Just set the error state; don't print msg.
     error ("");
 
-  __mex->abort();
+  mex_context->abort ();
 }
 
 void
@@ -800,282 +2888,6 @@
   va_end (args);
 }
 
-// Floating point representation.
-
-int mxIsFinite (const double v) { return lo_ieee_finite (v) != 0; }
-int mxIsInf (const double v) { return lo_ieee_isinf (v) != 0; }
-int mxIsNaN (const double v) { return lo_ieee_isnan (v) != 0; }
-
-double mxGetEps (void) { return DBL_EPSILON; }
-double mxGetInf (void) { return lo_ieee_inf_value (); }
-double mxGetNaN (void) { return lo_ieee_nan_value (); }
-
-int
-mexEvalString (const char *s)
-{
-  int parse_status;
-  octave_value_list ret;
-  ret = eval_string (s, false, parse_status, 0);
-  if (parse_status || error_state)
-    {
-      error_state = 0;
-      return 1;
-    }
-  else
-    return 0;
-}
-
-int
-mexCallMATLAB (int nargout, mxArray *argout[],
-	       int nargin, mxArray *argin[],
-	       const char *fname)
-{
-  octave_value_list args;
-
-  // FIXME -- do we need unwind protect to clean up args?  Off hand, I
-  // would say that this problem is endemic to Octave and we will
-  // continue to have memory leaks after Ctrl-C until proper exception
-  // handling is implemented.  longjmp() only clears the stack, so any
-  // class which allocates data on the heap is going to leak.
-
-  args.resize (nargin);
-
-  for (int i = 0; i < nargin; i++)
-    args(i) = argin[i]->as_octave_value ();
-
-  octave_value_list retval = feval (fname, args, nargout);
-
-  if (error_state && __mex->trap_feval_error == 0)
-    {
-      // FIXME -- is this the correct way to clean up?  abort() is
-      // going to trigger a long jump, so the normal class destructors
-      // will not be called.  Hopefully this will reduce things to a
-      // tiny leak.  Maybe create a new octave memory tracer type
-      // which prints a friendly message every time it is
-      // created/copied/deleted to check this.
-
-      args.resize (0);
-      retval.resize (0);
-      __mex->abort ();
-    }
-
-  int num_to_copy = retval.length ();
-
-  if (nargout < retval.length ())
-    num_to_copy = nargout;
-
-  for (int i = 0; i < num_to_copy; i++)
-    {
-      // FIXME -- it would be nice to avoid copying the value here,
-      // but there is no way to steal memory from a matrix, never mind
-      // that matrix memory is allocated by new[] and mxArray memory
-      // is allocated by malloc().
-      argout[i] = __mex->make_value (retval (i));
-    }
-
-  while (num_to_copy < nargout)
-    argout[num_to_copy++] = 0;
-
-  if (error_state)
-    {
-      error_state = 0;
-      return 1;
-    }
-  else
-    return 0;
-}
-
-void mexSetTrapFlag (int flag) { __mex->trap_feval_error = flag;  }
-
-Pix mxMalloc (int n) { return __mex->malloc(n);  }
-Pix mxCalloc (int n, int size) { return __mex->calloc (n, size); }
-Pix mxRealloc (Pix ptr, int n) { return __mex->realloc (ptr, n); }
-void mxFree (Pix ptr) { __mex->free (ptr); }
-void mexMakeMemoryPersistent (Pix ptr) { __mex->persistent (ptr); }
-
-mxArray *
-mxCreateDoubleMatrix (int nr, int nc, int iscomplex)
-{
-  return __mex->make_value(nr, nc, iscomplex);
-}
-
-mxArray *
-mxCreateDoubleScalar (double val)
-{ 
-  mxArray *ptr = mxCreateDoubleMatrix (1, 1, 0);
-  *mxGetPr (ptr) = val;
-  return ptr;
-}
-
-mxArray *
-mxCreateLogicalScalar (int val)
-{ 
-  mxArray *ptr = mxCreateDoubleMatrix (1, 1, 0);
-  *mxGetPr (ptr) = val;
-  return ptr;
-}
-
-void mxDestroyArray (mxArray *v) { __mex->free (v);  }
-
-mxArray *
-mxDuplicateArray (const mxArray *ptr)
-{
-  return __mex->make_value (ptr->as_octave_value ());
-}
-
-void mexMakeArrayPersistent (mxArray *ptr) { __mex->persistent (ptr); }
-
-int mxIsChar (const mxArray *ptr) { return ptr->is_string (); }
-int mxIsSparse (const mxArray *ptr) { return ptr->is_sparse (); }
-int mxIsFull(const mxArray *ptr) { return !ptr->is_sparse (); }
-int mxIsNumeric (const mxArray *ptr) { return ptr->is_numeric (); }
-int mxIsComplex (const mxArray *ptr) { return ptr->is_complex (); }
-int mxIsDouble (const mxArray *) { return true; }
-int mxIsEmpty (const mxArray *ptr) { return ptr->is_empty (); }
-
-int
-mxIsLogicalScalar (const mxArray *ptr)
-{
-  return (ptr->is_numeric ()
-	  && ptr->rows () == 1 && ptr->columns () == 1
-	  && *ptr->real ());
-}
-
-double *mxGetPr (const mxArray *ptr) { return ptr->real (); }
-double *mxGetPi (const mxArray *ptr) { return ptr->imag (); }
-int mxGetM (const mxArray *ptr) { return ptr->rows (); }
-int mxGetN (const mxArray *ptr) { return ptr->columns (); }
-int mxGetNumberOfDimensions (const mxArray *ptr) { return ptr->dims (); }
-int mxGetNumberOfElements (const mxArray *ptr) { return ptr->rows () * ptr->columns (); }
-void mxSetM (mxArray *ptr, int M) { ptr->rows (M); }
-void mxSetN (mxArray *ptr, int N) { ptr->columns (N); }
-void mxSetPr (mxArray *ptr, double *pr) { ptr->real (pr); }
-void mxSetPi (mxArray *ptr, double *pi) { ptr->imag (pi); }
-
-double
-mxGetScalar (const mxArray *ptr)
-{
-  double *pr =  ptr->real ();
-  if (! pr)
-    mexErrMsgTxt ("calling mxGetScalar on an empty matrix");
-  return pr[0];
-}
-
-int
-mxGetString (const mxArray *ptr, char *buf, int buflen)
-{
-  if (ptr->is_string ())
-    {
-      int nr = ptr->rows ();
-      int nc = ptr->columns ();
-      int n = nr*nc < buflen ? nr*nc : buflen;
-      const double *pr = ptr->real ();
-      for (int i = 0; i < n; i++)
-	buf[i] = NINT (pr[i]);
-      if (n < buflen)
-	buf[n] = '\0';
-      return n >= buflen;
-    }
-  else
-    return 1;
-}
-
-char *
-mxArrayToString (const mxArray *ptr)
-{
-  int nr = ptr->rows ();
-  int nc = ptr->columns ();
-  int n = nr*nc*sizeof(mxChar)+1;
-  char *buf = static_cast<char *> (mxMalloc (n));
-  if (buf)
-    mxGetString (ptr, buf, n);
-
-  return buf;
-}
-
-mxArray *
-mxCreateString (const char *str)
-{
-  int n = strlen (str);
-  mxArray *m = __mex->make_value (1, n, 0);
-  if (! m)
-    return m;
-  m->is_string (true);
-
-  double *pr = m->real ();
-  for (int i = 0; i < n; i++)
-    pr[i] = str[i];
-
-  return m;
-}
-
-mxArray *
-mxCreateCharMatrixFromStrings (int n, const char **str)
-{
-  // Find length of the individual strings.
-  Array<int> len (n);
-
-  for (int i = 0; i < n; i++)
-    len(i) = strlen (str[i]);
-
-  // Find maximum length.
-  int maxlen = 0;
-  for (int i = 0; i < n; i++)
-    if (len(i) > maxlen)
-      maxlen = len(i);
-
-  // Need a place to copy them.
-  mxArray *m = __mex->make_value (n, maxlen, 0);
-  if (! m)
-    return m;
-  m->is_string (true);
-
-  // Do the copy (being sure not to exceed the length of any of the
-  // strings).
-  double *pr = m->real ();
-  for (int j = 0; j < maxlen; j++)
-    for (int i = 0; i < n; i++)
-      if (j < len(i))
-	*pr++ = str[i][j];
-      else
-	*pr++ = '\0';
-
-  return m;
-}
-
-int
-mexPutVariable (const char *space, const char *name, mxArray *ptr)
-{
-  if (! ptr)
-    return 1;
-
-  if (! name)
-    return 1;
-
-  if (name[0] == '\0')
-    name = ptr->name ();
-
-  if (! name || name[0] == '\0')
-    return 1;
-
-  if (! strcmp (space, "global"))
-    set_global_value (name, ptr->as_octave_value ());
-  else if (! strcmp (space, "caller"))
-    {
-      // FIXME -- this belongs in variables.cc.
-      symbol_record *sr = curr_sym_tab->lookup (name, true);
-      if (sr)
-	sr->define (ptr->as_octave_value ());
-      else
-	panic_impossible ();
-    }
-  else if (! strcmp (space, "base"))
-    mexErrMsgTxt ("mexPutVariable: 'base' symbol table not implemented");
-  else
-    mexErrMsgTxt ("mexPutVariable: symbol table does not exist");
-  return 0;
-}
-
 mxArray *
 mexGetVariable (const char *space, const char *name)
 {
@@ -1092,7 +2904,7 @@
   else if (! strcmp (space, "caller"))
     sr = curr_sym_tab->lookup (name);
   else if (! strcmp (space, "base"))
-    mexErrMsgTxt ("mexGetVariable: 'base' symbol table not implemented");
+    sr = top_level_sym_tab->lookup (name);
   else
     mexErrMsgTxt ("mexGetVariable: symbol table does not exist");
 
@@ -1102,8 +2914,9 @@
 
       if (sr_def.is_defined ())
 	{
-	  retval = __mex->make_value (sr_def);
-	  retval->name (name);
+	  retval = mex_context->make_value (sr_def);
+
+	  retval->set_name (name);
 	}
     }
 
@@ -1116,217 +2929,141 @@
   return mexGetVariable (space, name);
 }
 
-const char *mxGetName (const mxArray *ptr) { return ptr->name (); }
-
-void mxSetName (mxArray *ptr, const char*nm) { ptr->name (nm); }
-
-mxArray *
-mxCreateStructMatrix (int nr, int nc, int num_keys, const char **keys)
+int
+mexPutVariable (const char *space, const char *name, mxArray *ptr)
 {
-  const string_vector ordered_keys (keys, num_keys);
-  mxArray *m = __mex->make_value (nr, nc, ordered_keys);
-  return m;
-}
-
-mxArray *
-mxGetField (const mxArray *ptr, int index, const char *key)
-{
-  return ptr->field (key, index);
+  if (! ptr)
+    return 1;
+
+  if (! name)
+    return 1;
+
+  if (name[0] == '\0')
+    name = ptr->get_name ();
+
+  if (! name || name[0] == '\0')
+    return 1;
+
+  if (! strcmp (space, "global"))
+    set_global_value (name, ptr->as_octave_value ());
+  else
+    {
+      // FIXME -- this belongs in variables.cc.
+
+      symbol_record *sr = 0;
+
+      if (! strcmp (space, "caller"))
+	sr = curr_sym_tab->lookup (name, true);
+      else if (! strcmp (space, "base"))
+	sr = top_level_sym_tab->lookup (name, true);
+      else
+	mexErrMsgTxt ("mexPutVariable: symbol table does not exist");
+
+      if (sr)
+	sr->define (ptr->as_octave_value ());
+      else
+	panic_impossible ();
+    }
+
+  return 0;
 }
 
 void
-mxSetField (mxArray *ptr, int index, const char *key, mxArray *val)
-{
-  ptr->field (key, index, val);
-}
-
-int mxGetNumberOfFields (const mxArray *ptr) { return ptr->num_keys (); }
-int mxIsStruct (const mxArray *ptr) { return ptr->is_struct (); }
-
-const char *
-mxGetFieldNameByNumber (const mxArray *ptr, int key_num) 
+mexMakeArrayPersistent (mxArray *ptr)
 {
-  return ptr->key(key_num).c_str ();
-}
-
-int
-mxGetFieldNumber (const mxArray *ptr, const char *key)
-{
-  return ptr->key (key);
-}
-
-mxArray *
-mxGetFieldByNumber (const mxArray *ptr, int index, int key_num)
-{
-  return ptr->field (key_num, index);
+  if (mex_context)
+    mex_context->persistent (ptr);
 }
 
 void
-mxSetFieldByNumber (mxArray *ptr, int index, int key_num, mxArray *val)
+mexMakeMemoryPersistent (void *ptr)
 {
-  return ptr->field (key_num,index,val);
-}
-
-} // extern "C"
-
-// Fortran interface to mex functions
-//
-// Where possible, these call the equivalent C function since that API
-// is fixed.  It costs and extra function call, but is easier to
-// maintain.
-
-extern "C" {
-
-void F77_FUNC (mexerrmsgtxt, MEXERRMSGTXT) (const char *s, long slen)
-{
-  if (slen > 1 || (slen == 1 && s[0] != ' ') )
-    error ("%s: %.*s", mexFunctionName (), slen, s);
-  else
-    // Just set the error state; don't print msg.
-    error ("");
-
-  __mex->abort();
-}
-
-void F77_FUNC (mexprintf, MEXPRINTF) (const char *s, long slen)
-{
-  mexPrintf ("%.*s\n", slen, s);
+  if (mex_context)
+    mex_context->persistent (ptr);
 }
 
-int F77_FUNC (mexisfinite, MEXISFINITE) (double v) { return mxIsFinite (v); }
-int F77_FUNC (mexisinf, MEXISINF) (double v) { return mxIsInf (v); }
-int F77_FUNC (mexisnan, MEXISNAN) (double v) { return mxIsNaN (v); }
-
-double F77_FUNC (mexgeteps, MEXGETEPS) (void) { return mxGetEps (); }
-double F77_FUNC (mexgetinf, MEXGETINF) (void) { return mxGetInf (); }
-double F77_FUNC (mexgetnan, MEXGETNAN) (void) { return mxGetNaN (); }
-
-// Array access:
-
-Pix F77_FUNC (mxcreatefull, MXCREATEFULL)
-  (const int& nr, const int& nc, const int& iscomplex)
+int
+mexAtExit (void (*/*f*/) (void))
 {
-  return mxCreateDoubleMatrix (nr, nc, iscomplex);
-}
-
-void F77_FUNC (mxfreematrix, MXFREEMATRIX) (mxArray* &p)
-{
-  mxDestroyArray (p);
+  // FIXME
+  error ("mexAtExit: not implemented");
+  return 0;
 }
 
-Pix F77_FUNC (mxcalloc, MXCALLOC) (const int& n, const int& size)
+const mxArray *
+mexGet (double /*handle*/, const char */*property*/)
 {
-  return mxCalloc (n, size);
+  // FIXME
+  error ("mexGet: not implemented");
+  return 0;
 }
 
-void F77_FUNC (mxfree, MXFREE) (const Pix &p) { mxFree (p); }
-
-int F77_FUNC (mxgetm, MXGETM) (const mxArray* &p) { return mxGetM (p); }
-int F77_FUNC (mxgetn, MXGETN) (const mxArray* &p) { return mxGetN (p); }
-
-Pix F77_FUNC (mxgetpi, MXGETPI) (const mxArray* &p) { return mxGetPi (p); }
-Pix F77_FUNC (mxgetpr, MXGETPR) (const mxArray* &p) { return mxGetPr (p); }
-
-void F77_FUNC (mxsetm, MXSETM) (mxArray* &p, const int& m) { mxSetM (p, m); }
-void F77_FUNC (mxsetn, MXSETN) (mxArray* &p, const int& n) { mxSetN (p, n); }
-
-void F77_FUNC (mxsetpi, MXSETPI) (mxArray* &p, double *pi) { mxSetPi (p, pi); }
-void F77_FUNC (mxsetpr, MXSETPR) (mxArray* &p, double *pr) { mxSetPr (p, pr); }
-
-int F77_FUNC (mxiscomplex, MXISCOMPLEX) (const mxArray* &p)
+int
+mexIsGlobal (const mxArray *ptr)
 {
-  return mxIsComplex (p);
-}
-
-int F77_FUNC (mxisdouble, MXISDOUBLE) (const mxArray* &p)
-{
-  return mxIsDouble (p);
+  return mxIsFromGlobalWS (ptr);
 }
 
-int F77_FUNC (mxisnumeric, MXISNUMERIC) (const mxArray* &p)
-{
-  return mxIsNumeric(p);
-}
-
-int F77_FUNC (mxisfull, MXISFULL) (const mxArray* &p)
+int
+mexIsLocked (void)
 {
-  return 1 - mxIsSparse (p);
-}
-
-int F77_FUNC (mxissparse, MXISSPARSE) (const mxArray* &p)
-{
-  return mxIsSparse (p);
-}
-
-int F77_FUNC (mxisstring, MXISSTRING) (const mxArray* &p)
-{
-  return mxIsChar (p);
-}
-
-int F77_FUNC (mxgetstring, MXGETSTRING)
-  (const mxArray* &ptr, char *str, const int& len)
-{
-  return mxGetString (ptr, str, len);
+  int retval = 0;
+
+  if (mex_context)
+    {
+      const char *fname = mexFunctionName ();
+
+      retval = mislocked (fname);
+    }
+
+  return retval;
 }
 
-int F77_FUNC (mexcallmatlab, MEXCALLMATLAB)
-  (const int& nargout, mxArray **argout,
-   const int& nargin, mxArray **argin,
-   const char *fname,
-   long fnamelen)
-{
-  char str[mxMAXNAM+1];
-  strncpy (str, fname, (fnamelen < mxMAXNAM ? fnamelen : mxMAXNAM));
-  str[fnamelen] = '\0';
-  return mexCallMATLAB (nargout, argout, nargin, argin, str);
-}
-
-// Fake pointer support:
-
-void F77_FUNC (mxcopyreal8toptr, MXCOPYREAL8TOPTR)
-  (const double *d, const int& prref, const int& len)
+std::map<std::string,int> mex_lock_count;
+
+void
+mexLock (void)
 {
-  double *pr = (double *) prref;
-  for (int i = 0; i < len; i++)
-    pr[i] = d[i];
-}
-
-void F77_FUNC (mxcopyptrtoreal8, MXCOPYPTRTOREAL8)
-  (const int& prref, double *d, const int& len)
-{
-  double *pr = (double *) prref;
-  for (int i = 0; i < len; i++)
-    d[i] = pr[i];
-}
-
-void F77_FUNC (mxcopycomplex16toptr, MXCOPYCOMPLEX16TOPTR)
-  (const double *d, int& prref, int& piref, const int& len)
-{
-  double *pr = (double *) prref;
-  double *pi = (double *) piref;
-  for (int i = 0; i < len; i++)
+  if (mex_context)
     {
-      pr[i] = d[2*i];
-      pi[i] = d[2*i+1];
+      const char *fname = mexFunctionName ();
+
+      if (mex_lock_count.find (fname) == mex_lock_count.end ())
+	mex_lock_count[fname] = 1;
+      else
+	mex_lock_count[fname]++;
+
+      mlock (fname);
     }
 }
 
-void F77_FUNC (mxcopyptrtocomplex16, MXCOPYPTRTOCOMPLEX16)
-  (const int& prref, const int& piref, double *d, const int& len)
+int
+mexSet (double /*handle*/, const char */*property*/, mxArray */*val*/)
+{
+  // FIXME
+  error ("mexSet: not implemented");
+  return 0;
+}
+
+void
+mexUnlock (void)
 {
-  double *pr = (double *) prref;
-  double *pi = (double *) piref;
-  for (int i = 0; i < len; i++)
+  if (mex_context)
     {
-      d[2*i] = pr[i];
-      d[2*i+1] = pi[i];
+      const char *fname = mexFunctionName ();
+
+      if (mex_lock_count.find (fname) == mex_lock_count.end ())
+	warning ("mexUnlock: funtion `%s' is not locked", fname);
+      else
+	{
+	  int count = --mex_lock_count[fname];
+
+	  if (count == 0)
+	    {
+	      munlock (fname);
+
+	      mex_lock_count.erase (fname);
+	    }
+	}
     }
 }
-
-} // extern "C"
-
-/*
-;;; Local Variables: ***
-;;; mode: C++ ***
-;;; End: ***
-*/
--- a/src/mex.h
+++ b/src/mex.h
@@ -24,7 +24,7 @@
 /*
 
 This code was originally distributed as part of Octave Forge under
-the follwoing terms:
+the following terms:
 
 Author: Paul Kienzle
 I grant this code to the public domain.
@@ -53,44 +53,10 @@
 
 typedef void mxArray;
 
-enum mxComplexity
-  {
-    mxREAL = 0,
-    mxCOMPLEX = 1
-  };
-
-typedef enum
-  {
-    mxUNKNOWN_CLASS = 0,
-    mxCELL_CLASS,
-    mxSTRUCT_CLASS,
-    mxLOGICAL_CLASS,
-    mxCHAR_CLASS,
-    mxUNUSED_CLASS,
-    mxDOUBLE_CLASS,
-    mxSINGLE_CLASS,
-    mxINT8_CLASS,
-    mxUINT8_CLASS,
-    mxINT16_CLASS,
-    mxUINT16_CLASS,
-    mxINT32_CLASS,
-    mxUINT32_CLASS,
-    mxINT64_CLASS,
-    mxUINT64_CLASS,
-    mxFUNCTION_CLASS,
-  } mxClassID;
-
-#if 0
-/* typedef Uint16 mxChar; */
-typedef unsigned short mxChar;
-#endif
-
 #if ! defined (__cplusplus)
 typedef int bool;
 #endif
 
-typedef int mxLOGICAL;
-
 /* -V4 stuff */
 #if defined (V4)
 #define Matrix mxArray
--- a/src/mexproto.h
+++ b/src/mexproto.h
@@ -50,18 +50,17 @@
 #define MEXPROTO_H
 
 #if defined (__cplusplus)
+#include <cstdlib>
 extern "C" {
+#else
+#include <stdlib.h>
 #endif
 
-/* Floating point representation.  */
-extern int mxIsFinite (double v);
-extern int mxIsInf (double v);
-extern int mxIsNaN (double v);
-extern double mxGetEps (void);
-extern double mxGetInf (void);
-extern double mxGetNaN (void);
-  
-/* Interface to the interpreter */
+#define MXARRAY_TYPEDEFS_ONLY
+#include "mxarray.h"
+#undef MXARRAY_TYPEDEFS_ONLY
+
+// Interface to the interpreter.
 extern const char *mexFunctionName (void);
 
 extern int mexCallMATLAB (int nargout, mxArray *argout[], int nargin,
@@ -80,115 +79,8 @@
 
 extern int mexPutVariable (const char *space, const char *name, mxArray *ptr);
 
-/* Memory.  */
-extern void *mxMalloc (int n);
-extern void *mxCalloc (int n, int size);
-extern void mxFree (void *ptr);
 extern void mexMakeArrayPersistent (mxArray *ptr);
 extern void mexMakeMemoryPersistent (void *ptr);
-  
-/* Interpreter values.  */
-extern mxArray *mxCreateDoubleMatrix (int nr, int nc, int iscomplex);
-extern mxArray *mxCreateDoubleScalar (double val);
-extern mxArray *mxCreateLogicalScalar (int val);
-
-extern void mxDestroyArray (mxArray *v);
-
-extern mxArray *mxDuplicateArray (const mxArray *v);
-
-extern int mxIsChar (const mxArray *ptr);
-extern int mxIsComplex (const mxArray *ptr);
-extern int mxIsDouble (const mxArray *ptr);
-extern int mxIsEmpty (const mxArray *ptr);
-extern int mxIsFull (const mxArray *ptr);
-extern int mxIsLogicalScalar (const mxArray *ptr);
-extern int mxIsNumeric (const mxArray *ptr);
-extern int mxIsSparse (const mxArray *ptr);
-extern int mxIsStruct (const mxArray *ptr);
-
-extern int mxGetM (const mxArray *ptr);
-extern int mxGetN (const mxArray *ptr);
-extern int mxGetNumberOfDimensions (const mxArray *ptr);
-extern int mxGetNumberOfElements (const mxArray *ptr);
-
-extern double *mxGetPr (const mxArray *ptr);
-extern double *mxGetPi (const mxArray *ptr);
-
-/* Structure support.  */
-extern mxArray *mxGetField (const mxArray *ptr, int index, const char *key);
-extern void mxSetField (mxArray *ptr, int index, const char *key, mxArray *val);
-extern int mxGetNumberOfFields (const mxArray *ptr);
-extern const char *mxGetFieldNameByNumber (const mxArray *ptr, int key_num);
-extern int mxGetFieldNumber (const mxArray *ptr, const char *key);
-extern mxArray *mxGetFieldByNumber (const mxArray *ptr, int index, int key_num);
-extern void mxSetFieldByNumber (mxArray *ptr, int index, int key_num,
-				mxArray *val);
-extern mxArray *mxCreateStructMatrix (int rows, int cols, int num_keys,
-				      const char **keys);
-
-extern void mxSetM (mxArray *ptr, int M);
-extern void mxSetN (mxArray *ptr, int N);
-extern void mxSetPr (mxArray *ptr, double *pr);
-extern void mxSetPi (mxArray *ptr, double *pi);
-  
-extern int mxGetString (const mxArray *ptr, char *buf, int buflen);
-extern char *mxArrayToString (const mxArray *ptr);
-extern mxArray *mxCreateString (const char *str);
-  
-extern double mxGetScalar (const mxArray *ptr);
-  
-#if 0
-/* Not implemented.  */
-extern int mxAddField (mxArray *ptr, const char *field_name);
-extern void mxAssert (int expr, char *msg);
-extern void mxAssertS (int expr, char *msg);
-extern int mxCalcSingleSubscript (const mxArray *ptr, int nsubs, int *subs);
-extern void *mxCalloc (size_t n, size_t size);
-extern mxArray *mxCreateCellArray (int ndim, const int *dims);
-extern mxArray *mxCreateCellMatrix (int m, int n);
-extern mxArray *mxCreateCharArray (int ndim, const int *dims);
-extern mxArray *mxCreateCharMatrixFromStrings (int m, const char **str);
-extern mxArray *mxCreateLogicalArray (int ndim, const int *dims);
-extern mxArray *mxCreateLogicalMatrix (int m, int n);
-extern mxArray *mxCreateNumericArray (int ndim, const int *dims, mxClassID class, mxComplexity flag);
-extern mxArray *mxCreateNumericMatrix (int m, int n, mxClassID class, mxComplexity flag);
-extern mxArray *mxCreateSparse (int m, int n, int nzmax, mxComplexity flag);
-extern mxArray *mxCreateSparseLogicalMatrix (int m, int n, int nzmax);
-extern mxArray *mxGetCell (const mxArray *ptr, int idx);
-extern mxChar *mxGetChars (const mxArray *ptr);
-extern mxClassID mxGetClassID (const mxArray *ptr);
-extern const char *mxGetClassName (const mxArray *ptr);
-extern void mxGetData (const mxArray *ptr);
-extern int *mxGetDimensions (const mxArray *ptr);
-extern int mxGetElementSize (const mxArray *ptr);
-extern void *mxGetImagData (const mxArray *ptr);
-extern int *mxGetIr (const mxArray *ptr);
-extern int *mxGetJc (const mxArray *ptr);
-extern mxLogical *mxGetLogicals (const mxArray *ptr);
-extern int mxGetNzmax (const mxArray *ptr);
-extern int mxIsCell (const mxArray *ptr);
-extern int mxIsClass (const mxArray *ptr, const char *name);
-extern int mxIsFromGlobalWS (const mxArray *ptr);
-extern int mxIsInt16 (const mxArray *ptr);
-extern int mxIsInt32 (const mxArray *ptr);
-extern int mxIsInt64 (const mxArray *ptr);
-extern int mxIsInt8 (const mxArray *ptr);
-extern int mxIsLogical (const mxArray *ptr);
-extern int mxIsLogicalScalarTrue (const mxArray *ptr);
-extern int mxIsSingle (const mxArray *ptr);
-extern int mxIsUint16 (const mxArray *ptr);
-extern int mxIsUint32 (const mxArray *ptr);
-extern int mxIsUint64 (const mxArray *ptr);
-extern int mxIsUint8 (const mxArray *ptr);
-extern void mxRemoveField (mxArray *ptr, int num);
-extern void mxSetCell (mxArray *ptr, int idx, mxArray *val);
-extern void mxSetClassName (mxArray *ptr, const char *name);
-extern void mxSetData (mxArray *ptr, void *data);
-extern void mxSetDimensions (mxArray *ptr, int *dims, int ndim);
-extern void mxSetImagData (mxArray *ptr, void *pi);
-extern void mxSetIr (mxArray *ptr, int *ir);
-extern void mxSetJc (mxArray *ptr, int *ir);
-extern void mxSetNzmax (mxArray *ptr, int nzmax);
 
 extern int mexAtExit (void (*f) (void));
 extern const mxArray *mexGet (double handle, const char *property);
@@ -197,8 +89,178 @@
 extern void mexLock (void);
 extern int mexSet (double handle, const char *property, mxArray *val);
 extern void mexUnlock (void);
+
+// Floating point predicates.
+extern int mxIsFinite (double v);
+extern int mxIsInf (double v);
+extern int mxIsNaN (double v);
+
+// Floating point values.
+extern double mxGetEps (void);
+extern double mxGetInf (void);
+extern double mxGetNaN (void);
+  
+// Memory management.
+extern void *mxCalloc (size_t n, size_t size);
+extern void *mxMalloc (size_t n);
+extern void *mxRealloc (void *ptr, size_t size);
+extern void mxFree (void *ptr);
+  
+// Constructors.
+extern mxArray *mxCreateCellArray (int ndims, const int *dims);
+extern mxArray *mxCreateCellMatrix (int m, int n);
+extern mxArray *mxCreateCharArray (int ndims, const int *dims);
+extern mxArray *mxCreateCharMatrixFromStrings (int m, const char **str);
+extern mxArray *mxCreateDoubleMatrix (int nr, int nc, mxComplexity flag);
+extern mxArray *mxCreateDoubleScalar (double val);
+extern mxArray *mxCreateLogicalArray (int ndims, const int *dims);
+extern mxArray *mxCreateLogicalMatrix (int m, int n);
+extern mxArray *mxCreateLogicalScalar (int val);
+extern mxArray *mxCreateNumericArray (int ndims, const int *dims, mxClassID class_id, mxComplexity flag);
+extern mxArray *mxCreateNumericMatrix (int m, int n, mxClassID class_id, mxComplexity flag);
+extern mxArray *mxCreateSparse (int m, int n, int nzmax, mxComplexity flag);
+extern mxArray *mxCreateSparseLogicalMatrix (int m, int n, int nzmax);
+extern mxArray *mxCreateString (const char *str);
+extern mxArray *mxCreateStructArray (int ndims, int *dims, int num_keys, const char **keys);
+extern mxArray *mxCreateStructMatrix (int rows, int cols, int num_keys, const char **keys);
+
+// Copy constructor.
+extern mxArray *mxDuplicateArray (const mxArray *v);
+
+// Destructor.
+extern void mxDestroyArray (mxArray *v);
+
+// Type Predicates.
+extern int mxIsCell (const mxArray *ptr);
+extern int mxIsChar (const mxArray *ptr);
+extern int mxIsClass (const mxArray *ptr, const char *name);
+extern int mxIsComplex (const mxArray *ptr);
+extern int mxIsDouble (const mxArray *ptr);
+extern int mxIsInt16 (const mxArray *ptr);
+extern int mxIsInt32 (const mxArray *ptr);
+extern int mxIsInt64 (const mxArray *ptr);
+extern int mxIsInt8 (const mxArray *ptr);
+extern int mxIsLogical (const mxArray *ptr);
+extern int mxIsNumeric (const mxArray *ptr);
+extern int mxIsSingle (const mxArray *ptr);
+extern int mxIsSparse (const mxArray *ptr);
+extern int mxIsStruct (const mxArray *ptr);
+extern int mxIsUint16 (const mxArray *ptr);
+extern int mxIsUint32 (const mxArray *ptr);
+extern int mxIsUint64 (const mxArray *ptr);
+extern int mxIsUint8 (const mxArray *ptr);
+
+// Odd type+size predicate.
+extern int mxIsLogicalScalar (const mxArray *ptr);
+
+// Odd type+size+value predicate.
+extern int mxIsLogicalScalarTrue (const mxArray *ptr);
+
+// Size predicate.
+extern int mxIsEmpty (const mxArray *ptr);
+
+// Just plain odd thing to ask of a value.
+extern int mxIsFromGlobalWS (const mxArray *ptr);
+
+// Dimension extractors.
+extern int mxGetM (const mxArray *ptr);
+extern int mxGetN (const mxArray *ptr);
+extern int *mxGetDimensions (const mxArray *ptr);
+extern int mxGetNumberOfDimensions (const mxArray *ptr);
+extern int mxGetNumberOfElements (const mxArray *ptr);
+
+// Dimension setters.
+extern void mxSetM (mxArray *ptr, int M);
+extern void mxSetN (mxArray *ptr, int N);
+extern void mxSetDimensions (mxArray *ptr, int *dims, int ndims);
+  
+// Data extractors.
+extern double *mxGetPi (const mxArray *ptr);
+extern double *mxGetPr (const mxArray *ptr);
+extern double mxGetScalar (const mxArray *ptr);
+extern mxChar *mxGetChars (const mxArray *ptr);
+extern mxLogical *mxGetLogicals (const mxArray *ptr);
+extern void *mxGetData (const mxArray *ptr);
+extern void *mxGetImagData (const mxArray *ptr);
+
+// Data setters.
+extern void mxSetPr (mxArray *ptr, double *pr);
+extern void mxSetPi (mxArray *ptr, double *pi);
+extern void mxSetData (mxArray *ptr, void *data);
+extern void mxSetImagData (mxArray *ptr, void *pi);
+
+// Classes.
+extern mxClassID mxGetClassID (const mxArray *ptr);
+extern const char *mxGetClassName (const mxArray *ptr);
+
+extern void mxSetClassName (mxArray *ptr, const char *name);
+
+// Cell support.
+extern mxArray *mxGetCell (const mxArray *ptr, int idx);
+
+extern void mxSetCell (mxArray *ptr, int idx, mxArray *val);
+
+// Sparse support.
+extern int *mxGetIr (const mxArray *ptr);
+extern int *mxGetJc (const mxArray *ptr);
+extern int mxGetNzmax (const mxArray *ptr);
+
+extern void mxSetIr (mxArray *ptr, int *ir);
+extern void mxSetJc (mxArray *ptr, int *jc);
+extern void mxSetNzmax (mxArray *ptr, int nzmax);
+
+// Structure support.
+extern int mxAddField (mxArray *ptr, const char *key);
+
+extern void mxRemoveField (mxArray *ptr, int key_num);
+
+extern mxArray *mxGetField (const mxArray *ptr, int index, const char *key);
+extern mxArray *mxGetFieldByNumber (const mxArray *ptr, int index, int key_num);
+
+extern void mxSetField (mxArray *ptr, int index, const char *key, mxArray *val);
+extern void mxSetFieldByNumber (mxArray *ptr, int index, int key_num, mxArray *val);
+
+extern int mxGetNumberOfFields (const mxArray *ptr);
+
+extern const char *mxGetFieldNameByNumber (const mxArray *ptr, int key_num);
+extern int mxGetFieldNumber (const mxArray *ptr, const char *key);
+
+extern int mxGetString (const mxArray *ptr, char *buf, int buflen);
+extern char *mxArrayToString (const mxArray *ptr);
+  
+// Miscellaneous.
+#ifdef NDEBUG
+#define mxAssert(expr, msg) \
+  do \
+    { \
+      if (! expr) \
+        { \
+          mexPrintf ("Assertion failed: %s, at line %d of file \"%s\".\n%s\n", \
+                     #expr, __LINE__, __FILE__, msg); \
+        } \
+    } \
+  while (0)
+
+#define mxAssertS(expr, msg) \
+  do \
+    { \
+      if (! expr) \
+        { \
+          mexPrintf ("Assertion failed at line %d of file \"%s\".\n%s\n", \
+                     __LINE__, __FILE__, msg); \
+          abort (); \
+        } \
+    } \
+  while (0)
+#else
+#define mxAssert(expr, msg)
+#define mxAssertS(expr, msg)
 #endif
 
+extern int mxCalcSingleSubscript (const mxArray *ptr, int nsubs, int *subs);
+
+extern int mxGetElementSize (const mxArray *ptr);
+
 #if defined (__cplusplus)
 }
 #endif
new file mode 100644
--- /dev/null
+++ b/src/mxarray.h
@@ -0,0 +1,339 @@
+/*
+
+Copyright (C) 2001, 2006 Paul Kienzle
+
+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.
+
+*/
+
+/*
+
+Part of this code was originally distributed as part of Octave Forge under
+the following terms:
+
+Author: Paul Kienzle
+I grant this code to the public domain.
+2001-03-22
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+*/
+
+#if ! defined (MXARRAY_H)
+#define MXARRAY_H
+
+typedef enum
+  {
+    mxREAL = 0,
+    mxCOMPLEX = 1
+  }
+  mxComplexity;
+
+typedef enum
+  {
+    mxUNKNOWN_CLASS = 0,
+    mxCELL_CLASS,
+    mxSTRUCT_CLASS,
+    mxLOGICAL_CLASS,
+    mxCHAR_CLASS,
+    mxUNUSED_CLASS,
+    mxDOUBLE_CLASS,
+    mxSINGLE_CLASS,
+    mxINT8_CLASS,
+    mxUINT8_CLASS,
+    mxINT16_CLASS,
+    mxUINT16_CLASS,
+    mxINT32_CLASS,
+    mxUINT32_CLASS,
+    mxINT64_CLASS,
+    mxUINT64_CLASS,
+    mxFUNCTION_CLASS,
+  }
+  mxClassID;
+
+typedef int mxLogical;
+
+/* typedef Uint16 mxChar; */
+typedef unsigned short mxChar;
+
+#if ! defined (MXARRAY_TYPEDEFS_ONLY)
+
+class octave_value;
+
+#define DO_MUTABLE_METHOD(RET_T, METHOD_CALL) \
+  RET_T retval = rep->METHOD_CALL; \
+ \
+  if (rep->mutation_needed ()) \
+    { \
+      maybe_mutate (); \
+      retval = rep->METHOD_CALL; \
+    } \
+ \
+  return retval
+
+#define DO_VOID_MUTABLE_METHOD(METHOD_CALL) \
+  rep->METHOD_CALL; \
+ \
+  if (rep->mutation_needed ()) \
+    { \
+      maybe_mutate (); \
+      rep->METHOD_CALL; \
+    }
+
+// This just provides a way to avoid infinite recursion when building
+// mxArray objects.
+
+struct
+xmxArray
+{
+  xmxArray (void) { }
+};
+
+// The main interface class.  The representation can be based on an
+// octave_value object or a separate object that tries to reproduce
+// the semantics of mxArray objects in Matlab more directly.
+
+class mxArray
+{
+public:
+
+  mxArray (const octave_value& ov);
+
+  mxArray (mxClassID id, int ndims, const int *dims,
+	   mxComplexity flag = mxREAL);
+
+  mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag = mxREAL);
+
+  mxArray (mxClassID id, int m, int n, mxComplexity flag = mxREAL);
+
+  mxArray (mxClassID id, double val);
+
+  mxArray (mxClassID id, mxLogical val);
+
+  mxArray (const char *str);
+
+  mxArray (int m, const char **str);
+
+  mxArray (mxClassID id, int m, int n, int nzmax, mxComplexity flag = mxREAL);
+
+  mxArray (int ndims, const int *dims, int num_keys, const char **keys);
+
+  mxArray (const dim_vector& dv, int num_keys, const char **keys);
+
+  mxArray (int m, int n, int num_keys, const char **keys);
+
+  mxArray (int ndims, const int *dims);
+
+  mxArray (const dim_vector& dv);
+
+  mxArray (int m, int n);
+
+  virtual mxArray *clone (void) const
+  {
+    mxArray *new_rep = rep->clone ();
+
+    return new mxArray (new_rep, name, persistent);
+  }
+
+  virtual ~mxArray (void);
+
+  virtual octave_value as_octave_value (void) const;
+
+  void mark_persistent (void) const { persistent = true; }
+
+  void unmark_persistent (void) const { persistent = false; }
+
+  bool is_persistent (void) const { return persistent; }
+
+  virtual bool is_octave_value (void) const { return rep->is_octave_value (); }
+
+  virtual int is_cell (void) const { return rep->is_cell (); }
+
+  virtual int is_char (void) const { return rep->is_char (); }
+
+  virtual int is_class (const char *name_arg) const { return rep->is_class (name_arg); }
+
+  virtual int is_complex (void) const { return rep->is_complex (); }
+
+  virtual int is_double (void) const { return rep->is_double (); }
+
+  virtual int is_int16 (void) const { return rep->is_int16 (); }
+
+  virtual int is_int32 (void) const { return rep->is_int32 (); }
+
+  virtual int is_int64 (void) const { return rep->is_int64 (); }
+
+  virtual int is_int8 (void) const { return rep->is_int8 (); }
+
+  virtual int is_logical (void) const { return rep->is_logical (); }
+
+  virtual int is_numeric (void) const { return rep->is_numeric (); }
+
+  virtual int is_single (void) const { return rep->is_single (); }
+
+  virtual int is_sparse (void) const { return rep->is_sparse (); }
+
+  virtual int is_struct (void) const { return rep->is_struct (); }
+
+  virtual int is_uint16 (void) const { return rep->is_uint16 (); }
+
+  virtual int is_uint32 (void) const { return rep->is_uint32 (); }
+
+  virtual int is_uint64 (void) const { return rep->is_uint64 (); }
+
+  virtual int is_uint8 (void) const { return rep->is_uint8 (); }
+
+  virtual int is_logical_scalar (void) const { return rep->is_logical_scalar (); }
+
+  virtual int is_logical_scalar_true (void) const { return rep->is_logical_scalar_true (); }
+
+  virtual int get_m (void) const { return rep->get_m (); }
+
+  virtual int get_n (void) const { return rep->get_n (); }
+
+  virtual int *get_dimensions (void) const { return rep->get_dimensions (); }
+
+  virtual int get_number_of_dimensions (void) const { return rep->get_number_of_dimensions (); }
+
+  virtual void set_m (int m) { rep->set_m (m); }
+
+  virtual void set_n (int n) { rep->set_n (n); }
+
+  virtual void set_dimensions (int *dims_arg, int ndims_arg) { rep->set_dimensions (dims_arg, ndims_arg); }
+
+  virtual int get_number_of_elements (void) const { return rep->get_number_of_elements (); }
+
+  virtual int is_empty (void) const { return get_number_of_elements () == 0; }
+
+  const char *get_name (void) const { return name; }
+
+  void set_name (const char *name_arg);
+
+  virtual mxClassID get_class_id (void) const { return rep->get_class_id (); }
+
+  virtual const char *get_class_name (void) const { return rep->get_class_name (); }
+
+  virtual void set_class_name (const char *name_arg) { DO_VOID_MUTABLE_METHOD (set_class_name (name_arg)); }
+
+  virtual mxArray *get_cell (int idx) const { DO_MUTABLE_METHOD (mxArray *, get_cell (idx)); }
+
+  virtual void set_cell (int idx, mxArray *val) { DO_VOID_MUTABLE_METHOD (set_cell (idx, val)); }
+
+  virtual void *get_data (void) const { DO_MUTABLE_METHOD (void *, get_data ()); }
+
+  virtual void *get_imag_data (void) const { DO_MUTABLE_METHOD (void *, get_imag_data ()); }
+
+  virtual void set_data (void *pr) { DO_VOID_MUTABLE_METHOD (set_data (pr)); }
+
+  virtual void set_imag_data (void *pi) { DO_VOID_MUTABLE_METHOD (set_imag_data (pi)); }
+
+  virtual int *get_ir (void) const { DO_MUTABLE_METHOD (int *, get_ir ()); }
+
+  virtual int *get_jc (void) const { DO_MUTABLE_METHOD (int *, get_jc ()); }
+
+  virtual int get_nzmax (void) const { return rep->get_nzmax (); }
+
+  virtual void set_ir (int *ir) { DO_VOID_MUTABLE_METHOD (set_ir (ir)); }
+
+  virtual void set_jc (int *jc) { DO_VOID_MUTABLE_METHOD (set_jc (jc)); }
+
+  virtual void set_nzmax (int nzmax) { DO_VOID_MUTABLE_METHOD (set_nzmax (nzmax)); }
+
+  virtual int add_field (const char *key) { DO_MUTABLE_METHOD (int, add_field (key)); }
+
+  virtual void remove_field (int key_num) { DO_VOID_MUTABLE_METHOD (remove_field (key_num)); }
+
+  virtual mxArray *get_field_by_number (int index, int key_num) const { DO_MUTABLE_METHOD (mxArray *, get_field_by_number (index, key_num)); }
+
+  virtual void set_field_by_number (int index, int key_num, mxArray *val) { DO_VOID_MUTABLE_METHOD (set_field_by_number (index, key_num, val)); }
+
+  virtual int get_number_of_fields (void) const { return rep->get_number_of_fields (); }
+
+  virtual const char *get_field_name_by_number (int key_num) const { DO_MUTABLE_METHOD (const char*, get_field_name_by_number (key_num)); }
+
+  virtual int get_field_number (const char *key) const { DO_MUTABLE_METHOD (int, get_field_number (key)); }
+
+  virtual int get_string (char *buf, int buflen) const { return rep->get_string (buf, buflen); }
+
+  virtual char *array_to_string (void) const { return rep->array_to_string (); }
+
+  virtual int calc_single_subscript (int nsubs, int *subs) const { return rep->calc_single_subscript (nsubs, subs); }
+
+  virtual int get_element_size (void) const { return rep->get_element_size (); }
+
+  virtual bool mutation_needed (void) const { return rep->mutation_needed (); }
+
+  virtual mxArray *mutate (void) const { return rep->mutate (); }
+
+  static void *malloc (size_t n);
+
+  static void *calloc (size_t n, size_t t);
+
+  static char *strsave (const char *str)
+  {
+    char *retval = 0;
+
+    if (str)
+      {
+	int sz =  sizeof (mxChar) * (strlen (str) + 1);
+	retval = static_cast<char *> (mxArray::malloc (sz));
+	strcpy (retval, str);
+      }
+
+    return retval;
+  }
+
+protected:
+
+  mxArray (const xmxArray&) : rep (0), name (0), persistent (false) { }
+
+private:
+
+  mutable mxArray *rep;
+
+  char *name;
+
+  mutable bool persistent;
+
+  mxArray (mxArray *r, const char *n, bool p)
+    : rep (r), name (strsave (n)), persistent (p) { }
+
+  void maybe_mutate (void) const;
+
+  // No copying!
+
+  mxArray (const mxArray&);
+
+  mxArray& operator = (const mxArray&);
+};
+
+#undef DO_MUTABLE_METHOD
+#undef DO_VOID_MUTABLE_METHOD
+
+#endif
+#endif
--- a/src/oct-map.cc
+++ b/src/oct-map.cc
@@ -91,13 +91,6 @@
 string_vector
 Octave_map::keys (void) const
 {
-  if (length () != key_list.size ())
-    {
-      std::cerr << "length () = " << length () << std::endl;
-      std::cerr << "key_list.size () = " << key_list.size () << std::endl;
-      abort ();
-    }
-
   assert (length () == key_list.size ());
 
   return string_vector (key_list);
--- a/src/ov-base-mat.h
+++ b/src/ov-base-mat.h
@@ -134,6 +134,10 @@
 
   void print_info (std::ostream& os, const std::string& prefix) const;
 
+  // Unsafe.  This function exists to support the MEX interface.
+  // You should not use it anywhere else.
+  void *mex_get_data (void) const { return matrix.mex_get_data (); }
+
 protected:
 
   MT matrix;
--- a/src/ov-base-scalar.h
+++ b/src/ov-base-scalar.h
@@ -104,6 +104,10 @@
 
   bool print_name_tag (std::ostream& os, const std::string& name) const;
 
+  // Unsafe.  This function exists to support the MEX interface.
+  // You should not use it anywhere else.
+  void *mex_get_data (void) const { return const_cast<ST *> (&scalar); }
+
 protected:
 
   // The value of this scalar.
--- a/src/ov-base-sparse.h
+++ b/src/ov-base-sparse.h
@@ -146,6 +146,14 @@
 
   bool load_ascii (std::istream& is);
 
+  // Unsafe.  These functions exists to support the MEX interface.
+  // You should not use them anywhere else.
+  void *mex_get_data (void) const { return matrix.mex_get_data (); }
+
+  octave_idx_type *mex_get_ir (void) const { return matrix.mex_get_ir (); }
+
+  octave_idx_type *mex_get_jc (void) const { return matrix.mex_get_jc (); }
+
 protected:
 
   T matrix;
--- a/src/ov-base.cc
+++ b/src/ov-base.cc
@@ -222,6 +222,13 @@
   return -1;
 }
 
+octave_idx_type
+octave_base_value::nfields (void) const
+{
+  gripe_wrong_type_arg ("octave_base_value::nfields ()", type_name ());
+  return -1;
+}
+
 octave_value
 octave_base_value::reshape (const dim_vector&) const
 {
@@ -865,6 +872,14 @@
   return false;
 }
 
+mxArray *
+octave_base_value::as_mxArray (void) const
+{
+  gripe_wrong_type_arg ("octave_base_value::as_mxArray ()", type_name ());
+
+  return 0;
+}
+
 static void
 gripe_indexed_assignment (const std::string& tn1, const std::string& tn2)
 {
--- a/src/ov-base.h
+++ b/src/ov-base.h
@@ -36,6 +36,7 @@
 
 #include "Range.h"
 #include "data-conv.h"
+#include "mxarray.h"
 #include "mx-base.h"
 #include "str-vec.h"
 
@@ -175,6 +176,8 @@
 
   virtual octave_idx_type nzmax (void) const;
 
+  virtual octave_idx_type nfields (void) const;
+
   virtual octave_value reshape (const dim_vector&) const;
 
   virtual octave_value permute (const Array<int>& vec, bool = false) const;
@@ -434,6 +437,14 @@
 	 oct_data_conv::data_type output_type, int skip,
 	 oct_mach_info::float_format flt_fmt) const;
 
+  virtual void *mex_get_data (void) const { return 0; }
+
+  virtual octave_idx_type *mex_get_ir (void) const { return 0; }
+
+  virtual octave_idx_type *mex_get_jc (void) const { return 0; }
+
+  virtual mxArray *as_mxArray (void) const;
+
 protected:
 
   // This should only be called for derived types.
--- a/src/ov-bool-mat.cc
+++ b/src/ov-bool-mat.cc
@@ -470,6 +470,23 @@
 
 #endif
 
+mxArray *
+octave_bool_matrix::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxLOGICAL_CLASS, dims (), mxREAL);
+
+  bool *pr = static_cast<bool *> (retval->get_data ());
+
+  int nel = numel ();
+
+  const bool *p = matrix.data ();
+
+  for (int i = 0; i < nel; i++)
+    pr[i] = p[i];
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-bool-mat.h
+++ b/src/ov-bool-mat.h
@@ -185,6 +185,8 @@
 	     oct_mach_info::float_format flt_fmt) const
     { return os.write (matrix, block_size, output_type, skip, flt_fmt); }
 
+  mxArray *as_mxArray (void) const;
+
 protected:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-bool-sparse.cc
+++ b/src/ov-bool-sparse.cc
@@ -315,6 +315,7 @@
 }
 
 #if defined (HAVE_HDF5)
+
 bool
 octave_sparse_bool_matrix::save_hdf5 (hid_t loc_id, const char *name, bool)
 {
@@ -686,8 +687,16 @@
 
   return retval;
 }
+
 #endif
 
+mxArray *
+octave_sparse_bool_matrix::as_mxArray (void) const
+{
+  // FIXME
+  return 0;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-bool-sparse.h
+++ b/src/ov-bool-sparse.h
@@ -134,6 +134,8 @@
   bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
 #endif
 
+  mxArray *as_mxArray (void) const;
+
 protected:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-bool.cc
+++ b/src/ov-bool.cc
@@ -241,6 +241,18 @@
 
 #endif
 
+mxArray *
+octave_bool::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxLOGICAL_CLASS, 1, 1, mxREAL);
+
+  bool *pr = static_cast<bool *> (retval->get_data ());
+
+  pr[0] = scalar;
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-bool.h
+++ b/src/ov-bool.h
@@ -180,6 +180,8 @@
 		       skip, flt_fmt);
     }
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-cell.cc
+++ b/src/ov-cell.cc
@@ -1167,6 +1167,23 @@
   return retval;
 }
 
+mxArray *
+octave_cell::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (dims ());
+
+  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
+
+  int nel = numel ();
+
+  const octave_value *p = matrix.data ();
+
+  for (int i = 0; i < nel; i++)
+    elts[i] = new mxArray (p[i]);
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-cell.h
+++ b/src/ov-cell.h
@@ -129,6 +129,8 @@
   bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
 #endif
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-ch-mat.cc
+++ b/src/ov-ch-mat.cc
@@ -98,6 +98,23 @@
 			 current_print_indent_level ());
 }
 
+mxArray *
+octave_char_matrix::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxCHAR_CLASS, dims (), mxREAL);
+
+  mxChar *pr = static_cast<mxChar *> (retval->get_data ());
+
+  int nel = numel ();
+
+  const char *p = matrix.data ();
+
+  for (int i = 0; i < nel; i++)
+    pr[i] = p[i];
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-ch-mat.h
+++ b/src/ov-ch-mat.h
@@ -120,6 +120,8 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
+  mxArray *as_mxArray (void) const;
+
 protected:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-complex.cc
+++ b/src/ov-complex.cc
@@ -347,6 +347,20 @@
 
 #endif
 
+mxArray *
+octave_complex::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxDOUBLE_CLASS, 1, 1, mxCOMPLEX);
+
+  double *pr = static_cast<double *> (retval->get_data ());
+  double *pi = static_cast<double *> (retval->get_imag_data ());
+
+  pr[0] = real (scalar);
+  pi[0] = imag (scalar);
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-complex.h
+++ b/src/ov-complex.h
@@ -141,6 +141,8 @@
 		       skip, flt_fmt);
     }
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-cx-mat.cc
+++ b/src/ov-cx-mat.cc
@@ -655,6 +655,27 @@
 			 current_print_indent_level ());
 }
 
+mxArray *
+octave_complex_matrix::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxCOMPLEX);
+
+  double *pr = static_cast<double *> (retval->get_data ());
+  double *pi = static_cast<double *> (retval->get_imag_data ());
+
+  int nel = numel ();
+
+  const Complex *p = matrix.data ();
+
+  for (int i = 0; i < nel; i++)
+    {
+      pr[i] = real (p[i]);
+      pi[i] = imag (p[i]);
+    }
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-cx-mat.h
+++ b/src/ov-cx-mat.h
@@ -147,6 +147,8 @@
 
   void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-cx-sparse.cc
+++ b/src/ov-cx-sparse.cc
@@ -337,6 +337,7 @@
 }
 
 #if defined (HAVE_HDF5)
+
 bool
 octave_sparse_complex_matrix::save_hdf5 (hid_t loc_id, const char *name, 
 					 bool save_as_floats)
@@ -758,6 +759,13 @@
 
 #endif
 
+mxArray *
+octave_sparse_complex_matrix::as_mxArray (void) const
+{
+  // FIXME
+  return 0;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-cx-sparse.h
+++ b/src/ov-cx-sparse.h
@@ -134,6 +134,8 @@
   bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
 #endif
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-int16.h
+++ b/src/ov-int16.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_int16_type
 
+#define OCTAVE_INT_MX_CLASS mxINT16_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov-int32.h
+++ b/src/ov-int32.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_int32_type
 
+#define OCTAVE_INT_MX_CLASS mxINT32_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov-int64.h
+++ b/src/ov-int64.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_int64_type
 
+#define OCTAVE_INT_MX_CLASS mxINT64_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov-int8.h
+++ b/src/ov-int8.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_int8_type
 
+#define OCTAVE_INT_MX_CLASS mxINT8_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov-intx.h
+++ b/src/ov-intx.h
@@ -162,6 +162,22 @@
 	     oct_mach_info::float_format flt_fmt) const
     { return os.write (matrix, block_size, output_type, skip, flt_fmt); }
 
+  mxArray *as_mxArray (void) const
+  {
+    mxArray *retval = new mxArray (OCTAVE_INT_MX_CLASS, dims (), mxREAL);
+
+    OCTAVE_INT_T::val_type *pr = static_cast<OCTAVE_INT_T::val_type *> (retval->get_data ());
+
+    int nel = numel ();
+
+    const OCTAVE_INT_T *p = matrix.data ();
+
+    for (int i = 0; i < nel; i++)
+      pr[i] = p[i].value ();
+
+    return retval;
+  }
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
@@ -344,6 +360,21 @@
 		       block_size, output_type, skip, flt_fmt);
     }
 
+  // Unsafe.  This function exists to support the MEX interface.
+  // You should not use it anywhere else.
+  void *mex_get_data (void) const { return scalar.mex_get_data (); }
+
+  mxArray *as_mxArray (void) const
+  {
+    mxArray *retval = new mxArray (OCTAVE_INT_MX_CLASS, 1, 1, mxREAL);
+
+    OCTAVE_INT_T::val_type *pr = static_cast<OCTAVE_INT_T::val_type *> (retval->get_data ());
+
+    pr[0] = scalar.value ();
+
+    return retval;
+  }
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-range.cc
+++ b/src/ov-range.cc
@@ -471,6 +471,25 @@
 
 #endif
 
+mxArray *
+octave_range::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
+
+  double *pr = static_cast<double *> (retval->get_data ());
+
+  int nel = numel ();
+
+  Matrix m = matrix_value ();
+
+  const double *p = m.data ();
+
+  for (int i = 0; i < nel; i++)
+    pr[i] = p[i];
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-range.h
+++ b/src/ov-range.h
@@ -206,6 +206,8 @@
 		       flt_fmt);
     }
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   Range range;
--- a/src/ov-re-mat.cc
+++ b/src/ov-re-mat.cc
@@ -665,6 +665,23 @@
 			 current_print_indent_level ());
 }
 
+mxArray *
+octave_matrix::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxDOUBLE_CLASS, dims (), mxREAL);
+
+  double *pr = static_cast<double *> (retval->get_data ());
+
+  int nel = numel ();
+
+  const double *p = matrix.data ();
+
+  for (int i = 0; i < nel; i++)
+    pr[i] = p[i];
+
+  return retval;
+}
+
 DEFUN (double, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} double (@var{x})\n\
--- a/src/ov-re-mat.h
+++ b/src/ov-re-mat.h
@@ -176,6 +176,8 @@
 	     oct_mach_info::float_format flt_fmt) const
     { return os.write (matrix, block_size, output_type, skip, flt_fmt); }
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-re-sparse.cc
+++ b/src/ov-re-sparse.cc
@@ -384,6 +384,7 @@
 }
 
 #if defined (HAVE_HDF5)
+
 bool
 octave_sparse_matrix::save_hdf5 (hid_t loc_id, const char *name, 
 				 bool save_as_floats)
@@ -781,8 +782,16 @@
 
   return true;
 }
+
 #endif
 
+mxArray *
+octave_sparse_matrix::as_mxArray (void) const
+{
+  // FIXME
+  return 0;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-re-sparse.h
+++ b/src/ov-re-sparse.h
@@ -137,6 +137,8 @@
   bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
 #endif
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-scalar.cc
+++ b/src/ov-scalar.cc
@@ -294,6 +294,18 @@
 
 #endif
 
+mxArray *
+octave_scalar::as_mxArray (void) const
+{
+  mxArray *retval = new mxArray (mxDOUBLE_CLASS, 1, 1, mxREAL);
+
+  double *pr = static_cast<double *> (retval->get_data ());
+
+  pr[0] = scalar;
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-scalar.h
+++ b/src/ov-scalar.h
@@ -198,6 +198,8 @@
 		       skip, flt_fmt);
     }
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-struct.cc
+++ b/src/ov-struct.cc
@@ -1275,6 +1275,37 @@
 
 #endif
 
+mxArray *
+octave_struct::as_mxArray (void) const
+{
+  int nf = nfields ();
+  string_vector kv = map_keys ();
+  const char **f = static_cast<const char **> (mxArray::malloc (nf * sizeof (const char *)));
+  for (int i = 0; i < nf; i++)
+    f[i] = mxArray::strsave (kv[i].c_str ());
+
+  mxArray *retval = new mxArray (dims (), nf, f);
+
+  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
+
+  int nel = numel ();
+
+  int ntot = nf * nel;
+
+  for (int i = 0; i < nf; i++)
+    {
+      Cell c = map.contents (kv[i]);
+
+      const octave_value *p = c.data ();
+
+      int k = 0;
+      for (int j = i; j < ntot; j += nf)
+	elts[j] = new mxArray (p[k++]);
+    }
+
+  return retval;
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/ov-struct.h
+++ b/src/ov-struct.h
@@ -87,6 +87,16 @@
 
   size_t byte_size (void) const;
 
+  // This is the number of elements in each field.  The total number
+  // of elements is numel () * nfields ().
+  octave_idx_type numel (void) const
+  {
+    dim_vector dv = dims ();
+    return dv.numel ();
+  }
+
+  octave_idx_type nfields (void) const { return map.length (); }
+
   octave_value reshape (const dim_vector& new_dims) const
     { return map.reshape (new_dims); }
 
@@ -123,6 +133,8 @@
   bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug);
 #endif
 
+  mxArray *as_mxArray (void) const;
+
 private:
 
   // The associative array used to manage the structure data.
--- a/src/ov-uint16.h
+++ b/src/ov-uint16.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_uint16_type
 
+#define OCTAVE_INT_MX_CLASS mxUINT16_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov-uint32.h
+++ b/src/ov-uint32.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_uint32_type
 
+#define OCTAVE_INT_MX_CLASS mxUINT32_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov-uint64.h
+++ b/src/ov-uint64.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_uint64_type
 
+#define OCTAVE_INT_MX_CLASS mxUINT64_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov-uint8.h
+++ b/src/ov-uint8.h
@@ -34,6 +34,8 @@
 
 #define OCTAVE_TYPE_PREDICATE_FUNCTION is_uint8_type
 
+#define OCTAVE_INT_MX_CLASS mxUINT8_CLASS
+
 #include "ov-intx.h"
 
 #undef OCTAVE_VALUE_INT_MATRIX_T
@@ -46,6 +48,8 @@
 
 #undef OCTAVE_TYPE_PREDICATE_FUNCTION
 
+#undef OCTAVE_INT_MX_CLASS
+
 #endif
 
 /*
@@ -53,4 +57,3 @@
 ;;; mode: C++ ***
 ;;; End: ***
 */
-
--- a/src/ov.h
+++ b/src/ov.h
@@ -38,6 +38,7 @@
 #include "data-conv.h"
 #include "idx-vector.h"
 #include "mach-info.h"
+#include "mxarray.h"
 #include "mx-base.h"
 #include "oct-alloc.h"
 #include "oct-time.h"
@@ -348,6 +349,8 @@
 
   octave_idx_type nzmax (void) const { return rep->nzmax (); }
 
+  octave_idx_type nfields (void) const { return rep->nfields (); }
+
   octave_value reshape (const dim_vector& dv) const
     { return rep->reshape (dv); }
 
@@ -804,6 +807,16 @@
 
   octave_base_value *internal_rep (void) const { return rep; }
 
+  // Unsafe.  These functions exist to support the MEX interface.
+  // You should not use them anywhere else.
+  void *mex_get_data (void) const { return rep->mex_get_data (); }
+
+  octave_idx_type *mex_get_ir (void) const { return rep->mex_get_ir (); }
+
+  octave_idx_type *mex_get_jc (void) const { return rep->mex_get_jc (); }
+
+  mxArray *as_mxArray (void) const { return rep->as_mxArray (); }
+
 protected:
 
   // The real representation.