changeset 5864:e884ab4f29ee

[project @ 2006-06-22 00:57:27 by jwe]
author jwe
date Thu, 22 Jun 2006 00:57:28 +0000
parents 4c16f3104aa5
children 4e6be3c306f1
files ChangeLog doc/interpreter/mkoctfile.1 examples/myfeval.c examples/myfevalf.f examples/myhello.c examples/myset.c examples/mystruct.c liboctave/ChangeLog liboctave/oct-shlib.cc mkoctfile.in src/ChangeLog src/Makefile.in src/defun-int.h src/defun.cc src/dynamic-ld.cc src/dynamic-ld.h src/load-path.cc src/load-path.h src/matrix.h src/mex.cc src/mex.h src/mexproto.h src/ov-base.h src/ov-builtin.cc src/ov-fcn.h src/ov-mex-fcn.cc src/ov-mex-fcn.h src/ov.h src/parse.y src/pt-id.cc src/symtab.cc src/symtab.h src/utils.cc src/utils.h src/variables.cc
diffstat 35 files changed, 2464 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2006-06-21  John W. Eaton  <jwe@octave.org>
+
+	* examples/myfeval.c, examples/myfevalf.f, examples/myhello.c,
+	examples/myset.c, examples/mystruct.c: New files.
+
+	* mkoctfile.in: New option, --mex.
+
 2006-06-13  John W. Eaton  <jwe@octave.org>
 
 	* configure.in (--enable-64): Include "(EXPERIMENTAL)" in help text.
--- a/doc/interpreter/mkoctfile.1
+++ b/doc/interpreter/mkoctfile.1
@@ -36,7 +36,8 @@
 Compile but do not link.
 .TP 8
 .B \-o FILE|\-\-output FILE
-Output file name; default extension is .oct.
+Output file name; default extension is .oct (or .mex if --mex is
+specified) unless linking a stand-alone executable.
 .TP
 .B \-p VAR|\-\-print VAR
 Print configuration variable VAR.  Recognized variables are:
@@ -65,6 +66,9 @@
 .TP 8
 .B \-\-link-stand-alone
 Link a stand-alone executable file.
+.B \-\-mex
+Assume we are creating a MEX file.  Set the default output extension
+to .mex.
 .TP 8
 .B \-s|--strip
 Strip the output file.
new file mode 100644
--- /dev/null
+++ b/examples/myfeval.c
@@ -0,0 +1,22 @@
+#include "mex.h"
+
+void
+mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+  char *str;
+
+  mexPrintf ("Hello, World!\n");
+
+  mexPrintf ("I have %d inputs and %d outputs\n", nrhs, nlhs);
+
+  if (nrhs < 1 || ! mxIsString (prhs[0])) 
+    mexErrMsgTxt ("function name expected");
+
+  str = mxArrayToString (prhs[0]);
+
+  mexPrintf ("I'm going to call the interpreter function %s\n", str);
+
+  mexCallMATLAB (nlhs, plhs, nrhs-1, prhs+1, str);
+
+  mxFree (str);
+}
new file mode 100644
--- /dev/null
+++ b/examples/myfevalf.f
@@ -0,0 +1,30 @@
+      subroutine mexFunction (nlhs, plhs, nrhs, prhs)
+
+      implicit none
+
+      integer*4 nlhs, nrhs
+
+* The following will need to be integer*8 on 64-bit systems, otherwise
+* these variables won't be large enough to hold pointers...
+      integer*4 plhs(*), prhs(*)
+
+      integer*4 mxIsString, mxGetString, mxGetN, mexCallMATLAB
+      integer*4 status, len
+      character*100 str
+
+      call mexPrintf ('Hello, World!')
+
+      if (nrhs .lt. 1 .or. mxIsString (prhs(1)) .ne. 1) then
+        call mexErrMsgTxt ('function name expected')
+      endif
+
+      len = mxGetN (prhs(1))
+
+      status = mxGetString (prhs(1), str, 100)
+
+      call mexPrintf ('FORTRAN will call the interpreter now')
+
+      status = mexCallMATLAB (nlhs, plhs, nrhs-1, prhs(2), str(1:len))
+
+      return
+      end
new file mode 100644
--- /dev/null
+++ b/examples/myhello.c
@@ -0,0 +1,13 @@
+#include "mex.h"
+
+void
+mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+  mxArray *v = mxCreateDoubleMatrix (1, 1, mxREAL);
+
+  double *data = mxGetPr (v);
+
+  *data = 1.23456789;
+
+  plhs[0] = v;
+}
new file mode 100644
--- /dev/null
+++ b/examples/myset.c
@@ -0,0 +1,33 @@
+#include "mex.h"
+
+void
+mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+  char *str;
+  mxArray *v;
+
+  if (nrhs != 2 || ! mxIsString (prhs[0]))
+    mexErrMsgTxt ("expects symbol name and value");
+
+  str = mxArrayToString (prhs[0]);
+
+  v = mexGetArray (str, "global");
+
+  if (v)
+    {
+      mexPrintf ("%s is a global variable with the following value:\n", str);
+      mexCallMATLAB (0, 0, 1, &v, "disp");
+    }
+
+  v = mexGetArray (str, "caller");
+
+  if (v)
+    {
+      mexPrintf ("%s is a caller variable with the following value:\n", str);
+      mexCallMATLAB (0, 0, 1, &v, "disp");
+    }
+
+  // WARNING!! Can't do this in MATLAB!  Must copy variable first.
+  mxSetName (prhs[1], str);  
+  mexPutArray (prhs[1], "caller");
+}
new file mode 100644
--- /dev/null
+++ b/examples/mystruct.c
@@ -0,0 +1,34 @@
+#include "mex.h"
+
+void
+mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+  int i, j;
+  mxArray *v;
+  const char *keys[] = { "this", "that" };
+
+  if (nrhs != 1 || ! mxIsStruct (prhs[0]))
+    mexErrMsgTxt ("expects struct");
+
+  for (i = 0; i < mxGetNumberOfFields (prhs[0]); i++)
+    for (j=0; j < mxGetNumberOfElements(prhs[0]); j++)
+      {
+	mexPrintf ("field %s(%d) = ", mxGetFieldNameByNumber (prhs[0], i), j);
+	v = mxGetFieldByNumber (prhs[0], j, i);
+	mexCallMATLAB(0, 0, 1, &v, "disp");
+      }
+
+  v = mxCreateStructMatrix (2, 2, 2, keys);
+
+  mxSetFieldByNumber (v, 0, 0, mxCreateString ("this1"));
+  mxSetFieldByNumber (v, 0, 1, mxCreateString ("that1"));
+  mxSetFieldByNumber (v, 1, 0, mxCreateString ("this2"));
+  mxSetFieldByNumber (v, 1, 1, mxCreateString ("that2"));
+  mxSetFieldByNumber (v, 2, 0, mxCreateString ("this3"));
+  mxSetFieldByNumber (v, 2, 1, mxCreateString ("that3"));
+  mxSetFieldByNumber (v, 3, 0, mxCreateString ("this4"));
+  mxSetFieldByNumber (v, 3, 1, mxCreateString ("that4"));
+
+  if (nlhs)
+    plhs[0] = v;
+}
--- a/liboctave/ChangeLog
+++ b/liboctave/ChangeLog
@@ -1,3 +1,9 @@
+2006-06-21  John W. Eaton  <jwe@octave.org>
+
+	* oct-shlib.cc (octave_dlopen_shlib::close,
+	octave_shl_load_shlib::close, octave_w32_shlib::close):
+	Skip do_close_hook if cl_hook is 0.
+
 2006-06-16  John W. Eaton  <jwe@octave.org>
 
 	* oct-sort.h: Don't include config.h, lo-mappers.h, or quit.h.
