mex.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2006-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #include <config.h>
00024 
00025 #include <cfloat>
00026 #include <csetjmp>
00027 #include <cstdarg>
00028 #include <cstdlib>
00029 #include <cstring>
00030 #include <cctype>
00031 
00032 #include <set>
00033 
00034 #include "f77-fcn.h"
00035 #include "lo-ieee.h"
00036 #include "oct-locbuf.h"
00037 
00038 // mxArray must be declared as a class before including mexproto.h.
00039 class mxArray;
00040 #include "Cell.h"
00041 #include "mexproto.h"
00042 #include "oct-map.h"
00043 #include "oct-obj.h"
00044 #include "ov.h"
00045 #include "ov-mex-fcn.h"
00046 #include "ov-usr-fcn.h"
00047 #include "pager.h"
00048 #include "parse.h"
00049 #include "toplev.h"
00050 #include "unwind-prot.h"
00051 #include "utils.h"
00052 #include "variables.h"
00053 #include "graphics.h"
00054 
00055 // #define DEBUG 1
00056 
00057 static void
00058 xfree (void *ptr)
00059 {
00060   ::free (ptr);
00061 }
00062 
00063 static mwSize
00064 max_str_len (mwSize m, const char **str)
00065 {
00066   int max_len = 0;
00067 
00068   for (mwSize i = 0; i < m; i++)
00069     {
00070       mwSize tmp = strlen (str[i]);
00071 
00072       if (tmp > max_len)
00073         max_len = tmp;
00074     }
00075 
00076   return max_len;
00077 }
00078 
00079 static int
00080 valid_key (const char *key)
00081 {
00082   int retval = 0;
00083 
00084   int nel = strlen (key);
00085 
00086   if (nel > 0)
00087     {
00088       if (isalpha (key[0]))
00089         {
00090           for (int i = 1; i < nel; i++)
00091             {
00092               if (! (isalnum (key[i]) || key[i] == '_'))
00093                 goto done;
00094             }
00095 
00096           retval = 1;
00097         }
00098     }
00099 
00100  done:
00101 
00102   return retval;
00103 }
00104 
00105 // ------------------------------------------------------------------
00106 
00107 // A class to provide the default implemenation of some of the virtual
00108 // functions declared in the mxArray class.
00109 
00110 class mxArray_base : public mxArray
00111 {
00112 protected:
00113 
00114   mxArray_base (void) : mxArray (xmxArray ()) { }
00115 
00116 public:
00117 
00118   mxArray *dup (void) const = 0;
00119 
00120   ~mxArray_base (void) { }
00121 
00122   bool is_octave_value (void) const { return false; }
00123 
00124   int is_cell (void) const = 0;
00125 
00126   int is_char (void) const = 0;
00127 
00128   int is_class (const char *name_arg) const
00129   {
00130     int retval = 0;
00131 
00132     const char *cname = get_class_name ();
00133 
00134     if (cname && name_arg)
00135       retval = ! strcmp (cname, name_arg);
00136 
00137     return retval;
00138   }
00139 
00140   int is_complex (void) const = 0;
00141 
00142   int is_double (void) const = 0;
00143 
00144   int is_function_handle (void) const = 0;
00145 
00146   int is_int16 (void) const = 0;
00147 
00148   int is_int32 (void) const = 0;
00149 
00150   int is_int64 (void) const = 0;
00151 
00152   int is_int8 (void) const = 0;
00153 
00154   int is_logical (void) const = 0;
00155 
00156   int is_numeric (void) const = 0;
00157 
00158   int is_single (void) const = 0;
00159 
00160   int is_sparse (void) const = 0;
00161 
00162   int is_struct (void) const = 0;
00163 
00164   int is_uint16 (void) const = 0;
00165 
00166   int is_uint32 (void) const = 0;
00167 
00168   int is_uint64 (void) const = 0;
00169 
00170   int is_uint8 (void) const = 0;
00171 
00172   int is_logical_scalar (void) const
00173   {
00174     return is_logical () && get_number_of_elements () == 1;
00175   }
00176 
00177   int is_logical_scalar_true (void) const = 0;
00178 
00179   mwSize get_m (void) const = 0;
00180 
00181   mwSize get_n (void) const = 0;
00182 
00183   mwSize *get_dimensions (void) const = 0;
00184 
00185   mwSize get_number_of_dimensions (void) const = 0;
00186 
00187   void set_m (mwSize m) = 0;
00188 
00189   void set_n (mwSize n) = 0;
00190 
00191   void set_dimensions (mwSize *dims_arg, mwSize ndims_arg) = 0;
00192 
00193   mwSize get_number_of_elements (void) const = 0;
00194 
00195   int is_empty (void) const = 0;
00196 
00197   mxClassID get_class_id (void) const = 0;
00198 
00199   const char *get_class_name (void) const = 0;
00200 
00201   void set_class_name (const char *name_arg) = 0;
00202 
00203   mxArray *get_cell (mwIndex /*idx*/) const
00204   {
00205     invalid_type_error ();
00206     return 0;
00207   }
00208 
00209   void set_cell (mwIndex idx, mxArray *val) = 0;
00210 
00211   double get_scalar (void) const = 0;
00212 
00213   void *get_data (void) const = 0;
00214 
00215   void *get_imag_data (void) const = 0;
00216 
00217   void set_data (void *pr) = 0;
00218 
00219   void set_imag_data (void *pi) = 0;
00220 
00221   mwIndex *get_ir (void) const = 0;
00222 
00223   mwIndex *get_jc (void) const = 0;
00224 
00225   mwSize get_nzmax (void) const = 0;
00226 
00227   void set_ir (mwIndex *ir) = 0;
00228 
00229   void set_jc (mwIndex *jc) = 0;
00230 
00231   void set_nzmax (mwSize nzmax) = 0;
00232 
00233   int add_field (const char *key) = 0;
00234 
00235   void remove_field (int key_num) = 0;
00236 
00237   mxArray *get_field_by_number (mwIndex index, int key_num) const = 0;
00238 
00239   void set_field_by_number (mwIndex index, int key_num, mxArray *val) = 0;
00240 
00241   int get_number_of_fields (void) const = 0;
00242 
00243   const char *get_field_name_by_number (int key_num) const = 0;
00244 
00245   int get_field_number (const char *key) const = 0;
00246 
00247   int get_string (char *buf, mwSize buflen) const = 0;
00248 
00249   char *array_to_string (void) const = 0;
00250 
00251   mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const = 0;
00252 
00253   size_t get_element_size (void) const = 0;
00254 
00255   bool mutation_needed (void) const { return false; }
00256 
00257   mxArray *mutate (void) const { return 0; }
00258 
00259 protected:
00260 
00261   octave_value as_octave_value (void) const = 0;
00262 
00263   mxArray_base (const mxArray_base&) : mxArray (xmxArray ()) { }
00264 
00265   void invalid_type_error (void) const
00266   {
00267     error ("invalid type for operation");
00268   }
00269 
00270   void error (const char *msg) const
00271   {
00272     // FIXME
00273     ::error ("%s", msg);
00274   }
00275 };
00276 
00277 static mwIndex
00278 calc_single_subscript_internal (mwSize ndims, const mwSize *dims,
00279                                 mwSize nsubs, const mwIndex *subs)
00280 {
00281   mwIndex retval = 0;
00282 
00283   switch (nsubs)
00284     {
00285     case 0:
00286       break;
00287 
00288     case 1:
00289       retval = subs[0];
00290       break;
00291 
00292     default:
00293       {
00294         // Both nsubs and ndims should be at least 2 here.
00295 
00296         mwSize n = nsubs <= ndims ? nsubs : ndims;
00297 
00298         retval = subs[--n];
00299 
00300         while (--n >= 0)
00301           retval = dims[n] * retval + subs[n];
00302       }
00303       break;
00304     }
00305 
00306   return retval;
00307 }
00308 
00309 // The object that handles values pass to MEX files from Octave.  Some
00310 // methods in this class may set mutate_flag to TRUE to tell the
00311 // mxArray class to convert to the Matlab-style representation and
00312 // then invoke the method on that object instead (for example, getting
00313 // a pointer to real or imaginary data from a complex object requires
00314 // a mutation but getting a pointer to real data from a real object
00315 // does not).  Changing the representation causes a copy so we try to
00316 // avoid it unless it is really necessary.  Once the conversion
00317 // happens, we delete this representation, so the conversion can only
00318 // happen once per call to a MEX file.
00319 
00320 static inline void *maybe_mark_foreign (void *ptr);
00321 
00322 class mxArray_octave_value : public mxArray_base
00323 {
00324 public:
00325 
00326   mxArray_octave_value (const octave_value& ov)
00327     : mxArray_base (), val (ov), mutate_flag (false),
00328       id (mxUNKNOWN_CLASS), class_name (0), ndims (-1), dims (0) { }
00329 
00330   mxArray *dup (void) const
00331   {
00332     mxArray *retval = val.as_mxArray ();
00333 
00334     if (! retval)
00335       retval = new mxArray_octave_value (*this);
00336 
00337     return retval;
00338   }
00339 
00340   ~mxArray_octave_value (void)
00341   {
00342     mxFree (class_name);
00343     mxFree (dims);
00344   }
00345 
00346   bool is_octave_value (void) const { return true; }
00347 
00348   int is_cell (void) const { return val.is_cell (); }
00349 
00350   int is_char (void) const { return val.is_string (); }
00351 
00352   int is_complex (void) const { return val.is_complex_type (); }
00353 
00354   int is_double (void) const { return val.is_double_type (); }
00355 
00356   int is_function_handle (void) const { return val.is_function_handle (); }
00357 
00358   int is_int16 (void) const { return val.is_int16_type (); }
00359 
00360   int is_int32 (void) const { return val.is_int32_type (); }
00361 
00362   int is_int64 (void) const { return val.is_int64_type (); }
00363 
00364   int is_int8 (void) const { return val.is_int8_type (); }
00365 
00366   int is_logical (void) const { return val.is_bool_type (); }
00367 
00368   int is_numeric (void) const { return val.is_numeric_type (); }
00369 
00370   int is_single (void) const { return val.is_single_type (); }
00371 
00372   int is_sparse (void) const { return val.is_sparse_type (); }
00373 
00374   int is_struct (void) const { return val.is_map (); }
00375 
00376   int is_uint16 (void) const { return val.is_uint16_type (); }
00377 
00378   int is_uint32 (void) const { return val.is_uint32_type (); }
00379 
00380   int is_uint64 (void) const { return val.is_uint64_type (); }
00381 
00382   int is_uint8 (void) const { return val.is_uint8_type (); }
00383 
00384   int is_range (void) const { return val.is_range (); }
00385 
00386   int is_real_type (void) const { return val.is_real_type (); }
00387 
00388   int is_logical_scalar_true (void) const
00389   {
00390     return (is_logical_scalar () && val.is_true ());
00391   }
00392 
00393   mwSize get_m (void) const { return val.rows (); }
00394 
00395   mwSize get_n (void) const
00396   {
00397     mwSize n = 1;
00398 
00399     // Force dims and ndims to be cached.
00400     get_dimensions();
00401 
00402     for (mwIndex i = ndims - 1; i > 0; i--)
00403       n *= dims[i];
00404 
00405     return n;
00406   }
00407 
00408   mwSize *get_dimensions (void) const
00409   {
00410     if (! dims)
00411       {
00412         ndims = val.ndims ();
00413 
00414         dims = static_cast<mwSize *> (malloc (ndims * sizeof (mwSize)));
00415 
00416         dim_vector dv = val.dims ();
00417 
00418         for (mwIndex i = 0; i < ndims; i++)
00419           dims[i] = dv(i);
00420       }
00421 
00422     return dims;
00423   }
00424 
00425   mwSize get_number_of_dimensions (void) const
00426   {
00427     // Force dims and ndims to be cached.
00428     get_dimensions ();
00429 
00430     return ndims;
00431   }
00432 
00433   void set_m (mwSize /*m*/) { request_mutation (); }
00434 
00435   void set_n (mwSize /*n*/) { request_mutation (); }
00436 
00437   void set_dimensions (mwSize */*dims_arg*/, mwSize /*ndims_arg*/)
00438   {
00439     request_mutation ();
00440   }
00441 
00442   mwSize get_number_of_elements (void) const { return val.numel (); }
00443 
00444   int is_empty (void) const { return val.is_empty (); }
00445 
00446   mxClassID get_class_id (void) const
00447   {
00448     id = mxUNKNOWN_CLASS;
00449 
00450     std::string cn = val.class_name ();
00451 
00452     if (cn == "cell")
00453       id = mxCELL_CLASS;
00454     else if (cn == "struct")
00455       id = mxSTRUCT_CLASS;
00456     else if (cn == "logical")
00457       id = mxLOGICAL_CLASS;
00458     else if (cn == "char")
00459       id = mxCHAR_CLASS;
00460     else if (cn == "double")
00461       id = mxDOUBLE_CLASS;
00462     else if (cn == "single")
00463       id = mxSINGLE_CLASS;
00464     else if (cn == "int8")
00465       id = mxINT8_CLASS;
00466     else if (cn == "uint8")
00467       id = mxUINT8_CLASS;
00468     else if (cn == "int16")
00469       id = mxINT16_CLASS;
00470     else if (cn == "uint16")
00471       id = mxUINT16_CLASS;
00472     else if (cn == "int32")
00473       id = mxINT32_CLASS;
00474     else if (cn == "uint32")
00475       id = mxUINT32_CLASS;
00476     else if (cn == "int64")
00477       id = mxINT64_CLASS;
00478     else if (cn == "uint64")
00479       id = mxUINT64_CLASS;
00480     else if (cn == "function_handle")
00481       id = mxFUNCTION_CLASS;
00482 
00483     return id;
00484   }
00485 
00486   const char *get_class_name (void) const
00487   {
00488     if (! class_name)
00489       {
00490         std::string s = val.class_name ();
00491         class_name = strsave (s.c_str ());
00492       }
00493 
00494     return class_name;
00495   }
00496 
00497   // Not allowed.
00498   void set_class_name (const char */*name_arg*/) { request_mutation (); }
00499 
00500   mxArray *get_cell (mwIndex /*idx*/) const
00501   {
00502     request_mutation ();
00503     return 0;
00504   }
00505 
00506   // Not allowed.
00507   void set_cell (mwIndex /*idx*/, mxArray */*val*/) { request_mutation (); }
00508 
00509   double get_scalar (void) const { return val.scalar_value (true); }
00510 
00511   void *get_data (void) const
00512   {
00513     void *retval = val.mex_get_data ();
00514 
00515     if (retval)
00516       maybe_mark_foreign (retval);
00517     else
00518       request_mutation ();
00519 
00520     return retval;
00521   }
00522 
00523   void *get_imag_data (void) const
00524   {
00525     void *retval = 0;
00526 
00527     if (is_numeric () && is_real_type ())
00528       retval = 0;
00529     else
00530       request_mutation ();
00531 
00532     return retval;
00533   }
00534 
00535   // Not allowed.
00536   void set_data (void */*pr*/) { request_mutation (); }
00537 
00538   // Not allowed.
00539   void set_imag_data (void */*pi*/) { request_mutation (); }
00540 
00541   mwIndex *get_ir (void) const
00542   {
00543     return static_cast<mwIndex *> (maybe_mark_foreign (val.mex_get_ir ()));
00544   }
00545 
00546   mwIndex *get_jc (void) const
00547   {
00548     return static_cast<mwIndex *> (maybe_mark_foreign (val.mex_get_jc ()));
00549   }
00550 
00551   mwSize get_nzmax (void) const { return val.nzmax (); }
00552 
00553   // Not allowed.
00554   void set_ir (mwIndex */*ir*/) { request_mutation (); }
00555 
00556   // Not allowed.
00557   void set_jc (mwIndex */*jc*/) { request_mutation (); }
00558 
00559   // Not allowed.
00560   void set_nzmax (mwSize /*nzmax*/) { request_mutation (); }
00561 
00562   // Not allowed.
00563   int add_field (const char */*key*/)
00564   {
00565     request_mutation ();
00566     return 0;
00567   }
00568 
00569   // Not allowed.
00570   void remove_field (int /*key_num*/) { request_mutation (); }
00571 
00572   mxArray *get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
00573   {
00574     request_mutation ();
00575     return 0;
00576   }
00577 
00578   // Not allowed.
00579   void set_field_by_number (mwIndex /*index*/, int /*key_num*/, mxArray */*val*/)
00580   {
00581     request_mutation ();
00582   }
00583 
00584   int get_number_of_fields (void) const { return val.nfields (); }
00585 
00586   const char *get_field_name_by_number (int /*key_num*/) const
00587   {
00588     request_mutation ();
00589     return 0;
00590   }
00591 
00592   int get_field_number (const char */*key*/) const
00593   {
00594     request_mutation ();
00595     return 0;
00596   }
00597 
00598   int get_string (char *buf, mwSize buflen) const
00599   {
00600     int retval = 1;
00601 
00602     mwSize nel = get_number_of_elements ();
00603 
00604     if (val.is_string () && nel < buflen)
00605       {
00606         charNDArray tmp = val.char_array_value ();
00607 
00608         const char *p = tmp.data ();
00609 
00610         for (mwIndex i = 0; i < nel; i++)
00611           buf[i] = p[i];
00612 
00613         buf[nel] = 0;
00614 
00615         retval = 0;
00616       }
00617 
00618     return retval;
00619   }
00620 
00621   char *array_to_string (void) const
00622   {
00623     // FIXME -- this is suposed to handle multi-byte character
00624     // strings.
00625 
00626     char *buf = 0;
00627 
00628     if (val.is_string ())
00629       {
00630         mwSize nel = get_number_of_elements ();
00631 
00632         buf = static_cast<char *> (malloc (nel + 1));
00633 
00634         if (buf)
00635           {
00636             charNDArray tmp = val.char_array_value ();
00637 
00638             const char *p = tmp.data ();
00639 
00640             for (mwIndex i = 0; i < nel; i++)
00641               buf[i] = p[i];
00642 
00643             buf[nel] = '\0';
00644           }
00645       }
00646 
00647     return buf;
00648   }
00649 
00650   mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
00651   {
00652     // Force ndims, dims to be cached.
00653     get_dimensions ();
00654 
00655     return calc_single_subscript_internal (ndims, dims, nsubs, subs);
00656   }
00657 
00658   size_t get_element_size (void) const
00659   {
00660     // Force id to be cached.
00661     get_class_id ();
00662 
00663     switch (id)
00664       {
00665       case mxCELL_CLASS: return sizeof (mxArray *);
00666       case mxSTRUCT_CLASS: return sizeof (mxArray *);
00667       case mxLOGICAL_CLASS: return sizeof (mxLogical);
00668       case mxCHAR_CLASS: return sizeof (mxChar);
00669       case mxDOUBLE_CLASS: return sizeof (double);
00670       case mxSINGLE_CLASS: return sizeof (float);
00671       case mxINT8_CLASS: return 1;
00672       case mxUINT8_CLASS: return 1;
00673       case mxINT16_CLASS: return 2;
00674       case mxUINT16_CLASS: return 2;
00675       case mxINT32_CLASS: return 4;
00676       case mxUINT32_CLASS: return 4;
00677       case mxINT64_CLASS: return 8;
00678       case mxUINT64_CLASS: return 8;
00679       case mxFUNCTION_CLASS: return 0;
00680       default: return 0;
00681       }
00682   }
00683 
00684   bool mutation_needed (void) const { return mutate_flag; }
00685 
00686   void request_mutation (void) const
00687   {
00688     if (mutate_flag)
00689       panic_impossible ();
00690 
00691     mutate_flag = true;
00692   }
00693 
00694   mxArray *mutate (void) const { return val.as_mxArray (); }
00695 
00696 protected:
00697 
00698   octave_value as_octave_value (void) const { return val; }
00699 
00700   mxArray_octave_value (const mxArray_octave_value& arg)
00701     : mxArray_base (arg), val (arg.val), mutate_flag (arg.mutate_flag),
00702       id (arg.id), class_name (strsave (arg.class_name)), ndims (arg.ndims),
00703       dims (ndims > 0 ? static_cast<mwSize *> (malloc (ndims * sizeof (mwSize))) : 0)
00704   {
00705     if (dims)
00706       {
00707         for (mwIndex i = 0; i < ndims; i++)
00708           dims[i] = arg.dims[i];
00709       }
00710   }
00711 
00712 private:
00713 
00714   octave_value val;
00715 
00716   mutable bool mutate_flag;
00717 
00718   // Caching these does not cost much or lead to much duplicated
00719   // code.  For other things, we just request mutation to a
00720   // Matlab-style mxArray object.
00721 
00722   mutable mxClassID id;
00723   mutable char *class_name;
00724   mutable mwSize ndims;
00725   mutable mwSize *dims;
00726 
00727   // No assignment!  FIXME -- should this be implemented?  Note that we
00728   // do have a copy constructor.
00729 
00730   mxArray_octave_value& operator = (const mxArray_octave_value&);
00731 };
00732 
00733 // The base class for the Matlab-style representation, used to handle
00734 // things that are common to all Matlab-style objects.
00735 
00736 class mxArray_matlab : public mxArray_base
00737 {
00738 protected:
00739 
00740   mxArray_matlab (mxClassID id_arg = mxUNKNOWN_CLASS)
00741     : mxArray_base (), class_name (0), id (id_arg), ndims (0), dims (0) { }
00742 
00743   mxArray_matlab (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg)
00744     : mxArray_base (), class_name (0), id (id_arg),
00745       ndims (ndims_arg < 2 ? 2 : ndims_arg),
00746       dims (static_cast<mwSize *> (malloc (ndims * sizeof (mwSize))))
00747   {
00748     if (ndims_arg < 2)
00749       {
00750         dims[0] = 1;
00751         dims[1] = 1;
00752       }
00753 
00754     for (mwIndex i = 0; i < ndims_arg; i++)
00755       dims[i] = dims_arg[i];
00756 
00757     for (mwIndex i = ndims - 1; i > 1; i--)
00758       {
00759         if (dims[i] == 1)
00760           ndims--;
00761         else
00762           break;
00763       }
00764   }
00765 
00766   mxArray_matlab (mxClassID id_arg, const dim_vector& dv)
00767     : mxArray_base (), class_name (0), id (id_arg),
00768       ndims (dv.length ()),
00769       dims (static_cast<mwSize *> (malloc (ndims * sizeof (mwSize))))
00770   {
00771     for (mwIndex i = 0; i < ndims; i++)
00772       dims[i] = dv(i);
00773 
00774     for (mwIndex i = ndims - 1; i > 1; i--)
00775       {
00776         if (dims[i] == 1)
00777           ndims--;
00778         else
00779           break;
00780       }
00781   }
00782 
00783   mxArray_matlab (mxClassID id_arg, mwSize m, mwSize n)
00784     : mxArray_base (), class_name (0), id (id_arg), ndims (2),
00785       dims (static_cast<mwSize *> (malloc (ndims * sizeof (mwSize))))
00786   {
00787     dims[0] = m;
00788     dims[1] = n;
00789   }
00790 
00791 public:
00792 
00793   ~mxArray_matlab (void)
00794   {
00795     mxFree (class_name);
00796     mxFree (dims);
00797   }
00798 
00799   int is_cell (void) const { return id == mxCELL_CLASS; }
00800 
00801   int is_char (void) const { return id == mxCHAR_CLASS; }
00802 
00803   int is_complex (void) const { return 0; }
00804 
00805   int is_double (void) const { return id == mxDOUBLE_CLASS; }
00806 
00807   int is_function_handle (void) const { return id == mxFUNCTION_CLASS; }
00808 
00809   int is_int16 (void) const { return id == mxINT16_CLASS; }
00810 
00811   int is_int32 (void) const { return id == mxINT32_CLASS; }
00812 
00813   int is_int64 (void) const { return id == mxINT64_CLASS; }
00814 
00815   int is_int8 (void) const { return id == mxINT8_CLASS; }
00816 
00817   int is_logical (void) const { return id == mxLOGICAL_CLASS; }
00818 
00819   int is_numeric (void) const
00820   {
00821     return (id == mxDOUBLE_CLASS || id == mxSINGLE_CLASS
00822             || id == mxINT8_CLASS || id == mxUINT8_CLASS
00823             || id == mxINT16_CLASS || id == mxUINT16_CLASS
00824             || id == mxINT32_CLASS || id == mxUINT32_CLASS
00825             || id == mxINT64_CLASS || id == mxUINT64_CLASS);
00826   }
00827 
00828   int is_single (void) const { return id == mxSINGLE_CLASS; }
00829 
00830   int is_sparse (void) const { return 0; }
00831 
00832   int is_struct (void) const { return id == mxSTRUCT_CLASS; }
00833 
00834   int is_uint16 (void) const { return id == mxUINT16_CLASS; }
00835 
00836   int is_uint32 (void) const { return id == mxUINT32_CLASS; }
00837 
00838   int is_uint64 (void) const { return id == mxUINT64_CLASS; }
00839 
00840   int is_uint8 (void) const { return id == mxUINT8_CLASS; }
00841 
00842   int is_logical_scalar_true (void) const
00843   {
00844     return (is_logical_scalar ()
00845             && static_cast<mxLogical *> (get_data ())[0] != 0);
00846   }
00847 
00848   mwSize get_m (void) const { return dims[0]; }
00849 
00850   mwSize get_n (void) const
00851   {
00852     mwSize n = 1;
00853 
00854     for (mwSize i = ndims - 1 ; i > 0 ; i--)
00855       n *= dims[i];
00856 
00857     return n;
00858   }
00859 
00860   mwSize *get_dimensions (void) const { return dims; }
00861 
00862   mwSize get_number_of_dimensions (void) const { return ndims; }
00863 
00864   void set_m (mwSize m) { dims[0] = m; }
00865 
00866   void set_n (mwSize n) { dims[1] = n; }
00867 
00868   void set_dimensions (mwSize *dims_arg, mwSize ndims_arg)
00869   {
00870     dims = dims_arg;
00871     ndims = ndims_arg;
00872   }
00873 
00874   mwSize get_number_of_elements (void) const
00875   {
00876     mwSize retval = dims[0];
00877 
00878     for (mwIndex i = 1; i < ndims; i++)
00879       retval *= dims[i];
00880 
00881     return retval;
00882   }
00883 
00884   int is_empty (void) const { return get_number_of_elements () == 0; }
00885 
00886   mxClassID get_class_id (void) const { return id; }
00887 
00888   const char *get_class_name (void) const
00889   {
00890     switch (id)
00891       {
00892       case mxCELL_CLASS: return "cell";
00893       case mxSTRUCT_CLASS: return "struct";
00894       case mxLOGICAL_CLASS: return "logical";
00895       case mxCHAR_CLASS: return "char";
00896       case mxDOUBLE_CLASS: return "double";
00897       case mxSINGLE_CLASS: return "single";
00898       case mxINT8_CLASS: return "int8";
00899       case mxUINT8_CLASS: return "uint8";
00900       case mxINT16_CLASS: return "int16";
00901       case mxUINT16_CLASS: return "uint16";
00902       case mxINT32_CLASS: return "int32";
00903       case mxUINT32_CLASS: return "uint32";
00904       case mxINT64_CLASS: return "int64";
00905       case mxUINT64_CLASS: return "uint64";
00906       case mxFUNCTION_CLASS: return "function_handle";
00907       default: return "unknown";
00908       }
00909   }
00910 
00911   void set_class_name (const char *name_arg)
00912   {
00913     mxFree (class_name);
00914     class_name = static_cast<char *> (malloc (strlen (name_arg) + 1));
00915     strcpy (class_name, name_arg);
00916   }
00917 
00918   mxArray *get_cell (mwIndex /*idx*/) const
00919   {
00920     invalid_type_error ();
00921     return 0;
00922   }
00923 
00924   void set_cell (mwIndex /*idx*/, mxArray */*val*/)
00925   {
00926     invalid_type_error ();
00927   }
00928 
00929   double get_scalar (void) const
00930   {
00931     invalid_type_error ();
00932     return 0;
00933   }
00934 
00935   void *get_data (void) const
00936   {
00937     invalid_type_error ();
00938     return 0;
00939   }
00940 
00941   void *get_imag_data (void) const
00942   {
00943     invalid_type_error ();
00944     return 0;
00945   }
00946 
00947   void set_data (void */*pr*/)
00948   {
00949     invalid_type_error ();
00950   }
00951 
00952   void set_imag_data (void */*pi*/)
00953   {
00954     invalid_type_error ();
00955   }
00956 
00957   mwIndex *get_ir (void) const
00958   {
00959     invalid_type_error ();
00960     return 0;
00961   }
00962 
00963   mwIndex *get_jc (void) const
00964   {
00965     invalid_type_error ();
00966     return 0;
00967   }
00968 
00969   mwSize get_nzmax (void) const
00970   {
00971     invalid_type_error ();
00972     return 0;
00973   }
00974 
00975   void set_ir (mwIndex */*ir*/)
00976   {
00977     invalid_type_error ();
00978   }
00979 
00980   void set_jc (mwIndex */*jc*/)
00981   {
00982     invalid_type_error ();
00983   }
00984 
00985   void set_nzmax (mwSize /*nzmax*/)
00986   {
00987     invalid_type_error ();
00988   }
00989 
00990   int add_field (const char */*key*/)
00991   {
00992     invalid_type_error ();
00993     return -1;
00994   }
00995 
00996   void remove_field (int /*key_num*/)
00997   {
00998     invalid_type_error ();
00999   }
01000 
01001   mxArray *get_field_by_number (mwIndex /*index*/, int /*key_num*/) const
01002   {
01003     invalid_type_error ();
01004     return 0;
01005   }
01006 
01007   void set_field_by_number (mwIndex /*index*/, int /*key_num*/, mxArray */*val*/)
01008   {
01009     invalid_type_error ();
01010   }
01011 
01012   int get_number_of_fields (void) const
01013   {
01014     invalid_type_error ();
01015     return 0;
01016   }
01017 
01018   const char *get_field_name_by_number (int /*key_num*/) const
01019   {
01020     invalid_type_error ();
01021     return 0;
01022   }
01023 
01024   int get_field_number (const char */*key*/) const
01025   {
01026     return -1;
01027   }
01028 
01029   int get_string (char */*buf*/, mwSize /*buflen*/) const
01030   {
01031     invalid_type_error ();
01032     return 0;
01033   }
01034 
01035   char *array_to_string (void) const
01036   {
01037     invalid_type_error ();
01038     return 0;
01039   }
01040 
01041   mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const
01042   {
01043     return calc_single_subscript_internal (ndims, dims, nsubs, subs);
01044   }
01045 
01046   size_t get_element_size (void) const
01047   {
01048     switch (id)
01049       {
01050       case mxCELL_CLASS: return sizeof (mxArray *);
01051       case mxSTRUCT_CLASS: return sizeof (mxArray *);
01052       case mxLOGICAL_CLASS: return sizeof (mxLogical);
01053       case mxCHAR_CLASS: return sizeof (mxChar);
01054       case mxDOUBLE_CLASS: return sizeof (double);
01055       case mxSINGLE_CLASS: return sizeof (float);
01056       case mxINT8_CLASS: return 1;
01057       case mxUINT8_CLASS: return 1;
01058       case mxINT16_CLASS: return 2;
01059       case mxUINT16_CLASS: return 2;
01060       case mxINT32_CLASS: return 4;
01061       case mxUINT32_CLASS: return 4;
01062       case mxINT64_CLASS: return 8;
01063       case mxUINT64_CLASS: return 8;
01064       case mxFUNCTION_CLASS: return 0;
01065       default: return 0;
01066       }
01067   }
01068 
01069 protected:
01070 
01071   mxArray_matlab (const mxArray_matlab& val)
01072     : mxArray_base (val), class_name (strsave (val.class_name)),
01073       id (val.id), ndims (val.ndims),
01074       dims (static_cast<mwSize *> (malloc (ndims * sizeof (mwSize))))
01075   {
01076     for (mwIndex i = 0; i < ndims; i++)
01077       dims[i] = val.dims[i];
01078   }
01079 
01080   dim_vector
01081   dims_to_dim_vector (void) const
01082   {
01083     mwSize nd = get_number_of_dimensions ();
01084 
01085     mwSize *d = get_dimensions ();
01086 
01087     dim_vector dv;
01088     dv.resize (nd);
01089 
01090     for (mwIndex i = 0; i < nd; i++)
01091       dv(i) = d[i];
01092 
01093     return dv;
01094   }
01095 
01096 private:
01097 
01098   char *class_name;
01099 
01100   mxClassID id;
01101 
01102   mwSize ndims;
01103   mwSize *dims;
01104 
01105   void invalid_type_error (void) const
01106   {
01107     error ("invalid type for operation");
01108   }
01109 
01110   // No assignment!  FIXME -- should this be implemented?  Note that we
01111   // do have a copy constructor.
01112 
01113   mxArray_matlab& operator = (const mxArray_matlab&);
01114 };
01115 
01116 // Matlab-style numeric, character, and logical data.
01117 
01118 class mxArray_number : public mxArray_matlab
01119 {
01120 public:
01121 
01122   mxArray_number (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg,
01123                   mxComplexity flag = mxREAL)
01124     : mxArray_matlab (id_arg, ndims_arg, dims_arg),
01125       pr (calloc (get_number_of_elements (), get_element_size ())),
01126       pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { }
01127 
01128   mxArray_number (mxClassID id_arg, const dim_vector& dv,
01129                   mxComplexity flag = mxREAL)
01130     : mxArray_matlab (id_arg, dv),
01131       pr (calloc (get_number_of_elements (), get_element_size ())),
01132       pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { }
01133 
01134   mxArray_number (mxClassID id_arg, mwSize m, mwSize n, mxComplexity flag = mxREAL)
01135     : mxArray_matlab (id_arg, m, n),
01136       pr (calloc (get_number_of_elements (), get_element_size ())),
01137       pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { }
01138 
01139   mxArray_number (mxClassID id_arg, double val)
01140     : mxArray_matlab (id_arg, 1, 1),
01141       pr (calloc (get_number_of_elements (), get_element_size ())),
01142       pi (0)
01143   {
01144     double *dpr = static_cast<double *> (pr);
01145     dpr[0] = val;
01146   }
01147 
01148   mxArray_number (mxClassID id_arg, mxLogical val)
01149     : mxArray_matlab (id_arg, 1, 1),
01150       pr (calloc (get_number_of_elements (), get_element_size ())),
01151       pi (0)
01152   {
01153     mxLogical *lpr = static_cast<mxLogical *> (pr);
01154     lpr[0] = val;
01155   }
01156 
01157   mxArray_number (const char *str)
01158     : mxArray_matlab (mxCHAR_CLASS,
01159                       str ? (strlen (str) ? 1 : 0) : 0,
01160                       str ? strlen (str) : 0),
01161       pr (calloc (get_number_of_elements (), get_element_size ())),
01162       pi (0)
01163   {
01164     mxChar *cpr = static_cast<mxChar *> (pr);
01165     mwSize nel = get_number_of_elements ();
01166     for (mwIndex i = 0; i < nel; i++)
01167       cpr[i] = str[i];
01168   }
01169 
01170   // FIXME??
01171   mxArray_number (mwSize m, const char **str)
01172     : mxArray_matlab (mxCHAR_CLASS, m, max_str_len (m, str)),
01173       pr (calloc (get_number_of_elements (), get_element_size ())),
01174       pi (0)
01175   {
01176     mxChar *cpr = static_cast<mxChar *> (pr);
01177 
01178     mwSize *dv = get_dimensions ();
01179 
01180     mwSize nc = dv[1];
01181 
01182     for (mwIndex j = 0; j < m; j++)
01183       {
01184         const char *ptr = str[j];
01185 
01186         size_t tmp_len = strlen (ptr);
01187 
01188         for (size_t i = 0; i < tmp_len; i++)
01189           cpr[m*i+j] = static_cast<mxChar> (ptr[i]);
01190 
01191         for (size_t i = tmp_len; i < nc; i++)
01192           cpr[m*i+j] = static_cast<mxChar> (' ');
01193       }
01194   }
01195 
01196   mxArray_number *dup (void) const { return new mxArray_number (*this); }
01197 
01198   ~mxArray_number (void)
01199   {
01200     mxFree (pr);
01201     mxFree (pi);
01202   }
01203 
01204   int is_complex (void) const { return pi != 0; }
01205 
01206   double get_scalar (void) const
01207   {
01208     double retval = 0;
01209 
01210     switch (get_class_id ())
01211       {
01212       case mxLOGICAL_CLASS:
01213         retval = *(static_cast<bool *> (pr));
01214         break;
01215 
01216       case mxCHAR_CLASS:
01217         retval = *(static_cast<mxChar *> (pr));
01218         break;
01219 
01220       case mxSINGLE_CLASS:
01221         retval = *(static_cast<float *> (pr));
01222         break;
01223 
01224       case mxDOUBLE_CLASS:
01225         retval = *(static_cast<double *> (pr));
01226         break;
01227 
01228       case mxINT8_CLASS:
01229         retval = *(static_cast<int8_t *> (pr));
01230         break;
01231 
01232       case mxUINT8_CLASS:
01233         retval = *(static_cast<uint8_t *> (pr));
01234         break;
01235 
01236       case mxINT16_CLASS:
01237         retval = *(static_cast<int16_t *> (pr));
01238         break;
01239 
01240       case mxUINT16_CLASS:
01241         retval = *(static_cast<uint16_t *> (pr));
01242         break;
01243 
01244       case mxINT32_CLASS:
01245         retval = *(static_cast<int32_t *> (pr));
01246         break;
01247 
01248       case mxUINT32_CLASS:
01249         retval = *(static_cast<uint32_t *> (pr));
01250         break;
01251 
01252       case mxINT64_CLASS:
01253         retval = *(static_cast<int64_t *> (pr));
01254         break;
01255 
01256       case mxUINT64_CLASS:
01257         retval = *(static_cast<uint64_t *> (pr));
01258         break;
01259 
01260       default:
01261         panic_impossible ();
01262       }
01263 
01264     return retval;
01265   }
01266 
01267   void *get_data (void) const { return pr; }
01268 
01269   void *get_imag_data (void) const { return pi; }
01270 
01271   void set_data (void *pr_arg) { pr = pr_arg; }
01272 
01273   void set_imag_data (void *pi_arg) { pi = pi_arg; }
01274 
01275   int get_string (char *buf, mwSize buflen) const
01276   {
01277     int retval = 0;
01278 
01279     mwSize nel = get_number_of_elements ();
01280 
01281     if (! (nel < buflen))
01282       {
01283         retval = 1;
01284         if (buflen > 0)
01285           nel = buflen-1;
01286       }
01287 
01288     if (nel < buflen)
01289       {
01290         mxChar *ptr = static_cast<mxChar *> (pr);
01291 
01292         for (mwIndex i = 0; i < nel; i++)
01293           buf[i] = static_cast<char> (ptr[i]);
01294 
01295         buf[nel] = 0;
01296       }
01297 
01298     return retval;
01299   }
01300 
01301   char *array_to_string (void) const
01302   {
01303     // FIXME -- this is suposed to handle multi-byte character
01304     // strings.
01305 
01306     mwSize nel = get_number_of_elements ();
01307 
01308     char *buf = static_cast<char *> (malloc (nel + 1));
01309 
01310     if (buf)
01311       {
01312         mxChar *ptr = static_cast<mxChar *> (pr);
01313 
01314         for (mwIndex i = 0; i < nel; i++)
01315           buf[i] = static_cast<char> (ptr[i]);
01316 
01317         buf[nel] = '\0';
01318       }
01319 
01320     return buf;
01321   }
01322 
01323 protected:
01324 
01325   template <typename ELT_T, typename ARRAY_T, typename ARRAY_ELT_T>
01326   octave_value
01327   int_to_ov (const dim_vector& dv) const
01328   {
01329     octave_value retval;
01330 
01331     mwSize nel = get_number_of_elements ();
01332 
01333     ELT_T *ppr = static_cast<ELT_T *> (pr);
01334 
01335     if (pi)
01336       error ("complex integer types are not supported");
01337     else
01338       {
01339         ARRAY_T val (dv);
01340 
01341         ARRAY_ELT_T *ptr = val.fortran_vec ();
01342 
01343         for (mwIndex i = 0; i < nel; i++)
01344           ptr[i] = ppr[i];
01345 
01346         retval = val;
01347       }
01348 
01349     return retval;
01350   }
01351 
01352   octave_value as_octave_value (void) const
01353   {
01354     octave_value retval;
01355 
01356     dim_vector dv = dims_to_dim_vector ();
01357 
01358     switch (get_class_id ())
01359       {
01360       case mxLOGICAL_CLASS:
01361         retval = int_to_ov<bool, boolNDArray, bool> (dv);
01362         break;
01363 
01364       case mxCHAR_CLASS:
01365         {
01366           mwSize nel = get_number_of_elements ();
01367 
01368           mxChar *ppr = static_cast<mxChar *> (pr);
01369 
01370           charNDArray val (dv);
01371 
01372           char *ptr = val.fortran_vec ();
01373 
01374           for (mwIndex i = 0; i < nel; i++)
01375             ptr[i] = static_cast<char> (ppr[i]);
01376 
01377           retval = val;
01378         }
01379         break;
01380 
01381       case mxSINGLE_CLASS:
01382         {
01383           mwSize nel = get_number_of_elements ();
01384 
01385           float *ppr = static_cast<float *> (pr);
01386 
01387           if (pi)
01388             {
01389               FloatComplexNDArray val (dv);
01390 
01391               FloatComplex *ptr = val.fortran_vec ();
01392 
01393               float *ppi = static_cast<float *> (pi);
01394 
01395               for (mwIndex i = 0; i < nel; i++)
01396                 ptr[i] = FloatComplex (ppr[i], ppi[i]);
01397 
01398               retval = val;
01399             }
01400           else
01401             {
01402               FloatNDArray val (dv);
01403 
01404               float *ptr = val.fortran_vec ();
01405 
01406               for (mwIndex i = 0; i < nel; i++)
01407                 ptr[i] = ppr[i];
01408 
01409               retval = val;
01410             }
01411         }
01412         break;
01413 
01414       case mxDOUBLE_CLASS:
01415         {
01416           mwSize nel = get_number_of_elements ();
01417 
01418           double *ppr = static_cast<double *> (pr);
01419 
01420           if (pi)
01421             {
01422               ComplexNDArray val (dv);
01423 
01424               Complex *ptr = val.fortran_vec ();
01425 
01426               double *ppi = static_cast<double *> (pi);
01427 
01428               for (mwIndex i = 0; i < nel; i++)
01429                 ptr[i] = Complex (ppr[i], ppi[i]);
01430 
01431               retval = val;
01432             }
01433           else
01434             {
01435               NDArray val (dv);
01436 
01437               double *ptr = val.fortran_vec ();
01438 
01439               for (mwIndex i = 0; i < nel; i++)
01440                 ptr[i] = ppr[i];
01441 
01442               retval = val;
01443             }
01444         }
01445         break;
01446 
01447       case mxINT8_CLASS:
01448         retval = int_to_ov<int8_t, int8NDArray, octave_int8> (dv);
01449         break;
01450 
01451       case mxUINT8_CLASS:
01452         retval = int_to_ov<uint8_t, uint8NDArray, octave_uint8> (dv);
01453         break;
01454 
01455       case mxINT16_CLASS:
01456         retval = int_to_ov<int16_t, int16NDArray, octave_int16> (dv);
01457         break;
01458 
01459       case mxUINT16_CLASS:
01460         retval = int_to_ov<uint16_t, uint16NDArray, octave_uint16> (dv);
01461         break;
01462 
01463       case mxINT32_CLASS:
01464         retval = int_to_ov<int32_t, int32NDArray, octave_int32> (dv);
01465         break;
01466 
01467       case mxUINT32_CLASS:
01468         retval = int_to_ov<uint32_t, uint32NDArray, octave_uint32> (dv);
01469         break;
01470 
01471       case mxINT64_CLASS:
01472         retval = int_to_ov<int64_t, int64NDArray, octave_int64> (dv);
01473         break;
01474 
01475       case mxUINT64_CLASS:
01476         retval = int_to_ov<uint64_t, uint64NDArray, octave_uint64> (dv);
01477         break;
01478 
01479       default:
01480         panic_impossible ();
01481       }
01482 
01483     return retval;
01484   }
01485 
01486   mxArray_number (const mxArray_number& val)
01487     : mxArray_matlab (val),
01488       pr (malloc (get_number_of_elements () * get_element_size ())),
01489       pi (val.pi ? malloc (get_number_of_elements () * get_element_size ()) : 0)
01490   {
01491     size_t nbytes = get_number_of_elements () * get_element_size ();
01492 
01493     if (pr)
01494       memcpy (pr, val.pr, nbytes);
01495 
01496     if (pi)
01497       memcpy (pi, val.pi, nbytes);
01498   }
01499 
01500 private:
01501 
01502   void *pr;
01503   void *pi;
01504 
01505   // No assignment!  FIXME -- should this be implemented?  Note that we
01506   // do have a copy constructor.
01507 
01508   mxArray_number& operator = (const mxArray_number&);
01509 };
01510 
01511 // Matlab-style sparse arrays.
01512 
01513 class mxArray_sparse : public mxArray_matlab
01514 {
01515 public:
01516 
01517   mxArray_sparse (mxClassID id_arg, mwSize m, mwSize n, mwSize nzmax_arg,
01518                   mxComplexity flag = mxREAL)
01519     : mxArray_matlab (id_arg, m, n), nzmax (nzmax_arg),
01520       pr (calloc (nzmax, get_element_size ())),
01521       pi (flag == mxCOMPLEX ? calloc (nzmax, get_element_size ()) : 0),
01522       ir (static_cast<mwIndex *> (calloc (nzmax, sizeof (mwIndex)))),
01523       jc (static_cast<mwIndex *> (calloc (n + 1, sizeof (mwIndex))))
01524     { }
01525 
01526   mxArray_sparse *dup (void) const { return new mxArray_sparse (*this); }
01527 
01528   ~mxArray_sparse (void)
01529   {
01530     mxFree (pr);
01531     mxFree (pi);
01532     mxFree (ir);
01533     mxFree (jc);
01534   }
01535 
01536   int is_complex (void) const { return pi != 0; }
01537 
01538   int is_sparse (void) const { return 1; }
01539 
01540   void *get_data (void) const { return pr; }
01541 
01542   void *get_imag_data (void) const { return pi; }
01543 
01544   void set_data (void *pr_arg) { pr = pr_arg; }
01545 
01546   void set_imag_data (void *pi_arg) { pi = pi_arg; }
01547 
01548   mwIndex *get_ir (void) const { return ir; }
01549 
01550   mwIndex *get_jc (void) const { return jc; }
01551 
01552   mwSize get_nzmax (void) const { return nzmax; }
01553 
01554   void set_ir (mwIndex *ir_arg) { ir = ir_arg; }
01555 
01556   void set_jc (mwIndex *jc_arg) { jc = jc_arg; }
01557 
01558   void set_nzmax (mwSize nzmax_arg) { nzmax = nzmax_arg; }
01559 
01560 protected:
01561 
01562   octave_value as_octave_value (void) const
01563   {
01564     octave_value retval;
01565 
01566     dim_vector dv = dims_to_dim_vector ();
01567 
01568     switch (get_class_id ())
01569       {
01570       case mxLOGICAL_CLASS:
01571         {
01572           bool *ppr = static_cast<bool *> (pr);
01573 
01574           SparseBoolMatrix val (get_m (), get_n (),
01575                                 static_cast<octave_idx_type> (nzmax));
01576 
01577           for (mwIndex i = 0; i < nzmax; i++)
01578             {
01579               val.xdata(i) = ppr[i];
01580               val.xridx(i) = ir[i];
01581             }
01582 
01583           for (mwIndex i = 0; i < get_n () + 1; i++)
01584             val.xcidx(i) = jc[i];
01585 
01586           retval = val;
01587         }
01588         break;
01589 
01590       case mxSINGLE_CLASS:
01591         error ("single precision sparse data type not supported");
01592         break;
01593 
01594       case mxDOUBLE_CLASS:
01595         {
01596           if (pi)
01597             {
01598               double *ppr = static_cast<double *> (pr);
01599               double *ppi = static_cast<double *> (pi);
01600 
01601               SparseComplexMatrix val (get_m (), get_n (),
01602                                        static_cast<octave_idx_type> (nzmax));
01603 
01604               for (mwIndex i = 0; i < nzmax; i++)
01605                 {
01606                   val.xdata(i) = Complex (ppr[i], ppi[i]);
01607                   val.xridx(i) = ir[i];
01608                 }
01609 
01610               for (mwIndex i = 0; i < get_n () + 1; i++)
01611                 val.xcidx(i) = jc[i];
01612 
01613               retval = val;
01614             }
01615           else
01616             {
01617               double *ppr = static_cast<double *> (pr);
01618 
01619               SparseMatrix val (get_m (), get_n (),
01620                                 static_cast<octave_idx_type> (nzmax));
01621 
01622               for (mwIndex i = 0; i < nzmax; i++)
01623                 {
01624                   val.xdata(i) = ppr[i];
01625                   val.xridx(i) = ir[i];
01626                 }
01627 
01628               for (mwIndex i = 0; i < get_n () + 1; i++)
01629                 val.xcidx(i) = jc[i];
01630 
01631               retval = val;
01632             }
01633         }
01634         break;
01635 
01636       default:
01637         panic_impossible ();
01638       }
01639 
01640     return retval;
01641   }
01642 
01643 private:
01644 
01645   mwSize nzmax;
01646 
01647   void *pr;
01648   void *pi;
01649   mwIndex *ir;
01650   mwIndex *jc;
01651 
01652   mxArray_sparse (const mxArray_sparse& val)
01653     : mxArray_matlab (val), nzmax (val.nzmax),
01654       pr (malloc (nzmax * get_element_size ())),
01655       pi (val.pi ? malloc (nzmax * get_element_size ()) : 0),
01656       ir (static_cast<mwIndex *> (malloc (nzmax * sizeof (mwIndex)))),
01657       jc (static_cast<mwIndex *> (malloc (nzmax * sizeof (mwIndex))))
01658   {
01659     size_t nbytes = nzmax * get_element_size ();
01660 
01661     if (pr)
01662       memcpy (pr, val.pr, nbytes);
01663 
01664     if (pi)
01665       memcpy (pi, val.pi, nbytes);
01666 
01667     if (ir)
01668       memcpy (ir, val.ir, nzmax * sizeof (mwIndex));
01669 
01670     if (jc)
01671       memcpy (jc, val.jc, (val.get_n () + 1) * sizeof (mwIndex));
01672   }
01673 
01674   // No assignment!  FIXME -- should this be implemented?  Note that we
01675   // do have a copy constructor.
01676 
01677   mxArray_sparse& operator = (const mxArray_sparse&);
01678 };
01679 
01680 // Matlab-style struct arrays.
01681 
01682 class mxArray_struct : public mxArray_matlab
01683 {
01684 public:
01685 
01686   mxArray_struct (mwSize ndims_arg, const mwSize *dims_arg, int num_keys_arg,
01687                   const char **keys)
01688     : mxArray_matlab (mxSTRUCT_CLASS, ndims_arg, dims_arg), nfields (num_keys_arg),
01689       fields (static_cast<char **> (calloc (nfields, sizeof (char *)))),
01690       data (static_cast<mxArray **> (calloc (nfields * get_number_of_elements (), sizeof (mxArray *))))
01691   {
01692     init (keys);
01693   }
01694 
01695   mxArray_struct (const dim_vector& dv, int num_keys_arg, const char **keys)
01696     : mxArray_matlab (mxSTRUCT_CLASS, dv), nfields (num_keys_arg),
01697       fields (static_cast<char **> (calloc (nfields, sizeof (char *)))),
01698       data (static_cast<mxArray **> (calloc (nfields * get_number_of_elements (), sizeof (mxArray *))))
01699   {
01700     init (keys);
01701   }
01702 
01703   mxArray_struct (mwSize m, mwSize n, int num_keys_arg, const char **keys)
01704     : mxArray_matlab (mxSTRUCT_CLASS, m, n), nfields (num_keys_arg),
01705       fields (static_cast<char **> (calloc (nfields, sizeof (char *)))),
01706       data (static_cast<mxArray **> (calloc (nfields * get_number_of_elements (), sizeof (mxArray *))))
01707   {
01708     init (keys);
01709   }
01710 
01711   void init (const char **keys)
01712   {
01713     for (int i = 0; i < nfields; i++)
01714       fields[i] = strsave (keys[i]);
01715   }
01716 
01717   mxArray_struct *dup (void) const { return new mxArray_struct (*this); }
01718 
01719   ~mxArray_struct (void)
01720   {
01721     for (int i = 0; i < nfields; i++)
01722       mxFree (fields[i]);
01723 
01724     mxFree (fields);
01725 
01726     mwSize ntot = nfields * get_number_of_elements ();
01727 
01728     for  (mwIndex i = 0; i < ntot; i++)
01729       delete data[i];
01730 
01731     mxFree (data);
01732   }
01733 
01734   int add_field (const char *key)
01735   {
01736     int retval = -1;
01737 
01738     if (valid_key (key))
01739       {
01740         nfields++;
01741 
01742         fields = static_cast<char **> (mxRealloc (fields, nfields * sizeof (char *)));
01743 
01744         if (fields)
01745           {
01746             fields[nfields-1] = strsave (key);
01747 
01748             mwSize nel = get_number_of_elements ();
01749 
01750             mwSize ntot = nfields * nel;
01751 
01752             mxArray **new_data = static_cast<mxArray **> (malloc (ntot * sizeof (mxArray *)));
01753 
01754             if (new_data)
01755               {
01756                 mwIndex j = 0;
01757                 mwIndex k = 0;
01758                 mwIndex n = 0;
01759 
01760                 for (mwIndex i = 0; i < ntot; i++)
01761                   {
01762                     if (++n == nfields)
01763                       {
01764                         new_data[j++] = 0;
01765                         n = 0;
01766                       }
01767                     else
01768                       new_data[j++] = data[k++];
01769                   }
01770 
01771                 mxFree (data);
01772 
01773                 data = new_data;
01774 
01775                 retval = nfields - 1;
01776               }
01777           }
01778       }
01779 
01780     return retval;
01781   }
01782 
01783   void remove_field (int key_num)
01784   {
01785     if (key_num >= 0 && key_num < nfields)
01786       {
01787         mwSize nel = get_number_of_elements ();
01788 
01789         mwSize ntot = nfields * nel;
01790 
01791         int new_nfields = nfields - 1;
01792 
01793         char **new_fields = static_cast<char **> (malloc (new_nfields * sizeof (char *)));
01794 
01795         mxArray **new_data = static_cast<mxArray **> (malloc (new_nfields * nel * sizeof (mxArray *)));
01796 
01797         for (int i = 0; i < key_num; i++)
01798           new_fields[i] = fields[i];
01799 
01800         for (int i = key_num + 1; i < nfields; i++)
01801           new_fields[i-1] = fields[i];
01802 
01803         if (new_nfields > 0)
01804           {
01805             mwIndex j = 0;
01806             mwIndex k = 0;
01807             mwIndex n = 0;
01808 
01809             for (mwIndex i = 0; i < ntot; i++)
01810               {
01811                 if (n == key_num)
01812                   k++;
01813                 else
01814                   new_data[j++] = data[k++];
01815 
01816                 if (++n == nfields)
01817                   n = 0;
01818               }
01819           }
01820 
01821         nfields = new_nfields;
01822 
01823         mxFree (fields);
01824         mxFree (data);
01825 
01826         fields = new_fields;
01827         data = new_data;
01828       }
01829   }
01830 
01831   mxArray *get_field_by_number (mwIndex index, int key_num) const
01832   {
01833     return key_num >= 0 && key_num < nfields
01834       ? data[nfields * index + key_num] : 0;
01835   }
01836 
01837   void set_field_by_number (mwIndex index, int key_num, mxArray *val);
01838 
01839   int get_number_of_fields (void) const { return nfields; }
01840 
01841   const char *get_field_name_by_number (int key_num) const
01842   {
01843     return key_num >= 0 && key_num < nfields ? fields[key_num] : 0;
01844   }
01845 
01846   int get_field_number (const char *key) const
01847   {
01848     int retval = -1;
01849 
01850     for (int i = 0; i < nfields; i++)
01851       {
01852         if (! strcmp (key, fields[i]))
01853           {
01854             retval = i;
01855             break;
01856           }
01857       }
01858 
01859     return retval;
01860   }
01861 
01862   void *get_data (void) const { return data; }
01863 
01864   void set_data (void *data_arg) { data = static_cast<mxArray **> (data_arg); }
01865 
01866 protected:
01867 
01868   octave_value as_octave_value (void) const
01869   {
01870     dim_vector dv = dims_to_dim_vector ();
01871 
01872     string_vector keys (fields, nfields);
01873 
01874     octave_map m;
01875 
01876     mwSize ntot = nfields * get_number_of_elements ();
01877 
01878     for (int i = 0; i < nfields; i++)
01879       {
01880         Cell c (dv);
01881 
01882         octave_value *p = c.fortran_vec ();
01883 
01884         mwIndex k = 0;
01885         for (mwIndex j = i; j < ntot; j += nfields)
01886           p[k++] = mxArray::as_octave_value (data[j]);
01887 
01888         m.assign (keys[i], c);
01889       }
01890 
01891     return m;
01892   }
01893 
01894 private:
01895 
01896   int nfields;
01897 
01898   char **fields;
01899 
01900   mxArray **data;
01901 
01902   mxArray_struct (const mxArray_struct& val)
01903     : mxArray_matlab (val), nfields (val.nfields),
01904       fields (static_cast<char **> (malloc (nfields * sizeof (char *)))),
01905       data (static_cast<mxArray **> (malloc (nfields * get_number_of_elements () * sizeof (mxArray *))))
01906   {
01907     for (int i = 0; i < nfields; i++)
01908       fields[i] = strsave (val.fields[i]);
01909 
01910     mwSize nel = get_number_of_elements ();
01911 
01912     for (mwIndex i = 0; i < nel * nfields; i++)
01913       {
01914         mxArray *ptr = val.data[i];
01915         data[i] = ptr ? ptr->dup () : 0;
01916       }
01917   }
01918 
01919   // No assignment!  FIXME -- should this be implemented?  Note that we
01920   // do have a copy constructor.
01921 
01922   mxArray_struct& operator = (const mxArray_struct& val);
01923 };
01924 
01925 // Matlab-style cell arrays.
01926 
01927 class mxArray_cell : public mxArray_matlab
01928 {
01929 public:
01930 
01931   mxArray_cell (mwSize ndims_arg, const mwSize *dims_arg)
01932     : mxArray_matlab (mxCELL_CLASS, ndims_arg, dims_arg),
01933       data (static_cast<mxArray **> (calloc (get_number_of_elements (), sizeof (mxArray *)))) { }
01934 
01935   mxArray_cell (const dim_vector& dv)
01936     : mxArray_matlab (mxCELL_CLASS, dv),
01937       data (static_cast<mxArray **> (calloc (get_number_of_elements (), sizeof (mxArray *)))) { }
01938 
01939   mxArray_cell (mwSize m, mwSize n)
01940     : mxArray_matlab (mxCELL_CLASS, m, n),
01941       data (static_cast<mxArray **> (calloc (get_number_of_elements (), sizeof (mxArray *)))) { }
01942 
01943   mxArray_cell *dup (void) const { return new mxArray_cell (*this); }
01944 
01945   ~mxArray_cell (void)
01946   {
01947     mwSize nel = get_number_of_elements ();
01948 
01949     for  (mwIndex i = 0; i < nel; i++)
01950       delete data[i];
01951 
01952     mxFree (data);
01953   }
01954 
01955   mxArray *get_cell (mwIndex idx) const
01956   {
01957     return idx >= 0 && idx < get_number_of_elements () ? data[idx] : 0;
01958   }
01959 
01960   void set_cell (mwIndex idx, mxArray *val);
01961 
01962   void *get_data (void) const { return data; }
01963 
01964   void set_data (void *data_arg) { data = static_cast<mxArray **> (data_arg); }
01965 
01966 protected:
01967 
01968   octave_value as_octave_value (void) const
01969   {
01970     dim_vector dv = dims_to_dim_vector ();
01971 
01972     Cell c (dv);
01973 
01974     mwSize nel = get_number_of_elements ();
01975 
01976     octave_value *p = c.fortran_vec ();
01977 
01978     for (mwIndex i = 0; i < nel; i++)
01979       p[i] = mxArray::as_octave_value (data[i]);
01980 
01981     return c;
01982   }
01983 
01984 private:
01985 
01986   mxArray **data;
01987 
01988   mxArray_cell (const mxArray_cell& val)
01989     : mxArray_matlab (val),
01990       data (static_cast<mxArray **> (malloc (get_number_of_elements () * sizeof (mxArray *))))
01991   {
01992     mwSize nel = get_number_of_elements ();
01993 
01994     for (mwIndex i = 0; i < nel; i++)
01995       {
01996         mxArray *ptr = val.data[i];
01997         data[i] = ptr ? ptr->dup () : 0;
01998       }
01999   }
02000 
02001   // No assignment!  FIXME -- should this be implemented?  Note that we
02002   // do have a copy constructor.
02003 
02004   mxArray_cell& operator = (const mxArray_cell&);
02005 };
02006 
02007 // ------------------------------------------------------------------
02008 
02009 mxArray::mxArray (const octave_value& ov)
02010   : rep (new mxArray_octave_value (ov)), name (0) { }
02011 
02012 mxArray::mxArray (mxClassID id, mwSize ndims, const mwSize *dims, mxComplexity flag)
02013   : rep (new mxArray_number (id, ndims, dims, flag)), name (0) { }
02014 
02015 mxArray::mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag)
02016   : rep (new mxArray_number (id, dv, flag)), name (0) { }
02017 
02018 mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mxComplexity flag)
02019   : rep (new mxArray_number (id, m, n, flag)), name (0) { }
02020 
02021 mxArray::mxArray (mxClassID id, double val)
02022   : rep (new mxArray_number (id, val)), name (0) { }
02023 
02024 mxArray::mxArray (mxClassID id, mxLogical val)
02025   : rep (new mxArray_number (id, val)), name (0) { }
02026 
02027 mxArray::mxArray (const char *str)
02028   : rep (new mxArray_number (str)), name (0) { }
02029 
02030 mxArray::mxArray (mwSize m, const char **str)
02031   : rep (new mxArray_number (m, str)), name (0) { }
02032 
02033 mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
02034   : rep (new mxArray_sparse (id, m, n, nzmax, flag)), name (0) { }
02035 
02036 mxArray::mxArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys)
02037   : rep (new mxArray_struct (ndims, dims, num_keys, keys)), name (0) { }
02038 
02039 mxArray::mxArray (const dim_vector& dv, int num_keys, const char **keys)
02040   : rep (new mxArray_struct (dv, num_keys, keys)), name (0) { }
02041 
02042 mxArray::mxArray (mwSize m, mwSize n, int num_keys, const char **keys)
02043   : rep (new mxArray_struct (m, n, num_keys, keys)), name (0) { }
02044 
02045 mxArray::mxArray (mwSize ndims, const mwSize *dims)
02046   : rep (new mxArray_cell (ndims, dims)), name (0) { }
02047 
02048 mxArray::mxArray (const dim_vector& dv)
02049   : rep (new mxArray_cell (dv)), name (0) { }
02050 
02051 mxArray::mxArray (mwSize m, mwSize n)
02052   : rep (new mxArray_cell (m, n)), name (0) { }
02053 
02054 mxArray::~mxArray (void)
02055 {
02056   mxFree (name);
02057 
02058   delete rep;
02059 }
02060 
02061 void
02062 mxArray::set_name (const char *name_arg)
02063 {
02064   mxFree (name);
02065   name = strsave (name_arg);
02066 }
02067 
02068 octave_value
02069 mxArray::as_octave_value (mxArray *ptr)
02070 {
02071   return ptr ? ptr->as_octave_value () : octave_value (Matrix ());
02072 }
02073 
02074 octave_value
02075 mxArray::as_octave_value (void) const
02076 {
02077   return rep->as_octave_value ();
02078 }
02079 
02080 void
02081 mxArray::maybe_mutate (void) const
02082 {
02083   if (rep->is_octave_value ())
02084     {
02085       // The mutate function returns a pointer to a complete new
02086       // mxArray object (or 0, if no mutation happened).  We just want
02087       // to replace the existing rep with the rep from the new object.
02088 
02089       mxArray *new_val = rep->mutate ();
02090 
02091       if (new_val)
02092         {
02093           delete rep;
02094           rep = new_val->rep;
02095           new_val->rep = 0;
02096           delete new_val;
02097         }
02098     }
02099 }
02100 
02101 // ------------------------------------------------------------------
02102 
02103 // A class to manage calls to MEX functions.  Mostly deals with memory
02104 // management.
02105 
02106 class mex
02107 {
02108 public:
02109 
02110   mex (octave_mex_function *f)
02111     : curr_mex_fcn (f), memlist (), arraylist (), fname (0) { }
02112 
02113   ~mex (void)
02114   {
02115     if (! memlist.empty ())
02116       error ("mex: %s: cleanup failed", function_name ());
02117 
02118     mxFree (fname);
02119   }
02120 
02121   const char *function_name (void) const
02122   {
02123     if (! fname)
02124       {
02125         octave_function *fcn = octave_call_stack::current ();
02126 
02127         if (fcn)
02128           {
02129             std::string nm = fcn->name ();
02130             fname = mxArray::strsave (nm.c_str ());
02131           }
02132         else
02133           fname = mxArray::strsave ("unknown");
02134       }
02135 
02136     return fname;
02137   }
02138 
02139   // Free all unmarked pointers obtained from malloc and calloc.
02140   static void cleanup (void *ptr)
02141   {
02142     mex *context = static_cast<mex *> (ptr);
02143 
02144     // We can't use mex::free here because it modifies memlist.
02145     for (std::set<void *>::iterator p = context->memlist.begin ();
02146          p != context->memlist.end (); p++)
02147       xfree (*p);
02148 
02149     context->memlist.clear ();
02150 
02151     // We can't use mex::free_value here because it modifies arraylist.
02152     for (std::set<mxArray *>::iterator p = context->arraylist.begin ();
02153          p != context->arraylist.end (); p++)
02154       delete *p;
02155 
02156     context->arraylist.clear ();
02157   }
02158 
02159   // Allocate memory.
02160   void *malloc_unmarked (size_t n)
02161   {
02162     void *ptr = gnulib::malloc (n);
02163 
02164     if (! ptr)
02165       {
02166         // FIXME -- could use "octave_new_handler();" instead
02167 
02168         error ("%s: failed to allocate %d bytes of memory",
02169                function_name (), n);
02170 
02171         abort ();
02172       }
02173 
02174     global_mark (ptr);
02175 
02176     return ptr;
02177   }
02178 
02179   // Allocate memory to be freed on exit.
02180   void *malloc (size_t n)
02181   {
02182     void *ptr = malloc_unmarked (n);
02183 
02184     mark (ptr);
02185 
02186     return ptr;
02187   }
02188 
02189   // Allocate memory and initialize to 0.
02190   void *calloc_unmarked (size_t n, size_t t)
02191   {
02192     void *ptr = malloc_unmarked (n*t);
02193 
02194     memset (ptr, 0, n*t);
02195 
02196     return ptr;
02197   }
02198 
02199   // Allocate memory to be freed on exit and initialize to 0.
02200   void *calloc (size_t n, size_t t)
02201   {
02202     void *ptr = calloc_unmarked (n, t);
02203 
02204     mark (ptr);
02205 
02206     return ptr;
02207   }
02208 
02209   // Reallocate a pointer obtained from malloc or calloc. If the
02210   // pointer is NULL, allocate using malloc.  We don't need an
02211   // "unmarked" version of this.
02212   void *realloc (void *ptr, size_t n)
02213   {
02214     void *v;
02215 
02216     if (ptr)
02217       {
02218         v = gnulib::realloc (ptr, n);
02219 
02220         std::set<void *>::iterator p = memlist.find (ptr);
02221 
02222         if (v && p != memlist.end ())
02223           {
02224             memlist.erase (p);
02225             memlist.insert (v);
02226           }
02227 
02228         p = global_memlist.find (ptr);
02229 
02230         if (v && p != global_memlist.end ())
02231           {
02232             global_memlist.erase (p);
02233             global_memlist.insert (v);
02234           }
02235       }
02236     else
02237       v = malloc (n);
02238 
02239     return v;
02240   }
02241 
02242   // Free a pointer obtained from malloc or calloc.
02243   void free (void *ptr)
02244   {
02245     if (ptr)
02246       {
02247         unmark (ptr);
02248 
02249         std::set<void *>::iterator p = global_memlist.find (ptr);
02250 
02251         if (p != global_memlist.end ())
02252           {
02253             global_memlist.erase (p);
02254 
02255             xfree (ptr);
02256           }
02257         else
02258           {
02259             p = foreign_memlist.find (ptr);
02260 
02261             if (p != foreign_memlist.end ())
02262               foreign_memlist.erase (p);
02263 #ifdef DEBUG
02264             else
02265               warning ("mxFree: skipping memory not allocated by mxMalloc, mxCalloc, or mxRealloc");
02266 #endif
02267           }
02268       }
02269   }
02270 
02271   // Mark a pointer to be freed on exit.
02272   void mark (void *ptr)
02273   {
02274 #ifdef DEBUG
02275     if (memlist.find (ptr) != memlist.end ())
02276       warning ("%s: double registration ignored", function_name ());
02277 #endif
02278 
02279     memlist.insert (ptr);
02280   }
02281 
02282   // Unmark a pointer to be freed on exit, either because it was
02283   // made persistent, or because it was already freed.
02284   void unmark (void *ptr)
02285   {
02286     std::set<void *>::iterator p = memlist.find (ptr);
02287 
02288     if (p != memlist.end ())
02289       memlist.erase (p);
02290 #ifdef DEBUG
02291     else
02292       warning ("%s: value not marked", function_name ());
02293 #endif
02294   }
02295 
02296   mxArray *mark_array (mxArray *ptr)
02297   {
02298     arraylist.insert (ptr);
02299     return ptr;
02300   }
02301 
02302   void unmark_array (mxArray *ptr)
02303   {
02304     std::set<mxArray *>::iterator p = arraylist.find (ptr);
02305 
02306     if (p != arraylist.end ())
02307       arraylist.erase (p);
02308   }
02309 
02310   // Mark a pointer as one we allocated.
02311   void mark_foreign (void *ptr)
02312   {
02313 #ifdef DEBUG
02314     if (foreign_memlist.find (ptr) != foreign_memlist.end ())
02315       warning ("%s: double registration ignored", function_name ());
02316 #endif
02317 
02318     foreign_memlist.insert (ptr);
02319   }
02320 
02321   // Unmark a pointer as one we allocated.
02322   void unmark_foreign (void *ptr)
02323   {
02324     std::set<void *>::iterator p = foreign_memlist.find (ptr);
02325 
02326     if (p != foreign_memlist.end ())
02327       foreign_memlist.erase (p);
02328 #ifdef DEBUG
02329     else
02330       warning ("%s: value not marked", function_name ());
02331 #endif
02332 
02333   }
02334 
02335   // Make a new array value and initialize from an octave value; it will be
02336   // freed on exit unless marked as persistent.
02337   mxArray *make_value (const octave_value& ov)
02338   {
02339     return mark_array (new mxArray (ov));
02340   }
02341 
02342   // Free an array and its contents.
02343   bool free_value (mxArray *ptr)
02344   {
02345     bool inlist = false;
02346 
02347     std::set<mxArray *>::iterator p = arraylist.find (ptr);
02348 
02349     if (p != arraylist.end ())
02350       {
02351         inlist = true;
02352         arraylist.erase (p);
02353         delete ptr;
02354       }
02355 #ifdef DEBUG
02356     else
02357       warning ("mex::free_value: skipping memory not allocated by mex::make_value");
02358 #endif
02359 
02360     return inlist;
02361   }
02362 
02363   octave_mex_function *current_mex_function (void) const
02364   {
02365     return curr_mex_fcn;
02366   }
02367 
02368   // 1 if error should be returned to MEX file, 0 if abort.
02369   int trap_feval_error;
02370 
02371   // longjmp return point if mexErrMsgTxt or error.
02372   jmp_buf jump;
02373 
02374   // Trigger a long jump back to the mex calling function.
02375   void abort (void) { longjmp (jump, 1); }
02376 
02377 private:
02378 
02379   // Pointer to the mex function that corresponds to this mex context.
02380   octave_mex_function *curr_mex_fcn;
02381 
02382   // List of memory resources that need to be freed upon exit.
02383   std::set<void *> memlist;
02384 
02385   // List of mxArray objects that need to be freed upon exit.
02386   std::set<mxArray *> arraylist;
02387 
02388   // List of memory resources we know about, but that were allocated
02389   // elsewhere.
02390   std::set<void *> foreign_memlist;
02391 
02392   // The name of the currently executing function.
02393   mutable char *fname;
02394 
02395   // List of memory resources we allocated.
02396   static std::set<void *> global_memlist;
02397 
02398   // Mark a pointer as one we allocated.
02399   void global_mark (void *ptr)
02400   {
02401 #ifdef DEBUG
02402     if (global_memlist.find (ptr) != global_memlist.end ())
02403       warning ("%s: double registration ignored", function_name ());
02404 #endif
02405 
02406     global_memlist.insert (ptr);
02407   }
02408 
02409   // Unmark a pointer as one we allocated.
02410   void global_unmark (void *ptr)
02411   {
02412     std::set<void *>::iterator p = global_memlist.find (ptr);
02413 
02414     if (p != global_memlist.end ())
02415       global_memlist.erase (p);
02416 #ifdef DEBUG
02417     else
02418       warning ("%s: value not marked", function_name ());
02419 #endif
02420 
02421   }
02422 
02423   // No copying!
02424 
02425   mex (const mex&);
02426 
02427   mex& operator = (const mex&);
02428 };
02429 
02430 // List of memory resources we allocated.
02431 std::set<void *> mex::global_memlist;
02432 
02433 // Current context.
02434 mex *mex_context = 0;
02435 
02436 void *
02437 mxArray::malloc (size_t n)
02438 {
02439   return mex_context ? mex_context->malloc_unmarked (n) : gnulib::malloc (n);
02440 }
02441 
02442 void *
02443 mxArray::calloc (size_t n, size_t t)
02444 {
02445   return mex_context ? mex_context->calloc_unmarked (n, t) : ::calloc (n, t);
02446 }
02447 
02448 static inline void *
02449 maybe_mark_foreign (void *ptr)
02450 {
02451   if (mex_context)
02452     mex_context->mark_foreign (ptr);
02453 
02454   return ptr;
02455 }
02456 
02457 static inline mxArray *
02458 maybe_unmark_array (mxArray *ptr)
02459 {
02460   if (mex_context)
02461     mex_context->unmark_array (ptr);
02462 
02463   return ptr;
02464 }
02465 
02466 static inline void *
02467 maybe_unmark (void *ptr)
02468 {
02469   if (mex_context)
02470     mex_context->unmark (ptr);
02471 
02472   return ptr;
02473 }
02474 
02475 void
02476 mxArray_struct::set_field_by_number (mwIndex index, int key_num, mxArray *val)
02477 {
02478   if (key_num >= 0 && key_num < nfields)
02479     data[nfields * index + key_num] = maybe_unmark_array (val);
02480 }
02481 
02482 void
02483 mxArray_cell::set_cell (mwIndex idx, mxArray *val)
02484 {
02485   if (idx >= 0 && idx < get_number_of_elements ())
02486     data[idx] = maybe_unmark_array (val);
02487 }
02488 
02489 // ------------------------------------------------------------------
02490 
02491 // C interface to mxArray objects:
02492 
02493 // Floating point predicates.
02494 
02495 int
02496 mxIsFinite (const double v)
02497 {
02498   return lo_ieee_finite (v) != 0;
02499 }
02500 
02501 int
02502 mxIsInf (const double v)
02503 {
02504   return lo_ieee_isinf (v) != 0;
02505 }
02506 
02507 int
02508 mxIsNaN (const double v)
02509 {
02510   return lo_ieee_isnan (v) != 0;
02511 }
02512 
02513 double
02514 mxGetEps (void)
02515 {
02516   return DBL_EPSILON;
02517 }
02518 
02519 double
02520 mxGetInf (void)
02521 {
02522   return lo_ieee_inf_value ();
02523 }
02524 
02525 double
02526 mxGetNaN (void)
02527 {
02528   return lo_ieee_nan_value ();
02529 }
02530 
02531 // Memory management.
02532 void *
02533 mxCalloc (size_t n, size_t size)
02534 {
02535   return mex_context ? mex_context->calloc (n, size) : calloc (n, size);
02536 }
02537 
02538 void *
02539 mxMalloc (size_t n)
02540 {
02541   return mex_context ? mex_context->malloc (n) : gnulib::malloc (n);
02542 }
02543 
02544 void *
02545 mxRealloc (void *ptr, size_t size)
02546 {
02547   return mex_context ? mex_context->realloc (ptr, size) : gnulib::realloc (ptr, size);
02548 }
02549 
02550 void
02551 mxFree (void *ptr)
02552 {
02553   if (mex_context)
02554     mex_context->free (ptr);
02555   else
02556     xfree (ptr);
02557 }
02558 
02559 static inline mxArray *
02560 maybe_mark_array (mxArray *ptr)
02561 {
02562   return mex_context ? mex_context->mark_array (ptr) : ptr;
02563 }
02564 
02565 // Constructors.
02566 mxArray *
02567 mxCreateCellArray (mwSize ndims, const mwSize *dims)
02568 {
02569   return maybe_mark_array (new mxArray (ndims, dims));
02570 }
02571 
02572 mxArray *
02573 mxCreateCellMatrix (mwSize m, mwSize n)
02574 {
02575   return maybe_mark_array (new mxArray (m, n));
02576 }
02577 
02578 mxArray *
02579 mxCreateCharArray (mwSize ndims, const mwSize *dims)
02580 {
02581   return maybe_mark_array (new mxArray (mxCHAR_CLASS, ndims, dims));
02582 }
02583 
02584 mxArray *
02585 mxCreateCharMatrixFromStrings (mwSize m, const char **str)
02586 {
02587   return maybe_mark_array (new mxArray (m, str));
02588 }
02589 
02590 mxArray *
02591 mxCreateDoubleMatrix (mwSize m, mwSize n, mxComplexity flag)
02592 {
02593   return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, flag));
02594 }
02595 
02596 mxArray *
02597 mxCreateDoubleScalar (double val)
02598 {
02599   return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, val));
02600 }
02601 
02602 mxArray *
02603 mxCreateLogicalArray (mwSize ndims, const mwSize *dims)
02604 {
02605   return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, ndims, dims));
02606 }
02607 
02608 mxArray *
02609 mxCreateLogicalMatrix (mwSize m, mwSize n)
02610 {
02611   return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n));
02612 }
02613 
02614 mxArray *
02615 mxCreateLogicalScalar (mxLogical val)
02616 {
02617   return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, val));
02618 }
02619 
02620 mxArray *
02621 mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id,
02622                       mxComplexity flag)
02623 {
02624   return maybe_mark_array (new mxArray (class_id, ndims, dims, flag));
02625 }
02626 
02627 mxArray *
02628 mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id, mxComplexity flag)
02629 {
02630   return maybe_mark_array (new mxArray (class_id, m, n, flag));
02631 }
02632 
02633 mxArray *
02634 mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag)
02635 {
02636   return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, nzmax, flag));
02637 }
02638 
02639 mxArray *
02640 mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax)
02641 {
02642   return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n, nzmax));
02643 }
02644 
02645 mxArray *
02646 mxCreateString (const char *str)
02647 {
02648   return maybe_mark_array (new mxArray (str));
02649 }
02650 
02651 mxArray *
02652 mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys)
02653 {
02654   return maybe_mark_array (new mxArray (ndims, dims, num_keys, keys));
02655 }
02656 
02657 mxArray *
02658 mxCreateStructMatrix (mwSize m, mwSize n, int num_keys, const char **keys)
02659 {
02660   return maybe_mark_array (new mxArray (m, n, num_keys, keys));
02661 }
02662 
02663 // Copy constructor.
02664 mxArray *
02665 mxDuplicateArray (const mxArray *ptr)
02666 {
02667   return maybe_mark_array (ptr->dup ());
02668 }
02669 
02670 // Destructor.
02671 void
02672 mxDestroyArray (mxArray *ptr)
02673 {
02674   if (! (mex_context && mex_context->free_value (ptr)))
02675     delete ptr;
02676 }
02677 
02678 // Type Predicates.
02679 int
02680 mxIsCell (const mxArray *ptr)
02681 {
02682   return ptr->is_cell ();
02683 }
02684 
02685 int
02686 mxIsChar (const mxArray *ptr)
02687 {
02688   return ptr->is_char ();
02689 }
02690 
02691 int
02692 mxIsClass (const mxArray *ptr, const char *name)
02693 {
02694   return ptr->is_class (name);
02695 }
02696 
02697 int
02698 mxIsComplex (const mxArray *ptr)
02699 {
02700   return ptr->is_complex ();
02701 }
02702 
02703 int
02704 mxIsDouble (const mxArray *ptr)
02705 {
02706   return ptr->is_double ();
02707 }
02708 
02709 int
02710 mxIsFunctionHandle (const mxArray *ptr)
02711 {
02712   return ptr->is_function_handle ();
02713 }
02714 
02715 int
02716 mxIsInt16 (const mxArray *ptr)
02717 {
02718   return ptr->is_int16 ();
02719 }
02720 
02721 int
02722 mxIsInt32 (const mxArray *ptr)
02723 {
02724   return ptr->is_int32 ();
02725 }
02726 
02727 int
02728 mxIsInt64 (const mxArray *ptr)
02729 {
02730   return ptr->is_int64 ();
02731 }
02732 
02733 int
02734 mxIsInt8 (const mxArray *ptr)
02735 {
02736   return ptr->is_int8 ();
02737 }
02738 
02739 int
02740 mxIsLogical (const mxArray *ptr)
02741 {
02742   return ptr->is_logical ();
02743 }
02744 
02745 int
02746 mxIsNumeric (const mxArray *ptr)
02747 {
02748   return ptr->is_numeric ();
02749 }
02750 
02751 int
02752 mxIsSingle (const mxArray *ptr)
02753 {
02754   return ptr->is_single ();
02755 }
02756 
02757 int
02758 mxIsSparse (const mxArray *ptr)
02759 {
02760   return ptr->is_sparse ();
02761 }
02762 
02763 int
02764 mxIsStruct (const mxArray *ptr)
02765 {
02766   return ptr->is_struct ();
02767 }
02768 
02769 int
02770 mxIsUint16 (const mxArray *ptr)
02771 {
02772   return ptr->is_uint16 ();
02773 }
02774 
02775 int
02776 mxIsUint32 (const mxArray *ptr)
02777 {
02778   return ptr->is_uint32 ();
02779 }
02780 
02781 int
02782 mxIsUint64 (const mxArray *ptr)
02783 {
02784   return ptr->is_uint64 ();
02785 }
02786 
02787 int
02788 mxIsUint8 (const mxArray *ptr)
02789 {
02790   return ptr->is_uint8 ();
02791 }
02792 
02793 // Odd type+size predicate.
02794 int
02795 mxIsLogicalScalar (const mxArray *ptr)
02796 {
02797   return ptr->is_logical_scalar ();
02798 }
02799 
02800 // Odd type+size+value predicate.
02801 int
02802 mxIsLogicalScalarTrue (const mxArray *ptr)
02803 {
02804   return ptr->is_logical_scalar_true ();
02805 }
02806 
02807 // Size predicate.
02808 int
02809 mxIsEmpty (const mxArray *ptr)
02810 {
02811   return ptr->is_empty ();
02812 }
02813 
02814 // Just plain odd thing to ask of a value.
02815 int
02816 mxIsFromGlobalWS (const mxArray */*ptr*/)
02817 {
02818   // FIXME
02819   abort ();
02820   return 0;
02821 }
02822 
02823 // Dimension extractors.
02824 size_t
02825 mxGetM (const mxArray *ptr)
02826 {
02827   return ptr->get_m ();
02828 }
02829 
02830 size_t
02831 mxGetN (const mxArray *ptr)
02832 {
02833   return ptr->get_n ();
02834 }
02835 
02836 mwSize *
02837 mxGetDimensions (const mxArray *ptr)
02838 {
02839   return ptr->get_dimensions ();
02840 }
02841 
02842 mwSize
02843 mxGetNumberOfDimensions (const mxArray *ptr)
02844 {
02845   return ptr->get_number_of_dimensions ();
02846 }
02847 
02848 size_t
02849 mxGetNumberOfElements (const mxArray *ptr)
02850 {
02851   return ptr->get_number_of_elements ();
02852 }
02853 
02854 // Dimension setters.
02855 void
02856 mxSetM (mxArray *ptr, mwSize m)
02857 {
02858   ptr->set_m (m);
02859 }
02860 
02861 void
02862 mxSetN (mxArray *ptr, mwSize n)
02863 {
02864   ptr->set_n (n);
02865 }
02866 
02867 void
02868 mxSetDimensions (mxArray *ptr, const mwSize *dims, mwSize ndims)
02869 {
02870   ptr->set_dimensions (static_cast<mwSize *> (
02871                          maybe_unmark (const_cast<mwSize *> (dims))),
02872                        ndims);
02873 }
02874 
02875 // Data extractors.
02876 double *
02877 mxGetPr (const mxArray *ptr)
02878 {
02879   return static_cast<double *> (ptr->get_data ());
02880 }
02881 
02882 double *
02883 mxGetPi (const mxArray *ptr)
02884 {
02885   return static_cast<double *> (ptr->get_imag_data ());
02886 }
02887 
02888 double
02889 mxGetScalar (const mxArray *ptr)
02890 {
02891   return ptr->get_scalar ();
02892 }
02893 
02894 mxChar *
02895 mxGetChars (const mxArray *ptr)
02896 {
02897   return static_cast<mxChar *> (ptr->get_data ());
02898 }
02899 
02900 mxLogical *
02901 mxGetLogicals (const mxArray *ptr)
02902 {
02903   return static_cast<mxLogical *> (ptr->get_data ());
02904 }
02905 
02906 void *
02907 mxGetData (const mxArray *ptr)
02908 {
02909   return ptr->get_data ();
02910 }
02911 
02912 void *
02913 mxGetImagData (const mxArray *ptr)
02914 {
02915   return ptr->get_imag_data ();
02916 }
02917 
02918 // Data setters.
02919 void
02920 mxSetPr (mxArray *ptr, double *pr)
02921 {
02922   ptr->set_data (maybe_unmark (pr));
02923 }
02924 
02925 void
02926 mxSetPi (mxArray *ptr, double *pi)
02927 {
02928   ptr->set_imag_data (maybe_unmark (pi));
02929 }
02930 
02931 void
02932 mxSetData (mxArray *ptr, void *pr)
02933 {
02934   ptr->set_data (maybe_unmark (pr));
02935 }
02936 
02937 void
02938 mxSetImagData (mxArray *ptr, void *pi)
02939 {
02940   ptr->set_imag_data (maybe_unmark (pi));
02941 }
02942 
02943 // Classes.
02944 mxClassID
02945 mxGetClassID (const mxArray *ptr)
02946 {
02947   return ptr->get_class_id ();
02948 }
02949 
02950 const char *
02951 mxGetClassName (const mxArray *ptr)
02952 {
02953   return ptr->get_class_name ();
02954 }
02955 
02956 void
02957 mxSetClassName (mxArray *ptr, const char *name)
02958 {
02959   ptr->set_class_name (name);
02960 }
02961 
02962 // Cell support.
02963 mxArray *
02964 mxGetCell (const mxArray *ptr, mwIndex idx)
02965 {
02966   return ptr->get_cell (idx);
02967 }
02968 
02969 void
02970 mxSetCell (mxArray *ptr, mwIndex idx, mxArray *val)
02971 {
02972   ptr->set_cell (idx, val);
02973 }
02974 
02975 // Sparse support.
02976 mwIndex *
02977 mxGetIr (const mxArray *ptr)
02978 {
02979   return ptr->get_ir ();
02980 }
02981 
02982 mwIndex *
02983 mxGetJc (const mxArray *ptr)
02984 {
02985   return ptr->get_jc ();
02986 }
02987 
02988 mwSize
02989 mxGetNzmax (const mxArray *ptr)
02990 {
02991   return ptr->get_nzmax ();
02992 }
02993 
02994 void
02995 mxSetIr (mxArray *ptr, mwIndex *ir)
02996 {
02997   ptr->set_ir (static_cast <mwIndex *> (maybe_unmark (ir)));
02998 }
02999 
03000 void
03001 mxSetJc (mxArray *ptr, mwIndex *jc)
03002 {
03003   ptr->set_jc (static_cast<mwIndex *> (maybe_unmark (jc)));
03004 }
03005 
03006 void
03007 mxSetNzmax (mxArray *ptr, mwSize nzmax)
03008 {
03009   ptr->set_nzmax (nzmax);
03010 }
03011 
03012 // Structure support.
03013 int
03014 mxAddField (mxArray *ptr, const char *key)
03015 {
03016   return ptr->add_field (key);
03017 }
03018 
03019 void
03020 mxRemoveField (mxArray *ptr, int key_num)
03021 {
03022   ptr->remove_field (key_num);
03023 }
03024 
03025 mxArray *
03026 mxGetField (const mxArray *ptr, mwIndex index, const char *key)
03027 {
03028   int key_num = mxGetFieldNumber (ptr, key);
03029   return mxGetFieldByNumber (ptr, index, key_num);
03030 }
03031 
03032 mxArray *
03033 mxGetFieldByNumber (const mxArray *ptr, mwIndex index, int key_num)
03034 {
03035   return ptr->get_field_by_number (index, key_num);
03036 }
03037 
03038 void
03039 mxSetField (mxArray *ptr, mwIndex index, const char *key, mxArray *val)
03040 {
03041   int key_num = mxGetFieldNumber (ptr, key);
03042   mxSetFieldByNumber (ptr, index, key_num, val);
03043 }
03044 
03045 void
03046 mxSetFieldByNumber (mxArray *ptr, mwIndex index, int key_num, mxArray *val)
03047 {
03048   ptr->set_field_by_number (index, key_num, val);
03049 }
03050 
03051 int
03052 mxGetNumberOfFields (const mxArray *ptr)
03053 {
03054   return ptr->get_number_of_fields ();
03055 }
03056 
03057 const char *
03058 mxGetFieldNameByNumber (const mxArray *ptr, int key_num)
03059 {
03060   return ptr->get_field_name_by_number (key_num);
03061 }
03062 
03063 int
03064 mxGetFieldNumber (const mxArray *ptr, const char *key)
03065 {
03066   return ptr->get_field_number (key);
03067 }
03068 
03069 int
03070 mxGetString (const mxArray *ptr, char *buf, mwSize buflen)
03071 {
03072   return ptr->get_string (buf, buflen);
03073 }
03074 
03075 char *
03076 mxArrayToString (const mxArray *ptr)
03077 {
03078   return ptr->array_to_string ();
03079 }
03080 
03081 mwIndex
03082 mxCalcSingleSubscript (const mxArray *ptr, mwSize nsubs, mwIndex *subs)
03083 {
03084   return ptr->calc_single_subscript (nsubs, subs);
03085 }
03086 
03087 size_t
03088 mxGetElementSize (const mxArray *ptr)
03089 {
03090   return ptr->get_element_size ();
03091 }
03092 
03093 // ------------------------------------------------------------------
03094 
03095 typedef void (*cmex_fptr) (int nlhs, mxArray **plhs, int nrhs, mxArray **prhs);
03096 typedef F77_RET_T (*fmex_fptr) (int& nlhs, mxArray **plhs, int& nrhs, mxArray **prhs);
03097 
03098 octave_value_list
03099 call_mex (bool have_fmex, void *f, const octave_value_list& args,
03100           int nargout_arg, octave_mex_function *curr_mex_fcn)
03101 {
03102   // Use at least 1 for nargout since even for zero specified args,
03103   // still want to be able to return an ans.
03104 
03105   volatile int nargout = nargout_arg;
03106 
03107   int nargin = args.length ();
03108   OCTAVE_LOCAL_BUFFER (mxArray *, argin, nargin);
03109   for (int i = 0; i < nargin; i++)
03110     argin[i] = 0;
03111 
03112   int nout = nargout == 0 ? 1 : nargout;
03113   OCTAVE_LOCAL_BUFFER (mxArray *, argout, nout);
03114   for (int i = 0; i < nout; i++)
03115     argout[i] = 0;
03116 
03117   unwind_protect_safe frame;
03118 
03119   // Save old mex pointer.
03120   frame.protect_var (mex_context);
03121 
03122   mex context (curr_mex_fcn);
03123 
03124   frame.add (mex::cleanup, static_cast<void *> (&context));
03125 
03126   for (int i = 0; i < nargin; i++)
03127     argin[i] = context.make_value (args(i));
03128 
03129   if (setjmp (context.jump) == 0)
03130     {
03131       mex_context = &context;
03132 
03133       if (have_fmex)
03134         {
03135           fmex_fptr fcn = FCN_PTR_CAST (fmex_fptr, f);
03136 
03137           int tmp_nargout = nargout;
03138           int tmp_nargin = nargin;
03139 
03140           fcn (tmp_nargout, argout, tmp_nargin, argin);
03141         }
03142       else
03143         {
03144           cmex_fptr fcn = FCN_PTR_CAST (cmex_fptr, f);
03145 
03146           fcn (nargout, argout, nargin, argin);
03147         }
03148     }
03149 
03150   // Convert returned array entries back into octave values.
03151 
03152   octave_value_list retval;
03153 
03154   if (! error_state)
03155     {
03156       if (nargout == 0 && argout[0])
03157         {
03158           // We have something for ans.
03159           nargout = 1;
03160         }
03161 
03162       retval.resize (nargout);
03163 
03164       for (int i = 0; i < nargout; i++)
03165         retval(i) = mxArray::as_octave_value (argout[i]);
03166     }
03167 
03168   // Clean up mex resources.
03169   frame.run ();
03170 
03171   return retval;
03172 }
03173 
03174 // C interface to mex functions:
03175 
03176 const char *
03177 mexFunctionName (void)
03178 {
03179   return mex_context ? mex_context->function_name () : "unknown";
03180 }
03181 
03182 int
03183 mexCallMATLAB (int nargout, mxArray *argout[], int nargin, mxArray *argin[],
03184                const char *fname)
03185 {
03186   octave_value_list args;
03187 
03188   // FIXME -- do we need unwind protect to clean up args?  Off hand, I
03189   // would say that this problem is endemic to Octave and we will
03190   // continue to have memory leaks after Ctrl-C until proper exception
03191   // handling is implemented.  longjmp() only clears the stack, so any
03192   // class which allocates data on the heap is going to leak.
03193 
03194   args.resize (nargin);
03195 
03196   for (int i = 0; i < nargin; i++)
03197     args(i) = mxArray::as_octave_value (argin[i]);
03198 
03199   octave_value_list retval = feval (fname, args, nargout);
03200 
03201   if (error_state && mex_context->trap_feval_error == 0)
03202     {
03203       // FIXME -- is this the correct way to clean up?  abort() is
03204       // going to trigger a long jump, so the normal class destructors
03205       // will not be called.  Hopefully this will reduce things to a
03206       // tiny leak.  Maybe create a new octave memory tracer type
03207       // which prints a friendly message every time it is
03208       // created/copied/deleted to check this.
03209 
03210       args.resize (0);
03211       retval.resize (0);
03212       mex_context->abort ();
03213     }
03214 
03215   int num_to_copy = retval.length ();
03216 
03217   if (nargout < retval.length ())
03218     num_to_copy = nargout;
03219 
03220   for (int i = 0; i < num_to_copy; i++)
03221     {
03222       // FIXME -- it would be nice to avoid copying the value here,
03223       // but there is no way to steal memory from a matrix, never mind
03224       // that matrix memory is allocated by new[] and mxArray memory
03225       // is allocated by malloc().
03226       argout[i] = mex_context->make_value (retval (i));
03227     }
03228 
03229   while (num_to_copy < nargout)
03230     argout[num_to_copy++] = 0;
03231 
03232   if (error_state)
03233     {
03234       error_state = 0;
03235       return 1;
03236     }
03237   else
03238     return 0;
03239 }
03240 
03241 void
03242 mexSetTrapFlag (int flag)
03243 {
03244   if (mex_context)
03245     mex_context->trap_feval_error = flag;
03246 }
03247 
03248 int
03249 mexEvalString (const char *s)
03250 {
03251   int retval = 0;
03252 
03253   int parse_status;
03254 
03255   octave_value_list ret;
03256 
03257   ret = eval_string (s, false, parse_status, 0);
03258 
03259   if (parse_status || error_state)
03260     {
03261       error_state = 0;
03262 
03263       retval = 1;
03264     }
03265 
03266   return retval;
03267 }
03268 
03269 void
03270 mexErrMsgTxt (const char *s)
03271 {
03272   if (s && strlen (s) > 0)
03273     error ("%s: %s", mexFunctionName (), s);
03274   else
03275     // Just set the error state; don't print msg.
03276     error ("");
03277 
03278   mex_context->abort ();
03279 }
03280 
03281 void
03282 mexErrMsgIdAndTxt (const char *id, const char *fmt, ...)
03283 {
03284   if (fmt && strlen (fmt) > 0)
03285     {
03286       const char *fname = mexFunctionName ();
03287       size_t len = strlen (fname) + 2 + strlen (fmt) + 1;
03288       OCTAVE_LOCAL_BUFFER (char, tmpfmt, len);
03289       sprintf (tmpfmt, "%s: %s", fname, fmt);
03290       va_list args;
03291       va_start (args, fmt);
03292       verror_with_id (id, tmpfmt, args);
03293       va_end (args);
03294     }
03295   else
03296     // Just set the error state; don't print msg.
03297     error ("");
03298 
03299   mex_context->abort ();
03300 }
03301 
03302 void
03303 mexWarnMsgTxt (const char *s)
03304 {
03305   warning ("%s", s);
03306 }
03307 
03308 void
03309 mexWarnMsgIdAndTxt (const char *id, const char *fmt, ...)
03310 {
03311   // FIXME -- is this right?  What does Matlab do if fmt is NULL or
03312   // an empty string?
03313 
03314   if (fmt && strlen (fmt) > 0)
03315     {
03316       const char *fname = mexFunctionName ();
03317       size_t len = strlen (fname) + 2 + strlen (fmt) + 1;
03318       OCTAVE_LOCAL_BUFFER (char, tmpfmt, len);
03319       sprintf (tmpfmt, "%s: %s", fname, fmt);
03320       va_list args;
03321       va_start (args, fmt);
03322       vwarning_with_id (id, tmpfmt, args);
03323       va_end (args);
03324     }
03325 }
03326 
03327 int
03328 mexPrintf (const char *fmt, ...)
03329 {
03330   int retval;
03331   va_list args;
03332   va_start (args, fmt);
03333   retval = octave_vformat (octave_stdout, fmt, args);
03334   va_end (args);
03335   return retval;
03336 }
03337 
03338 mxArray *
03339 mexGetVariable (const char *space, const char *name)
03340 {
03341   mxArray *retval = 0;
03342 
03343   octave_value val;
03344 
03345   if (! strcmp (space, "global"))
03346     val = get_global_value (name);
03347   else
03348     {
03349       // FIXME -- should this be in variables.cc?
03350 
03351       unwind_protect frame;
03352 
03353       bool caller = ! strcmp (space, "caller");
03354       bool base = ! strcmp (space, "base");
03355 
03356       if (caller || base)
03357         {
03358           if (caller)
03359             octave_call_stack::goto_caller_frame ();
03360           else
03361             octave_call_stack::goto_base_frame ();
03362 
03363           if (! error_state)
03364             frame.add_fcn (octave_call_stack::pop);
03365 
03366           val = symbol_table::varval (name);
03367         }
03368       else
03369         mexErrMsgTxt ("mexGetVariable: symbol table does not exist");
03370     }
03371 
03372   if (val.is_defined ())
03373     {
03374       retval = mex_context->make_value (val);
03375 
03376       retval->set_name (name);
03377     }
03378 
03379   return retval;
03380 }
03381 
03382 const mxArray *
03383 mexGetVariablePtr (const char *space, const char *name)
03384 {
03385   return mexGetVariable (space, name);
03386 }
03387 
03388 int
03389 mexPutVariable (const char *space, const char *name, mxArray *ptr)
03390 {
03391   if (! ptr)
03392     return 1;
03393 
03394   if (! name)
03395     return 1;
03396 
03397   if (name[0] == '\0')
03398     name = ptr->get_name ();
03399 
03400   if (! name || name[0] == '\0')
03401     return 1;
03402 
03403   if (! strcmp (space, "global"))
03404     set_global_value (name, mxArray::as_octave_value (ptr));
03405   else
03406     {
03407       // FIXME -- should this be in variables.cc?
03408 
03409       unwind_protect frame;
03410 
03411       bool caller = ! strcmp (space, "caller");
03412       bool base = ! strcmp (space, "base");
03413 
03414       if (caller || base)
03415         {
03416           if (caller)
03417             octave_call_stack::goto_caller_frame ();
03418           else
03419             octave_call_stack::goto_base_frame ();
03420 
03421           if (! error_state)
03422             frame.add_fcn (octave_call_stack::pop);
03423 
03424           symbol_table::varref (name) = mxArray::as_octave_value (ptr);
03425         }
03426       else
03427         mexErrMsgTxt ("mexPutVariable: symbol table does not exist");
03428     }
03429 
03430   return 0;
03431 }
03432 
03433 void
03434 mexMakeArrayPersistent (mxArray *ptr)
03435 {
03436   maybe_unmark_array (ptr);
03437 }
03438 
03439 void
03440 mexMakeMemoryPersistent (void *ptr)
03441 {
03442   maybe_unmark (ptr);
03443 }
03444 
03445 int
03446 mexAtExit (void (*f) (void))
03447 {
03448   if (mex_context)
03449     {
03450       octave_mex_function *curr_mex_fcn = mex_context->current_mex_function ();
03451 
03452       assert (curr_mex_fcn);
03453 
03454       curr_mex_fcn->atexit (f);
03455     }
03456 
03457   return 0;
03458 }
03459 
03460 const mxArray *
03461 mexGet (double handle, const char *property)
03462 {
03463   mxArray *m = 0;
03464   octave_value ret = get_property_from_handle (handle, property, "mexGet");
03465 
03466   if (!error_state && ret.is_defined())
03467     m = ret.as_mxArray ();
03468   return m;
03469 }
03470 
03471 int
03472 mexIsGlobal (const mxArray *ptr)
03473 {
03474   return mxIsFromGlobalWS (ptr);
03475 }
03476 
03477 int
03478 mexIsLocked (void)
03479 {
03480   int retval = 0;
03481 
03482   if (mex_context)
03483     {
03484       const char *fname = mexFunctionName ();
03485 
03486       retval = mislocked (fname);
03487     }
03488 
03489   return retval;
03490 }
03491 
03492 std::map<std::string,int> mex_lock_count;
03493 
03494 void
03495 mexLock (void)
03496 {
03497   if (mex_context)
03498     {
03499       const char *fname = mexFunctionName ();
03500 
03501       if (mex_lock_count.find (fname) == mex_lock_count.end ())
03502         mex_lock_count[fname] = 1;
03503       else
03504         mex_lock_count[fname]++;
03505 
03506       mlock ();
03507     }
03508 }
03509 
03510 int
03511 mexSet (double handle, const char *property, mxArray *val)
03512 {
03513   bool ret =
03514     set_property_in_handle (handle, property, mxArray::as_octave_value (val),
03515                             "mexSet");
03516   return (ret ? 0 : 1);
03517 }
03518 
03519 void
03520 mexUnlock (void)
03521 {
03522   if (mex_context)
03523     {
03524       const char *fname = mexFunctionName ();
03525 
03526       std::map<std::string,int>::iterator p = mex_lock_count.find (fname);
03527 
03528       if (p != mex_lock_count.end ())
03529         {
03530           int count = --mex_lock_count[fname];
03531 
03532           if (count == 0)
03533             {
03534               munlock (fname);
03535 
03536               mex_lock_count.erase (p);
03537             }
03538         }
03539     }
03540 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines