/* **************************************************************************** * Gambit-C foreign function interface Additions * * This file extends Gambit's gambit-c-2.2/run/c-intf.c file to * provide conversion from a 32-bit C integer to a Scheme gennum. That is, * if the C number is small enough, it is converted into FIXNUM, otherwise * a corresponding BIGNUM is created. There is also a function to go * the other way around. * * Note on BIGNUM representation in Gambit (see gambit-c-2.2/run/header.scm) * BIGNUM is a vector16 * elem 0 = sign (1 means positive, 0 means negative) * slot 1 = least significant digit (in radix 2^14) * slot 2... = other digits * Thus to pack a 32-bit unsigned integer (that is for sure bigger than 2^19-1) * we make-vector16 of four elements and set * elem[0] = 1 -- meaning positive BIGNUM * elem[1] = x % radix -- least significant digit in radix 2^14 * elem[2] = (x / radix) % radix -- next significant digit * elem[3] = x / radix^2 -- most significant digit * * $Id: c-intf-add.c,v 1.1 1996/05/03 16:12:03 oleg Exp oleg $ * **************************************************************************** */ #define ___VERSION 4 #include "gambit.h" /* Some definitions pertaining to FIXNUm and BIGNUM */ /* taken from run/header.scm */ /*(##define-macro (max-fixnum) 268435455) */ /* complement of the largest FIXNUM */ #define LARGEST_FIXNUM_COMPL (~(___INT(((unsigned int)(-1))))) /*(##define-macro (radix) 16384) ; must be <= sqrt(max fixnum)+1*/ #define RADIX_WIDTH 14 #define RADIX_MINUS_1 16383 /* Allocate a Scheme vector of size n (bytes) */ /* defined in gambit-c-2.2/run/c-intf.c */ extern ___WORD alloc_bvector(int n); /* Convert x to FIXNUM or BIGNUM (if big enough)*/ /* The following code supplants the function */ /* defined in gambit-c-2.2/run/c-intf.c */ /* Unlike the latter, the present function can */ /* handle BIGNUM numbers, too. */ /* The function always returns 0 (success) */ int ___uint_to_scmobj(const ___U32 x, ___WORD * obj) { if( x & LARGEST_FIXNUM_COMPL ) { /* x is too big: pack into BIGNUM */ const ___WORD vector = alloc_bvector(4*2); /* (##make-vector16 4) */ ___U16* vp = (___U16*)(vector-___tSUBTYPED+___WS); /* skip the 1st word: header */ *vp++ = 1; /* sign positive */ *vp++ = x & RADIX_MINUS_1; *vp++ = (x >> RADIX_WIDTH) & RADIX_MINUS_1; *vp++ = x >> (2*RADIX_WIDTH); ___HEADER(vector) = (___HEADER(vector)&___LMASK)+(___sBIGNUM<<___TB); return *obj = vector, 0; } else return *obj = ___FIX(x), 0; /* small enough to fit into FIXNUM */ } /* Convert BIGNUM into a "C" unsigned int */ /* (if fits, of course) */ /* If it doesn't, return 1 */ static int bignum_to_uint(const ___WORD bignum, unsigned int *xp) { register int i = (___VECTOR16LENGTH(bignum))>>___TB; /* in U16 words */ ___U16* dp = (___U16*)(bignum-___tSUBTYPED+___WS) + i;/* Digit pointer*/ unsigned int acc; while( --i > 0 && *--dp == 0 ) /* Skip leading zeros (if any) */ ; if( i == 0 ) return *xp = 0, 0; /* All digits are zero */ acc = *dp; if( i > 3 || ( i==3 && acc >= (1<<(32-2*RADIX_WIDTH)) ) ) return 1; /* BIGNUM is too big for int */ while( --i > 0 ) acc = (acc<