--- a/liboctave/oct-shlib.cc
+++ b/liboctave/oct-shlib.cc
@@ -299,7 +299,8 @@
 {
   if (is_open ())
     {
-      do_close_hook (cl_hook);
+      if (cl_hook)
+	do_close_hook (cl_hook);
 
       dlclose (library);
 
@@ -402,7 +403,8 @@
 {
   if (is_open ())
     {
-      do_close_hook (cl_hook);
+      if (cl_hook)
+	do_close_hook (cl_hook);
 
       shl_unload (library);
 
@@ -530,7 +532,8 @@
 {
   if (is_open ())
     {
-      do_close_hook (cl_hook);
+      if (cl_hook)
+	do_close_hook (cl_hook);
 
       FreeLibrary (handle);
 
--- a/mkoctfile.in
+++ b/mkoctfile.in
@@ -83,6 +83,7 @@
 no_oct_file_strip_on_this_platform=%NO_OCT_FILE_STRIP%
 link=true
 link_stand_alone=false
+output_ext=".oct"
 depend=false
 compile=true
 
@@ -150,7 +151,8 @@
   -c, --compile           Compile, but do not link.
 
   -o FILE, --output FILE  Output file name.  Default extension is .oct
-                          unless linking a stand-alone executable.
+                          (or .mex if --mex is specified) unless linking
+                          a stand-alone executable.
 
   -p VAR, --print VAR     Print configuration variable VAR.  Recognized
                           variables are:
@@ -178,6 +180,9 @@
 
   --link-stand-alone      Link a stand-alone executable file.
 
+  --mex                   Assume we are creating a MEX file.  Set the
+                          default output extension to ".mex".
+
   -s, --strip             Strip output file.
 
   -v, --verbose           Echo commands as they are executed.
@@ -247,6 +252,9 @@
     --link-stand-alone)
       link_stand_alone=true
     ;;
+    --mex)
+      output_ext=".mex"
+    ;;
     -W*)
       pass_on_options="$pass_on_options $1"
     ;;
@@ -271,7 +279,7 @@
   if [ -n "$outputfile" ]; then
     octfile="$outputfile"
   else
-    octfile=`echo $octfile | $SED 's,\.[^.]*$,,'`.oct
+    octfile=`echo $octfile | $SED 's,\.[^.]*$,,'`$output_ext
   fi
 fi
 
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,55 @@
+2006-06-21  John W. Eaton  <jwe@octave.org>
+
+	* variables.cc (do_who): Handle mex.
+
+	* symtab.cc (SYMBOL_DEF::type_as_string, SYMBOL_DEF::which,
+	symbol_table::clear_functions, table::clear_function,
+	symbol_table::clear_function_pattern): 
+	Handle mex.
+	* symtab.h (symbol_record::is_mex_function,
+	symbol_record::symbol_def::is_mex_function): New functions.
+	(symbol_record::TYPE): New value, MEX_FUNCTION.
+	(symbol_record::is_function, symbol_table::user_function_name_list,
+	SYMTAB_ALL_TYPES): Handle MEX_FUNCTION.
+
+	* ov-fcn.h (octave_function::octave_function):
+	Provide default for doc string arg.
+
+	* defun.cc (install_mex_function): New function.
+	* defun-int.h: Provide decl.
+
+	* ov-builtin.cc (any_arg_is_magic_colon): Delete.
+	(octave_builtin::do_multi_index_op): Call has_magic_colon method
+	for args instead of any_arg_is_magic_colon.
+
+	* ov-base.h (octave_base_value::is_mex_function): New function.
+	* ov.h (octave_value::is_mex_function): New function.
+
+	* ov-mex-fcn.h, ov-mex-fcn.cc: New files.
+
+	* parse.y (load_fcn_from_file): Also handle .mex files.
+
+	* dynamic-ld.cc (octave_dynamic_loader::load_oct): Rename from load.
+	(octave_dynamic_loader::do_load_oct): Rename from do_load.
+	* dynamic-ld.h: Fix decls.
+
+	* utils.cc (mex_file_in_path): New function.
+	* utils.h: Provide decl.
+
+	* variables.cc (symbol_out_of_date): Also handle mex files.
+
+	* load-path.cc (load_path::dir_info::get_file_list,
+	load_path::dir_info::get_private_function_map,
+	load_path::do_find_fcn, load_path::add_to_fcn_map,
+	load_path::do_display): Also handle mex files.
+	* load-path.h (load_path::find_mex_file): New static function.
+	(load_path::MEX_FILE): New static data member.
+	(load_path::do_find_fcn): By default, also look for mex files.
+
+	* matrix.h, mex.h, mex.cc: New files from Octave Forge
+	* mexproto.h: New file, extracted from mex.h.
+	* Makefile.in: Add them to the appropriate lists.
+
 2006-06-20  John W. Eaton  <jwe@octave.org>
 
 	* ov-re-mat.cc (octave_matrix::convert_to_str_internal):
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -80,8 +80,8 @@
 	ov-colon.h ov-base.h ov-base-mat.h ov-base-scalar.h \
 	ov-streamoff.h ov-str-mat.h ov-bool-mat.h ov-bool.h \
 	ov-cell.h ov.h ov-fcn.h ov-builtin.h ov-dld-fcn.h \
-	ov-mapper.h ov-usr-fcn.h ov-fcn-handle.h ov-fcn-inline.h \
-	ov-typeinfo.h ov-type-conv.h \
+	ov-mapper.h ov-mex-fcn.cc ov-usr-fcn.h ov-fcn-handle.h \
+	ov-fcn-inline.h ov-typeinfo.h ov-type-conv.h \
 	$(OV_INTTYPE_INC)
 
 OV_SPARSE_INCLUDES := \
@@ -98,6 +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 \
 	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 \
@@ -151,7 +152,8 @@
 	ov-streamoff.cc ov-struct.cc \
 	ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-cell.cc \
 	ov.cc ov-fcn.cc ov-builtin.cc ov-dld-fcn.cc ov-mapper.cc \
-	ov-usr-fcn.cc ov-fcn-handle.cc ov-fcn-inline.cc ov-typeinfo.cc \
+	ov-mex-fcn.cc ov-usr-fcn.cc ov-fcn-handle.cc ov-fcn-inline.cc \
+	ov-typeinfo.cc \
 	$(OV_INTTYPE_SRC) \
 	$(OV_SPARSE_SRC)
 
@@ -167,7 +169,7 @@
 	help.cc input.cc lex.l load-path.cc load-save.cc ls-hdf5.cc \
 	ls-mat-ascii.cc ls-mat4.cc ls-mat5.cc ls-oct-ascii.cc \
 	ls-oct-binary.cc ls-utils.cc main.c mappers.cc matherr.c \
-	oct-fstrm.cc oct-hist.cc oct-iostrm.cc oct-map.cc \
+	mex.cc oct-fstrm.cc oct-hist.cc oct-iostrm.cc oct-map.cc \
 	oct-obj.cc oct-prcstrm.cc oct-procbuf.cc oct-stream.cc \
 	octave.cc zfstream.cc oct-strstrm.cc oct-lvalue.cc pager.cc \
 	parse.y pr-output.cc procstream.cc sighandlers.cc \
--- a/src/defun-int.h
+++ b/src/defun-int.h
@@ -53,6 +53,10 @@
 		      const std::string& doc, bool is_text_fcn = false);
 
 extern void
+install_mex_function (void *fptr, bool fmex, const std::string& name,
+		      const octave_shlib& shl, bool is_text_fcn = false);
+
+extern void
 alias_builtin (const std::string& alias, const std::string& name);
 
 #define DECLARE_FUNX(name, args_name, nargout_name) \
--- a/src/defun.cc
+++ b/src/defun.cc
@@ -38,6 +38,7 @@
 #include "ov-dld-fcn.h"
 #include "ov-fcn.h"
 #include "ov-mapper.h"
+#include "ov-mex-fcn.h"
 #include "ov-usr-fcn.h"
 #include "oct-obj.h"
 #include "pager.h"
@@ -187,6 +188,29 @@
 }
 
 void
+install_mex_function (void *fptr, bool fmex, const std::string& name,
+		      const octave_shlib& shl, bool is_text_fcn)
+{
+  symbol_record *sym_rec = fbi_sym_tab->lookup (name, true);
+
+  unsigned int t = symbol_record::MEX_FUNCTION;
+
+  if (is_text_fcn)
+    t |= symbol_record::COMMAND;
+
+  sym_rec->unprotect ();
+  sym_rec->define (new octave_mex_function (fptr, fmex, shl, name), t);
+
+  // Also insert the full name in the symbol table.  This way, we can
+  // properly cope with changes to LOAD_PATH.
+
+  symbol_record *full_sr = fbi_sym_tab->lookup (shl.file_name (), true);
+
+  full_sr->alias (sym_rec, true);
+  full_sr->hide ();
+}
+
+void
 alias_builtin (const std::string& alias, const std::string& name)
 {
   symbol_record *sr_name = fbi_sym_tab->lookup (name);
--- a/src/dynamic-ld.cc
+++ b/src/dynamic-ld.cc
@@ -39,6 +39,9 @@
 #include "utils.h"
 #include "variables.h"
 
+#define STRINGIFY(s) STRINGIFY1(s)
+#define STRINGIFY1(s) #s
+
 class
 octave_shlib_list
 {
@@ -169,6 +172,98 @@
   return (instance_ok ()) ? instance->do_search (fcn_name, shl, mangler) : 0;
 }
 
+class
+octave_mex_file_list
+{
+public:
+
+  static void append (const octave_shlib& shl);
+
+  static void remove (octave_shlib& shl);
+
+private:
+
+  octave_mex_file_list (void) { }
+
+  ~octave_mex_file_list (void) { }
+
+  void do_append (const octave_shlib& shl);
+
+  void do_remove (octave_shlib& shl);
+
+  static octave_mex_file_list *instance;
+
+  static bool instance_ok (void);
+
+  // List of libraries we have loaded.
+  std::list<octave_shlib> file_list;
+
+  // No copying!
+
+  octave_mex_file_list (const octave_mex_file_list&);
+
+  octave_mex_file_list& operator = (const octave_mex_file_list&);
+};
+
+octave_mex_file_list *octave_mex_file_list::instance = 0;
+
+void
+octave_mex_file_list::do_append (const octave_shlib& shl)
+{
+  file_list.push_back (shl);
+}
+
+void
+octave_mex_file_list::do_remove (octave_shlib& shl)
+{
+  
+  for (std::list<octave_shlib>::iterator p = file_list.begin ();
+       p != file_list.end ();
+       p++)
+    {
+      if (*p == shl)
+	{
+	  shl.close ();
+
+	  file_list.erase (p);
+
+	  break;
+	}
+    }
+}
+
+bool
+octave_mex_file_list::instance_ok (void)
+{
+  bool retval = true;
+
+  if (! instance)
+    instance = new octave_mex_file_list ();
+
+  if (! instance)
+    {
+      ::error ("unable to create shared library list object!");
+
+      retval = false;
+    }
+
+  return retval;
+}
+
+void
+octave_mex_file_list::append (const octave_shlib& shl)
+{
+  if (instance_ok ())
+    instance->do_append (shl);
+}
+
+void
+octave_mex_file_list::remove (octave_shlib& shl)
+{
+  if (instance_ok ())
+    instance->do_remove (shl);
+}
+
 octave_dynamic_loader *octave_dynamic_loader::instance = 0;
 
 bool octave_dynamic_loader::doing_load = false;
@@ -205,8 +300,8 @@
 }
 
 bool
-octave_dynamic_loader::do_load (const std::string& fcn_name,
-				const std::string& file_name)
+octave_dynamic_loader::do_load_oct (const std::string& fcn_name,
+				    const std::string& file_name)
 {
   bool retval = false;
 
@@ -259,6 +354,7 @@
 			     oct_file_name.c_str ());
 		}
 	    }
