Mercurial > forge
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extra/mex/mex.cc Wed Oct 10 19:54:49 2001 +0000 @@ -0,0 +1,1002 @@ +// 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]; + } + +} ;