/* -*-C-*- -------------------------------------------------------------------- | Module: wine.xs | | ---------------------------------------------------------------------------- | | Purpose: Perl gateway to wine API calls | | | | Functions: | | call_wine_API -- call a wine API function | | | ------------------------------------------------------------------------------*/ #include #include #include #include #include enum ret_type { RET_VOID = 0, RET_INT = 1, RET_WORD = 2, RET_PTR = 3 }; /* max arguments for a function call */ #define MAX_ARGS 16 extern unsigned long perl_call_wine ( char *module, char *function, int n_args, unsigned long *args, unsigned int *last_error, int debug ); /*---------------------------------------------------------------------- | XS module | | | | | ----------------------------------------------------------------------*/ MODULE = wine PACKAGE = wine # -------------------------------------------------------------------- # Function: call_wine_API # -------------------------------------------------------------------- # Purpose: Call perl_call_wine(), which calls a wine API function # # Parameters: module -- module (dll) to get function from # function -- API function to call # ret_type -- return type # debug -- debug flag # ... -- args to pass to API function # # Returns: list containing 2 elements: the last error code and the # value returned by the API function # -------------------------------------------------------------------- void call_wine_API(module, function, ret_type, debug, ...) char *module; char *function; int ret_type; int debug; PROTOTYPE: $$$$@ PPCODE: /*-------------------------------------------------------------- | Begin call_wine_API --------------------------------------------------------------*/ /* Local types */ struct arg { int ival; void *pval; }; /* Locals */ int n_fixed = 4; int n_args = (items - n_fixed); struct arg args[MAX_ARGS+1]; unsigned long f_args[MAX_ARGS+1]; unsigned int i, n; unsigned int last_error = 0xdeadbeef; char *p; SV *sv; unsigned long r; if (n_args > MAX_ARGS) croak("Too many arguments"); /*-------------------------------------------------------------- | Prepare function args --------------------------------------------------------------*/ if (debug) { fprintf( stderr, " [wine.xs/call_wine_API()]\n"); } for (i = 0; (i < n_args); i++) { sv = ST (n_fixed + i); args[i].pval = NULL; if (! SvOK (sv)) continue; /*-------------------------------------------------------------- | Ref --------------------------------------------------------------*/ if (SvROK (sv)) { sv = SvRV (sv); /*-------------------------------------------------------------- | Integer ref -- pass address of value --------------------------------------------------------------*/ if (SvIOK (sv)) { args[i].ival = SvIV (sv); f_args[i] = (unsigned long) &(args[i].ival); if (debug) { fprintf( stderr, " [RV->IV] 0x%lx\n", f_args[i]); } } /*-------------------------------------------------------------- | Number ref -- convert and pass address of value --------------------------------------------------------------*/ else if (SvNOK (sv)) { args[i].ival = (unsigned long) SvNV (sv); f_args[i] = (unsigned long) &(args[i].ival); if (debug) { fprintf( stderr, " [RV->NV] 0x%lx\n", f_args[i]); } } /*-------------------------------------------------------------- | String ref -- pass pointer --------------------------------------------------------------*/ else if (SvPOK (sv)) { f_args[i] = (unsigned long) ((char *) SvPV (sv, PL_na)); if (debug) { fprintf( stderr, " [RV->PV] 0x%lx\n", f_args[i]); } } } /*-------------------------------------------------------------- | Scalar --------------------------------------------------------------*/ else { /*-------------------------------------------------------------- | Integer -- pass value --------------------------------------------------------------*/ if (SvIOK (sv)) { f_args[i] = (unsigned long) SvIV (sv); if (debug) { fprintf( stderr, " [IV] %ld (0x%lx)\n", f_args[i], f_args[i]); } } /*-------------------------------------------------------------- | Number -- convert and pass value --------------------------------------------------------------*/ else if (SvNOK (sv)) { f_args[i] = (unsigned long) SvNV (sv); if (debug) { fprintf( stderr, " [NV] %ld (0x%lx)\n", f_args[i], f_args[i]); } } /*-------------------------------------------------------------- | String -- pass pointer to copy --------------------------------------------------------------*/ else if (SvPOK (sv)) { p = SvPV (sv, n); if ((args[i].pval = malloc( n+2 ))) { memcpy (args[i].pval, p, n); ((char *)(args[i].pval))[n] = 0; /* add final NULL */ ((char *)(args[i].pval))[n+1] = 0; /* and another one for Unicode too */ f_args[i] = (unsigned long) args[i].pval; if (debug) { fprintf( stderr, " [PV] 0x%lx\n", f_args[i]); } } } } } /* end for */ /*-------------------------------------------------------------- | Here we go --------------------------------------------------------------*/ r = perl_call_wine ( module, function, n_args, f_args, &last_error, debug ); /*-------------------------------------------------------------- | Handle modified parameter values | | There are four possibilities for parameter values: | | 1) integer value | 2) string value | 3) ref to integer value | 4) ref to string value | | In cases 1 and 2, the intent is that the values won't be | modified, because they're not passed by ref. So we leave | them alone here. | | In case 4, the address of the actual string buffer has | already been passed to the wine API function, which had | opportunity to modify it if it wanted to. So again, we | don't have anything to do here. | | The case we need to handle is case 3. For integers passed | by ref, we created a local containing the initial value, | and passed its address to the wine API function, which | (potentially) modified it. Now we have to copy the | (potentially) new value back to the Perl variable passed | in, using sv_setiv(). (Which will take fewer lines of code | to do than it took lines of comment to describe ...) --------------------------------------------------------------*/ for (i = 0; (i < n_args); i++) { sv = ST (n_fixed + i); if (! SvOK (sv)) continue; if (SvROK (sv) && (sv = SvRV (sv)) && SvIOK (sv)) { sv_setiv (sv, args[i].ival); } } /*-------------------------------------------------------------- | Put appropriate return value on the stack for Perl to pick | up --------------------------------------------------------------*/ EXTEND(SP,2); if (last_error != 0xdeadbeef) PUSHs(sv_2mortal(newSViv(last_error))); else PUSHs( &PL_sv_undef ); switch (ret_type) { case RET_VOID: PUSHs( &PL_sv_undef ); break; case RET_INT: PUSHs(sv_2mortal(newSViv( (int)r ))); break; case RET_WORD: PUSHs(sv_2mortal(newSViv( (int)r & 0xffff ))); break; case RET_PTR: PUSHs(sv_2mortal(newSVpv( (char *)r, 0 ))); break; default: croak( "Bad return type %d", ret_type ); break; } /*-------------------------------------------------------------- | Free up allocated memory --------------------------------------------------------------*/ for (i = 0; (i < n_args); i++) { if (args[i].pval) free(args[i].pval); } /*-------------------------------------------------------------- | End call_wine_API --------------------------------------------------------------*/ # -------------------------------------------------------------------- # Function: load_library # -------------------------------------------------------------------- # Purpose: Load a Wine library # # Parameters: module -- module (dll) to load # # Returns: module handle # -------------------------------------------------------------------- unsigned int load_library(module) char *module; PROTOTYPE: $