+
 	}
     }
 
@@ -270,7 +366,8 @@
       retval = f (oct_file);
 
       if (! retval)
-	::error ("failed to install dld function `%s'", fcn_name.c_str ());
+	::error ("failed to install .oct file function `%s'",
+		 fcn_name.c_str ());
     }
   
   unwind_protect::run_frame ("octave_dynamic_loader::do_load");
@@ -279,6 +376,66 @@
 }
 
 bool
+octave_dynamic_loader::do_load_mex (const std::string& fcn_name,
+				    const std::string& file_name)
+{
+  bool retval = false;
+
+  octave_shlib mex_file;
+
+  unwind_protect::begin_frame ("octave_dynamic_loader::do_load");
+
+  unwind_protect_bool (octave_dynamic_loader::doing_load);
+
+  doing_load = true;
+
+  std::string mex_file_name
+    = file_name.empty () ? mex_file_in_path (fcn_name) : file_name;
+
+  void *function = 0;
+
+  bool have_fmex = false;
+
+  if (! mex_file_name.empty ())
+    {
+      mex_file.open (mex_file_name);
+
+      if (! error_state)
+	{
+	  if (mex_file)
+	    {
+	      octave_mex_file_list::append (mex_file);
+
+	      function = mex_file.search ("mexFunction");
+
+	      if (! function)
+		{
+		  function = mex_file.search (STRINGIFY (F77_FUNC (mexfunction, MEXFUNCTION)));
+		  if (function)
+		    have_fmex = true;
+		}
+	    }
+	  else
+	    ::error ("%s is not a valid shared library",
+		     mex_file_name.c_str ());
+	}
+    }
+
+  if (function)
+    {
+      install_mex_function (function, have_fmex, fcn_name, mex_file);
+
+      retval = true;
+    }
+  else
+    ::error ("failed to install .mex file function `%s'", fcn_name.c_str ());
+  
+  unwind_protect::run_frame ("octave_dynamic_loader::do_load");
+
+  return retval;
+}
+
+bool
 octave_dynamic_loader::do_remove (const std::string& fcn_name, octave_shlib& shl)
 {
   bool retval = false;
@@ -298,10 +455,17 @@
 }
 
 bool
-octave_dynamic_loader::load (const std::string& fcn_name,
-			     const std::string& file_name)
+octave_dynamic_loader::load_oct (const std::string& fcn_name,
+				 const std::string& file_name)
 {
-  return (instance_ok ()) ? instance->do_load (fcn_name, file_name) : false;
+  return (instance_ok ()) ? instance->do_load_oct (fcn_name, file_name) : false;
+}
+
+bool
+octave_dynamic_loader::load_mex (const std::string& fcn_name,
+				 const std::string& file_name)
+{
+  return (instance_ok ()) ? instance->do_load_mex (fcn_name, file_name) : false;
 }
 
 bool
