Here's my solution to this problem. (I've used this solution for a while.)
Icon code:
----------
# Dynamically-loaded procedure to do C's "sprintf(format,x)".
procedure sprintf1(a[])
return (sprintf1 := pathload("libCutils.so","isprintf"))!a
end
C code (really, RTL, has to be run through "rtt")
--------------------
#include "Icon2C.h"
int isprintf(int argc, struct descrip argv[]) {
char cs[32];
ArgString(1); ArgReal(2);
sprintf(cs, StringVal(argv[1]), RealVal(argv[2]));
/* RTL hiding inside this macro: */
RetString(cs);
}
The whole "trick" is in the Icon2c.h file, which is my replacement of the
standard "icall.h". I append this file below.
Kostas
============================================================================
/*
===================================
ICON PROCEDURES CALLING C FUNCTIONS
===================================
0. Declaration of the C function.
1. Entering the C function:
a. Checking and converting arguments
b. Getting the C values
2. Allocations of Icon structures
3. Returning to Icon
NOTE: a C routine *must* contain code for *all* of the above
steps, as some macros assume that others have been called before
them. In particular, 1b depends on 1a, and 2 on 1.
*/
/*
0. Declaration of the C function.
=================================
To allow dynamic loading by Icon, the C function *must* be declared as
int func(int argc, dptr argv)
or like
int func(int argc, struct descrip argv[])
See src/runtime/fload.r.
The call of this in Icon looks like "func(x,y,z,...)".
*/
/*
1a. Entering the C function: checking and converting arguments
=============================================================
This is the most conceptually difficult part. Familiarity with the
implementation book is necessary! Also some familiarity with RTL.
We have to check the types of the Icon descriptors and "convert" them.
To understand the details, see the functions cnv_int(), cnv_real(), cnv_str()
in runtime/cnv.r. They convert a source descriptor "s" to a destination
descriptor "d", and return 1 on success and 0 on failure.
Instead of the following macros one could have used the functions cnv_c_int(),
cnv_c_dbl(), cnv_c_str() (see runtime/cnv.r), plus error checking.
*/
#define ArgInteger(i) do { if (argc < (i)) FailCode(101); \
if (!cnv_int(&argv[i],&argv[i])) ArgError(i,101); } while(0)
#define ArgReal(i) \
do {if (argc < (i)) FailCode(102); \
if (!cnv_real(&argv[i],&argv[i])) ArgError(i,102); \
} while(0);
#define ArgString(i) \
do {if (argc < (i)) FailCode(103); \
if (!cnv_str(&argv[i],&argv[i])) ArgError(i,103); \
} while(0);
#define ArgList(i) \
do {if (argc < (i)) FailCode(101); \
if (argv[i].dword != D_List) ArgError(i,108); \
} while(0);
#define ListLen(d) ((d).vword.bptr->list.size)
/*
1b. Entering the C function: getting the C values
=============================================================
Here we get C values out of Icon descriptors.
The following macros *assume* that the descriptor conversions in 1a above have
taken place.
*/
#define IntegerVal(d) ((d).vword.integr)
#define RealVal(d) getdbl(&(d))
#define StringVal(d) \
(*(char*)((d).vword.sptr+(d).dword) ? cnv_c_str(&(d),&(d)) : 0,
(char*)((d).vword.sptr))
/*
Given an Icon list descrip "d", fill the C array of ints "a".
Using cpslots() shortens the necessary code, and takes care of lists that
have been constructed or modified by put() and get(), etc.
*/
#define IListVal(d,a) \
do {if (sizeof(a[0]) != sizeof(int)) FailCode(101); \
register int n = ListLen(d); \
register int i; \
struct descrip slot[n]; \
cpslots(&(d),&slot[0],1,n+1); \
for(i=0; i<n; i++) a[i] = IntegerVal(slot[i]); \
} while(0);
/* Given an Icon list descrip "d", fill the C array of doubles "a". */
#define RListVal(d,a) \
do {if (sizeof(a[0]) != sizeof(double)) FailCode(102); \
register int n = ListLen(d); \
register int i; \
struct descrip slot[n]; \
cpslots(&(d),&slot[0],1,n+1); \
for (i=0; i<n; i++) a[i] = RealVal(slot[i]); \
} while(0);
/*
2. Allocations of Icon structures.
=============================================================
The point here is this: if memory is allocated dynamically inside a C routine
for an Icon structure, say for a block holding a real, the request for space
to the Icon run-time system may trigger a garbage collection. The garbage
collector must be able to recognize and save all values that might be
referenced after the collection. Otherwise bugs that are virtually impossible
to find will ensue.
The garbage collector is informed by declaring pointers as "tended". See
section 4.2 of the RTL paper (The Run-Time Implemenation Language for Icon).
E.g. if "d" is a C double,
tended struct b_real *bp;
Protect(bp = alcreal(d), ReturnErrNum(307,Error));
The Protect() macro checks that the request for space succeeded. It is
defined in h/grttin.h.
If a C routine wants to return an Icon real or string, the allocation occurs
inside the macros RetReal() and RetString() below.
For allocating lists of integers and reals see
mkIlist() and mkRlist()
in "mklist.r" here.
*/
/*
3. Returning from the C function to Icon.
=============================================================
*/
/* A dynamically-loaded C function returns 0 on success, -1 on failure,
or a positive error code. */
#define FailCode(n) return n;
/* Return argv[i] as offending value for error code n */
#define ArgError(i,n) return (argv[0] = argv[i], n)
/* Integers, reals, strings, lists */
#define RetInteger(n) \
return (argv->dword = D_Integer, argv->vword.integr = n, 0)
/* Given a C double "x", return an Icon real to the calling routine. */
#define RetReal(x) do { \
tended struct b_real *d; \
Protect(d = alcreal(x), ReturnErrNum(307,Error)); \
return (argv->dword = D_Real, argv->vword.bptr = (union block *)d, 0); \
} while(0);
/* Given a C string "s", return an Icon string to the calling routine. */
#define RetString(s) do { \
tended struct descrip d; \
int len = strlen(s); \
Protect(StrLoc(d) = alcstr(s,len), ReturnErrNum(306,Error)); \
StrLen(d) = len; \
return (argv->dword = StrLen(d), argv->vword.sptr = StrLoc(d), 0); \
} while (0);
#define RetConstString(s) \
return (argv->dword = strlen(s), argv->vword.sptr = s, 0)
/* Here L is supposed to be L = mkIlist(...) or L = mkRlist(...). */
#define RetList(L) \
return (argv[0].dword = D_List, argv[0].vword.bptr = (union block *)L, 0)
-------------------------------------------------------
This SF.Net email is sponsored by: INetU
Attention Web Developers & Consultants: Become An INetU Hosting Partner.
Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission!
INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php
_______________________________________________
Unicon-group mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/unicon-group