#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include "fitsio.h" #include "util.h" /* newSVuv seems to be perl 5.6.0-ism */ #ifndef newSVuv #define newSVuv newSViv #endif static int perly_unpacking = 1; /* state variable */ /* * Get the width of a string column in an ASCII or binary table */ long column_width(fitsfile * fptr, int colnum) { int hdutype, status=0, tfields; long repeat, size; long start_col,end_col; /* starting and ending positions for ASCII tables */ long rowlen, nrows, *tbcol; char typechar[FLEN_VALUE]; fits_get_hdu_type(fptr,&hdutype,&status); check_status(status); switch (hdutype) { case ASCII_TBL: /* Get starting column of field */ fits_get_acolparms( fptr,colnum,NULL,&start_col,NULL,NULL,NULL,NULL,NULL,NULL, &status ); check_status(status); /* Get length of each row and number of fields */ fits_read_atblhdr( fptr,0,&rowlen,&nrows,&tfields,NULL,NULL,NULL,NULL,NULL,&status ); check_status(status); if (colnum == tfields) { end_col = rowlen + 1; } else { tbcol = get_mortalspace(tfields,TLONG); fits_read_atblhdr( fptr,tfields,&rowlen,&nrows,&tfields,NULL, tbcol,NULL,NULL,NULL,&status ); check_status(status); end_col = tbcol[colnum] + 1; } size = end_col - start_col; break; /* Get the typechar parameter, which should be of form 'An', where * n is an the width of the field */ case BINARY_TBL: fits_get_bcolparms( fptr,colnum,NULL,NULL,typechar,&repeat,NULL,NULL, NULL,NULL,&status ); check_status(status); if (typechar[0] != 'A') { /* perhaps variable size? */ fits_read_key_lng(fptr,"NAXIS2",&rowlen,NULL,&status); check_status(status); size = rowlen+1; } else size = repeat; break; default: croak("column_width() - unrecognized HDU type (%d)",hdutype); } return size; } /* * croaks() if the argument is non-zero, useful for checking on cfitsio * routines. */ void check_status(int status) { if (status != 0) { fits_report_error(stderr,status); croak("cfitsio library detected an error...I'm outta here"); } } /* * 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; sbyte sbscalar; byte bscalar; unsigned short usscalar; short sscalar; unsigned int uiscalar; int iscalar; unsigned long ulscalar; long lscalar; LONGLONG llscalar; float fscalar; double dscalar; float cmpval[2]; double dblcmpval[2]; AV* array; I32 i,n; SV* work; SV** work2; 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 TSBYTE: sbscalar = SvIV(arg); sv_setpvn(work, (char *) &sbscalar, size); break; case TBYTE: bscalar = SvUV(arg); sv_setpvn(work, (char *) &bscalar, size); break; case TUSHORT: usscalar = SvUV(arg); sv_setpvn(work, (char *) &usscalar, size); break; case TSHORT: sscalar = SvIV(arg); sv_setpvn(work, (char *) &sscalar, size); break; case TUINT: uiscalar = SvUV(arg); sv_setpvn(work, (char *) &uiscalar, size); break; case TINT: iscalar = SvIV(arg); sv_setpvn(work, (char *) &iscalar, size); break; case TULONG: ulscalar = SvUV(arg); sv_setpvn(work, (char *) &ulscalar, size); break; case TLONG: lscalar = SvIV(arg); sv_setpvn(work, (char *) &lscalar, size); break; case TLONGLONG: llscalar = SvIV(arg); sv_setpvn(work, (char *) &llscalar, 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; if (i>0) places[i-1]++; } else break; } } free(places); free(avs); } void unpackND (SV* arg, void* var, int ndims, long *dims, int datatype, int perlyunpack) { LONGLONG* dimsll = malloc(ndims*sizeof(LONGLONG)); int i; for (i=0; i