@@ -310,9 +474,6 @@
   return (instance_ok ()) ? instance->do_remove (fcn_name, shl) : false;
 }
 
-#define STRINGIFY(s) STRINGIFY1(s)
-#define STRINGIFY1(s) #s
-
 std::string
 octave_dynamic_loader::mangle_name (const std::string& name)
 {
--- a/src/dynamic-ld.h
+++ b/src/dynamic-ld.h
@@ -39,8 +39,11 @@
 
   virtual ~octave_dynamic_loader (void) { }
 
-  static bool load (const std::string& fcn_name,
-		    const std::string& file_name = std::string ());
+  static bool load_oct (const std::string& fcn_name,
+			const std::string& file_name = std::string ());
+
+  static bool load_mex (const std::string& fcn_name,
+			const std::string& file_name = std::string ());
 
   static bool remove (const std::string& fcn_name, octave_shlib& shl);
 
@@ -56,8 +59,11 @@
 
   static bool instance_ok (void);
 
-  bool do_load (const std::string& fcn_name,
-		const std::string& file_name = std::string ());
+  bool do_load_oct (const std::string& fcn_name,
+		    const std::string& file_name = std::string ());
+
+  bool do_load_mex (const std::string& fcn_name,
+		    const std::string& file_name = std::string ());
 
   bool do_remove (const std::string& fcn_name, octave_shlib& shl);
 
--- a/src/load-path.cc
+++ b/src/load-path.cc
@@ -146,7 +146,7 @@
 		    {
 		      std::string ext = fname.substr (pos);
 
-		      if (ext == ".m" || ext == ".oct")
+		      if (ext == ".m" || ext == ".oct" || ext == ".mex")
 			{
 			  std::string base = fname.substr (0, pos);
 
@@ -203,6 +203,8 @@
 		    t = load_path::M_FILE;
 		  else if (ext == ".oct")
 		    t = load_path::OCT_FILE;
+		  else if (ext == ".mex")
+		    t = load_path::MEX_FILE;
 
 		  private_function_map[base] |= t;
 		}
@@ -630,6 +632,14 @@
 		  break;
 		}
 	    }
+	  else if (type == load_path::MEX_FILE)
+	    {
+	      if ((type & t) == load_path::MEX_FILE)
+		{
+		  retval += ".mex";
+		  break;
+		}
+	    }
 	  else if (type == (load_path::M_FILE | load_path::OCT_FILE))
 	    {
 	      if (t & load_path::OCT_FILE)
@@ -643,6 +653,51 @@
 		  break;
 		}
 	    }
+	  else if (type == (load_path::M_FILE | load_path::MEX_FILE))
+	    {
+	      if (t & load_path::MEX_FILE)
+		{
+		  retval += ".mex";
+		  break;
+		}
+	      else if (t & load_path::M_FILE)
+		{
+		  retval += ".m";
+		  break;
+		}
+	    }
+	  else if (type == (load_path::OCT_FILE | load_path::MEX_FILE))
+	    {
+	      if (t & load_path::OCT_FILE)
+		{
+		  retval += ".oct";
+		  break;
+		}
+	      else if (t & load_path::MEX_FILE)
+		{
+		  retval += ".mex";
+		  break;
+		}
+	    }
+	  else if (type == (load_path::M_FILE | load_path::OCT_FILE
+			    | load_path::MEX_FILE))
+	    {
+	      if (t & load_path::OCT_FILE)
+		{
+		  retval += ".oct";
+		  break;
+		}
+	      else if (t & load_path::MEX_FILE)
+		{
+		  retval += ".mex";
+		  break;
+		}
+	      else if (t & load_path::M_FILE)
+		{
+		  retval += ".m";
+		  break;
+		}
+	    }
 	  else
 	    error ("load_path::do_find_fcn: %s: invalid type code = %d",
 		   fcn.c_str (), type);
@@ -928,6 +983,14 @@
 		  printed_type = true;
 		}
 
+	      if (types & load_path::MEX_FILE)
+		{
+		  if (printed_type)
+		    os << "|";
+		  os << "mex";
+		  printed_type = true;
+		}
+
 	      if (types & load_path::M_FILE)
 		{
 		  if (printed_type)
@@ -968,6 +1031,14 @@
 	      printed_type = true;
 	    }
 
