#define FORTRANOBJECT_C
#include "fortranobject.h"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
/*
This file implements: FortranObject, array_from_pyobj, copy_ND_array
Author: Pearu Peterson <pearu@cens.ioc.ee>
$Revision: 1.52 $
$Date: 2005/07/11 07:44:20 $
*/
int
F2PyDict_SetItemString(PyObject *dict, char *name, PyObject *obj)
{
if (obj == NULL) {
fprintf(stderr, "Error loading %s\n", name);
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
return -1;
}
return PyDict_SetItemString(dict, name, obj);
}
/*
* Python-only fallback for thread-local callback pointers
*/
void *
F2PySwapThreadLocalCallbackPtr(char *key, void *ptr)
{
PyObject *local_dict, *value;
void *prev;
local_dict = PyThreadState_GetDict();
if (local_dict == NULL) {
Py_FatalError(
"F2PySwapThreadLocalCallbackPtr: PyThreadState_GetDict "
"failed");
}
value = PyDict_GetItemString(local_dict, key);
if (value != NULL) {
prev = PyLong_AsVoidPtr(value);
if (PyErr_Occurred()) {
Py_FatalError(
"F2PySwapThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
}
}
else {
prev = NULL;
}
value = PyLong_FromVoidPtr((void *)ptr);
if (value == NULL) {
Py_FatalError(
"F2PySwapThreadLocalCallbackPtr: PyLong_FromVoidPtr failed");
}
if (PyDict_SetItemString(local_dict, key, value) != 0) {
Py_FatalError(
"F2PySwapThreadLocalCallbackPtr: PyDict_SetItemString failed");
}
Py_DECREF(value);
return prev;
}
void *
F2PyGetThreadLocalCallbackPtr(char *key)
{
PyObject *local_dict, *value;
void *prev;
local_dict = PyThreadState_GetDict();
if (local_dict == NULL) {
Py_FatalError(
"F2PyGetThreadLocalCallbackPtr: PyThreadState_GetDict failed");
}
value = PyDict_GetItemString(local_dict, key);
if (value != NULL) {
prev = PyLong_AsVoidPtr(value);
if (PyErr_Occurred()) {
Py_FatalError(
"F2PyGetThreadLocalCallbackPtr: PyLong_AsVoidPtr failed");
}
}
else {
prev = NULL;
}
return prev;
}
static PyArray_Descr *
get_descr_from_type_and_elsize(const int type_num, const int elsize) {
PyArray_Descr * descr = PyArray_DescrFromType(type_num);
if (type_num == NPY_STRING) {
// PyArray_DescrFromType returns descr with elsize = 0.
PyArray_DESCR_REPLACE(descr);
if (descr == NULL) {
return NULL;
}
descr->elsize = elsize;
}
return descr;
}
/************************* FortranObject *******************************/
typedef PyObject *(*fortranfunc)(PyObject *, PyObject *, PyObject *, void *);
PyObject *
PyFortranObject_New(FortranDataDef *defs, f2py_void_func init)
{
int i;
PyFortranObject *fp = NULL;
PyObject *v = NULL;
if (init != NULL) { /* Initialize F90 module objects */
(*(init))();
}
fp = PyObject_New(PyFortranObject, &PyFortran_Type);
if (fp == NULL) {
return NULL;
}
if ((fp->dict = PyDict_New()) == NULL) {
Py_DECREF(fp);
return NULL;
}
fp->len = 0;
while (defs[fp->len].name != NULL) {
fp->len++;
}
if (fp->len == 0) {
goto fail;
}
fp->defs = defs;
for (i = 0; i < fp->len; i++) {
if (fp->defs[i].rank == -1) { /* Is Fortran routine */
v = PyFortranObject_NewAsAttr(&(fp->defs[i]));
if (v == NULL) {
goto fail;
}
PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
Py_XDECREF(v);
}
else if ((fp->defs[i].data) !=
NULL) { /* Is Fortran variable or array (not allocatable) */
PyArray_Descr *
descr = get_descr_from_type_and_elsize(fp->defs[i].type,
fp->defs[i].elsize);
if (descr == NULL) {
goto fail;
}
v = PyArray_NewFromDescr(&PyArray_Type, descr, fp->defs[i].rank,
fp->defs[i].dims.d, NULL, fp->defs[i].data,
NPY_ARRAY_FARRAY, NULL);
if (v == NULL) {
Py_DECREF(descr);
goto fail;
}
PyDict_SetItemString(fp->dict, fp->defs[i].name, v);
Py_XDECREF(v);
}
}
return (PyObject *)fp;
fail:
Py_XDECREF(fp);
return NULL;
}
PyObject *
PyFortranObject_NewAsAttr(FortranDataDef *defs)
{ /* used for calling F90 module routines */
PyFortranObject *fp = NULL;
fp = PyObject_New(PyFortranObject, &PyFortran_Type);
if (fp == NULL)
return NULL;
if ((fp->dict = PyDict_New()) == NULL) {
PyObject_Del(fp);
return NULL;
}
fp->len = 1;
fp->defs = defs;
if (defs->rank == -1) {
PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("function %s", defs->name));
} else if (defs->rank == 0) {
PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("scalar %s", defs->name));
} else {
PyDict_SetItemString(fp->dict, "__name__", PyUnicode_FromFormat("array %s", defs->name));
}
return (PyObject *)fp;
}
/* Fortran methods */
static void
fortran_dealloc(PyFortranObject *fp)
{
Py_XDECREF(fp->dict);
PyObject_Del(fp);
}
/* Returns number of bytes consumed from buf, or -1 on error. */
static Py_ssize_t
format_def(char *buf, Py_ssize_t size, FortranDataDef def)
{
char *p = buf;
int i;
npy_intp n;
n = PyOS_snprintf(p, size, "array(%" NPY_INTP_FMT, def.dims.d[0]);
if (n < 0 || n >= size) {
return -1;
}
p += n;
size -= n;
for (i = 1; i < def.rank; i++) {
n = PyOS_snprintf(p, size, ",%" NPY_INTP_FMT, def.dims.d[i]);
if (n < 0 || n >= size) {
return -1;
}
p += n;
size -= n;
}
if (size <= 0) {
return -1;
}
*p++ = ')';
size--;
if (def.data == NULL) {
static const char notalloc[] = ", not allocated";
if ((size_t)size < sizeof(notalloc)) {
return -1;
}
memcpy(p, notalloc, sizeof(notalloc));
p += sizeof(notalloc);
size -= sizeof(notalloc);
}
return p - buf;
}
static PyObject *
fortran_doc(FortranDataDef def)
{
char *buf, *p;
PyObject *s = NULL;
Py_ssize_t n, origsize, size = 100;
if (def.doc != NULL) {
size += strlen(def.doc);
}
origsize = size;
buf = p = (char *)PyMem_Malloc(size);
if (buf == NULL) {
return PyErr_NoMemory();
}
if (def.rank == -1) {
if (def.doc) {
n = strlen(def.doc);
if (n > size) {
goto fail;
}
memcpy(p, def.doc, n);
p += n;
size -= n;
}
else {
n = PyOS_snprintf(p, size, "%s - no docs available", def.name);
if (n < 0 || n >= size) {
goto fail;
}
p += n;
size -= n;
}
}
else {
PyArray_Descr *d = PyArray_DescrFromType(def.type);
n = PyOS_snprintf(p, size, "%s : '%c'-", def.name, d->type);
Py_DECREF(d);
if (n < 0 || n >= size) {
goto fail;
}
p += n;
size -= n;
if (def.data == NULL) {
n = format_def(p, size, def);
if (n < 0) {
goto fail;
}
p += n;
size -= n;
}
else if (def.rank > 0) {
n = format_def(p, size, def);
if (n < 0) {
goto fail;
}
p += n;
size -= n;
}
else {
n = strlen("scalar");