Mercurial > forge
view extra/mex/mex.cc @ 0:6b33357c7561 octave-forge
Initial revision
author | pkienzle |
---|---|
date | Wed, 10 Oct 2001 19:54:49 +0000 |
parents | |
children | 7a7e93cfbd1e |
line wrap: on
line source
// Author: Paul Kienzle, 2001-03-22 // I grant this code to the public domain. // // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. // 2001-06-21 Paul Kienzle <pkienzle@users.sf.net> // * fix is_numeric so that character strings aren't called numeric. // * use unsigned short for mxChar rather than char // 2001-09-20 Paul Kienzle <pkienzle@users.sf.net> // * Need <float.h> for DBL_EPSILON #include <float.h> #include <iomanip.h> extern "C" { #include <stdlib.h> #include <setjmp.h> extern const char *mexFunctionName; } ; #include <octave/oct.h> #include <octave/pager.h> #include <octave/SLList.h> // XXX FIXME XXX --- this belongs in SLList.h, not SLList.cc template <class T> SLList<T>::~SLList (void) { clear(); } #include <octave/f77-fcn.h> #include <octave/unwind-prot.h> #include <octave/lo-mappers.h> #include <octave/lo-ieee.h> #include <octave/parse.h> #include <octave/toplev.h> #include <octave/variables.h> // ================ Octave 2.0 support ================== #if defined(HAVE_OCTAVE_20) #include <octave/symtab.h> class unwind_protect { public: static void add(cleanup_func fptr, void *ptr) { add_unwind_protect (fptr, ptr); } static void run(void) { run_unwind_protect (); } } ; static octave_value_list eval_string (const string& s, int print, int& parse_status, int nargout) { return eval_string(s,print,parse_status); } static int octave_vformat (std::ostream& os, const char *fmt, va_list args) { int retval = -1; #if defined (__GNUG__) ostrstream buf; buf.vform (fmt, args); buf << ends; char *s = buf.str (); os << s; retval = strlen (s); delete [] s; #else char *s = octave_vsnprintf (fmt, args); if (s) { os << s; retval = strlen (s); free (s); } #endif return retval; } #endif #if 0 #define TRACEFN cout << __FUNCTION__ << endl << flush #else #define TRACEFN do { } while(0) #endif /* ============== mxArray data type ============= */ // Class mxArray is not much more than a struct for keeping together // dimensions and data. It doesn't even ensure consistency between // the dimensions and the data. Unfortunately you can't do better // than this without restricting the operations available in Matlab // for directly manipulating its mxArray type. typedef unsigned short mxChar; const int mxMAXNAM=64; class mxArray { public: ~mxArray () { } int rows() const { return nr; } int columns() const { return nc; } void rows(int r) { nr = r; } void columns(int c) { nc = c; } double *imag() const { return pi; } double *real() const { return pr; } void imag(double *p) { pi = p; } void real(double *p) { pr = p; } bool is_empty() const { return nr==0 || nc==0; } bool is_numeric() const { return !isstr && (pr != NULL || nr==0 || nc==0); } bool is_complex() const { return pi != NULL; } bool is_sparse() const { return false; } bool is_string() const { return isstr; } void is_string(bool set) { isstr = set; } const char* name() const { return aname; } void name(const char *nm) { strncpy(aname,nm,mxMAXNAM); aname[mxMAXNAM]='\0'; } octave_value as_octave_value() const; private: int nr, nc; double *pr, *pi; bool isstr; char aname[mxMAXNAM+1]; } ; octave_value mxArray::as_octave_value() const { octave_value ret; if (isstr) { charMatrix chm(nr,nc); char *pchm = chm.fortran_vec(); for (int i=0; i < nr*nc; i++) pchm[i] = NINT(pr[i]); ret = octave_value(chm, true); } else if (pi) { ComplexMatrix cm(nr, nc); Complex *pcm = cm.fortran_vec(); for (int i=0; i < nr*nc; i++) pcm[i] = Complex(pr[i], pi[i]); ret = cm; } else if (pr) { Matrix m(nr,nc); double *pm = m.fortran_vec(); memcpy(pm, pr, nr*nc*sizeof(double)); ret = m; } else ret = Matrix(0,0); return ret; } /* ========== mex file context ============= */ // Class mex keeps track of all memory allocated and frees anything // not explicitly marked persistent when the it is destroyed. It also // maintains the setjump/longjump buffer required for non-local exit // from the mex file, and any other state local to this instance of // the mex function invocation. class mex { public: mex() { } ~mex() { if (!memlist.empty()) error("mex: no cleanup performed"); } // free all unmarked pointers obtained from malloc and calloc static void cleanup(void* context); // allocate a pointer, and mark it to be freed on exit Pix malloc(int n); // allocate a pointer to be freed on exit, and initialize to 0 Pix calloc(int n, int t); // reallocate a pointer obtained from malloc or calloc Pix realloc(Pix ptr, int n); // free a pointer obtained from malloc or calloc void free(Pix ptr); // mark a pointer so that it will not be freed on exit void persistent(Pix ptr) { unmark(ptr); } // make a new array value and initialize it with zeros; it will be // freed on exit unless marked as persistent mxArray *make_value(int nr, int nc, int cmplx); // make a new array value and initialize from an octave value; it will be // freed on exit unless marked as persistent mxArray *make_value(const octave_value&); // free an array and its contents void free_value(mxArray* ptr); // mark an array and its contents so it will not be freed on exit void persistent(mxArray* ptr); // 1 if error should be returned to MEX file, 0 if abort int trap_feval_error; // longjmp return point if mexErrMsgTxt or error jmp_buf jump; // trigger a long jump back to the mex calling function void abort() { longjmp(jump, 1); } private: // list of memory resources that need to be freed upon exit SLList<Pix> memlist; // mark a pointer to be freed on exit void mark(Pix p); // unmark a pointer to be freed on exit, either because it was // made persistent, or because it was already freed void unmark(Pix p); } ; template class SLList<Pix>; // free all unmarked pointers obtained from malloc and calloc void mex::cleanup(Pix ptr) { mex* context = (mex*)ptr; for (Pix p = context->memlist.first(); p; context->memlist.next(p)) ::free(context->memlist(p)); context->memlist.clear(); } // XXX FIXME XXX --- could this be added to class SLList<T>? void del(SLList<Pix>& l, const Pix& v) { if (l.front() == v) l.del_front(); else { Pix before = l.first(); Pix p = before; l.next(p); while (p && l(p) != v) { before = p; l.next(p); } if (p) l.del_after(before); } } // mark a pointer to be freed on exit void mex::mark(Pix p) { if (memlist.owns(p)) warning("%s: double registration ignored", mexFunctionName); else memlist.prepend(p); } // unmark a pointer to be freed on exit, either because it was // made persistent, or because it was already freed void mex::unmark(Pix p) { del(memlist, p); } // allocate a pointer, and mark it to be freed on exit Pix mex::malloc(int n) { if (n == 0) return NULL; #if 0 // XXX FIXME XXX --- how do you allocate and free aligned, non-typed // memory in C++? Pix ptr = Pix(new double[(n+sizeof(double)-1)/sizeof(double)]); #else // XXX FIXME XXX --- can we mix C++ and C-style heap management? Pix ptr = ::malloc(n); if (ptr == NULL) { // XXX FIXME XXX --- could use "octave_new_handler();" instead error("%s: out of memory", mexFunctionName); abort(); } #endif mark(ptr); return ptr; } // allocate a pointer to be freed on exit, and initialize to 0 Pix mex::calloc(int n, int t) { Pix v = malloc(n*t); memset(v, 0, n*t); return v; } // reallocate a pointer obtained from malloc or calloc Pix mex::realloc(Pix ptr, int n) { #if 0 error("%s: cannot reallocate using C++ new/delete operations", mexFunctionName); abort(); #else Pix v = NULL; if (n == 0) free(ptr); else if (ptr == NULL) v = malloc(n); else { v = ::realloc(ptr, n); if (v && memlist.owns(ptr)) { del(memlist, ptr); memlist.prepend(v); } } #endif return v; } // free a pointer obtained from malloc or calloc void mex::free(Pix ptr) { unmark(ptr); #if 0 delete [] ptr; #else ::free(ptr); #endif } // make a new array value and initialize from an octave value; it will be // freed on exit unless marked as persistent mxArray* mex::make_value(const octave_value &ov) { int nr=-1, nc=-1; double *pr = NULL, *pi = NULL; if (ov.is_numeric_type() || ov.is_string()) { nr = ov.rows(); nc = ov.columns(); } if (nr > 0 && nc > 0) { if (ov.is_string()) { // XXX FIXME XXX - must use 16 bit unicode to represent strings. const Matrix m(ov.matrix_value(1)); pr = (double *)malloc(nr*nc*sizeof(double)); memcpy(pr, m.data(), nr*nc*sizeof(double)); } else if (ov.is_complex_type()) { // XXX FIXME XXX --- may want to consider lazy copying of the // matrix, but this will only help if the matrix is being // passed on to octave via callMATLAB later. const ComplexMatrix cm(ov.complex_matrix_value()); const Complex * pz = cm.data(); pr = (double *)malloc(nr*nc*sizeof(double)); pi = (double *)malloc(nr*nc*sizeof(double)); for (int i=0; i < nr*nc; i++) { pr[i] = real(pz[i]); pi[i] = imag(pz[i]); } } else { const Matrix m(ov.matrix_value()); pr = (double *)malloc(nr*nc*sizeof(double)); memcpy(pr, m.data(), nr*nc*sizeof(double)); } } mxArray *value = (mxArray*)malloc(sizeof(mxArray)); value->is_string(ov.is_string()); value->real(pr); value->imag(pi); value->rows(nr); value->columns(nc); value->name(""); return value; } // make a new array value and initialize it with zeros; it will be // freed on exit unless marked as persistent mxArray *mex::make_value(int nr, int nc, int cmplx) { mxArray *value = (mxArray*)malloc(sizeof(mxArray)); double*p = (double*)calloc(nr*nc, sizeof(double)); value->real(p); if (cmplx) value->imag((double*)calloc(nr*nc, sizeof(double))); else value->imag((double*)Pix(0)); value->rows(nr); value->columns(nc); value->is_string(false); value->name(""); return value; } // free an array and its contents void mex::free_value(mxArray* ptr) { free(ptr->real()); free(ptr->imag()); free(ptr); } // mark an array and its contents so it will not be freed on exit void mex::persistent(mxArray* ptr) { persistent(Pix(ptr->real())); persistent(Pix(ptr->imag())); persistent(Pix(ptr)); } /* ========== Octave interface to mex files ============ */ mex* __mex = NULL; extern "C" { void F77_FCN(mexfunction,MEXFUNCTION) (const int& nargout, mxArray *plhs[], const int& nargin, mxArray *prhs[]); void mexFunction(const int nargout, mxArray *plhs[], const int nargin, mxArray *prhs[]); } ; #if 0 /* Don't bother trapping stop/exit */ // To trap for STOP in fortran code, this needs to be registered with atexit static void mex_exit() { if (__mex) { error("%s: program aborted", mexFunctionName); __mex->abort(); } } #endif enum callstyle { use_fortran, use_C }; octave_value_list call_mex(callstyle cs, const octave_value_list& args, const int nargout) { #if 0 /* Don't bother trapping stop/exit */ // XXX FIXME XXX ---- should really push "mex_exit" onto the octave // atexit stack before we start and pop it when we are through, but // the stack handle isn't exported from toplev.cc, so we can't. mex_exit // would have to be declared as DEFUN(mex_exit,,,"") of course. static bool unregistered = true; if (unregistered) { atexit(mex_exit); unregistered = false; } #endif // nargout+1 since even for zero specified args, still want to be able // to return an ans. const int nargin = args.length(); mxArray * argin[nargin], * argout[nargout+1]; for (int i=0; i < nargin; i++) argin[i] = NULL; for (int i=0; i < nargout+1; i++) argout[i] = NULL; mex context; unwind_protect::add(mex::cleanup, Pix(&context)); for (int i=0; i < nargin; i++) argin[i] = context.make_value(args(i)); unwind_protect_ptr(__mex); // save old mex pointer if (setjmp(context.jump) == 0) { __mex = &context; if (cs == use_fortran) F77_FCN(mexfunction,MEXFUNCTION)(nargout, argout, nargin, argin); else mexFunction(nargout, argout, nargin, argin); } unwind_protect::run(); // restore old mex pointer // convert returned array entries back into octave values octave_value_list retval; if (! error_state) { for (int i=0; i < nargout+1; i++) if (argout[i]) retval(i) = argout[i]->as_octave_value(); //retval(i) = argout[i] ? argout[i]->as_octave_value() : octave_value(); } unwind_protect::run(); // clean up mex resources return retval; } octave_value_list Fortran_mex(const octave_value_list& args, const int nargout) { return call_mex(use_fortran, args, nargout); } octave_value_list C_mex(const octave_value_list& args, const int nargout) { return call_mex(use_C, args, nargout); } /* ============ C interface to mex functions =============== */ extern "C" { void mexErrMsgTxt (const char *s) { if (s && strlen(s) > 0) error("%s: %s", mexFunctionName, s); else error(""); // just set the error state; don't print msg __mex->abort(); } void mexWarnMsgTxt (const char *s) { warning("%s", s); } void mexPrintf (const char *fmt, ...) { va_list args; va_start (args, fmt); octave_vformat(octave_diary, fmt, args); octave_vformat(octave_stdout, fmt, args); va_end (args); } // floating point representation int mxIsNaN(const double v) { return xisnan(v) != 0; } int mxIsFinite(const double v) { return xfinite(v) != 0; } int mxIsInf(const double v) { return xisinf(v) != 0; } double mxGetEps() { return DBL_EPSILON; } double mxGetInf() { return octave_Inf; } double mxGetNaN() { return octave_NaN; } int mexEvalString(const char* s) { int parse_status; octave_value_list ret; ret = eval_string(s, false, parse_status, 0); if ( parse_status || error_state ) { error_state = 0; return 1; } else return 0; } int mexCallMATLAB(const int nargout, mxArray* argout[], const int nargin, const mxArray* argin[], const char* fname) { octave_value_list args; // XXX FIXME XXX --- do we need unwind protect to clean up args? // Off hand, I would say that this problem is endemic to Octave // and we will continue to have memory leaks after Ctrl-C until // proper exception handling is implemented. longjmp() only // clears the stack, so any class which allocates data on the // heap is going to leak. args.resize(nargin); for (int i=0; i < nargin; i++) { args(i) = argin[i]->as_octave_value(); } octave_value_list retval = feval(fname, args, nargout); if (error_state && __mex->trap_feval_error == 0) { // XXX FIXME XXX --- is this the correct way to clean up? // abort() is going to trigger a long jump, so the normal // class destructors will not be called. Hopefully this // will reduce things to a tiny leak. Maybe create a new // octave memory tracer type which prints a friendly message // every time it is created/copied/deleted to check this. args.resize(0); retval.resize(0); __mex->abort(); } int num_to_copy = retval.length(); if (nargout < retval.length()) num_to_copy = nargout; for (int i=0; i < num_to_copy; i++) { // XXX FIXME XXX --- it would be nice to avoid copying the // value here, but there is no way to steal memory from a // matrix, never mind that matrix memory is allocated // by new[] and mxArray memory is allocated by malloc(). argout[i] = __mex->make_value(retval(i)); } while (num_to_copy < nargout) argout[num_to_copy++] = NULL; if (error_state) { error_state = 0; return 1; } else return 0; } void mexSetTrapFlag(int flag) { __mex->trap_feval_error = flag; } Pix mxMalloc(int n) { return __mex->malloc(n); } Pix mxCalloc(int n, int size) { return __mex->calloc(n, size); } Pix mxRealloc(Pix ptr, int n) { return __mex->realloc(ptr,n); } void mxFree(Pix ptr) { __mex->free(ptr); } void mexMakeMemoryPersistent(Pix ptr) { __mex->persistent(ptr); } mxArray* mxCreateDoubleMatrix(int nr, int nc, int iscomplex) { return __mex->make_value(nr, nc, iscomplex); } void mxDestroyArray(mxArray *v) { __mex->free(v); } void mexMakeArrayPersistent(mxArray *ptr) { __mex->persistent(ptr); } int mxIsChar (const mxArray* ptr) { return ptr->is_string(); } int mxIsSparse (const mxArray* ptr) { return ptr->is_sparse(); } int mxIsFull(const mxArray* ptr) { return !ptr->is_sparse(); } int mxIsNumeric (const mxArray* ptr) { return ptr->is_numeric(); } int mxIsComplex (const mxArray* ptr) { return ptr->is_complex(); } int mxIsDouble (const mxArray* ptr) { return true; } int mxIsEmpty (const mxArray* ptr) { return ptr->is_empty(); } Pix mxGetPr (const mxArray* ptr) { return ptr->real(); } Pix mxGetPi (const mxArray* ptr) { return ptr->imag(); } int mxGetM (const mxArray* ptr) { return ptr->rows(); } int mxGetN (const mxArray* ptr) { return ptr->columns(); } void mxSetM (mxArray* ptr, const int M) { return ptr->rows(M); } void mxSetN (mxArray* ptr, const int N) { return ptr->columns(N); } void mxSetPr (mxArray* ptr, Pix pr) { ptr->real((double *)pr); } void mxSetPi (mxArray* ptr, Pix pi) { ptr->imag((double *)pi); } double mxGetScalar (const mxArray* ptr) { double *pr = ptr->real(); if (pr) return pr[0]; else mexErrMsgTxt("calling mxGetScalar on an empty matrix"); } int mxGetString (const mxArray* ptr, char *buf, int buflen) { if (ptr->is_string()) { const int nr = ptr->rows(); const int nc = ptr->columns(); const int n = nr*nc > buflen ? nr*nc : buflen; const double *pr = ptr->real(); for (int i = 0; i < n; i++) buf[i] = NINT(pr[i]); if (n < buflen) buf[n] = '\0'; return n >= buflen; } else return 1; } char *mxArrayToString (const mxArray* ptr) { const int nr = ptr->rows(); const int nc = ptr->columns(); const int n = nr*nc*sizeof(mxChar)+1; char *buf = (char *)mxMalloc(n); if (buf) mxGetString(ptr, buf, n); return buf; } mxArray *mxCreateString(const char *str) { const int n = strlen(str); mxArray *m = __mex->make_value(1, n, 0); if (m==NULL) return m; m->is_string(true); double *pr = m->real(); for (int i=0; i < n; i++) pr[i] = str[i]; return m; } mxArray *mxCreateCharMatrixFromStrings (int n, const char **str) { // Find length of the individual strings Array<int> len(n); for (int i=0; i < n; i++) len(i) = strlen(str[i]); // Find maximum length int maxlen = 0; for (int i=0; i < n; i++) if (len(i) > maxlen) maxlen = len(i); // Need a place to copy them mxArray *m = __mex->make_value(n, maxlen, 0); if (m==NULL) return m; m->is_string(true); // Do the copy (being sure not to exceed the length of any of the // strings) double *pr = m->real(); for (int j = 0; j < maxlen; j++) for (int i = 0; i < n; i++) if (j < len(i)) *pr++ = str[i][j]; else *pr++ = '\0'; return m; } int mexPutArray(mxArray *ptr, const char *space) { if (ptr == NULL) return 1; const char *name = ptr->name(); if (name[0]=='\0') return 1; if (strcmp(space,"global") == 0) set_global_value (name, ptr->as_octave_value()); else if (strcmp(space,"caller") == 0) { // XXX FIXME XXX --- this belongs in variables.cc symbol_record *sr = curr_sym_tab->lookup (name, true); if (sr) sr->define(ptr->as_octave_value()); else panic_impossible (); } else if (strcmp(space,"base") == 0) mexErrMsgTxt("mexPutArray: 'base' symbol table not implemented"); else mexErrMsgTxt("mexPutArray: symbol table does not exist"); } mxArray *mexGetArray(const char *name, const char *space) { // XXX FIXME XXX --- this should be in variable.cc, but the correct // functionality is not exported. Particularly, get_global_value() // generates an error if the symbol is undefined. symbol_record *sr; if (strcmp(space,"global") == 0) sr = global_sym_tab->lookup (name); else if (strcmp(space,"caller") == 0) sr = curr_sym_tab->lookup (name); else if (strcmp(space,"base") == 0) mexErrMsgTxt("mexGetArray: 'base' symbol table not implemented"); else mexErrMsgTxt("mexGetArray: symbol table does not exist"); if (sr) { #if defined(HAVE_OCTAVE_20) octave_value sr_def = sr->variable_value(); #else octave_value sr_def = sr->def (); #endif if (!sr_def.is_undefined ()) { mxArray* ptr = __mex->make_value(sr_def); ptr->name(name); return ptr; } else return NULL; } else return NULL; } mxArray *mexGetArrayPtr(const char *name, const char *space) { return mexGetArray(name, space); } const char* mxGetName(const mxArray* ptr) { return ptr->name(); } void mxSetName(mxArray* ptr, const char*nm) { ptr->name(nm); } } ; /* ============ Fortran interface to mex functions ============== */ // Where possible, these call the equivalent C function since that API is // fixed. It costs and extra function call, but is easier to maintain. extern "C" { void F77_FCN(mexerrmsgtxt, MEXERRMSGTXT) (const char *s, const int slen) { if (slen > 1 || (slen == 1 && s[0] != ' ') ) error("%s: %.*s", mexFunctionName, slen, s); else error(""); // just set the error state; don't print msg __mex->abort(); } void F77_FCN(mexprintf,MEXPRINTF) (const char *s, const int slen) { mexPrintf("%.*s\n", slen, s); } double F77_FCN(mexgeteps,MEXGETEPS)() { return mxGetEps(); } double F77_FCN(mexgetinf,MEXGETINF)() { return mxGetInf(); } double F77_FCN(mexgetnan,MEXGETNAN)() { return mxGetNaN(); } int F77_FCN(mexisfinite,MEXISFINITE)(double v) { return mxIsFinite(v); } int F77_FCN(mexisinf,MEXISINF)(double v) { return mxIsInf(v); } int F77_FCN(mexisnan,MEXISNAN)(double v) { return mxIsNaN(v); } // ====> Array access Pix F77_FCN(mxcreatefull,MXCREATEFULL) (const int& nr, const int& nc, const int& iscomplex) { return mxCreateDoubleMatrix(nr,nc,iscomplex); } void F77_FCN(mxfreematrix,MXFREEMATRIX) (mxArray* &ptr) { mxDestroyArray(ptr); } Pix F77_FCN(mxcalloc,MXCALLOC)(const int& n, const int& size) { return mxCalloc(n,size); } void F77_FCN(mxfree,MXFREE) (const Pix &ptr) { mxFree(ptr); } int F77_FCN(mxgetm,MXGETM) (const mxArray* &ptr) { return mxGetM(ptr); } int F77_FCN(mxgetn,MXGETN) (const mxArray* &ptr) { return mxGetN(ptr); } Pix F77_FCN(mxgetpi,MXGETPI) (const mxArray* &ptr) { return mxGetPi(ptr); } Pix F77_FCN(mxgetpr,MXGETPR) (const mxArray* &ptr) { return mxGetPr(ptr); } void F77_FCN(mxsetm,MXSETM) (mxArray* &ptr, const int& m) { mxSetM(ptr, m); } void F77_FCN(mxsetn,MXSETN) (mxArray* &ptr, const int& n) { mxSetN(ptr, n); } void F77_FCN(mxsetpi,MXSETPI) (mxArray* &ptr, Pix &pi) { mxSetPi(ptr, pi); } void F77_FCN(mxsetpr,MXSETPR) (mxArray* &ptr, Pix &pr) { mxSetPr(ptr, pr); } int F77_FCN(mxiscomplex,MXISCOMPLEX) (const mxArray* &ptr) { return mxIsComplex(ptr); } int F77_FCN(mxisdouble,MXISDOUBLE) (const mxArray* &ptr) { return mxIsDouble(ptr); } int F77_FCN(mxisnumeric,MXISNUMERIC) (const mxArray* &ptr) { return mxIsNumeric(ptr); } int F77_FCN(mxisfull,MXISFULL) (const mxArray* &ptr) { return 1 - mxIsSparse(ptr); } int F77_FCN(mxissparse,MXISSPARSE) (const mxArray* &ptr) { return mxIsSparse(ptr); } int F77_FCN(mxisstring,MXISSTRING) (const mxArray* &ptr) { return mxIsChar(ptr); } int F77_FCN(mxgetstring,MXGETSTRING) (const mxArray* &ptr, char *str, const int& len) { return mxGetString(ptr, str, len); } int F77_FCN(mexcallmatlab,MEXCALLMATLAB) (const int& nargout, mxArray** argout, const int& nargin, const mxArray** argin, const char* fname, const int fnamelen) { char str[mxMAXNAM+1]; strncpy(str, fname, fnamelen<mxMAXNAM?fnamelen:mxMAXNAM); str[fnamelen] = '\0'; return mexCallMATLAB(nargout, argout, nargin, argin, str); } // ======> Fake pointer support void F77_FCN(mxcopyreal8toptr,MXCOPYREAL8TOPTR) (const double *d, const int& prref, const int& len) { TRACEFN; double *pr = (double *)prref; for (int i=0; i < len; i++) pr[i] = d[i]; } void F77_FCN(mxcopyptrtoreal8,MXCOPYPTRTOREAL8) (const int& prref, double *d, const int& len) { TRACEFN; double *pr = (double *)prref; for (int i=0; i < len; i++) d[i] = pr[i]; } void F77_FCN(mxcopycomplex16toptr,MXCOPYCOMPLEX16TOPTR) (const double *d, int& prref, int& piref, const int& len) { TRACEFN; double *pr = (double *)prref; double *pi = (double *)piref; for (int i=0; i < len; i++) pr[i] = d[2*i], pi[i] = d[2*i+1]; } void F77_FCN(mxcopyptrtocomplex16,MXCOPYPTRTOCOMPLEX16) (const int& prref, const int& piref, double *d, const int& len) { TRACEFN; double *pr = (double *)prref; double *pi = (double *)piref; for (int i=0; i < len; i++) d[2*i]=pr[i], d[2*i+1] = pi[i]; } } ;