+	  if (p->types & load_path::MEX_FILE)
+	    {
+	      if (printed_type)
+		os << "|";
+	      os << "mex";
+	      printed_type = true;
+	    }
+
 	  if (p->types & load_path::M_FILE)
 	    {
 	      if (printed_type)
@@ -1026,6 +1097,8 @@
 	t = load_path::M_FILE;
       else if (ext == ".oct")
 	t = load_path::OCT_FILE;
+      else if (ext == ".mex")
+	t = load_path::MEX_FILE;
 
       if (p == file_info_list.end ())
 	{
--- a/src/load-path.h
+++ b/src/load-path.h
@@ -104,6 +104,12 @@
       instance->do_find_fcn (fcn, OCT_FILE) : std::string ();
   }
 
+  static std::string find_mex_file (const std::string& fcn)
+  {
+    return instance_ok () ?
+      instance->do_find_fcn (fcn, MEX_FILE) : std::string ();
+  }
+
   static std::string find_file (const std::string& file)
   {
     return instance_ok ()
@@ -170,6 +176,7 @@
 
   static const int M_FILE = 1;
   static const int OCT_FILE = 2;
+  static const int MEX_FILE = 4;
 
   class dir_info
   {
@@ -302,7 +309,7 @@
   void do_update (void) const;
 
   std::string do_find_fcn (const std::string& fcn,
-			   int type = M_FILE | OCT_FILE) const;
+			   int type = M_FILE | OCT_FILE | MEX_FILE) const;
 
   std::string do_find_file (const std::string& file) const;
 
new file mode 100644
--- /dev/null
+++ b/src/matrix.h
@@ -0,0 +1,1 @@
+#include "mex.h"
new file mode 100644
--- /dev/null
+++ b/src/mex.cc
@@ -0,0 +1,1307 @@
+/*
+
+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 follwoing 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 <cfloat>
+#include <csetjmp>
+#include <cstdlib>
+
+#include <iomanip>
+#include <set>
+#include <string>
+
+typedef void *Pix;
+typedef std::set<Pix> MemSet;
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "oct.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 "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 funcitons.  Must declare mxArray as a class
+// before including this file.
+#include "mexproto.h"
+
+class mex
+{
+public:
+
+  mex (void) { }
+
+  ~mex (void)
+  {
+    if (! memlist.empty ())
+      error("mex: no cleanup performed");
+  }
+
+  // free all unmarked pointers obtained from malloc and calloc
+  static void cleanup (void *context);
+
+  // 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
+  int trap_feval_error;
+
+  // longjmp return point if mexErrMsgTxt or error
+  jmp_buf jump;
+
+  // 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)
+{
+#ifdef DEBUG
+  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)
+{
+#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 ();
+    }
+#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);
+#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';
+  }
+
+  ~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)
+  {
+    strncpy (aname, nm, mxMAXNAM);
+    aname[mxMAXNAM]='\0';
+  }
+
+  // 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
+{
+  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;
+    }
+  else
+    ret = Matrix (0, 0);
+
+  return ret;
+}
+
+
+// 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)
+{
+  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;
+}
+
+// Make a new array value and initialize it with zeros; it will be
+// freed on exit unless marked as persistent.
+
+mxArray *
+mex::make_value (int nr, int nc, int cmplx)
+{
+
+  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;
+}
+
+// Make a new structure value and initialize with empty matrices
+// FIXME does this leak memory?  Is it persistent?
+
+mxArray *
+mex::make_value (int nr, int nc, const string_vector& keys)
+{
+  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;
+}
+
+// free an array and its contents
+
+void
+mex::free_value (mxArray *ptr)
+{
+  free (ptr->real ());
+  free (ptr->imag ());
+  free (ptr);
+}
+
+// mark an array and its contents so it will not be freed on exit
+
+void
+mex::persistent (mxArray *ptr)
+{
+  persistent (Pix (ptr->real ()));
+  persistent (Pix (ptr->imag ()));
+  persistent (Pix (ptr));
+}
+
+
+// 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()
+{
+  if (__mex)
+    {
+      error ("%s: program aborted", mexFunctionName ());
+      __mex->abort ();
+    }
+}
+#endif
+
+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);
+
+enum callstyle { use_fortran, use_C };
+
+octave_value_list
+call_mex (callstyle cs, void *f, const octave_value_list& args, int nargout)
+{
+#if 0
+  // Don't bother trapping stop/exit
+  // FIXME -- should really push "mex_exit" onto the octave
+  // atexit stack before we start and pop it when we are through, but
+  // 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);
+      unregistered = false;
+    }
+#endif
+
+  // Use nargout+1 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);
+  for (int i = 0; i < nargin; i++)
+    argin[i] = 0;
+
+  int nout = nargout == 0 ? 1 : nargout;
+  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));
+
+  for (int i = 0; i < nargin; i++)
+    argin[i] = context.make_value (args(i));
+
+  // Save old mex pointer.
+  unwind_protect_ptr (__mex);
+
+  if (setjmp (context.jump) == 0)
+    {
+      __mex = &context;
+
+      if (cs == use_fortran)
+	{
+	  fmex_fptr fcn = FCN_PTR_CAST (fmex_fptr, f);
+
+	  int tmp_nargout = nargout;
+	  int tmp_nargin = nargin;
+
+	  fcn (tmp_nargout, argout, tmp_nargin, argin);
+	}
+      else
+	{
+	  cmex_fptr fcn = FCN_PTR_CAST (cmex_fptr, f);
+
+	  fcn (nargout, argout, nargin, argin);
+	}
+    }
+
+  // Restore old mex pointer.
+  unwind_protect::run ();
+
+  // Convert returned array entries back into octave values.
+
+  octave_value_list retval;
+
+  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])
+	      retval(i) = argout[i]->as_octave_value ();
+	}
+    }
+
+  // Clean up mex resources.
+  unwind_protect::run ();
+
+  return retval;
+}
+
+octave_value_list
+Fortran_mex (void *f, const octave_value_list& args, int nargout)
+{
+  return call_mex (use_fortran, f, args, nargout);
+}
+
+octave_value_list
+C_mex (void *f, const octave_value_list& args, int nargout)
+{
+  return call_mex (use_C, f, args, nargout);
+}
+
+// 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)
+    {
+      std::string nm = fcn->name ();
+      retval = strsave (nm.c_str ());
+    }
+  else
+    retval = strsave ("unknown");
+
+  return retval;
+}
+
+void
+mexErrMsgTxt (const char *s)
+{
+  if (s && strlen (s) > 0)
+    error("%s: %s", mexFunctionName (), s);
+  else
+    // Just set the error state; don't print msg.
+    error ("");
+
+  __mex->abort();
+}
+
+void mexWarnMsgTxt (const char *s) { warning("%s", s); }
+
+void
+mexPrintf (const char *fmt, ...)
+{
+  va_list args;
+  va_start (args, fmt);
+  octave_vformat (octave_stdout, fmt, args);
+  va_end (args);
+}
+
+// Floating point representation.
+
+int mxIsNaN (const double v) { return lo_ieee_isnan (v) != 0; }
+int mxIsFinite (const double v) { return lo_ieee_finite (v) != 0; }
+int mxIsInf (const double v) { return lo_ieee_isinf (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 *
+mexGetArray (const char *name, const char *space)
+{
+  mxArray *retval = 0;
+
+  // FIXME -- this should be in variable.cc, but the correct
+  // functionality is not exported.  Particularly, get_global_value()
+  // generates an error if the symbol is undefined.
+
+  symbol_record *sr = 0;
+
+  if (! strcmp (space, "global"))
+    sr = global_sym_tab->lookup (name);
+  else if (! strcmp (space, "caller"))
+    sr = curr_sym_tab->lookup (name);
+  else if (! strcmp (space, "base"))
+    mexErrMsgTxt ("mexGetArray: 'base' symbol table not implemented");
+  else
+    mexErrMsgTxt ("mexGetArray: symbol table does not exist");
+
+  if (sr)
+    {
+      octave_value sr_def = sr->def ();
+
+      if (sr_def.is_defined ())
+	{
+	  retval = __mex->make_value (sr_def);
+	  retval->name (name);
+	}
+    }
+
+  return retval;
+}
+
+mxArray *
+mexGetArrayPtr (const char *name, const char *space)
+{
+  return mexGetArray (name, space);
+}
+
+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)
+{
+  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);
+}
+
+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) 
+{
+  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);
+}
+void
+mxSetFieldByNumber (mxArray *ptr, int index, int key_num, mxArray *val)
+{
+  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);
+}
+
+double F77_FUNC (mexgeteps, MEXGETEPS) (void) { return mxGetEps (); }
+double F77_FUNC (mexgetinf, MEXGETINF) (void) { return mxGetInf (); }
+double F77_FUNC (mexgetnan, MEXGETNAN) (void) { return mxGetNaN (); }
+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); }
+
+// Array access:
+
+Pix F77_FUNC (mxcreatefull, MXCREATEFULL)
+  (const int& nr, const int& nc, const int& iscomplex)
+{
+  return mxCreateDoubleMatrix (nr, nc, iscomplex);
+}
+
+void F77_FUNC (mxfreematrix, MXFREEMATRIX) (mxArray* &p)
+{
+  mxDestroyArray (p);
+}
+
+Pix F77_FUNC (mxcalloc, MXCALLOC) (const int& n, const int& size)
+{
+  return mxCalloc (n, size);
+}
+
+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)
+{
+  return mxIsComplex (p);
+}
+
+int F77_FUNC (mxisdouble, MXISDOUBLE) (const mxArray* &p)
+{
+  return mxIsDouble (p);
+}
+
+int F77_FUNC (mxisnumeric, MXISNUMERIC) (const mxArray* &p)
+{
+  return mxIsNumeric(p);
+}
+
+int F77_FUNC (mxisfull, MXISFULL) (const mxArray* &p)
+{
+  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 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)
+{
+  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++)
+    {
+      pr[i] = d[2*i];
+      pi[i] = d[2*i+1];
+    }
+}
+
+void F77_FUNC (mxcopyptrtocomplex16, MXCOPYPTRTOCOMPLEX16)
+  (const int& prref, const int& piref, double *d, const int& len)
+{
+  double *pr = (double *) prref;
+  double *pi = (double *) piref;
+  for (int i = 0; i < len; i++)
+    {
+      d[2*i] = pr[i];
+      d[2*i+1] = pi[i];
+    }
+}
+
+} // extern "C"
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/mex.h
@@ -0,0 +1,117 @@
+/*
+
+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 follwoing 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.
+
+*/
+
+/* mex.h is for use in C-programs only; do NOT include it in mex.cc */
+
+#if ! defined (MEX_H)
+#define MEX_H
+
+#define HAVE_OCTAVE
+
+typedef void mxArray;
+typedef unsigned short mxChar;
+enum mxComplexity { mxREAL = 0, mxCOMPLEX = 1 };
+
+#if ! defined (__cplusplus)
+typedef int bool;
+#endif
+
+typedef int mxLOGICAL;
+
+/* -V4 stuff */
+#if defined (V4)
+#define Matrix mxArray
+#define REAL mxREAL
+#endif
+
+#define mxMAXNAME 64
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#if defined (V4)
+void mexFunction (int nlhs, mxArray* plhs[], int nrhs, mxArray* prhs[]);
+#else
+void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]);
+#endif
+  
+#include "mexproto.h"
+
+/* V4 floating point routines renamed in V5.  */
+#define mexIsNaN mxIsNaN
+#define mexIsFinite mxIsFinite
+#define mexIsInf mxIsInf
+#define mexGetEps mxGetEps
+#define mexGetInf mxGetInf
+#define mexGetNaN mxGetNan
+  
+#define mexGetGlobal(nm) mexGetArray (nm, "global")
+#define mexGetMatrix(nm) mexGetArray (nm, "caller")
+#define mexGetMatrixPtr(nm) mexGetArrayPtr (nm, "caller")
+
+#define mexPutMatrix(ptr) mexPutVariable ("caller", "", ptr)
+#define mexPutArray(ptr, space) mexPutVariable (space, "", ptr)
+  
+#define mxCreateFull mxCreateDoubleMatrix
+
+#define mxCreateScalarDouble mxCreateDoubleScalar
+
+#define mxFreeMatrix mxDestroyArray
+
+#define mxIsString mxIsChar
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/mexproto.h
@@ -0,0 +1,152 @@
+/*
+
+Copyright (C) 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 follwoing 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.
+
+*/
+
+/* mex.h is for use in C-programs only; do NOT include it in mex.cc */
+
+#if ! defined (MEXPROTO_H)
+#define MEXPROTO_H
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/* Floating point representation.  */
+extern int mxIsNaN (double v);
+extern int mxIsFinite (double v);
+extern int mxIsInf (double v);
+extern double mxGetEps (void);
+extern double mxGetInf (void);
+extern double mxGetNaN (void);
+  
+/* Interface to the interpreter */
+extern const char *mexFunctionName (void);
+
+extern int mexCallMATLAB (int nargout, mxArray *argout[], int nargin,
+			  mxArray *argin[], const char *fname);
+
+extern void mexSetTrapFlag (int flag);
+extern int mexEvalString (const char *s);
+extern void mexErrMsgTxt (const char *s);
+extern void mexWarnMsgTxt (const char *s);
+extern void mexPrintf (const char *fmt, ...);
+  
+extern mxArray *mexGetArray (const char *name, const char *space);
+extern mxArray *mexGetArrayPtr (const char *name, const char *space);
+
+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 mxIsSparse (const mxArray *ptr);
+extern int mxIsStruct (const mxArray *ptr);
+extern int mxIsFull (const mxArray *ptr);
+extern int mxIsDouble (const mxArray *ptr);
+extern int mxIsNumeric (const mxArray *ptr);
+extern int mxIsComplex (const mxArray *ptr);
+extern int mxIsEmpty (const mxArray *ptr);
+extern int mxIsLogicalScalar (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);
+
+/* Structure support.  */
+extern int mxIsStruct (const mxArray *ptr);
+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);
+#if 0
+extern mxArray *mxCreateStructArray (int num_dims, const int  *dims, 
+				     int numkeys, const char **keys);
+#endif
+
+extern double *mxGetPi (const mxArray *ptr);
+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 defined (__cplusplus)
+}
+#endif
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C ***
+;;; End: ***
+*/
--- a/src/ov-base.h
+++ b/src/ov-base.h
@@ -264,6 +264,8 @@
 
   virtual bool is_dld_function (void) const { return false; }
 
