File Coverage

util.c
Criterion Covered Total %
statement 207 538 38.4
branch 86 424 20.2
condition n/a
subroutine n/a
pod n/a
total 293 962 30.4


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #include
6             #include
7             #include "fitsio.h"
8             #include "util.h"
9              
10             /* newSVuv seems to be perl 5.6.0-ism */
11             #ifndef newSVuv
12             #define newSVuv newSViv
13             #endif
14              
15             static int perly_unpacking = 1; /* state variable */
16              
17              
18             /*
19             * Get the width of a string column in an ASCII or binary table
20             */
21 7           long column_width(fitsfile * fptr, int colnum) {
22 7           int hdutype, status=0, tfields, dispwidth;
23             long repeat, size;
24             long start_col,end_col; /* starting and ending positions for ASCII tables */
25             long rowlen, nrows, *tbcol;
26             char typechar[FLEN_VALUE];
27              
28 7           fits_get_hdu_type(fptr,&hdutype,&status);
29 7           check_status(status);
30 7           switch (hdutype) {
31             case ASCII_TBL:
32              
33             /* Get starting column of field */
34 5           fits_get_acolparms(
35             fptr,colnum,NULL,&start_col,NULL,NULL,NULL,NULL,NULL,NULL,
36             &status
37             );
38 5           check_status(status);
39              
40             /* Get length of each row and number of fields */
41 5           fits_read_atblhdr(
42             fptr,0,&rowlen,&nrows,&tfields,NULL,NULL,NULL,NULL,NULL,&status
43             );
44 5           check_status(status);
45              
46 5 50         if (colnum == tfields) {
47 0           end_col = rowlen + 1;
48             }
49             else {
50 5           tbcol = get_mortalspace(tfields,TLONG);
51 5           fits_read_atblhdr(
52             fptr,tfields,&rowlen,&nrows,&tfields,NULL,
53             tbcol,NULL,NULL,NULL,&status
54             );
55 5           check_status(status);
56 5           end_col = tbcol[colnum] + 1;
57             }
58 5           size = end_col - start_col;
59 5           break;
60              
61             case BINARY_TBL:
62 2           fits_get_col_display_width(fptr, colnum, &dispwidth, &status);
63 2           check_status(status);
64 2           size = dispwidth;
65 2           break;
66              
67             default:
68 0           croak("column_width() - unrecognized HDU type (%d)",hdutype);
69             }
70 7           return size;
71             }
72              
73             /*
74             * croaks() if the argument is non-zero, useful for checking on cfitsio
75             * routines.
76             */
77 24           void check_status(int status) {
78 24 50         if (status != 0) {
79 0           fits_report_error(stderr,status);
80 0           croak("cfitsio library detected an error...I'm outta here");
81             }
82 24           }
83              
84             /*
85             * Is argument a Perl reference? To a scalar?
86             */
87 230           int is_scalar_ref (SV* arg) {
88 230 100         if (!SvROK(arg))
89 59           return 0;
90 171 50         if (SvPOK(SvRV(arg)))
91 0           return 1;
92             else
93 171           return 0;
94             }
95              
96             /*
97             * Swap values in a long array inplace.
98             */
99 0           void swap_dims(int ndims, long * dims) {
100             int i;
101             long tmp;
102              
103 0 0         for (i=0; i
104 0           tmp = dims[i];
105 0           dims[i] = dims[ndims-1-i];
106 0           dims[ndims-i-1] = tmp;
107             }
108 0           }
109              
110             /*
111             * Returns the current value of perly_unpacking, if argument is non-negative
112             * the perly_unpacking is set to that value, as well.
113             */
114 126           int PerlyUnpacking( int value ) {
115 126 100         if (value >= 0)
116 2           perly_unpacking=value;
117 126           return perly_unpacking;
118             }
119              
120             /*
121             * Packs a Perl array reference into the appropriate C datatype
122             */
123 8           void* pack1D ( SV* arg, int datatype ) {
124             int size;
125             char * stringscalar;
126             logical logscalar;
127             sbyte sbscalar;
128             byte bscalar;
129             unsigned short usscalar;
130             short sscalar;
131             unsigned int uiscalar;
132             int iscalar;
133             unsigned long ulscalar;
134             long lscalar;
135             LONGLONG llscalar;
136             float fscalar;
137             double dscalar;
138             float cmpval[2];
139             double dblcmpval[2];
140             AV* array;
141             I32 i,n;
142             SV* work;
143             SV** work2;
144             STRLEN len;
145              
146 8 50         if (arg == &PL_sv_undef)
147 0           return (void *) NULL;
148              
149 8 50         if (is_scalar_ref(arg)) /* Scalar ref */
150 0 0         return (void*) SvPV(SvRV(arg), len);
151              
152 8           size = sizeof_datatype(datatype);
153              
154 8           work = sv_2mortal(newSVpv("", 0));
155              
156             /* Is arg a scalar? Return scalar*/
157 8 50         if (!SvROK(arg) && SvTYPE(arg)!=SVt_PVGV) {
    50          
158 8           switch (datatype) {
159             case TSTRING:
160 1 50         return (void *) SvPV(arg,PL_na);
161             case TLOGICAL:
162 0 0         logscalar = SvIV(arg);
163 0           sv_setpvn(work, (char *) &logscalar, size);
164 0           break;
165             case TSBYTE:
166 0 0         sbscalar = SvIV(arg);
167 0           sv_setpvn(work, (char *) &sbscalar, size);
168 0           break;
169             case TBYTE:
170 1 50         bscalar = SvUV(arg);
171 1           sv_setpvn(work, (char *) &bscalar, size);
172 1           break;
173             case TUSHORT:
174 0 0         usscalar = SvUV(arg);
175 0           sv_setpvn(work, (char *) &usscalar, size);
176 0           break;
177             case TSHORT:
178 1 50         sscalar = SvIV(arg);
179 1           sv_setpvn(work, (char *) &sscalar, size);
180 1           break;
181             case TUINT:
182 0 0         uiscalar = SvUV(arg);
183 0           sv_setpvn(work, (char *) &uiscalar, size);
184 0           break;
185             case TINT:
186 2 50         iscalar = SvIV(arg);
187 2           sv_setpvn(work, (char *) &iscalar, size);
188 2           break;
189             case TULONG:
190 0 0         ulscalar = SvUV(arg);
191 0           sv_setpvn(work, (char *) &ulscalar, size);
192 0           break;
193             case TLONG:
194 1 50         lscalar = SvIV(arg);
195 1           sv_setpvn(work, (char *) &lscalar, size);
196 1           break;
197             case TLONGLONG:
198 0 0         llscalar = SvIV(arg);
199 0           sv_setpvn(work, (char *) &llscalar, size);
200 0           break;
201             case TFLOAT:
202 1 50         fscalar = SvNV(arg);
203 1           sv_setpvn(work, (char *) &fscalar, size);
204 1           break;
205             case TDOUBLE:
206 1 50         dscalar = SvNV(arg);
207 1           sv_setpvn(work, (char *) &dscalar, size);
208 1           break;
209             case TCOMPLEX:
210 0           warn("pack1D() - packing scalar into TCOMPLEX...setting imaginary component to zero");
211 0 0         cmpval[0] = SvNV(arg);
212 0           cmpval[1] = 0.0;
213 0           sv_setpvn(work, (char *) cmpval, size);
214 0           break;
215             case TDBLCOMPLEX:
216 0           warn("pack1D() - packing scalar into TDBLCOMPLEX...setting imaginary component to zero");
217 0 0         dblcmpval[0] = SvNV(arg);
218 0           dblcmpval[1] = 0.0;
219 0           sv_setpvn(work, (char *) dblcmpval, size);
220 0           break;
221             default:
222 0           croak("pack1D() scalar code: unrecognized datatype (%d) was passed",datatype);
223             }
224 7 50         return (void *) SvPV(work,PL_na);
225             }
226              
227             /* Is it a glob or reference to an array? */
228 0 0         if (SvTYPE(arg)==SVt_PVGV || (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV)) {
    0          
    0          
229              
230 0 0         if (SvTYPE(arg)==SVt_PVGV)
231 0 0         array = (AV *) GvAVn((GV*) arg); /* glob */
232             else
233 0           array = (AV *) SvRV(arg); /* reference */
234              
235 0           n = av_len(array) + 1;
236              
237 0           switch (datatype) {
238             case TSTRING:
239 0 0         SvGROW(work, size * n);
    0          
240 0 0         for (i=0; i
241 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
242 0           stringscalar = "";
243             else {
244 0 0         if (SvROK(*work2))
245 0           goto errexit;
246 0 0         stringscalar = SvPV(*work2,PL_na);
247             }
248 0           sv_catpvn(work, (char *) &stringscalar, size);
249             }
250 0           break;
251             case TLOGICAL:
252 0 0         SvGROW(work, size * n);
    0          
253 0 0         for (i=0; i
254 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
255 0           logscalar = 0;
256             else {
257 0 0         if (SvROK(*work2))
258 0           goto errexit;
259 0 0         logscalar = (logical) SvIV(*work2);
260             }
261 0           sv_catpvn(work, (char *) &logscalar, size);
262             }
263 0           break;
264             case TSBYTE:
265 0 0         SvGROW(work, size * n);
    0          
266 0 0         for (i=0; i
267 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
268 0           sbscalar = 0;
269             else {
270 0 0         if (SvROK(*work2))
271 0           goto errexit;
272 0 0         sbscalar = (sbyte) SvIV(*work2);
273             }
274 0           sv_catpvn(work, (char *) &sbscalar, size);
275             }
276 0           break;
277             case TBYTE:
278 0 0         SvGROW(work, size * n);
    0          
279 0 0         for (i=0; i
280 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
281 0           bscalar = 0;
282             else {
283 0 0         if (SvROK(*work2))
284 0           goto errexit;
285 0 0         bscalar = (byte) SvUV(*work2);
286             }
287 0           sv_catpvn(work, (char *) &bscalar, size);
288             }
289 0           break;
290             case TUSHORT:
291 0 0         SvGROW(work, size * n);
    0          
292 0 0         for (i=0; i
293 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
294 0           usscalar = 0;
295             else {
296 0 0         if (SvROK(*work2))
297 0           goto errexit;
298 0 0         usscalar = SvUV(*work2);
299             }
300 0           sv_catpvn(work, (char *) &usscalar, size);
301             }
302 0           break;
303             case TSHORT:
304 0 0         SvGROW(work, size * n);
    0          
305 0 0         for (i=0; i
306 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
307 0           sscalar = 0;
308             else {
309 0 0         if (SvROK(*work2))
310 0           goto errexit;
311 0 0         sscalar = SvIV(*work2);
312             }
313 0           sv_catpvn(work, (char *) &sscalar, size);
314             }
315 0           break;
316             case TUINT:
317 0 0         SvGROW(work, size * n);
    0          
318 0 0         for (i=0; i
319 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
320 0           uiscalar = 0;
321             else {
322 0 0         if (SvROK(*work2))
323 0           goto errexit;
324 0 0         uiscalar = SvUV(*work2);
325             }
326 0           sv_catpvn(work, (char *) &uiscalar, size);
327             }
328 0           break;
329             case TINT:
330 0 0         SvGROW(work, size * n);
    0          
331 0 0         for (i=0; i
332 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
333 0           iscalar = 0;
334             else {
335 0 0         if (SvROK(*work2))
336 0           goto errexit;
337 0 0         iscalar = SvIV(*work2);
338             }
339 0           sv_catpvn(work, (char *) &iscalar, size);
340             }
341 0           break;
342             case TULONG:
343 0 0         SvGROW(work, size * n);
    0          
344 0 0         for (i=0; i
345 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
346 0           ulscalar = 0;
347             else {
348 0 0         if (SvROK(*work2))
349 0           goto errexit;
350 0 0         ulscalar = SvUV(*work2);
351             }
352 0           sv_catpvn(work, (char *) &ulscalar, size);
353             }
354 0           break;
355             case TLONG:
356 0 0         SvGROW(work, size * n);
    0          
357 0 0         for (i=0; i
358 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
359 0           lscalar = 0;
360             else {
361 0 0         if (SvROK(*work2))
362 0           goto errexit;
363 0 0         lscalar = SvIV(*work2);
364             }
365 0           sv_catpvn(work, (char *) &lscalar, size);
366             }
367 0           break;
368             case TLONGLONG:
369 0 0         SvGROW(work, size * n);
    0          
370 0 0         for (i=0; i
371 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
372 0           llscalar = 0;
373             else {
374 0 0         if (SvROK(*work2))
375 0           goto errexit;
376 0 0         llscalar = SvIV(*work2);
377             }
378 0           sv_catpvn(work, (char *) &llscalar, size);
379             }
380 0           break;
381             case TCOMPLEX:
382 0           size /= 2;
383             case TFLOAT:
384 0 0         SvGROW(work, size * n);
    0          
385 0 0         for (i=0; i
386 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
387 0           fscalar = 0.0;
388             else {
389 0 0         if (SvROK(*work2))
390 0           goto errexit;
391 0 0         fscalar = SvNV(*work2);
392             }
393 0           sv_catpvn(work, (char *) &fscalar, size);
394             }
395 0           break;
396             case TDBLCOMPLEX:
397 0           size /= 2;
398             case TDOUBLE:
399 0 0         SvGROW(work, size);
    0          
400 0 0         for (i=0; i
401 0 0         if ((work2=av_fetch(array,i,0)) == NULL)
402 0           dscalar = 0.0;
403             else {
404 0 0         if (SvROK(*work2))
405 0           goto errexit;
406 0 0         dscalar = SvNV(*work2);
407             }
408 0           sv_catpvn(work, (char *) &dscalar, size);
409             }
410 0           break;
411             default:
412 0           croak("pack1D() array code: unrecognized datatype (%d) was passed",datatype);
413             }
414              
415 0 0         return (void *) SvPV(work, PL_na);
416             }
417              
418             errexit:
419 8           croak("pack1D() - can only handle scalar values or refs to 1D arrays of scalars");
420             }
421              
422 150           void* packND ( SV* arg, int datatype ) {
423              
424             SV* work;
425              
426 150 50         if (arg == &PL_sv_undef)
427 0           return (void *) NULL;
428              
429 150 50         if (is_scalar_ref(arg))
430 0 0         return (void*) SvPV(SvRV(arg), PL_na);
431              
432 150           work = sv_2mortal(newSVpv("", 0));
433 150           pack_element(work, &arg, datatype);
434 150 50         return (void *) SvPV(work, PL_na);
435              
436             }
437              
438             /* Internal function of packND - pack an element recursively */
439              
440 780           void pack_element(SV* work, SV** arg, int datatype) {
441              
442             char * stringscalar;
443             logical logscalar;
444             sbyte sbscalar;
445             byte bscalar;
446             unsigned short usscalar;
447             short sscalar;
448             unsigned int uiscalar;
449             int iscalar;
450             unsigned long ulscalar;
451             long lscalar;
452             LONGLONG llscalar;
453             #ifdef TULONGLONG
454             ULONGLONG ullscalar;
455             #endif
456             float fscalar;
457             double dscalar;
458              
459             int size;
460             I32 i,n;
461             AV* array;
462              
463 780           size = sizeof_datatype(datatype);
464              
465             /* Pack element arg onto work recursively */
466              
467             /* Is arg a scalar? Pack and return */
468 780 50         if (arg==NULL || (!SvROK(*arg) && SvTYPE(*arg)!=SVt_PVGV)) {
    100          
    50          
469 638           switch (datatype) {
470             case TSTRING:
471 147 50         stringscalar = arg ? SvPV(*arg,PL_na) : "";
    50          
472 147           sv_catpvn(work, (char *) &stringscalar, size);
473 147           break;
474             case TLOGICAL:
475 72 50         logscalar = arg ? SvIV(*arg) : 0;
    50          
476 72           sv_catpvn(work, (char *) &logscalar, size);
477 72           break;
478             case TSBYTE:
479 0 0         sbscalar = arg ? SvIV(*arg) : 0;
    0          
480 0           sv_catpvn(work, (char *) &sbscalar, size);
481 0           break;
482             case TBYTE:
483 205 50         bscalar = arg ? SvUV(*arg) : 0;
    50          
484 205           sv_catpvn(work, (char *) &bscalar, size);
485 205           break;
486             case TUSHORT:
487 0 0         usscalar = arg ? SvUV(*arg) : 0;
    0          
488 0           sv_catpvn(work, (char *) &usscalar, size);
489 0           break;
490             case TSHORT:
491 32 50         sscalar = arg ? SvIV(*arg) : 0;
    50          
492 32           sv_catpvn(work, (char *) &sscalar, size);
493 32           break;
494             case TUINT:
495 0 0         uiscalar = arg ? SvUV(*arg) : 0;
    0          
496 0           sv_catpvn(work, (char *) &uiscalar, size);
497 0           break;
498             case TINT:
499 23 50         iscalar = arg ? SvIV(*arg) : 0;
    50          
500 23           sv_catpvn(work, (char *) &iscalar,size);
501 23           break;
502             case TULONG:
503 0 0         ulscalar = arg ? SvUV(*arg) : 0;
    0          
504 0           sv_catpvn(work, (char *) &ulscalar, size);
505 0           break;
506             case TLONG:
507 29 50         lscalar = arg ? SvIV(*arg) : 0;
    50          
508 29           sv_catpvn(work, (char *) &lscalar, size);
509 29           break;
510             case TLONGLONG:
511 0 0         llscalar = arg ? SvIV(*arg) : 0;
    0          
512 0           sv_catpvn(work, (char *) &llscalar, size);
513 0           break;
514             #ifdef TULONGLONG
515             case TULONGLONG:
516 0 0         ullscalar = arg ? SvIV(*arg) : 0;
    0          
517 0           sv_catpvn(work, (char *) &ullscalar, size);
518 0           break;
519             #endif
520             case TCOMPLEX:
521 0           size /= 2;
522             case TFLOAT:
523 65 50         fscalar = arg ? SvNV(*arg) : 0.0;
    100          
524 65           sv_catpvn(work, (char *) &fscalar, size);
525 65           break;
526             case TDBLCOMPLEX:
527 0           size /= 2;
528             case TDOUBLE:
529 65 50         dscalar = arg ? SvNV(*arg) : 0.0;
    100          
530 65           sv_catpvn(work, (char *) &dscalar, size);
531 65           break;
532             default:
533 0           croak("pack_element() - unrecognized datatype (%d) was passed",datatype);
534             }
535 638           }
536              
537             /* Is it a glob or reference to an array? */
538 284 50         else if (SvTYPE(*arg)==SVt_PVGV || (SvROK(*arg) && SvTYPE(SvRV(*arg))==SVt_PVAV)) {
    50          
    50          
539              
540             /* Dereference */
541 142 50         if (SvTYPE(*arg)==SVt_PVGV)
542 0 0         array = GvAVn((GV*)*arg); /* glob */
543             else
544 142           array = (AV *) SvRV(*arg); /* reference */
545              
546             /* Pack each array element */
547 142           n = av_len(array) + 1;
548 772 100         for (i=0; i
549 630           pack_element(work, av_fetch(array, i, 0), datatype );
550              
551             }
552              
553             else
554 0           croak("pack_element() - can only handle scalars or refs to N-D arrays of scalars");
555 780           }
556              
557 0           void unpack2D(SV* arg, void* var, LONGLONG* dims, int datatype, int perlyunpack)
558             {
559             long i,skip;
560             AV *array;
561 0           char * tmp_var = (char *)var;
562              
563 0 0         if (! PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
    0          
    0          
564 0           unpack2scalar(arg,var,dims[0]*dims[1],datatype);
565 0           return;
566             }
567              
568 0           coerce1D(arg,dims[0]);
569 0           array = (AV*)SvRV(arg);
570              
571 0           skip = dims[1] * sizeof_datatype(datatype);
572 0 0         for (i=0;i
573 0           unpack1D(*av_fetch(array,i,0),tmp_var,dims[1],datatype,perlyunpack);
574 0           tmp_var += skip;
575             }
576             }
577              
578 0           void unpack3D(SV* arg, void* var, LONGLONG* dims, int datatype, int perlyunpack)
579             {
580             long i,j,skip;
581             AV *array1,*array2;
582             SV *tmp_sv;
583 0           char *tmp_var = (char *)var;
584              
585 0 0         if (! PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
    0          
    0          
586 0           unpack2scalar(arg,var,dims[0]*dims[1]*dims[2],datatype);
587 0           return;
588             }
589              
590 0           coerce1D(arg,dims[0]);
591 0           array1 = (AV*)SvRV(arg);
592              
593 0           skip = dims[2] * sizeof_datatype(datatype);
594 0 0         for (i=0; i
595 0           tmp_sv = *av_fetch(array1,i,0);
596 0           coerce1D(tmp_sv,dims[1]);
597 0           array2 = (AV*)SvRV(tmp_sv);
598 0 0         for (j=0; j
599 0           unpack1D(*av_fetch(array2,j,0),tmp_var,dims[2],datatype,perlyunpack);
600 0           tmp_var += skip;
601             }
602             }
603             }
604              
605             /*
606             * This routine is known to have problems
607             */
608 0           void unpackNDll ( SV * arg, void * var, int ndims, LONGLONG *dims,
609             int datatype, int perlyunpack )
610             {
611             int i;
612             OFF_T ndata, nbytes, written, *places, skip;
613             AV **avs;
614 0           char *tmp_var = (char *)var;
615              
616             /* number of pixels to read, number of bytes therein */
617 0           ndata = 1;
618 0 0         for (i=0;i
619 0           ndata *= dims[i];
620 0           nbytes = ndata * sizeof_datatype(datatype);
621              
622 0 0         if (! PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
    0          
    0          
623 0           unpack2scalar(arg,var,ndata,datatype);
624 0           return;
625             }
626              
627 0           places = calloc(ndims-1, sizeof(OFF_T));
628 0           avs = malloc((ndims-1) * sizeof(AV*));
629              
630 0           coerceND(arg,ndims,dims);
631              
632 0           avs[0] = (AV*)SvRV(arg);
633 0           skip = dims[ndims-1] * sizeof_datatype(datatype);
634              
635 0           written = 0;
636 0 0         while (written < nbytes) {
637              
638 0 0         for (i=1;i
639 0           avs[i] = (AV*)SvRV(*av_fetch(avs[i-1],places[i-1],0));
640              
641 0           unpack1D(*av_fetch(avs[ndims-2],places[ndims-2],0),tmp_var,dims[ndims-1],datatype,perlyunpack);
642 0           tmp_var += skip;
643 0           written += skip;
644              
645 0           places[ndims-2]++;
646 0 0         for (i=ndims-2;i>=0; i--) {
647 0 0         if (places[i] >= dims[i]) {
648 0           places[i] = 0;
649 0 0         if (i>0)
650 0           places[i-1]++;
651             }
652             else
653 0           break;
654             }
655             }
656 0           free(places);
657 0           free(avs);
658             }
659              
660 0           void unpackND (SV* arg, void* var, int ndims, long *dims,
661             int datatype, int perlyunpack)
662             {
663             LONGLONG* dimsll;
664             int i;
665              
666 0 0         if (1==ndims) {
667 0           unpack1D(arg, var, dims[0], datatype, perlyunpack);
668 0           return;
669             }
670              
671 0           dimsll = malloc(ndims*sizeof(LONGLONG));
672              
673 0 0         for (i=0; i
674 0           dimsll[i] = dims[i];
675 0           unpackNDll(arg, var, ndims, dimsll, datatype, perlyunpack);
676 0           free(dimsll);
677 0           return;
678             }
679              
680             /*
681             * Set argument's value to (copied) data.
682             */
683 0           void unpack2scalar ( SV * arg, void * var, long n, int datatype ) {
684             long data_length;
685              
686 0 0         if (datatype == TSTRING)
687 0           croak("unpack2scalar() - how did you manage to call me with a TSTRING datatype?!");
688              
689 0           data_length = n * sizeof_datatype(datatype);
690              
691 0 0         SvGROW(arg, data_length);
    0          
692 0 0         memcpy(SvPV(arg,PL_na), var, data_length);
693              
694 0           return;
695             }
696              
697             /*
698             * Takes a pointer to a single value of any given type, puts
699             * that value into the passed Perl scalar
700             *
701             * Note that type TSTRING does _not_ imply a (char **) was passed,
702             * but rather a (char *).
703             */
704 12           void unpackScalar(SV * arg, void * var, int datatype) {
705             SV* tmp_sv[2];
706              
707 12 50         if (var == NULL) {
708 0           sv_setpvn(arg,"",0);
709 0           return;
710             }
711 12           switch (datatype) {
712             case TSTRING:
713 1           sv_setpv(arg,(char *)var); break;
714             case TLOGICAL:
715 0           sv_setiv(arg,(IV)(*(logical *)var)); break;
716             case TSBYTE:
717 0           sv_setiv(arg,(IV)(*(sbyte *)var)); break;
718             case TBYTE:
719 1           sv_setuv(arg,(UV)(*(byte *)var)); break;
720             case TUSHORT:
721 0           sv_setuv(arg,(UV)(*(unsigned short *)var)); break;
722             case TSHORT:
723 1           sv_setiv(arg,(IV)(*(short *)var)); break;
724             case TUINT:
725 0           sv_setuv(arg,(UV)(*(unsigned int *)var)); break;
726             case TINT:
727 2           sv_setiv(arg,(IV)(*(int *)var)); break;
728             case TULONG:
729 0           sv_setuv(arg,(UV)(*(unsigned long *)var)); break;
730             case TLONG:
731 1           sv_setiv(arg,(IV)(*(long *)var)); break;
732             case TLONGLONG:
733 0           sv_setiv(arg,(IV)(*(LONGLONG *)var)); break;
734             #ifdef TULONGLONG
735             case TULONGLONG:
736 0           sv_setiv(arg,(IV)(*(ULONGLONG *)var)); break;
737             #endif
738             case TFLOAT:
739 1           sv_setnv(arg,(double)(*(float *)var)); break;
740             case TDOUBLE:
741 1           sv_setnv(arg,(double)(*(double *)var)); break;
742             case TCOMPLEX:
743 2           tmp_sv[0] = newSVnv(*((float *)var));
744 2           tmp_sv[1] = newSVnv(*((float *)var+1));
745 2           sv_setsv(arg,newRV_noinc((SV*)av_make(2,tmp_sv)));
746 2           SvREFCNT_dec(tmp_sv[0]);
747 2           SvREFCNT_dec(tmp_sv[1]);
748 2           break;
749             case TDBLCOMPLEX:
750 2           tmp_sv[0] = newSVnv(*((double *)var));
751 2           tmp_sv[1] = newSVnv(*((double *)var+1));
752 2           sv_setsv(arg,newRV_noinc((SV*)av_make(2,tmp_sv)));
753 2           SvREFCNT_dec(tmp_sv[0]);
754 2           SvREFCNT_dec(tmp_sv[1]);
755 2           break;
756             default:
757 0           croak("unpackScalar() - invalid type (%d) given",datatype);
758             }
759 12           return;
760             }
761              
762 72           void unpack1D (SV* arg, void* var, LONGLONG n, int datatype, int perlyunpack)
763             {
764             char ** stringvar;
765             logical * logvar;
766             sbyte * sbvar;
767             byte * bvar;
768             unsigned short * usvar;
769             short * svar;
770             unsigned int * uivar;
771             int * ivar;
772             unsigned long * ulvar;
773             long * lvar;
774             LONGLONG * llvar;
775             #ifdef TULONGLONG
776             ULONGLONG * ullvar;
777             #endif
778             float * fvar;
779             double * dvar;
780             SV *tmp_sv[2];
781             AV *array;
782             I32 i,m;
783              
784 72 50         if (!PERLYUNPACKING(perlyunpack) && datatype != TSTRING) {
    50          
    0          
785 0           unpack2scalar(arg,var,n,datatype);
786 0           return;
787             }
788              
789 72           m=n;
790 72           array = coerce1D( arg, m );
791              
792             /* This could screw up routines like fits_read_imghdr */
793             /*
794             if (m==0)
795             m = av_len(array)+1;
796             */
797              
798 72           switch (datatype) {
799             case TSTRING: /* array of strings, I suppose */
800 15           stringvar = (char **)var;
801 149 100         for (i=0; i
802 134           av_store(array,i,newSVpv(stringvar[i],0));
803 15           break;
804             case TLOGICAL:
805 7           logvar = (logical *) var;
806 164 100         for(i=0; i
807 157           av_store(array, i, newSViv( (IV)logvar[i] ));
808 7           break;
809             case TSBYTE:
810 0           sbvar = (sbyte *) var;
811 0 0         for(i=0; i
812 0           av_store(array, i, newSViv( (IV)sbvar[i] ));
813 0           break;
814             case TBYTE:
815 10           bvar = (byte *) var;
816 231 100         for(i=0; i
817 221           av_store(array, i, newSVuv( (UV)bvar[i] ));
818 10           break;
819             case TUSHORT:
820 0           usvar = (unsigned short *) var;
821 0 0         for(i=0; i
822 0           av_store(array, i, newSVuv( (UV)usvar[i] ));
823 0           break;
824             case TSHORT:
825 8           svar = (short *) var;
826 130 100         for(i=0; i
827 122           av_store(array, i, newSViv( (IV)svar[i] ));
828 8           break;
829             case TUINT:
830 0           uivar = (unsigned int *) var;
831 0 0         for(i=0; i
832 0           av_store(array, i, newSVuv( (UV)uivar[i] ));
833 0           break;
834             case TINT:
835 1           ivar = (int *) var;
836 4 100         for(i=0; i
837 3           av_store(array, i, newSViv( (IV)ivar[i] ));
838 1           break;
839             case TULONG:
840 0           ulvar = (unsigned long *) var;
841 0 0         for(i=0; i
842 0           av_store(array, i, newSVuv( (UV)ulvar[i] ));
843 0           break;
844             case TLONG:
845 11           lvar = (long *) var;
846 134 100         for(i=0; i
847 123           av_store(array, i, newSViv( (IV)lvar[i] ));
848 11           break;
849             case TLONGLONG:
850 0           llvar = (LONGLONG *) var;
851 0 0         for(i=0; i
852 0           av_store(array, i, newSViv( (IV)llvar[i] ));
853 0           break;
854             #ifdef TULONGLONG
855             case TULONGLONG:
856 0           ullvar = (ULONGLONG *) var;
857 0 0         for(i=0; i
858 0           av_store(array, i, newSViv( (IV)ullvar[i] ));
859 0           break;
860             #endif
861             case TFLOAT:
862 9           fvar = (float *) var;
863 134 100         for(i=0; i
864 125           av_store(array, i, newSVnv( (double)fvar[i] ));
865 9           break;
866             case TDOUBLE:
867 9           dvar = (double *) var;
868 134 100         for(i=0; i
869 125           av_store(array, i, newSVnv( (double)dvar[i] ));
870 9           break;
871             case TCOMPLEX:
872 1           fvar = (float *) var;
873 22 100         for (i=0; i
874 21           tmp_sv[0] = newSVnv( (double)fvar[2*i] );
875 21           tmp_sv[1] = newSVnv( (double)fvar[2*i+1] );
876 21           av_store(array, i, newRV((SV *)av_make(2,tmp_sv)));
877 21           SvREFCNT_dec(tmp_sv[0]); SvREFCNT_dec(tmp_sv[1]);
878             }
879 1           break;
880             case TDBLCOMPLEX:
881 1           dvar = (double *) var;
882 22 100         for (i=0; i
883 21           tmp_sv[0] = newSVnv( (double)dvar[2*i] );
884 21           tmp_sv[1] = newSVnv( (double)dvar[2*i+1] );
885 21           av_store(array, i, newRV_noinc((SV*)(av_make(2,tmp_sv))));
886 21           SvREFCNT_dec(tmp_sv[0]); SvREFCNT_dec(tmp_sv[1]);
887             }
888 1           break;
889             default:
890 0           croak("unpack1D() - invalid datatype (%d)",datatype);
891             }
892 72           return;
893             }
894              
895 72           AV* coerce1D (SV* arg, LONGLONG n)
896             {
897             AV* array;
898             I32 i;
899              
900 72 50         if (is_scalar_ref(arg))
901 0           return (AV*)NULL;
902              
903 72 50         if (SvTYPE(arg)==SVt_PVGV)
904 0 0         array = GvAVn((GV*)arg);
905 72 100         else if (SvROK(arg) && SvTYPE(SvRV(arg))==SVt_PVAV)
    50          
906 29           array = (AV *) SvRV(arg);
907             else {
908 43           array = (AV*)sv_2mortal((SV*)newAV());
909 43           sv_setsv(arg, sv_2mortal(newRV((SV*) array)));
910             }
911              
912 677 100         for (i=av_len(array)+1; i
913 605           av_store( array, i, newSViv((IV) 0));
914              
915 72           return array;
916             }
917              
918 0           AV* coerceND (SV* arg, int ndims, LONGLONG *dims)
919             {
920             AV* array;
921             I32 j;
922              
923 0 0         if (!ndims || (array=coerce1D(arg,dims[0])) == NULL)
    0          
924 0           return (AV *)NULL;
925              
926 0 0         for (j=0; j
927 0           coerceND(*av_fetch(array,j,0),ndims-1,dims+1);
928              
929 0           return array;
930             }
931              
932             /*
933             * A way of getting temporary memory without having to free() it
934             * by making a mortal Perl variable of the appropriate size.
935             */
936 402           void* get_mortalspace(LONGLONG n, int datatype) {
937             LONGLONG datalen;
938             SV *work;
939              
940 402           work = sv_2mortal(newSVpv("", 0));
941 402           datalen = sizeof_datatype(datatype) * n;
942 402 50         SvGROW(work,datalen);
    100          
943              
944             /*
945             * One could imagine allocating some space with this routine,
946             * passing the pointer off to cfitsio, ending up with an error
947             * and then having xsubpp set the output SV to the contents
948             * of memory pointed to by this said pointer, which may or
949             * may not have a NUL in its random contents.
950             */
951 402 50         if (datalen)
952 402 50         *((char *)SvPV(work,PL_na)) = '\0';
953              
954 402 50         return (void *) SvPV(work, PL_na);
955             }
956              
957             /*
958             * Return the number of bytes required for a datum of the given type.
959             */
960 1190           int sizeof_datatype(int datatype) {
961 1190           switch (datatype) {
962             case TSTRING:
963 206           return sizeof(char *);
964             case TLOGICAL:
965 81           return sizeof(logical);
966             case TSBYTE:
967 0           return sizeof(sbyte);
968             case TBYTE:
969 548           return sizeof(byte);
970             case TUSHORT:
971 0           return sizeof(unsigned short);
972             case TSHORT:
973 58           return sizeof(short);
974             case TUINT:
975 0           return sizeof(unsigned int);
976             case TINT:
977 39           return sizeof(int);
978             case TULONG:
979 0           return sizeof(unsigned long);
980             case TLONG:
981 58           return sizeof(long);
982             case TLONGLONG:
983 0           return sizeof(LONGLONG);
984             #ifdef TULONGLONG
985             case TULONGLONG:
986 0           return sizeof(ULONGLONG);
987             #endif
988             case TFLOAT:
989 97           return sizeof(float);
990             case TDOUBLE:
991 97           return sizeof(double);
992             case TCOMPLEX:
993 3           return 2*sizeof(float);
994             case TDBLCOMPLEX:
995 3           return 2*sizeof(double);
996             default:
997 0           croak("sizeof_datatype() - invalid datatype (%d) given",datatype);
998             }
999             }
1000              
1001              
1002             /* takes an array of longs, reversing their order inplace
1003             * useful for reversing the order of naxes before passing them
1004             * off to unpack?D() */
1005              
1006 0           void order_reversell (int nelem, LONGLONG *vals) {
1007             LONGLONG tmp;
1008             int i;
1009 0 0         for (i=0; i
1010 0           tmp = vals[i];
1011 0           vals[i] = vals[nelem-i-1];
1012 0           vals[nelem-i-1] = tmp;
1013             }
1014 0           }
1015              
1016 0           void order_reverse (int nelem, long *vals) {
1017             long tmp;
1018             int i;
1019 0 0         for (i=0; i
1020 0           tmp = vals[i];
1021 0           vals[i] = vals[nelem-i-1];
1022 0           vals[nelem-i-1] = tmp;
1023             }
1024 0           }