10
/* newSVuv seems to be perl 5.6.0-ism */
12
#define newSVuv newSViv
15
static int perly_unpacking = 1; /* state variable */
19
* Get the width of a string column in an ASCII or binary table
21
long column_width(fitsfile * fptr, int colnum) {
22
int hdutype, status=0, tfields;
24
long start_col,end_col; /* starting and ending positions for ASCII tables */
25
long rowlen, nrows, *tbcol;
26
char typechar[FLEN_VALUE];
28
fits_get_hdu_type(fptr,&hdutype,&status);
33
/* Get starting column of field */
35
fptr,colnum,NULL,&start_col,NULL,NULL,NULL,NULL,NULL,NULL,
40
/* Get length of each row and number of fields */
42
fptr,0,&rowlen,&nrows,&tfields,NULL,NULL,NULL,NULL,NULL,&status
46
if (colnum == tfields) {
50
tbcol = get_mortalspace(tfields,TLONG);
52
fptr,tfields,&rowlen,&nrows,&tfields,NULL,
53
tbcol,NULL,NULL,NULL,&status
56
end_col = tbcol[colnum] + 1;
58
size = end_col - start_col;
61
/* Get the typechar parameter, which should be of form 'An', where
62
* n is an the width of the field
66
fptr,colnum,NULL,NULL,typechar,&repeat,NULL,NULL,
70
if (typechar[0] != 'A') { /* perhaps variable size? */
71
fits_read_key_lng(fptr,"NAXIS2",&rowlen,NULL,&status);
79
croak("column_width() - unrecognized HDU type (%d)",hdutype);
85
* croaks() if the argument is non-zero, useful for checking on cfitsio
88
void check_status(int status) {
90
fits_report_error(stderr,status);
91
croak("cfitsio library detected an error...I'm outta here");
96
* Is argument a Perl reference? To a scalar?
98
int is_scalar_ref (SV* arg) {
101
if (SvPOK(SvRV(arg)))
108
* Swap values in a long array inplace.
110
void swap_dims(int ndims, long * dims) {
114
for (i=0; i<ndims/2; i++) {
116
dims[i] = dims[ndims-1-i];
117
dims[ndims-i-1] = tmp;
122
* Returns the current value of perly_unpacking, if argument is non-negative
123
* the perly_unpacking is set to that value, as well.
125
int PerlyUnpacking( int value ) {
127
perly_unpacking=value;
128
return perly_unpacking;
132
* Packs a Perl array reference into the appropriate C datatype
134
void* pack1D ( SV* arg, int datatype ) {
140
unsigned short usscalar;
142
unsigned int uiscalar;
144
unsigned long ulscalar;
157
if (arg == &PL_sv_undef)
158
return (void *) NULL;
160
if (is_scalar_ref(arg)) /* Scalar ref */
161
return (void*) SvPV(SvRV(arg), len);
163
size = sizeof_datatype(datatype);
165
work = sv_2mortal(newSVpv("", 0));
167
/* Is arg a scalar? Return scalar*/
168
if (!SvROK(arg) && SvTYPE(arg)!=SVt_PVGV) {
171
return (void *) SvPV(arg,PL_na);
173
logscalar = SvIV(arg);
174
sv_setpvn(work, (char *) &logscalar, size);
177
sbscalar = SvIV(arg);
178
sv_setpvn(work, (char *) &sbscalar, size);
182
sv_setpvn(work, (char *) &bscalar, size);
185
usscalar = SvUV(arg);
186
sv_setpvn(work, (char *) &usscalar, size);
190
sv_setpvn(work, (char *) &sscalar, size);
193
uiscalar = SvUV(arg);
194
sv_setpvn(work, (char *) &uiscalar, size);
198
sv_setpvn(work, (char *) &iscalar, size);
201
ulscalar = SvUV(arg);
202
sv_setpvn(work, (char *) &ulscalar, size);
206
sv_setpvn(work, (char *) &lscalar, size);
209
llscalar = SvIV(arg);
210
sv_setpvn(work, (char *) &llscalar, size);
214
sv_setpvn(work, (char *) &fscalar, size);
218
sv_setpvn(work, (char *) &dscalar, size);
221
warn("pack1D() - packing scalar into TCOMPLEX...setting imaginary component to zero");
222
cmpval[0] = SvNV(arg);
224
sv_setpvn(work, (char *) cmpval, size);
227
warn("pack1D() - packing scalar into TDBLCOMPLEX...setting imaginary component to zero");
228
dblcmpval[0] = SvNV(arg);
230
sv_setpvn(work, (char *) dblcmpval, size);
233
croak("pack1D() scalar code: unrecognized datatype (%d) was passed",datatype);
235
return (void *) SvPV(work,PL_na);
238
/* Is it a glob or reference to an array? */
239
if (SvTYPE(arg)==SVt_PVGV || (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV)) {
241
if (SvTYPE(arg)==SVt_PVGV)
242
array = (AV *) GvAVn((GV*) arg); /* glob */
244
array = (AV *) SvRV(arg); /* reference */
246
n = av_len(array) + 1;
250
SvGROW(work, size * n);
251
for (i=0; i<n; i++) {
252
if ((work2=av_fetch(array,i,0)) == NULL)
257
stringscalar = SvPV(*work2,PL_na);
259
sv_catpvn(work, (char *) &stringscalar, size);
263
SvGROW(work, size * n);
264
for (i=0; i<n; i++) {
265
if ((work2=av_fetch(array,i,0)) == NULL)
270
logscalar = (logical) SvIV(*work2);
272
sv_catpvn(work, (char *) &logscalar, size);
276
SvGROW(work, size * n);
277
for (i=0; i<n; i++) {
278
if ((work2=av_fetch(array,i,0)) == NULL)
283
sbscalar = (sbyte) SvIV(*work2);
285
sv_catpvn(work, (char *) &sbscalar, size);
289
SvGROW(work, size * n);
290
for (i=0; i<n; i++) {
291
if ((work2=av_fetch(array,i,0)) == NULL)
296
bscalar = (byte) SvUV(*work2);
298
sv_catpvn(work, (char *) &bscalar, size);
302
SvGROW(work, size * n);
303
for (i=0; i<n; i++) {
304
if ((work2=av_fetch(array,i,0)) == NULL)
309
usscalar = SvUV(*work2);
311
sv_catpvn(work, (char *) &usscalar, size);
315
SvGROW(work, size * n);
316
for (i=0; i<n; i++) {
317
if ((work2=av_fetch(array,i,0)) == NULL)
322
sscalar = SvIV(*work2);
324
sv_catpvn(work, (char *) &sscalar, size);
328
SvGROW(work, size * n);
329
for (i=0; i<n; i++) {
330
if ((work2=av_fetch(array,i,0)) == NULL)
335
uiscalar = SvUV(*work2);
337
sv_catpvn(work, (char *) &uiscalar, size);
341
SvGROW(work, size * n);
342
for (i=0; i<n; i++) {
343
if ((work2=av_fetch(array,i,0)) == NULL)
348
iscalar = SvIV(*work2);
350
sv_catpvn(work, (char *) &iscalar, size);
354
SvGROW(work, size * n);
355
for (i=0; i<n; i++) {
356
if ((work2=av_fetch(array,i,0)) == NULL)
361
ulscalar = SvUV(*work2);
363
sv_catpvn(work, (char *) &ulscalar, size);
367
SvGROW(work, size * n);
368
for (i=0; i<n; i++) {
369
if ((work2=av_fetch(array,i,0)) == NULL)
374
lscalar = SvIV(*work2);
376
sv_catpvn(work, (char *) &lscalar, size);
380
SvGROW(work, size * n);
381
for (i=0; i<n; i++) {
382
if ((work2=av_fetch(array,i,0)) == NULL)
387
llscalar = SvIV(*work2);
389
sv_catpvn(work, (char *) &llscalar, size);
395
SvGROW(work, size * n);
396
for (i=0; i<n; i++) {
397
if ((work2=av_fetch(array,i,0)) == NULL)
402
fscalar = SvNV(*work2);
404
sv_catpvn(work, (char *) &fscalar, size);
411
for (i=0; i<n; i++) {
412
if ((work2=av_fetch(array,i,0)) == NULL)
417
dscalar = SvNV(*work2);
419
sv_catpvn(work, (char *) &dscalar, size);
423
croak("pack1D() array code: unrecognized datatype (%d) was passed",datatype);
426
return (void *) SvPV(work, PL_na);
430
croak("pack1D() - can only handle scalar values or refs to 1D arrays of scalars");
433
void* packND ( SV* arg, int datatype ) {
437
if (arg == &PL_sv_undef)
438
return (void *) NULL;
440
if (is_scalar_ref(arg))
441
return (void*) SvPV(SvRV(arg), PL_na);
443
work = sv_2mortal(newSVpv("", 0));
444
pack_element(work, &arg, datatype);
445
return (void *) SvPV(work, PL_na);
449
/* Internal function of packND - pack an element recursively */
451
void pack_element(SV* work, SV** arg, int datatype) {
457
unsigned short usscalar;
459
unsigned int uiscalar;
461
unsigned long ulscalar;
471
size = sizeof_datatype(datatype);
473
/* Pack element arg onto work recursively */
475
/* Is arg a scalar? Pack and return */
476
if (arg==NULL || (!SvROK(*arg) && SvTYPE(*arg)!=SVt_PVGV)) {
479
stringscalar = arg ? SvPV(*arg,PL_na) : "";
480
sv_catpvn(work, (char *) &stringscalar, size);
483
logscalar = arg ? SvIV(*arg) : 0;
484
sv_catpvn(work, (char *) &logscalar, size);
487
sbscalar = arg ? SvIV(*arg) : 0;
488
sv_catpvn(work, (char *) &sbscalar, size);
491
bscalar = arg ? SvUV(*arg) : 0;
492
sv_catpvn(work, (char *) &bscalar, size);
495
usscalar = arg ? SvUV(*arg) : 0;
496
sv_catpvn(work, (char *) &usscalar, size);
499
sscalar = arg ? SvIV(*arg) : 0;
500
sv_catpvn(work, (char *) &sscalar, size);
503
uiscalar = arg ? SvUV(*arg) : 0;
504
sv_catpvn(work, (char *) &uiscalar, size);
507
iscalar = arg ? SvIV(*arg) : 0;
508
sv_catpvn(work, (char *) &iscalar,size);
511
ulscalar = arg ? SvUV(*arg) : 0;
512
sv_catpvn(work, (char *) &ulscalar, size);
515
lscalar = arg ? SvIV(*arg) : 0;
516
sv_catpvn(work, (char *) &lscalar, size);
519
llscalar = arg ? SvIV(*arg) : 0;
520
sv_catpvn(work, (char *) &llscalar, size);
525
fscalar = arg ? SvNV(*arg) : 0.0;
526
sv_catpvn(work, (char *) &fscalar, size);
531
dscalar = arg ? SvNV(*arg) : 0.0;
532
sv_catpvn(work, (char *) &dscalar, size);
535
croak("pack_element() - unrecognized datatype (%d) was passed",datatype);
539
/* Is it a glob or reference to an array? */
540
else if (SvTYPE(*arg)==SVt_PVGV || (SvROK(*arg) && SvTYPE(SvRV(*arg))==SVt_PVAV)) {
543
if (SvTYPE(*arg)==SVt_PVGV)
544
array = GvAVn((GV*)*arg); /* glob */
546
array = (AV *) SvRV(*arg); /* reference */
548
/* Pack each array element */
549
n = av_len(array) + 1;
551
pack_element(work, av_fetch(array, i, 0), datatype );
556
croak("pack_element() - can only handle scalars or refs to N-D arrays of scalars");
559
void unpack2D( SV * arg, void * var, long *dims, int datatype, int perlyunpack) {
562
char * tmp_var = (char *)var;
564
if (! PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
565
unpack2scalar(arg,var,dims[0]*dims[1],datatype);
569
coerce1D(arg,dims[0]);
570
array = (AV*)SvRV(arg);
572
skip = dims[1] * sizeof_datatype(datatype);
573
for (i=0;i<dims[0];i++) {
574
unpack1D(*av_fetch(array,i,0),tmp_var,dims[1],datatype,perlyunpack);
579
void unpack3D( SV * arg, void * var, long *dims, int datatype, int perlyunpack) {
583
char *tmp_var = (char *)var;
585
if (! PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
586
unpack2scalar(arg,var,dims[0]*dims[1]*dims[2],datatype);
590
coerce1D(arg,dims[0]);
591
array1 = (AV*)SvRV(arg);
593
skip = dims[2] * sizeof_datatype(datatype);
594
for (i=0; i<dims[0]; i++) {
595
tmp_sv = *av_fetch(array1,i,0);
596
coerce1D(tmp_sv,dims[1]);
597
array2 = (AV*)SvRV(tmp_sv);
598
for (j=0; j<dims[1]; j++) {
599
unpack1D(*av_fetch(array2,j,0),tmp_var,dims[2],datatype,perlyunpack);
606
* This routine is known to have problems
608
void unpackND ( SV * arg, void * var, int ndims, long *dims, int datatype,
611
OFF_T ndata, nbytes, written, *places, skip;
613
char *tmp_var = (char *)var;
615
/* number of pixels to read, number of bytes therein */
617
for (i=0;i<ndims;i++)
619
nbytes = ndata * sizeof_datatype(datatype);
621
if (! PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
622
unpack2scalar(arg,var,ndata,datatype);
626
places = calloc(ndims-1, sizeof(OFF_T));
627
avs = malloc((ndims-1) * sizeof(AV*));
629
coerceND(arg,ndims,dims);
631
avs[0] = (AV*)SvRV(arg);
632
skip = dims[ndims-1] * sizeof_datatype(datatype);
635
while (written < nbytes) {
637
for (i=1;i<ndims-1;i++)
638
avs[i] = (AV*)SvRV(*av_fetch(avs[i-1],places[i-1],0));
640
unpack1D(*av_fetch(avs[ndims-2],places[ndims-2],0),tmp_var,dims[ndims-1],datatype,perlyunpack);
645
for (i=ndims-2;i>=0; i--) {
646
if (places[i] >= dims[i]) {
660
* Set argument's value to (copied) data.
662
void unpack2scalar ( SV * arg, void * var, long n, int datatype ) {
665
if (datatype == TSTRING)
666
croak("unpack2scalar() - how did you manage to call me with a TSTRING datatype?!");
668
data_length = n * sizeof_datatype(datatype);
670
SvGROW(arg, data_length);
671
memcpy(SvPV(arg,PL_na), var, data_length);
677
* Takes a pointer to a single value of any given type, puts
678
* that value into the passed Perl scalar
680
* Note that type TSTRING does _not_ imply a (char **) was passed,
681
* but rather a (char *).
683
void unpackScalar(SV * arg, void * var, int datatype) {
692
sv_setpv(arg,(char *)var); break;
694
sv_setiv(arg,(IV)(*(logical *)var)); break;
696
sv_setiv(arg,(IV)(*(sbyte *)var)); break;
698
sv_setuv(arg,(UV)(*(byte *)var)); break;
700
sv_setuv(arg,(UV)(*(unsigned short *)var)); break;
702
sv_setiv(arg,(IV)(*(short *)var)); break;
704
sv_setuv(arg,(UV)(*(unsigned int *)var)); break;
706
sv_setiv(arg,(IV)(*(int *)var)); break;
708
sv_setuv(arg,(UV)(*(unsigned long *)var)); break;
710
sv_setiv(arg,(IV)(*(long *)var)); break;
712
sv_setiv(arg,(IV)(*(LONGLONG *)var)); break;
714
sv_setnv(arg,(double)(*(float *)var)); break;
716
sv_setnv(arg,(double)(*(double *)var)); break;
718
tmp_sv[0] = newSVnv(*((float *)var));
719
tmp_sv[1] = newSVnv(*((float *)var+1));
720
sv_setsv(arg,newRV_noinc((SV*)av_make(2,tmp_sv)));
721
SvREFCNT_dec(tmp_sv[0]);
722
SvREFCNT_dec(tmp_sv[1]);
725
tmp_sv[0] = newSVnv(*((double *)var));
726
tmp_sv[1] = newSVnv(*((double *)var+1));
727
sv_setsv(arg,newRV_noinc((SV*)av_make(2,tmp_sv)));
728
SvREFCNT_dec(tmp_sv[0]);
729
SvREFCNT_dec(tmp_sv[1]);
732
croak("unpackScalar() - invalid type (%d) given",datatype);
737
void unpack1D ( SV * arg, void * var, long n, int datatype,
744
unsigned short * usvar;
746
unsigned int * uivar;
748
unsigned long * ulvar;
757
if (!PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
758
unpack2scalar(arg,var,n,datatype);
763
array = coerce1D( arg, m );
765
/* This could screw up routines like fits_read_imghdr */
772
case TSTRING: /* array of strings, I suppose */
773
stringvar = (char **)var;
775
av_store(array,i,newSVpv(stringvar[i],0));
778
logvar = (logical *) var;
780
av_store(array, i, newSViv( (IV)logvar[i] ));
783
sbvar = (sbyte *) var;
785
av_store(array, i, newSViv( (IV)sbvar[i] ));
790
av_store(array, i, newSVuv( (UV)bvar[i] ));
793
usvar = (unsigned short *) var;
795
av_store(array, i, newSVuv( (UV)usvar[i] ));
798
svar = (short *) var;
800
av_store(array, i, newSViv( (IV)svar[i] ));
803
uivar = (unsigned int *) var;
805
av_store(array, i, newSVuv( (UV)uivar[i] ));
810
av_store(array, i, newSViv( (IV)ivar[i] ));
813
ulvar = (unsigned long *) var;
815
av_store(array, i, newSVuv( (UV)ulvar[i] ));
820
av_store(array, i, newSViv( (IV)lvar[i] ));
823
llvar = (LONGLONG *) var;
825
av_store(array, i, newSViv( (IV)llvar[i] ));
828
fvar = (float *) var;
830
av_store(array, i, newSVnv( (double)fvar[i] ));
833
dvar = (double *) var;
835
av_store(array, i, newSVnv( (double)dvar[i] ));
838
fvar = (float *) var;
839
for (i=0; i<m; i++) {
840
tmp_sv[0] = newSVnv( (double)fvar[2*i] );
841
tmp_sv[1] = newSVnv( (double)fvar[2*i+1] );
842
av_store(array, i, newRV((SV *)av_make(2,tmp_sv)));
843
SvREFCNT_dec(tmp_sv[0]); SvREFCNT_dec(tmp_sv[1]);
847
dvar = (double *) var;
848
for (i=0; i<m; i++) {
849
tmp_sv[0] = newSVnv( (double)dvar[2*i] );
850
tmp_sv[1] = newSVnv( (double)dvar[2*i+1] );
851
av_store(array, i, newRV_noinc((SV*)(av_make(2,tmp_sv))));
852
SvREFCNT_dec(tmp_sv[0]); SvREFCNT_dec(tmp_sv[1]);
856
croak("unpack1D() - invalid datatype (%d)",datatype);
861
AV* coerce1D ( SV* arg, long n) {
865
if (is_scalar_ref(arg))
868
if (SvTYPE(arg)==SVt_PVGV)
869
array = GvAVn((GV*)arg);
870
else if (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV)
871
array = (AV *) SvRV(arg);
873
array = (AV*)sv_2mortal((SV*)newAV());
874
sv_setsv(arg, sv_2mortal(newRV((SV*) array)));
877
for (i=av_len(array)+1; i<n; i++)
878
av_store( array, i, newSViv((IV) 0));
883
AV* coerceND (SV *arg, int ndims, long *dims) {
887
if (!ndims || (array=coerce1D(arg,dims[0])) == NULL)
890
for (j=0; j<dims[0]; j++)
891
coerceND(*av_fetch(array,j,0),ndims-1,dims+1);
897
* A way of getting temporary memory without having to free() it
898
* by making a mortal Perl variable of the appropriate size.
900
void* get_mortalspace( long n, int datatype ) {
904
work = sv_2mortal(newSVpv("", 0));
905
datalen = sizeof_datatype(datatype) * n;
906
SvGROW(work,datalen);
909
* One could imagine allocating some space with this routine,
910
* passing the pointer off to cfitsio, ending up with an error
911
* and then having xsubpp set the output SV to the contents
912
* of memory pointed to by this said pointer, which may or
913
* may not have a NUL in its random contents.
916
*((char *)SvPV(work,PL_na)) = '\0';
918
return (void *) SvPV(work, PL_na);
922
* Return the number of bytes required for a datum of the given type.
924
int sizeof_datatype(int datatype) {
927
return sizeof(char *);
929
return sizeof(logical);
931
return sizeof(sbyte);
935
return sizeof(unsigned short);
937
return sizeof(short);
939
return sizeof(unsigned int);
943
return sizeof(unsigned long);
947
return sizeof(LONGLONG);
949
return sizeof(float);
951
return sizeof(double);
953
return 2*sizeof(float);
955
return 2*sizeof(double);
957
croak("sizeof_datatype() - invalid datatype (%d) given",datatype);
962
/* takes an array of longs, reversing their order inplace
963
* useful for reversing the order of naxes before passing them
964
* off to unpack?D() */
965
void order_reverse (int nelem, long *vals) {
968
for (i=0; i<nelem/2; i++) {
970
vals[i] = vals[nelem-i-1];
971
vals[nelem-i-1] = tmp;