#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include "wcs.h" #include "util.h" static int perly_unpacking = 1; /* state variable */ /* * Is argument a Perl reference? To a scalar? */ int is_scalar_ref (SV* arg) { if (!SvROK(arg)) return 0; if (SvPOK(SvRV(arg))) return 1; else return 0; } /* * Swap values in a long array inplace. */ void swap_dims(int ndims, long * dims) { int i; long tmp; for (i=0; i= 0) perly_unpacking=value; return perly_unpacking; } /* * Packs a Perl array reference into the appropriate C datatype */ void* pack1D ( SV* arg, int datatype ) { int size; char * stringscalar; logical logscalar; byte bscalar; unsigned short usscalar; short sscalar; unsigned int uiscalar; int iscalar; unsigned long ulscalar; long lscalar; float fscalar; double dscalar; float cmpval[2]; double dblcmpval[2]; AV* array; I32 i,n; SV* work; SV** work2; double nval; STRLEN len; if (arg == &PL_sv_undef) return (void *) NULL; if (is_scalar_ref(arg)) /* Scalar ref */ return (void*) SvPV(SvRV(arg), len); size = sizeof_datatype(datatype); work = sv_2mortal(newSVpv("", 0)); /* Is arg a scalar? Return scalar*/ if (!SvROK(arg) && SvTYPE(arg)!=SVt_PVGV) { switch (datatype) { case TSTRING: return (void *) SvPV(arg,PL_na); case TLOGICAL: logscalar = SvIV(arg); sv_setpvn(work, (char *) &logscalar, size); break; case TBYTE: bscalar = SvIV(arg); sv_setpvn(work, (char *) &bscalar, size); break; case TUSHORT: usscalar = SvIV(arg); sv_setpvn(work, (char *) &usscalar, size); break; case TSHORT: sscalar = SvIV(arg); sv_setpvn(work, (char *) &sscalar, size); break; case TUINT: uiscalar = SvIV(arg); sv_setpvn(work, (char *) &uiscalar, size); break; case TINT: iscalar = SvIV(arg); sv_setpvn(work, (char *) &iscalar, size); break; case TULONG: ulscalar = SvIV(arg); sv_setpvn(work, (char *) &ulscalar, size); break; case TLONG: lscalar = SvIV(arg); sv_setpvn(work, (char *) &lscalar, size); break; case TFLOAT: fscalar = SvNV(arg); sv_setpvn(work, (char *) &fscalar, size); break; case TDOUBLE: dscalar = SvNV(arg); sv_setpvn(work, (char *) &dscalar, size); break; case TCOMPLEX: warn("pack1D - packing scalar into TCOMPLEX...setting imaginary component to zero"); cmpval[0] = SvNV(arg); cmpval[1] = 0.0; sv_setpvn(work, (char *) cmpval, size); break; case TDBLCOMPLEX: warn("pack1D - packing scalar into TDBLCOMPLEX...setting imaginary component to zero"); dblcmpval[0] = SvNV(arg); dblcmpval[1] = 0.0; sv_setpvn(work, (char *) dblcmpval, size); break; default: croak("pack1D() scalar code: unrecognized datatype (%d) was passed",datatype); } return (void *) SvPV(work,PL_na); } /* Is it a glob or reference to an array? */ if (SvTYPE(arg)==SVt_PVGV || (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV)) { if (SvTYPE(arg)==SVt_PVGV) array = (AV *) GvAVn((GV*) arg); /* glob */ else array = (AV *) SvRV(arg); /* reference */ n = av_len(array) + 1; switch (datatype) { case TSTRING: SvGROW(work, size * n); for (i=0; i=0; i--) { if (places[i] >= dims[i]) { places[i] = 0; places[i-1]++; } else break; } } free(places); free(avs); } /* * Set argument's value to (copied) data. */ void unpack2scalar ( SV * arg, void * var, long n, int datatype ) { long data_length; if (datatype == TSTRING) croak("unpack2scalar() - how did you manage to call me with a TSTRING datatype?!"); data_length = n * sizeof_datatype(datatype); /*sv_setpvn(arg, (char *)var, data_length);*/ /* TBYTEs were screwy */ SvGROW(arg, data_length); memcpy(SvPV(arg,PL_na), var, data_length); return; } /* * Takes a pointer to a single value of any given type, puts * that value into the passed Perl scalar * * Note that type TSTRING does _not_ imply a (char **) was passed, * but rather a (char *). */ void unpackScalar(SV * arg, void * var, int datatype) { SV* tmp_sv[2]; if (var == NULL) { sv_setpvn(arg,"",0); return; } switch (datatype) { case TSTRING: sv_setpv(arg,(char *)var); break; case TLOGICAL: sv_setiv(arg,(IV)(*(logical *)var)); break; case TBYTE: sv_setiv(arg,(IV)(*(byte *)var)); break; case TUSHORT: sv_setiv(arg,(IV)(*(unsigned short *)var)); break; case TSHORT: sv_setiv(arg,(IV)(*(short *)var)); break; case TUINT: sv_setiv(arg,(IV)(*(unsigned int *)var)); break; case TINT: sv_setiv(arg,(IV)(*(int *)var)); break; case TULONG: sv_setiv(arg,(IV)(*(unsigned long *)var)); break; case TLONG: sv_setiv(arg,(IV)(*(long *)var)); break; case TFLOAT: sv_setnv(arg,(double)(*(float *)var)); break; case TDOUBLE: sv_setnv(arg,(double)(*(double *)var)); break; case TCOMPLEX: tmp_sv[0] = newSVnv(*((float *)var)); tmp_sv[1] = newSVnv(*((float *)var+1)); sv_setsv(arg,newRV_noinc((SV*)av_make(2,tmp_sv))); SvREFCNT_dec(tmp_sv[0]); SvREFCNT_dec(tmp_sv[1]); break; case TDBLCOMPLEX: tmp_sv[0] = newSVnv(*((double *)var)); tmp_sv[1] = newSVnv(*((double *)var+1)); sv_setsv(arg,newRV_noinc((SV*)av_make(2,tmp_sv))); SvREFCNT_dec(tmp_sv[0]); SvREFCNT_dec(tmp_sv[1]); break; default: croak("unpackScalar() - invalid type (%d) given",datatype); } return; } void unpack1D ( SV * arg, void * var, long n, int datatype ) { char ** stringvar; logical * logvar; byte * bvar; unsigned short * usvar; short * svar; unsigned int * uivar; int * ivar; unsigned long * ulvar; long * lvar; float * fvar; double * dvar; SV *tmp_sv[2]; AV *array; I32 i,m; if (!PerlyUnpacking(-1) && datatype != TSTRING) { unpack2scalar(arg,var,n,datatype); return; } m=n; array = coerce1D( arg, m ); /* This could screw up routines like fits_read_imghdr */ /* if (m==0) m = av_len(array)+1; */ switch (datatype) { case TSTRING: /* array of strings, I suppose */ stringvar = (char **)var; for (i=0; i