+  virtual bool is_mex_function (void) const { return false; }
+
   virtual short int short_value (bool = false, bool = false) const;
 
   virtual unsigned short int ushort_value (bool = false, bool = false) const;
--- a/src/ov-builtin.cc
+++ b/src/ov-builtin.cc
@@ -38,20 +38,6 @@
 				     "built-in function",
 				     "built-in function");
 
-// Are any of the arguments `:'?
-
-static bool
-any_arg_is_magic_colon (const octave_value_list& args)
-{
-  int nargin = args.length ();
-
-  for (int i = 0; i < nargin; i++)
-    if (args(i).is_magic_colon ())
-      return true;
-
-  return false;
-}
-
 octave_value_list
 octave_builtin::subsref (const std::string& type,
 			 const std::list<octave_value_list>& idx,
@@ -105,7 +91,7 @@
   if (error_state)
     return retval;
 
-  if (any_arg_is_magic_colon (args))
+  if (args.has_magic_colon ())
     ::error ("invalid use of colon in function argument list");
   else
     {
--- a/src/ov-fcn.h
+++ b/src/ov-fcn.h
@@ -90,7 +90,8 @@
 
 protected:
 
-  octave_function (const std::string& nm, const std::string& ds)
+  octave_function (const std::string& nm,
+		   const std::string& ds = std::string ())
     : my_name (nm), doc (ds) { }
 
   // The name of this function.
new file mode 100644
--- /dev/null
+++ b/src/ov-mex-fcn.cc
@@ -0,0 +1,159 @@
+/*
+
+Copyright (C) 1996, 1997 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "oct-shlib.h"
+
+#include <defaults.h>
+#include "dynamic-ld.h"
+#include "error.h"
+#include "oct-obj.h"
+#include "ov-mex-fcn.h"
+#include "ov.h"
+#include "toplev.h"
+#include "unwind-prot.h"
+
+DEFINE_OCTAVE_ALLOCATOR (octave_mex_function);
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_mex_function,
+				     "mex function", "mex function");
+
+octave_mex_function::octave_mex_function
+  (void *fptr, bool fmex, const octave_shlib& shl,
+   const std::string& nm)
+  : octave_function (nm), mex_fcn_ptr (fptr), have_fmex (fmex), sh_lib (shl)
+{
+  mark_fcn_file_up_to_date (time_parsed ());
+
+  std::string file_name = fcn_file_name ();
+
+  system_fcn_file
+    = (! file_name.empty ()
+       && Voct_file_dir == file_name.substr (0, Voct_file_dir.length ()));
+}
+
+octave_mex_function::~octave_mex_function (void)
+{
+  octave_dynamic_loader::remove (my_name, sh_lib);
+}
+
+std::string
+octave_mex_function::fcn_file_name (void) const
+{
+  return sh_lib.file_name ();
+}
+
+octave_time
+octave_mex_function::time_parsed (void) const
+{
+  return sh_lib.time_loaded ();
+}
+
+octave_value_list
+octave_mex_function::subsref (const std::string& type,
+			      const std::list<octave_value_list>& idx,
+			      int nargout)
+{
+  octave_value_list retval;
+
+  switch (type[0])
+    {
+    case '(':
+      {
+	int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
+
+	retval = do_multi_index_op (tmp_nargout, idx.front ());
+      }
+      break;
+
+    case '{':
+    case '.':
+      {
+	std::string nm = type_name ();
+	error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
+      }
+      break;
+
+    default:
+      panic_impossible ();
+    }
+
+  // FIXME -- perhaps there should be an
+  // octave_value_list::next_subsref member function?  See also
+  // octave_user_function::subsref.
+  //
+  // FIXME -- Note that if a function call returns multiple
+  // values, and there is further indexing to perform, then we are
+  // ignoring all but the first value.  Is this really what we want to
+  // do?  If it is not, then what should happen for stat("file").size,
+  // for exmaple?
+
+  if (idx.size () > 1)
+    retval = retval(0).next_subsref (nargout, type, idx);
+
+  return retval;
+}
+
+extern octave_value_list
+C_mex (void *f, const octave_value_list& args, int nargout);
+
+extern octave_value_list
+Fortran_mex (void *f, const octave_value_list& args, int nargout);
+
+octave_value_list
+octave_mex_function::do_multi_index_op (int nargout,
+					const octave_value_list& args)
+{
+  octave_value_list retval;
+
+  if (error_state)
+    return retval;
+
+  if (args.has_magic_colon ())
+    ::error ("invalid use of colon in function argument list");
+  else
+    {
+      unwind_protect::begin_frame ("mex_func_eval");
+
+      octave_call_stack::push (this);
+
+      unwind_protect::add (octave_call_stack::unwind_pop, 0);
+
+      retval = have_fmex
+	? Fortran_mex (mex_fcn_ptr, args, nargout)
+	: C_mex (mex_fcn_ptr, args, nargout);
+
+      unwind_protect::run_frame ("mex_func_eval");
+    }
+
+  return retval;
+}
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
new file mode 100644
--- /dev/null
+++ b/src/ov-mex-fcn.h
@@ -0,0 +1,118 @@
+/*
+
+Copyright (C) 1996, 1997 John W. Eaton
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+*/
+
+#if !defined (octave_mex_function_h)
+#define octave_mex_function_h 1
+
+#include <string>
+
+#include "oct-shlib.h"
+
+#include "ov-fcn.h"
+#include "ov-builtin.h"
+#include "ov-typeinfo.h"
+
+class octave_shlib;
+
+class octave_value;
+class octave_value_list;
+
+// Dynamically-linked functions.
+
+class
+octave_mex_function : public octave_function
+{
+public:
+
+  octave_mex_function (void) { }
+
+  octave_mex_function (void *fptr, bool fmex, const octave_shlib& shl,
+		       const std::string& nm = std::string ());
+
+  ~octave_mex_function (void);
+
+  octave_value subsref (const std::string&,
+			const std::list<octave_value_list>&)
+    {
+      panic_impossible ();
+      return octave_value ();
+    }
+
+  octave_value_list subsref (const std::string& type,
+			     const std::list<octave_value_list>& idx,
+			     int nargout);
+
+  octave_function *function_value (bool = false) { return this; }
+
+  void mark_fcn_file_up_to_date (const octave_time& t) { t_checked = t; }
+
+  std::string fcn_file_name (void) const;
+
+  octave_time time_parsed (void) const;
+
+  octave_time time_checked (void) const { return t_checked; }
+
+  bool is_system_fcn_file (void) const { return system_fcn_file; }
+
+  bool is_builtin_function (void) const { return false; }
+
+  bool is_mex_function (void) const { return true; }
+
+  octave_value_list
+  do_multi_index_op (int nargout, const octave_value_list& args);
+
+private:
+
+  void *mex_fcn_ptr;
+
+  bool have_fmex;
+
+  octave_shlib sh_lib;
+
+  // The time the file was last checked to see if it needs to be
+  // parsed again.
+  mutable octave_time t_checked;
+
+  // True if this function came from a file that is considered to be a
+  // system function.  This affects whether we check the time stamp
+  // on the file to see if it has changed.
+  bool system_fcn_file;
+
+  // No copying!
+
+  octave_mex_function (const octave_mex_function& fn);
+
+  octave_mex_function& operator = (const octave_mex_function& fn);
+
+  DECLARE_OCTAVE_ALLOCATOR
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+#endif
+
+/*
+;;; Local Variables: ***
+;;; mode: C++ ***
+;;; End: ***
+*/
--- a/src/ov.h
+++ b/src/ov.h
@@ -498,6 +498,9 @@
   bool is_dld_function (void) const
     { return rep->is_dld_function (); }
 
+  bool is_mex_function (void) const
+    { return rep->is_mex_function (); }
+
   // Values.
 
   octave_value eval (void) { return *this; }
--- a/src/parse.y
+++ b/src/parse.y
@@ -3389,6 +3389,7 @@
 
   if (octave_env::absolute_pathname (nm)
       && ((nm_len > 4 && nm.substr (nm_len-4) == ".oct")
+	  || (nm_len > 4 && nm.substr (nm_len-4) == ".mex")
 	  || (nm_len > 2 && nm.substr (nm_len-4) == ".m")))
     {
       file = nm;
@@ -3413,7 +3414,12 @@
 
   if (len > 4 && file.substr (len-4, len-1) == ".oct")
     {
-      if (octave_dynamic_loader::load (nm, file))
+      if (octave_dynamic_loader::load_oct (nm, file))
+        force_link_to_function (nm);
+    }
+  else if (len > 4 && file.substr (len-4, len-1) == ".mex")
+    {
+      if (octave_dynamic_loader::load_mex (nm, file))
         force_link_to_function (nm);
     }
   else if (len > 2)
--- a/src/pt-id.cc
+++ b/src/pt-id.cc
@@ -99,8 +99,8 @@
 //   * If the identifier is still undefined, try looking for an
 //     function file to parse.
 //
-//   * On systems that support dynamic linking, we prefer .oct files
-//     over .m files.
+//   * On systems that support dynamic linking, we prefer .oct files,
+//     then .mex files, then .m files.
 
 octave_value
 tree_identifier::do_lookup (bool& script_file_executed, bool exec_script)
--- a/src/symtab.cc
+++ b/src/symtab.cc
@@ -87,6 +87,8 @@
     retval = "built-in function";
   else if (is_dld_function ())
     retval = "dynamically-linked function";
+  else if (is_mex_function ())
+    retval = "dynamically-linked mex function";
 
   return retval;
 }
@@ -148,7 +150,7 @@
 {
   std::string retval;
 
-  if (is_user_function () || is_dld_function ())
+  if (is_user_function () || is_dld_function () || is_mex_function ())
     {
       octave_function *defn = definition.function_value ();
 
@@ -166,7 +168,7 @@
 {
   os << name;
 
-  if (is_user_function () || is_dld_function ())
+  if (is_user_function () || is_dld_function () || is_mex_function ())
     {
       octave_function *defn = definition.function_value ();
 
@@ -827,7 +829,9 @@
 
       while (ptr)
 	{
-	  if (ptr->is_user_function () || ptr->is_dld_function ())
+	  if (ptr->is_user_function ()
+	      || ptr->is_dld_function ()
+	      || ptr->is_mex_function ())
 	    ptr->clear ();
 
 	  ptr = ptr->next ();
@@ -927,7 +931,9 @@
   while (ptr)
     {
       if (ptr->name () == nm
-	  && (ptr->is_user_function () || ptr->is_dld_function ()))
+	  && (ptr->is_user_function ()
+	      || ptr->is_dld_function ()
+	      || ptr->is_mex_function ()))
 	{
 	  ptr->clear ();
 	  return true;
@@ -1011,7 +1017,9 @@
 
       while (ptr)
 	{
-	  if (ptr->is_user_function () || ptr->is_dld_function ())
+	  if (ptr->is_user_function ()
+	      || ptr->is_dld_function ()
+	      || ptr->is_mex_function ())
 	    {
 	      glob_match pattern (pat);
 
--- a/src/symtab.h
+++ b/src/symtab.h
@@ -74,7 +74,8 @@
       BUILTIN_FUNCTION = 8,
       COMMAND = 16,
       RAWCOMMAND = 32,
-      MAPPER_FUNCTION = 64
+      MAPPER_FUNCTION = 64,
+      MEX_FUNCTION = 128,
     };
 
 private:
@@ -103,6 +104,7 @@
       {
 	return (symbol_type & symbol_record::USER_FUNCTION
 		|| symbol_type & symbol_record::DLD_FUNCTION
+		|| symbol_type & symbol_record::MEX_FUNCTION
 		|| symbol_type & symbol_record::BUILTIN_FUNCTION);
       }
 
@@ -141,6 +143,9 @@
     bool is_dld_function (void) const
       { return (symbol_type & symbol_record::DLD_FUNCTION); }
 
+    bool is_mex_function (void) const
+      { return (symbol_type & symbol_record::MEX_FUNCTION); }
+
     // FIXME
     bool is_map_element (const std::string& /* elts */) const
       { return false; }
@@ -317,6 +322,9 @@
   bool is_dld_function (void) const
     { return definition->is_dld_function (); }
 
+  bool is_mex_function (void) const
+    { return definition->is_mex_function (); }
+
   bool is_variable (void) const
     { return definition->is_variable (); }
 
@@ -485,7 +493,8 @@
 			  | symbol_record::BUILTIN_FUNCTION \
 			  | symbol_record::COMMAND \
   			  | symbol_record::RAWCOMMAND \
-			  | symbol_record::MAPPER_FUNCTION)
+			  | symbol_record::MAPPER_FUNCTION \
+			  | symbol_record::MEX_FUNCTION)
 
 #define SYMTAB_VARIABLES (symbol_record::USER_VARIABLE)
 
@@ -555,7 +564,7 @@
     {
       return name_list
 	(string_vector (), false,
-	 symbol_record::USER_FUNCTION|symbol_record::DLD_FUNCTION,
+	 symbol_record::USER_FUNCTION|symbol_record::DLD_FUNCTION|symbol_record::MEX_FUNCTION,
 	 SYMTAB_ALL_SCOPES);
     }
 
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -433,7 +433,7 @@
   return retval;
 }
 
-// See if there is an octave file in the path.  If so, return the
+// See if there is a .oct file in the path.  If so, return the
 // full path to the file.
 
 std::string
@@ -462,6 +462,35 @@
   return retval;
 }
 
+// See if there is a .mex file in the path.  If so, return the
+// full path to the file.
+
+std::string
+mex_file_in_path (const std::string& name)
+{
+  std::string retval;
+
+  int len = name.length ();
+  
+  if (len > 0)
+    {
+      if (octave_env::absolute_pathname (name))
+	{
+	  file_stat fs (name);
+
+	  if (fs.exists ())
+	    retval = name;
+	}
+      else if (len > 4 && name [len - 4] == '.' && name [len - 3] == 'm'
+	       && name [len - 2] == 'e' && name [len - 1] == 'x')
+	retval = load_path::find_mex_file (name.substr (0, len-4));
+      else
+	retval = load_path::find_mex_file (name);
+    }
+
+  return retval;
+}
+
 // Replace backslash escapes in a string with the real values.
 
 std::string
--- a/src/utils.h
+++ b/src/utils.h
@@ -58,6 +58,7 @@
 extern std::string file_in_path (const std::string&, const std::string&);
 extern std::string fcn_file_in_path (const std::string&);
 extern std::string oct_file_in_path (const std::string&);
+extern std::string mex_file_in_path (const std::string&);
 
 extern std::string do_string_escapes (const std::string& s);
 
--- a/src/variables.cc
+++ b/src/variables.cc
@@ -821,7 +821,8 @@
 	    {
 	      if (type == "any" || type == "file")
 		{
-		  if (len > 4 && file_name.substr (len-4) == ".oct")
+		  if (len > 4 && (file_name.substr (len-4) == ".oct"
+				  || file_name.substr (len-4) == ".mex"))
 		    retval = 3;
 		  else
 		    retval = 2;
@@ -886,8 +887,8 @@
 @deftypefn {Built-in Function} {} exist (@var{name}, @var{type})\n\
 Return 1 if the name exists as a variable, 2 if the name (after\n\
 appending @samp{.m}) is a function file in Octave's @code{path}, 3 if the\n\
-name is a @samp{.oct} file in Octave's @code{path}, 5 if the name is a\n\
-built-in function, 7 if the name is a directory, or 103\n\
+name is a @samp{.oct} or @samp{.mex} file in Octave's @code{path},\n\
+5 if the name is a built-in function, 7 if the name is a directory, or 103\n\
 if the name is a function not associated with a file (entered on\n\
 the command line).\n\
 \n\
@@ -1014,7 +1015,8 @@
 		  std::string file;
 
 		  if (octave_env::absolute_pathname (nm)
-		      && ((nm_len > 4 && nm.substr (nm_len-4) == ".oct")
+		      && ((nm_len > 4 && (nm.substr (nm_len-4) == ".oct"
+					  || nm.substr (nm_len-4) == ".mex"))
 			  || (nm_len > 2 && nm.substr (nm_len-4) == ".m")))
 		    {
 		      file = nm;
@@ -1605,6 +1607,7 @@
       Array<symbol_record *> s5 (dv);
       Array<symbol_record *> s6 (dv);
       Array<symbol_record *> s7 (dv);
+      Array<symbol_record *> s8 (dv);
 
       if (show_builtins)
 	{
@@ -1619,14 +1622,17 @@
 
 	  s5 = fbi_sym_tab->symbol_list (pats, symbol_record::USER_FUNCTION,
 					 SYMTAB_ALL_SCOPES);
+
+	  s6 = fbi_sym_tab->symbol_list (pats, symbol_record::MEX_FUNCTION,
+					 SYMTAB_ALL_SCOPES);
 	}
 
       if (show_variables)
 	{
-	  s6 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
+	  s7 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
 					  SYMTAB_LOCAL_SCOPE);
 
-	  s7 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
+	  s8 = curr_sym_tab->symbol_list (pats, symbol_record::USER_VARIABLE,
 					  SYMTAB_GLOBAL_SCOPE);
 	}
 
@@ -1635,8 +1641,10 @@
       octave_idx_type s5_len = s5.length ();
       octave_idx_type s6_len = s6.length ();
       octave_idx_type s7_len = s7.length ();
-
-      octave_idx_type symbols_len = s3_len + s4_len + s5_len + s6_len + s7_len;
+      octave_idx_type s8_len = s8.length ();
+
+      octave_idx_type symbols_len
+	= s3_len + s4_len + s5_len + s6_len + s7_len + s8_len;
 
       Array<symbol_record *> symbols (dim_vector (symbols_len, 1));
 
@@ -1651,6 +1659,8 @@
       symbols.insert (s6, k, 0);
       k += s6_len;
       symbols.insert (s7, k, 0);
+      k += s7_len;
+      symbols.insert (s8, k, 0);
 
       symbols.qsort (symbol_record_name_compare);
 
@@ -1740,6 +1750,11 @@
 	    ("*** currently compiled functions:", pats,
 	     octave_stdout, show_verbose, symbol_record::USER_FUNCTION,
 	     SYMTAB_ALL_SCOPES);
+
+	  pad_after += fbi_sym_tab->maybe_list
+	    ("*** mex functions:", pats,
+	     octave_stdout, show_verbose, symbol_record::MEX_FUNCTION,
+	     SYMTAB_ALL_SCOPES);
 	}
 
       if (show_variables)