1 /*********************************************************************
2 Fits - View and manipulate FITS extensions and/or headers.
3 Fits is part of GNU Astronomy Utilities (Gnuastro) package.
4
5 Original author:
6 Mohammad Akhlaghi <mohammad@akhlaghi.org>
7 Contributing author(s):
8 Copyright (C) 2017-2021, Free Software Foundation, Inc.
9
10 Gnuastro is free software: you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation, either version 3 of the License, or (at your
13 option) any later version.
14
15 Gnuastro is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
22 **********************************************************************/
23 #include <config.h>
24
25 #include <errno.h>
26 #include <error.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include <gnuastro/wcs.h>
31 #include <gnuastro/list.h>
32 #include <gnuastro/fits.h>
33 #include <gnuastro/blank.h>
34 #include <gnuastro/pointer.h>
35 #include <gnuastro/statistics.h>
36
37 #include <gnuastro-internal/timing.h>
38 #include <gnuastro-internal/checkset.h>
39
40 #include "main.h"
41
42 #include "fits.h"
43 #include "keywords.h"
44
45
46
47 int
fits_has_error(struct fitsparams * p,int actioncode,char * string,int status)48 fits_has_error(struct fitsparams *p, int actioncode, char *string, int status)
49 {
50 char *action=NULL;
51 int r=EXIT_SUCCESS;
52
53 switch(actioncode)
54 {
55 case FITS_ACTION_DELETE: action="deleted"; break;
56 case FITS_ACTION_RENAME: action="renamed"; break;
57 case FITS_ACTION_UPDATE: action="updated"; break;
58 case FITS_ACTION_WRITE: action="written"; break;
59 case FITS_ACTION_COPY: action="copied"; break;
60 case FITS_ACTION_REMOVE: action="removed"; break;
61
62 default:
63 error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at '%s' so we "
64 "can fix this problem. The value of 'actioncode' must not be %d",
65 __func__, PACKAGE_BUGREPORT, actioncode);
66 }
67
68 if(p->quitonerror)
69 {
70 fits_report_error(stderr, status);
71 error(EXIT_FAILURE, 0, "%s: %s: not %s\n", __func__, string, action);
72 }
73 else
74 {
75 fprintf(stderr, "%s: Not %s.\n", string, action);
76 r=EXIT_FAILURE;
77 }
78 return r;
79 }
80
81
82
83
84
85 /* Print all the extension informations. */
86 void
fits_print_extension_info(struct fitsparams * p)87 fits_print_extension_info(struct fitsparams *p)
88 {
89 uint16_t *ui16;
90 fitsfile *fptr;
91 size_t i, numext, *dsize, ndim;
92 int hascomments=0, hasblankname=0;
93 char **tstra, **estra, **sstra, **cmstra;
94 int j, nc, numhdu, hdutype, status=0, type;
95 gal_data_t *tmp, *cols=NULL, *sizecol, *commentscol;
96 char *msg, *tstr=NULL, sstr[1000], extname[FLEN_VALUE];
97
98
99 /* Open the FITS file and read the first extension type, upon moving to
100 the next extension, we will read its type, so for the first we will
101 need to do it explicitly. */
102 fptr=gal_fits_hdu_open(p->input->v, "0", READONLY);
103 if (fits_get_hdu_type(fptr, &hdutype, &status) )
104 gal_fits_io_error(status, "reading first extension");
105
106
107 /* Get the number of HDUs. */
108 if( fits_get_num_hdus(fptr, &numhdu, &status) )
109 gal_fits_io_error(status, "finding number of HDUs");
110 numext=numhdu;
111
112
113 /* Allocate all the columns (in reverse order, since this is a simple
114 linked list). */
115 gal_list_data_add_alloc(&cols, NULL, GAL_TYPE_STRING, 1, &numext, NULL, 1,
116 -1, 1, "HDU_COMMENT", "note", "Possible comment");
117 gal_list_data_add_alloc(&cols, NULL, GAL_TYPE_STRING, 1, &numext, NULL, 1,
118 -1, 1, "HDU_SIZE", "name", "Size of image or table "
119 "number of rows and columns.");
120 gal_list_data_add_alloc(&cols, NULL, GAL_TYPE_STRING, 1, &numext, NULL, 1,
121 -1, 1, "HDU_TYPE", "name", "Image data type or "
122 "'table' format (ASCII or binary).");
123 gal_list_data_add_alloc(&cols, NULL, GAL_TYPE_STRING, 1, &numext, NULL, 1,
124 -1, 1, "EXTNAME", "name", "Extension name of this "
125 "HDU (EXTNAME in FITS).");
126 gal_list_data_add_alloc(&cols, NULL, GAL_TYPE_UINT16, 1, &numext, NULL, 1,
127 -1, 1, "HDU_INDEX", "count", "Index (starting from "
128 "zero) of each HDU (extension).");
129
130
131 /* Keep pointers to the array of each column for easy writing. */
132 ui16 = cols->array;
133 estra = cols->next->array;
134 tstra = cols->next->next->array;
135
136 sizecol = cols->next->next->next;
137 sstra = sizecol->array;
138
139 commentscol = cols->next->next->next->next;
140 cmstra = commentscol->array;
141
142 cols->next->disp_width=15;
143 cols->next->next->disp_width=15;
144
145
146 /* Fill in each column. */
147 for(i=0;i<numext;++i)
148 {
149 /* Work based on the type of the extension. */
150 switch(hdutype)
151 {
152 case IMAGE_HDU:
153 gal_fits_img_info(fptr, &type, &ndim, &dsize, NULL, NULL);
154 tstr = ndim==0 ? "no-data" : gal_type_name(type , 1);
155 break;
156
157 case ASCII_TBL:
158 case BINARY_TBL:
159 ndim=2;
160 tstr = hdutype==ASCII_TBL ? "table_ascii" : "table_binary";
161 dsize=gal_pointer_allocate(GAL_TYPE_SIZE_T, 2, 0, __func__,
162 "dsize");
163 gal_fits_tab_size(fptr, dsize+1, dsize);
164 break;
165
166 default:
167 error(EXIT_FAILURE, 0, "%s: a bug! the 'hdutype' code %d not "
168 "recognized", __func__, hdutype);
169 }
170
171
172 /* Read the extension name*/
173 fits_read_keyword(fptr, "EXTNAME", extname, NULL, &status);
174 switch(status)
175 {
176 case 0:
177 gal_fits_key_clean_str_value(extname);
178 break;
179
180 case KEY_NO_EXIST:
181 sprintf(extname, "%s", GAL_BLANK_STRING);
182 hasblankname=1;
183 status=0;
184 break;
185
186 default:
187 gal_fits_io_error(status, "reading EXTNAME keyword");
188 }
189 status=0;
190
191
192 /* Check if its a healpix grid. */
193 if( gal_fits_hdu_is_healpix(fptr) )
194 {
195 hascomments=1;
196 gal_checkset_allocate_copy("HEALpix", cmstra+i);
197 }
198 else
199 gal_checkset_allocate_copy(GAL_BLANK_STRING, cmstra+i);
200
201
202 /* Write the size into a string. 'sprintf' returns the number of
203 written characters (excluding the '\0'). So for each dimension's
204 size that is written, we add to 'nc' (the number of
205 characters). Note that FITS allows blank extensions, in those
206 cases, return "0". */
207 if(ndim>0)
208 {
209 nc=0;
210 for(j=ndim-1;j>=0;--j)
211 nc += sprintf(sstr+nc, "%zux", dsize[j]);
212 sstr[nc-1]='\0';
213 free(dsize);
214 }
215 else
216 {
217 sstr[0]='0';
218 sstr[1]='\0';
219 }
220
221
222 /* Write the strings into the columns. */
223 j=0;
224 for(tmp=cols; tmp!=NULL; tmp=tmp->next)
225 {
226 switch(j)
227 {
228 case 0: ui16[i]=i; break;
229 case 1: gal_checkset_allocate_copy(extname, estra+i); break;
230 case 2: gal_checkset_allocate_copy(tstr, tstra+i); break;
231 case 3: gal_checkset_allocate_copy(sstr, sstra+i); break;
232 }
233 ++j;
234 }
235
236
237 /* Move to the next extension if we aren't on the last extension. */
238 if( i!=numext-1 && fits_movrel_hdu(fptr, 1, &hdutype, &status) )
239 {
240 if( asprintf(&msg, "moving to hdu %zu", i+1)<0 )
241 error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
242 gal_fits_io_error(status, msg);
243 }
244 }
245
246 /* Close the file. */
247 fits_close_file(fptr, &status);
248
249 /* If there weren't any comments, don't print the comment column. */
250 if(hascomments==0)
251 {
252 sizecol->next=NULL;
253 gal_data_free(commentscol);
254 }
255
256 /* Print the results. */
257 if(!p->cp.quiet)
258 {
259 printf("%s\nRun on %s-----\n", PROGRAM_STRING, ctime(&p->rawtime));
260 printf("HDU (extension) information: '%s'.\n", p->input->v);
261 printf(" Column 1: Index (counting from 0, usable with '--hdu').\n");
262 printf(" Column 2: Name ('EXTNAME' in FITS standard, usable with "
263 "'--hdu').\n");
264 if(hasblankname)
265 printf(" ('%s' means that no name is specified for this "
266 "HDU)\n", GAL_BLANK_STRING);
267 printf(" Column 3: Image data type or 'table' format (ASCII or "
268 "binary).\n");
269 printf(" Column 4: Size of data in HDU.\n");
270 if(hascomments)
271 printf(" Column 5: Comments about the HDU (e.g., if its HEALpix, or "
272 "etc).\n");
273 printf("-----\n");
274 }
275 gal_table_write(cols, NULL, NULL, GAL_TABLE_FORMAT_TXT, NULL, NULL, 0);
276 gal_list_data_free(cols);
277 }
278
279
280
281
282
283 static void
fits_hdu_number(struct fitsparams * p)284 fits_hdu_number(struct fitsparams *p)
285 {
286 fitsfile *fptr;
287 int numhdu, status=0;
288
289 /* Read the first extension (necessary for reading the rest). */
290 fptr=gal_fits_hdu_open(p->input->v, "0", READONLY);
291
292 /* Get the number of HDUs. */
293 if( fits_get_num_hdus(fptr, &numhdu, &status) )
294 gal_fits_io_error(status, "finding number of HDUs");
295
296 /* Close the file. */
297 fits_close_file(fptr, &status);
298
299 /* Print the result. */
300 printf("%d\n", numhdu);
301 }
302
303
304
305
306
307 static void
fits_datasum(struct fitsparams * p)308 fits_datasum(struct fitsparams *p)
309 {
310 printf("%ld\n", gal_fits_hdu_datasum(p->input->v, p->cp.hdu));
311 }
312
313
314
315
316
317 static void
fits_pixelscale(struct fitsparams * p)318 fits_pixelscale(struct fitsparams *p)
319 {
320 int nwcs=0;
321 size_t i, ndim=0;
322 struct wcsprm *wcs;
323 double multip, *pixelscale;
324
325 /* Read the desired WCS. */
326 wcs=gal_wcs_read(p->input->v, p->cp.hdu, p->cp.wcslinearmatrix,
327 0, 0, &nwcs);
328
329 /* If a WCS doesn't exist, let the user know and return. */
330 if(wcs)
331 ndim=wcs->naxis;
332 else
333 error(EXIT_FAILURE, 0, "%s (hdu %s): no WCS could be read by WCSLIB, "
334 "hence the pixel-scale cannot be determined", p->input->v,
335 p->cp.hdu);
336
337 /* Calculate the pixel-scale in each dimension. */
338 pixelscale=gal_wcs_pixel_scale(wcs);
339
340 /* If not in quiet-mode, print some extra information. We don't want the
341 last number to have a space after it, so we'll write the last one
342 outside the loop.*/
343 if(p->cp.quiet==0)
344 {
345 printf("Basic information for --pixelscale (remove extra info "
346 "with '--quiet' or '-q')\n");
347 printf(" Input: %s (hdu %s) has %zu dimensions.\n", p->input->v,
348 p->cp.hdu, ndim);
349 printf(" Pixel scale in each FITS dimension:\n");
350 for(i=0;i<ndim;++i)
351 {
352 if( !strcmp(wcs->cunit[i], "deg") )
353 printf(" %zu: %g (%s/pixel) = %g (arcsec/pixel)\n", i+1,
354 pixelscale[i], wcs->cunit[i], pixelscale[i]*3600);
355 else
356 printf(" %zu: %g (%s/slice)\n", i+1,
357 pixelscale[i], wcs->cunit[i]);
358 }
359
360 /* Pixel area/volume. */
361 if(ndim>=2)
362 {
363 /* Multiply the values in each dimension. */
364 multip=pixelscale[0]*pixelscale[1];
365
366 /* Pixel scale (applicable to 2 or 3 dimensions). */
367 printf(" Pixel area%s:\n", ndim==2?"":" (on each 2D slice) ");
368 if( strcmp(wcs->cunit[0], wcs->cunit[1]) )
369 printf(" %g (%s*%s)\n", multip, wcs->cunit[0],
370 wcs->cunit[1]);
371 else
372 if( strcmp(wcs->cunit[0], "deg") )
373 printf(" %g (%s^2)\n", multip, wcs->cunit[0]);
374 else
375 printf(" %g (deg^2) = %g (arcsec^2)\n",
376 multip, multip*3600*3600 );
377
378 /* For a 3 dimensional dataset, we need need extra info. */
379 if(ndim>=3)
380 {
381 multip*=pixelscale[2];
382 printf(" Voxel volume:\n");
383 if( strcmp(wcs->cunit[0], wcs->cunit[1]) )
384 printf(" %g (%s*%s*%s)\n", multip, wcs->cunit[0],
385 wcs->cunit[1], wcs->cunit[2]);
386 else
387 if( strcmp(wcs->cunit[0], "deg") )
388 printf(" %g (%s^2*%s)\n", multip, wcs->cunit[0],
389 wcs->cunit[2]);
390 else
391 {
392 if( strcmp(wcs->cunit[2], "m") )
393 printf(" %g (deg^2*%s) = %g (arcsec^2*%s)\n",
394 multip, wcs->cunit[2], multip*3600*3600,
395 wcs->cunit[2]);
396 else
397 printf(" %g (deg^2*m) = %g (arcsec^2*m) = "
398 "%g (arcsec^2*A)\n", multip, multip*3600*3600,
399 multip*3600*3600*1e10);
400 }
401
402 /* Higher-dimensional data are not yet supported. */
403 if(ndim>=4 && p->cp.quiet==0)
404 error(EXIT_SUCCESS, 0, "WARNING: the '--pixelscale' "
405 "option only prints area/volume information for "
406 "2 or 3 dimensional datasets, this dataset is "
407 "%zu dimensions! If you need this feature, please "
408 "contact '%s'. To suppress this warning, please "
409 "run with '--quiet'", ndim, PACKAGE_BUGREPORT);
410 }
411 }
412 }
413 else
414 {
415 multip=1;
416 for(i=0;i<ndim;++i)
417 {
418 multip*=pixelscale[i];
419 printf("%g ", pixelscale[i]);
420 }
421 switch(ndim)
422 {
423 case 2: printf("%g\n", multip); break;
424 case 3: printf("%g %g\n", pixelscale[0]*pixelscale[1], multip); break;
425 default: printf("\n");
426 }
427 }
428
429 /* Clean up. */
430 wcsfree(wcs);
431 free(pixelscale);
432 }
433
434
435
436
437
438 static void
fits_skycoverage(struct fitsparams * p)439 fits_skycoverage(struct fitsparams *p)
440 {
441 int nwcs=0;
442 size_t i, ndim;
443 struct wcsprm *wcs;
444 double *center, *width, *min, *max;
445
446 /* Find the coverage. */
447 if( gal_wcs_coverage(p->input->v, p->cp.hdu, &ndim,
448 ¢er, &width, &min, &max)==0 )
449 error(EXIT_FAILURE, 0, "%s (hdu %s): is not usable for finding "
450 "sky coverage (either doesn't have a WCS, or isn't an image "
451 "or cube HDU with 2 or 3 dimensions", p->input->v, p->cp.hdu);
452
453 /* Inform the user. */
454 if(p->cp.quiet)
455 {
456 /* First print the center and full-width. */
457 for(i=0;i<ndim;++i) printf("%-15.10g ", center[i]);
458 for(i=0;i<ndim;++i) printf("%-15.10g ", width[i]);
459 printf("\n");
460
461 /* Then print the range in coordinates. */
462 for(i=0;i<ndim;++i) printf("%-15.10g %-15.10g ", min[i], max[i]);
463 printf("\n");
464 }
465 else
466 {
467 printf("Input file: %s (hdu: %s)\n", p->input->v, p->cp.hdu);
468 printf("\nSky coverage by center and (full) width:\n");
469 switch(ndim)
470 {
471 case 2:
472 printf(" Center: %-15.10g%-15.10g\n", center[0], center[1]);
473 printf(" Width: %-15.10g%-15.10g\n", width[0], width[1]);
474 break;
475 case 3:
476 printf(" Center: %-15.10g%-15.10g%-15.10g\n", center[0],
477 center[1], center[2]);
478 printf(" width: %-15.10g%-15.10g%-15.10g\n", width[0],
479 width[1], width[2]);
480 break;
481 default:
482 error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to fix "
483 "the problem. 'ndim' value %zu is not recognized", __func__,
484 PACKAGE_BUGREPORT, ndim);
485 }
486
487 /* For the range type of coverage. */
488 wcs=gal_wcs_read(p->input->v, p->cp.hdu, p->cp.wcslinearmatrix,
489 0, 0, &nwcs);
490 printf("\nSky coverage by range along dimensions:\n");
491 for(i=0;i<ndim;++i)
492 printf(" %-8s %-15.10g%-15.10g\n", gal_wcs_dimension_name(wcs, i),
493 min[i], max[i]);
494 wcsfree(wcs);
495 }
496
497 /* Clean up. */
498 free(min);
499 free(max);
500 free(width);
501 free(center);
502 }
503
504
505
506
507
508 static char *
fits_list_certain_hdu_string(fitsfile * fptr,int hduindex)509 fits_list_certain_hdu_string(fitsfile *fptr, int hduindex)
510 {
511 size_t i;
512 int status=0;
513 char *out, extname[80];
514
515 /* See if an 'EXTNAME' keyword exists for this HDU. */
516 fits_read_keyword(fptr, "EXTNAME", extname, NULL, &status);
517
518 /* If EXTNAME doesn't exist, write the HDU index (counting from zero),
519 but if it does, remove the ending single quotes and possible extra
520 space characters (the staring single quote will be removed when
521 copying the name into 'out'). */
522 if(status) sprintf(extname, "%d", hduindex);
523 else
524 {
525 for(i=strlen(extname)-1; i>0; --i)
526 if(extname[i]!='\'' && extname[i]!=' ')
527 { extname[i+1]='\0'; break; }
528 }
529
530 /* Put the value into the allocated 'out' string. */
531 gal_checkset_allocate_copy(status ? extname : extname+1, &out);
532 return out;
533 }
534
535
536
537
538 static void
fits_certain_hdu(struct fitsparams * p,int list1has0,int table1image0)539 fits_certain_hdu(struct fitsparams *p, int list1has0,
540 int table1image0)
541 {
542 fitsfile *fptr;
543 gal_list_str_t *names=NULL;
544 int has=0, naxis, hducounter=1, hdutype, status=0;
545
546 /* Open the FITS file. */
547 fits_open_file(&fptr, p->input->v, READONLY, &status);
548 gal_fits_io_error(status, NULL);
549
550 /* Start by moving to the first HDU (counting from 1) and then parsing
551 through them. */
552 fits_movabs_hdu(fptr, hducounter, &hdutype, &status);
553 while(status==0)
554 {
555 /* Check the HDU type. */
556 switch(hdutype)
557 {
558
559 /* Tables are easy. */
560 case BINARY_TBL:
561 case ASCII_TBL:
562 if(table1image0)
563 {
564 if(list1has0)
565 gal_list_str_add(&names,
566 fits_list_certain_hdu_string(fptr,
567 hducounter-1),
568 0);
569 else has=1;
570 }
571 break;
572
573 /* For images, we need to check there is actually any data. */
574 case IMAGE_HDU:
575 if(table1image0==0)
576 {
577 fits_get_img_dim(fptr, &naxis, &status);
578 gal_fits_io_error(status, NULL);
579 if(naxis>0)
580 {
581 if(list1has0)
582 gal_list_str_add(&names,
583 fits_list_certain_hdu_string(fptr,
584 hducounter-1),
585 0);
586 else has=1;
587 }
588 }
589 break;
590
591 /* Just to avoid bad bugs. */
592 default:
593 error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s "
594 "to fix the problem. The value %d is not recognized "
595 "for 'hdutype'", __func__, PACKAGE_BUGREPORT, hdutype);
596 }
597
598 /* Move to the next HDU. */
599 fits_movabs_hdu(fptr, ++hducounter, &hdutype, &status);
600
601 /* If we are in "has" mode and the first HDU has already been found,
602 then there is no need to continue parsing the HDUs, so set
603 'status' to 1 to stop the 'while' above. */
604 if( list1has0==0 && has==1 ) status=1;
605 }
606
607 /* Close the file. */
608 status=0;
609 fits_close_file(fptr, &status);
610
611 /* Print the result. */
612 if( list1has0 )
613 {
614 gal_list_str_print(names);
615 gal_list_str_free(names, 1);
616 }
617 else printf("%d\n", has);
618 }
619
620
621
622
623
624 static void
fits_list_all_hdus(struct fitsparams * p)625 fits_list_all_hdus(struct fitsparams *p)
626 {
627 fitsfile *fptr;
628 gal_list_str_t *names=NULL;
629 int hducounter=1, hdutype, status=0;
630
631 /* Open the FITS file. */
632 fits_open_file(&fptr, p->input->v, READONLY, &status);
633 gal_fits_io_error(status, NULL);
634
635 /* Start by moving to the first HDU (counting from 1) and then parsing
636 through them. */
637 fits_movabs_hdu(fptr, hducounter, &hdutype, &status);
638 while(status==0)
639 {
640 gal_list_str_add(&names,
641 fits_list_certain_hdu_string(fptr,
642 hducounter-1),
643 0);
644 fits_movabs_hdu(fptr, ++hducounter, &hdutype, &status);
645 }
646
647 /* Close the file. */
648 status=0;
649 fits_close_file(fptr, &status);
650
651 /* Print the result. */
652 gal_list_str_print(names);
653 gal_list_str_free(names, 1);
654 }
655
656
657
658
659
660 static void
fits_hdu_remove(struct fitsparams * p,int * r)661 fits_hdu_remove(struct fitsparams *p, int *r)
662 {
663 char *hdu;
664 fitsfile *fptr;
665 int status=0, hdutype;
666
667 while(p->remove)
668 {
669 /* Pop-out the top element. */
670 hdu=gal_list_str_pop(&p->remove);
671
672 /* Open the FITS file at the specified HDU. */
673 fptr=gal_fits_hdu_open(p->input->v, hdu, READWRITE);
674
675 /* Delete the extension. */
676 if( fits_delete_hdu(fptr, &hdutype, &status) )
677 *r=fits_has_error(p, FITS_ACTION_REMOVE, hdu, status);
678 status=0;
679
680 /* Close the file. */
681 fits_close_file(fptr, &status);
682 }
683 }
684
685
686
687
688
689 /* This is similar to the library's 'gal_fits_open_to_write', except that
690 it won't create an empty first extension.*/
691 fitsfile *
fits_open_to_write_no_blank(char * filename)692 fits_open_to_write_no_blank(char *filename)
693 {
694 int status=0;
695 fitsfile *fptr;
696
697 /* When the file exists just open it. Otherwise, create the file. But we
698 want to leave the first extension as a blank extension and put the
699 image in the next extension to be consistent between tables and
700 images. */
701 if(access(filename,F_OK) == -1 )
702 {
703 /* Create the file. */
704 if( fits_create_file(&fptr, filename, &status) )
705 gal_fits_io_error(status, NULL);
706 }
707
708 /* Open the file, ready for later steps. */
709 if( fits_open_file(&fptr, filename, READWRITE, &status) )
710 gal_fits_io_error(status, NULL);
711
712 /* Return the pointer. */
713 return fptr;
714 }
715
716
717
718
719
720 static void
fits_hdu_copy(struct fitsparams * p,int cut1_copy0,int * r)721 fits_hdu_copy(struct fitsparams *p, int cut1_copy0, int *r)
722 {
723 char *hdu;
724 int status=0, hdutype;
725 fitsfile *in, *out=NULL;
726 gal_list_str_t *list = cut1_copy0 ? p->cut : p->copy;
727
728 /* Copy all the given extensions. */
729 while(list)
730 {
731 /* Pop-out the top element. */
732 hdu=gal_list_str_pop(&list);
733
734 /* Open the FITS file at the specified HDU. */
735 in=gal_fits_hdu_open(p->input->v, hdu,
736 cut1_copy0 ? READWRITE : READONLY);
737
738 /* If the output isn't opened yet, open it. */
739 if(out==NULL)
740 out = ( ( gal_fits_hdu_format(p->input->v, hdu)==IMAGE_HDU
741 && p->primaryimghdu )
742 ? fits_open_to_write_no_blank(p->cp.output)
743 : gal_fits_open_to_write(p->cp.output) );
744
745
746 /* Copy to the extension. */
747 if( fits_copy_hdu(in, out, 0, &status) )
748 *r=fits_has_error(p, FITS_ACTION_COPY, hdu, status);
749 status=0;
750
751 /* If this is a 'cut' operation, then remove the extension. */
752 if(cut1_copy0)
753 {
754 if( fits_delete_hdu(in, &hdutype, &status) )
755 *r=fits_has_error(p, FITS_ACTION_REMOVE, hdu, status);
756 status=0;
757 }
758
759 /* Close the input file. */
760 fits_close_file(in, &status);
761 }
762
763 /* Close the output file. */
764 if(out) fits_close_file(out, &status);
765 }
766
767
768
769
770
771 int
fits(struct fitsparams * p)772 fits(struct fitsparams *p)
773 {
774 int r=EXIT_SUCCESS, printhduinfo=1;
775
776 switch(p->mode)
777 {
778 /* Keywords, we have a separate set of functions in 'keywords.c'. */
779 case FITS_MODE_KEY:
780 r=keywords(p);
781 break;
782
783 /* HDU, functions defined here. */
784 case FITS_MODE_HDU:
785
786 /* Options that must be called alone. */
787 if(p->numhdus) fits_hdu_number(p);
788 else if(p->datasum) fits_datasum(p);
789 else if(p->pixelscale) fits_pixelscale(p);
790 else if(p->skycoverage) fits_skycoverage(p);
791 else if(p->hasimagehdu) fits_certain_hdu(p, 0, 0);
792 else if(p->hastablehdu) fits_certain_hdu(p, 0, 1);
793 else if(p->listimagehdus) fits_certain_hdu(p, 1, 0);
794 else if(p->listtablehdus) fits_certain_hdu(p, 1, 1);
795 else if(p->listallhdus) fits_list_all_hdus(p);
796
797 /* Options that can be called together. */
798 else
799 {
800 if(p->copy)
801 {
802 fits_hdu_copy(p, 0, &r);
803 printhduinfo=0;
804 }
805 if(p->cut)
806 {
807 fits_hdu_copy(p, 1, &r);
808 printhduinfo=0;
809 }
810 if(p->remove)
811 {
812 fits_hdu_remove(p, &r);
813 printhduinfo=0;
814 }
815
816 if(printhduinfo)
817 fits_print_extension_info(p);
818 }
819 break;
820
821 /* Not recognized. */
822 default:
823 error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s to address "
824 "the problem. The code %d is not recognized for p->mode",
825 __func__, PACKAGE_BUGREPORT, p->mode);
826 }
827
828 return r;
829 }
830