/*
Macros used to generate fortran compatible bindings for the C api.
These macros generate customized wrapper functions based on the determined
characteristics of the fortran compiler.
@author Peter Smith
*/
#ifndef __FORTRAN_API_H__
#define __FORTRAN_API_H__
#include <string.h>
/*
* These definitions control how the fortran function name is generated. One of
* FORTRAN_API_UPPERCASE, FORTRAN_API_LOWERCASE, or FORTRAN_API_NOCASE should be
* defined prior to inclusion, otherwise it will will default to upper case.
* Additionally, FORTRAN_API_PREFIX and FORTRAN_API_SUFFIX can be used to add
* leading or trailing characters to the exported function names (e.g. underscores)
*/
#if !defined(FORTRAN_API_UPPERCASE) && !defined(FORTRAN_API_LOWERCASE) && !defined(FORTRAN_API_NOCASE)
#define FORTRAN_API_UPPERCASE 1
#endif
#ifndef FORTRAN_API_PREFIX
#define FORTRAN_API_PREFIX
#endif
#ifndef FORTRAN_API_SUFFIX
#define FORTRAN_API_SUFFIX
#endif
/*
* Set up the macro to select the appropriate case for naming the fortan functions.
*/
#if FORTRAN_API_UPPERCASE
#define FORTRAN_API_NAME_SELECT(a,b,c) b
#elif FORTRAN_API_LOWERCASE
#define FORTRAN_API_NAME_SELECT(a,b,c) c
#else
#define FORTRAN_API_NAME_SELECT(a,b,c) a
#endif
/*
* Set up macros for mapping API 'types' to actual langauge types. These can be
* prefined if necessary.
*/
#ifndef FORTRAN_API_TYPE_INT32
#define FORTRAN_API_TYPE_INT32 int
#endif
#ifndef FORTRAN_API_TYPE_INT
#define FORTRAN_API_TYPE_INT int
#endif
#ifndef FORTRAN_API_TYPE_FLOAT64
#define FORTRAN_API_TYPE_FLOAT64 double
#endif
/************************************************************
All configuration control is above this point. Below
this are the code generation functions and macros.
************************************************************/
/*
* Thunking function to map a fixed length fortran string to a c-style null
* terminated string on input.
*/
static inline char* fortran_api_map_string_in(const char* i, unsigned FORTRAN_API_TYPE_INT maxlen) {
unsigned FORTRAN_API_TYPE_INT len = strlen(i);
char* o = malloc(maxlen + 1);
len = (len < maxlen) ? len : maxlen;
if (len == maxlen) while(len > 0 && i[len] == ' ') --len;
memcpy(o, i, len);
o[len] = 0;
return o;
}
/*
* Thunking function to map a c-style null terminated string to a fixed length fortran
* string on output.
*/
static inline void fortran_api_map_string_out(char* o, const char* i, unsigned FORTRAN_API_TYPE_INT maxlen) {
unsigned FORTRAN_API_TYPE_INT len = strlen(i);
len = (len < maxlen) ? len : maxlen;
memcpy(o, i, len);
while(len < maxlen) o[len++] = ' ';
}
/* Nested macro expansion (needed to support MS Visual C which has a more basic preprocessor) */
#define FORTRAN_API_EXPAND(x) x
/* Join simple strings */
#define FORTRAN_API_COMBINE2(A,B) A##B
#define FORTRAN_API_COMBINE3(A,B,C) A##B##C
/*
* Maros used to construct another macro name - for example,
* combining a macro prefix with a number to identify a macro that takes
* a specific number or arguments.
*/
#define FORTRAN_API_MAKENAME2(A,B) FORTRAN_API_COMBINE2(A,B)
#define FORTRAN_API_MAKENAME3(A,B,C) FORTRAN_API_COMBINE3(A,B,C)
/*
* Macros used to expand arguments to their appropriate type in an argument list.
*/
#define FORTRAN_API_ARG_PVOID void*
#define FORTRAN_API_ARG_STRING const char*
#define FORTRAN_API_ARG_PSTRING char*
#define FORTRAN_API_ARG_INT const FORTRAN_API_TYPE_INT*
#define FORTRAN_API_ARG_PINT FORTRAN_API_TYPE_INT*
#define FORTRAN_API_ARG_INT32 const FORTRAN_API_TYPE_INT32*
#define FORTRAN_API_ARG_PINT32 FORTRAN_API_TYPE_INT32*
#define FORTRAN_API_ARG_FLOAT64 const FORTRAN_API_TYPE_FLOAT64*
#define FORTRAN_API_ARG_PFLOAT64 FORTRAN_API_TYPE_FLOAT64*
/*
* Macros used to map types (e.g. 'OUT STRING' => 'PSTRING'). This just provides
* a convenience when declaring your API and makes it a bit clearer that it is an
* output value.
*/
#define FORTRAN_API_TYPEMAP_OUT _,P,
#define FORTRAN_API_TYPEMAP_JOIN23(_1,_2,_3,...) _2##_3
#define FORTRAN_API_TYPEMAP_JOIN(...) FORTRAN_API_EXPAND(FORTRAN_API_TYPEMAP_JOIN23(__VA_ARGS__))
#define FORTRAN_API_TYPEMAP(type) FORTRAN_API_TYPEMAP_JOIN(FORTRAN_API_COMBINE2(FORTRAN_API_TYPEMAP_, type),,type)
/*
* Macros used to generate argument lists. Primary arguments are prefixed with 'a', e.g.
* a1, a2, a3, ...
*/
#define FORTRAN_API_ARG_GENERATE(type) FORTRAN_API_EXPAND(FORTRAN_API_COMBINE2(FORTRAN_API_ARG_,type))
#define FORTRAN_API_ARG(type,n) FORTRAN_API_ARG_GENERATE(FORTRAN_API_TYPEMAP(type)) a##n
//#define FORTRAN_API_ARG(type,n) FORTRAN_API_EXPAND(FORTRAN_API_COMBINE2(FORTRAN_API_ARG_,type)) a##n
#define FORTRAN_API_ARGS1(t1) FORTRAN_API_ARG(t1,1)
#define FORTRAN_API_ARGS2(t1,t2) FORTRAN_API_ARGS1(t1), FORTRAN_API_ARG(t2,2)
#define FORTRAN_API_ARGS3(t1,t2,t3) FORTRAN_API_ARGS2(t1,t2), FORTRAN_API_ARG(t3,3)
#define FORTRAN_API_ARGS4(t1,t2,t3,t4) FORTRAN_API_ARGS3(t1,t2,t3), FORTRAN_API_ARG(t4,4)
#define FORTRAN_API_ARGS5(t1,t2,t3,t4,t5) FORTRAN_API_ARGS4(t1,t2,t3,t4), FORTRAN_API_ARG(t5,5)
#define FORTRAN_API_ARGS6(t1,t2,t3,t4,t5,t6) FORTRAN_API_ARGS5(t1,t2,t3,t4,t5), FORTRAN_API_ARG(t6,6)
#define FORTRAN_API_ARGS7(t1,t2,t3,t4,t5,t6,t7) FORTRAN_API_ARGS6(t1,t2,t3,t4,t5,t6), FORTRAN_API_ARG(t7,7)
#define FORTRAN_API_ARGS8(t1,t2,t3,t4,t5,t6,t7,t8) FORTRAN_API_ARGS7(t1,t2,t3,t4,t5,t6,t7), FORTRAN_API_ARG(t8,8)
#define FORTRAN_API_ARGS9(t1,t2,t3,t4,t5,t6,t7,t8,t9) FORTRAN_API_ARGS8(t1,t2,t3,t4,t5,t6,t7,t8), FORTRAN_API_ARG(t9,9)
#define FORTRAN_API_ARGS10(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) FORTRAN_API_ARGS9(t1,t2,t3,t4,t5,t6,t7,t8,t9), FORTRAN_API_ARG(t10,10)
#define FORTRAN_API_ARGS11(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11) FORTRAN_API_ARGS10(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10), FORTRAN_API_ARG(t11,11)
#define FORTRAN_API_ARGS12(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12) FORTRAN_API_ARGS11(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11), FORTRAN_API_ARG(t12,12)
#define FORTRAN_API_ARGS13(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13) FORTRAN_API_ARGS12(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12), FORTRAN_API_ARG(t13,13)
#define FORTRAN_API_ARGS14(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14) FORTRAN_API_ARGS13(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13), FORTRAN_API_ARG(t14,14)
#define FORTRAN_API_ARGS15(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15) FORTRAN_API_ARGS14(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14), FORTRAN_API_ARG(t15,15)
/*
* Macros used to generate the specific additional arguments based on the current
* argument type. Currently, only strings do this, and these ar prefixed with 'l'
* within an index that matches the primary argument. e.g. two string arguements
* in position 2 and 4 would create an additional two arguments l2, l4.
*/
#define FORTRAN_API_ARGX_PVOID(n)
#define FORTRAN_API_ARGX_STRING(n) , unsigned FORTRAN_API_TYPE_INT l##n
#define FORTRAN_API_ARGX_PSTRING(n) , unsigned FORTRAN_API_TYPE_INT l##n
#define FORTRAN_API_ARGX_INT(n)
#define FORTRAN_API_ARGX_PINT(n)
#define FORTRAN_API_ARGX_INT32(n)
#define FORTRAN_API_ARGX_PINT32(n)
#define FORTRAN_API_ARGX_FLOAT64(n)
#define FORTRAN_API_ARGX_PFLOAT64(n)
/*
* Macros used to generate extra arguments for input strings (in standard fortran calling
* convention, the length of a string is passed in as an additional argument to the function)
*/
#define FORTRAN_API_ARGX_GENERATE(type, n) FORTRAN_API_EXPAND(FORTRAN_API_COMBINE2(FORTRAN_API_ARGX_,type)(n))
#define FORTRAN_API_ARGX(type,n) FORTRAN_API_ARGX_GENERATE(FORTRAN_API_TYPEMAP(type),n)
//#define FORTRAN_API_ARGX(type,n) FORTRAN_API_EXPAND(FORTRAN_API_COMBINE2(FORTRAN_API_ARGX_,type)(n))
#define FORTRAN_API_ARGX1(t1) FORTRAN_API_ARGX(t1,1)
#define FORTRAN_API_ARGX2(t1,t2) FORTRAN_API_ARGX1(t1) FORTRAN_API_ARGX(t2,2)
#define FORTRAN_API_ARGX3(t1,t2,t3) FORTRAN_API_ARGX2(t1,t2) FORTRAN_API_ARGX(t3,3)
#define FORTRAN_API_ARGX4(t1,t2,t3,t4) FORTRAN_API_ARGX3(t1,t2,t