1 /* This file, cfileio.c, contains the low-level file access routines. */
2
3 /* The FITSIO software was written by William Pence at the High Energy */
4 /* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
5 /* Goddard Space Flight Center. */
6
7 #include <string.h>
8 #include <stdlib.h>
9 #include <math.h>
10 #include <ctype.h>
11 #include <errno.h>
12 #include <stddef.h> /* apparently needed to define size_t */
13 #include "fitsio2.h"
14 #include "group.h"
15 #ifdef CFITSIO_HAVE_CURL
16 #include <curl/curl.h>
17 #endif
18
19 #define MAX_PREFIX_LEN 20 /* max length of file type prefix (e.g. 'http://') */
20 #define MAX_DRIVERS 31 /* max number of file I/O drivers */
21
22 typedef struct /* structure containing pointers to I/O driver functions */
23 { char prefix[MAX_PREFIX_LEN];
24 int (*init)(void);
25 int (*shutdown)(void);
26 int (*setoptions)(int option);
27 int (*getoptions)(int *options);
28 int (*getversion)(int *version);
29 int (*checkfile)(char *urltype, char *infile, char *outfile);
30 int (*open)(char *filename, int rwmode, int *driverhandle);
31 int (*create)(char *filename, int *drivehandle);
32 int (*truncate)(int drivehandle, LONGLONG size);
33 int (*close)(int drivehandle);
34 int (*remove)(char *filename);
35 int (*size)(int drivehandle, LONGLONG *size);
36 int (*flush)(int drivehandle);
37 int (*seek)(int drivehandle, LONGLONG offset);
38 int (*read)(int drivehandle, void *buffer, long nbytes);
39 int (*write)(int drivehandle, void *buffer, long nbytes);
40 } fitsdriver;
41
42 fitsdriver driverTable[MAX_DRIVERS]; /* allocate driver tables */
43
44 FITSfile *FptrTable[NMAXFILES]; /* this table of Fptr pointers is */
45 /* used by fits_already_open */
46
47 int need_to_initialize = 1; /* true if CFITSIO has not been initialized */
48 int no_of_drivers = 0; /* number of currently defined I/O drivers */
49
50 static int pixel_filter_helper(fitsfile **fptr, char *outfile,
51 char *expr, int *status);
52 static int find_quote(char **string);
53 static int find_doublequote(char **string);
54 static int find_paren(char **string);
55 static int find_bracket(char **string);
56 static int find_curlybracket(char **string);
57 int comma2semicolon(char *string);
58
59 #ifdef _REENTRANT
60
61 pthread_mutex_t Fitsio_InitLock = PTHREAD_MUTEX_INITIALIZER;
62
63 #endif
64
65 /*--------------------------------------------------------------------------*/
fitsio_init_lock(void)66 int fitsio_init_lock(void)
67 {
68 int status = 0;
69
70 #ifdef _REENTRANT
71
72 static int need_to_init = 1;
73
74 pthread_mutexattr_t mutex_init;
75
76 FFLOCK1(Fitsio_InitLock);
77
78 if (need_to_init) {
79
80 /* Init the main fitsio lock here since we need a a recursive lock */
81
82 status = pthread_mutexattr_init(&mutex_init);
83 if (status) {
84 ffpmsg("pthread_mutexattr_init failed (fitsio_init_lock)");
85 return(status);
86 }
87
88 #ifdef __GLIBC__
89 status = pthread_mutexattr_settype(&mutex_init,
90 PTHREAD_MUTEX_RECURSIVE_NP);
91 #else
92 status = pthread_mutexattr_settype(&mutex_init,
93 PTHREAD_MUTEX_RECURSIVE);
94 #endif
95 if (status) {
96 ffpmsg("pthread_mutexattr_settype failed (fitsio_init_lock)");
97 return(status);
98 }
99
100 status = pthread_mutex_init(&Fitsio_Lock,&mutex_init);
101 if (status) {
102 ffpmsg("pthread_mutex_init failed (fitsio_init_lock)");
103 return(status);
104 }
105
106 need_to_init = 0;
107 }
108
109 FFUNLOCK1(Fitsio_InitLock);
110
111 #endif
112
113 return(status);
114 }
115 /*--------------------------------------------------------------------------*/
ffomem(fitsfile ** fptr,const char * name,int mode,void ** buffptr,size_t * buffsize,size_t deltasize,void * (* mem_realloc)(void * p,size_t newsize),int * status)116 int ffomem(fitsfile **fptr, /* O - FITS file pointer */
117 const char *name, /* I - name of file to open */
118 int mode, /* I - 0 = open readonly; 1 = read/write */
119 void **buffptr, /* I - address of memory pointer */
120 size_t *buffsize, /* I - size of buffer, in bytes */
121 size_t deltasize, /* I - increment for future realloc's */
122 void *(*mem_realloc)(void *p, size_t newsize), /* function */
123 int *status) /* IO - error status */
124 /*
125 Open an existing FITS file in core memory. This is a specialized version
126 of ffopen.
127 */
128 {
129 int ii, driver, handle, hdutyp, slen, movetotype, extvers, extnum;
130 char extname[FLEN_VALUE];
131 LONGLONG filesize;
132 char urltype[MAX_PREFIX_LEN], infile[FLEN_FILENAME], outfile[FLEN_FILENAME];
133 char extspec[FLEN_FILENAME], rowfilter[FLEN_FILENAME];
134 char binspec[FLEN_FILENAME], colspec[FLEN_FILENAME];
135 char imagecolname[FLEN_VALUE], rowexpress[FLEN_FILENAME];
136 char *url, errmsg[FLEN_ERRMSG];
137 char *hdtype[3] = {"IMAGE", "TABLE", "BINTABLE"};
138
139 if (*status > 0)
140 return(*status);
141
142 *fptr = 0; /* initialize null file pointer */
143
144 if (need_to_initialize) /* this is called only once */
145 {
146 *status = fits_init_cfitsio();
147
148 if (*status > 0)
149 return(*status);
150 }
151
152 url = (char *) name;
153 while (*url == ' ') /* ignore leading spaces in the file spec */
154 url++;
155
156 /* parse the input file specification */
157 fits_parse_input_url(url, urltype, infile, outfile, extspec,
158 rowfilter, binspec, colspec, status);
159
160 strcpy(urltype, "memkeep://"); /* URL type for pre-existing memory file */
161
162 *status = urltype2driver(urltype, &driver);
163
164 if (*status > 0)
165 {
166 ffpmsg("could not find driver for pre-existing memory file: (ffomem)");
167 return(*status);
168 }
169
170 /* call driver routine to open the memory file */
171 FFLOCK; /* lock this while searching for vacant handle */
172 *status = mem_openmem( buffptr, buffsize,deltasize,
173 mem_realloc, &handle);
174 FFUNLOCK;
175
176 if (*status > 0)
177 {
178 ffpmsg("failed to open pre-existing memory file: (ffomem)");
179 return(*status);
180 }
181
182 /* get initial file size */
183 *status = (*driverTable[driver].size)(handle, &filesize);
184
185 if (*status > 0)
186 {
187 (*driverTable[driver].close)(handle); /* close the file */
188 ffpmsg("failed get the size of the memory file: (ffomem)");
189 return(*status);
190 }
191
192 /* allocate fitsfile structure and initialize = 0 */
193 *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
194
195 if (!(*fptr))
196 {
197 (*driverTable[driver].close)(handle); /* close the file */
198 ffpmsg("failed to allocate structure for following file: (ffomem)");
199 ffpmsg(url);
200 return(*status = MEMORY_ALLOCATION);
201 }
202
203 /* allocate FITSfile structure and initialize = 0 */
204 (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
205
206 if (!((*fptr)->Fptr))
207 {
208 (*driverTable[driver].close)(handle); /* close the file */
209 ffpmsg("failed to allocate structure for following file: (ffomem)");
210 ffpmsg(url);
211 free(*fptr);
212 *fptr = 0;
213 return(*status = MEMORY_ALLOCATION);
214 }
215
216 slen = strlen(url) + 1;
217 slen = maxvalue(slen, 32); /* reserve at least 32 chars */
218 ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
219
220 if ( !(((*fptr)->Fptr)->filename) )
221 {
222 (*driverTable[driver].close)(handle); /* close the file */
223 ffpmsg("failed to allocate memory for filename: (ffomem)");
224 ffpmsg(url);
225 free((*fptr)->Fptr);
226 free(*fptr);
227 *fptr = 0; /* return null file pointer */
228 return(*status = MEMORY_ALLOCATION);
229 }
230
231 /* mem for headstart array */
232 ((*fptr)->Fptr)->headstart = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
233
234 if ( !(((*fptr)->Fptr)->headstart) )
235 {
236 (*driverTable[driver].close)(handle); /* close the file */
237 ffpmsg("failed to allocate memory for headstart array: (ffomem)");
238 ffpmsg(url);
239 free( ((*fptr)->Fptr)->filename);
240 free((*fptr)->Fptr);
241 free(*fptr);
242 *fptr = 0; /* return null file pointer */
243 return(*status = MEMORY_ALLOCATION);
244 }
245
246 /* mem for file I/O buffers */
247 ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
248
249 if ( !(((*fptr)->Fptr)->iobuffer) )
250 {
251 (*driverTable[driver].close)(handle); /* close the file */
252 ffpmsg("failed to allocate memory for iobuffer array: (ffomem)");
253 ffpmsg(url);
254 free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
255 free( ((*fptr)->Fptr)->filename);
256 free((*fptr)->Fptr);
257 free(*fptr);
258 *fptr = 0; /* return null file pointer */
259 return(*status = MEMORY_ALLOCATION);
260 }
261
262 /* initialize the ageindex array (relative age of the I/O buffers) */
263 /* and initialize the bufrecnum array as being empty */
264 for (ii = 0; ii < NIOBUF; ii++) {
265 ((*fptr)->Fptr)->ageindex[ii] = ii;
266 ((*fptr)->Fptr)->bufrecnum[ii] = -1;
267 }
268
269 /* store the parameters describing the file */
270 ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
271 ((*fptr)->Fptr)->filehandle = handle; /* file handle */
272 ((*fptr)->Fptr)->driver = driver; /* driver number */
273 strcpy(((*fptr)->Fptr)->filename, url); /* full input filename */
274 ((*fptr)->Fptr)->filesize = filesize; /* physical file size */
275 ((*fptr)->Fptr)->logfilesize = filesize; /* logical file size */
276 ((*fptr)->Fptr)->writemode = mode; /* read-write mode */
277 ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
278 ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
279 ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
280 ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
281
282 ffldrc(*fptr, 0, REPORT_EOF, status); /* load first record */
283
284 fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
285
286 if (ffrhdu(*fptr, &hdutyp, status) > 0) /* determine HDU structure */
287 {
288 ffpmsg(
289 "ffomem could not interpret primary array header of file: (ffomem)");
290 ffpmsg(url);
291
292 if (*status == UNKNOWN_REC)
293 ffpmsg("This does not look like a FITS file.");
294
295 ffclos(*fptr, status);
296 *fptr = 0; /* return null file pointer */
297 }
298
299 /* ---------------------------------------------------------- */
300 /* move to desired extension, if specified as part of the URL */
301 /* ---------------------------------------------------------- */
302
303 imagecolname[0] = '\0';
304 rowexpress[0] = '\0';
305
306 if (*extspec)
307 {
308 /* parse the extension specifier into individual parameters */
309 ffexts(extspec, &extnum,
310 extname, &extvers, &movetotype, imagecolname, rowexpress, status);
311
312
313 if (*status > 0)
314 return(*status);
315
316 if (extnum)
317 {
318 ffmahd(*fptr, extnum + 1, &hdutyp, status);
319 }
320 else if (*extname) /* move to named extension, if specified */
321 {
322 ffmnhd(*fptr, movetotype, extname, extvers, status);
323 }
324
325 if (*status > 0)
326 {
327 ffpmsg("ffomem could not move to the specified extension:");
328 if (extnum > 0)
329 {
330 snprintf(errmsg, FLEN_ERRMSG,
331 " extension number %d doesn't exist or couldn't be opened.",extnum);
332 ffpmsg(errmsg);
333 }
334 else
335 {
336 snprintf(errmsg, FLEN_ERRMSG,
337 " extension with EXTNAME = %s,", extname);
338 ffpmsg(errmsg);
339
340 if (extvers)
341 {
342 snprintf(errmsg, FLEN_ERRMSG,
343 " and with EXTVERS = %d,", extvers);
344 ffpmsg(errmsg);
345 }
346
347 if (movetotype != ANY_HDU)
348 {
349 snprintf(errmsg, FLEN_ERRMSG,
350 " and with XTENSION = %s,", hdtype[movetotype]);
351 ffpmsg(errmsg);
352 }
353
354 ffpmsg(" doesn't exist or couldn't be opened.");
355 }
356 return(*status);
357 }
358 }
359
360 return(*status);
361 }
362 /*--------------------------------------------------------------------------*/
ffdkopn(fitsfile ** fptr,const char * name,int mode,int * status)363 int ffdkopn(fitsfile **fptr, /* O - FITS file pointer */
364 const char *name, /* I - full name of file to open */
365 int mode, /* I - 0 = open readonly; 1 = read/write */
366 int *status) /* IO - error status */
367 /*
368 Open an existing FITS file on magnetic disk with either readonly or
369 read/write access. The routine does not support CFITSIO's extended
370 filename syntax and simply uses the entire input 'name' string as
371 the name of the file.
372 */
373 {
374 if (*status > 0)
375 return(*status);
376
377 *status = OPEN_DISK_FILE;
378
379 ffopen(fptr, name, mode, status);
380
381 return(*status);
382 }
383 /*--------------------------------------------------------------------------*/
ffdopn(fitsfile ** fptr,const char * name,int mode,int * status)384 int ffdopn(fitsfile **fptr, /* O - FITS file pointer */
385 const char *name, /* I - full name of file to open */
386 int mode, /* I - 0 = open readonly; 1 = read/write */
387 int *status) /* IO - error status */
388 /*
389 Open an existing FITS file with either readonly or read/write access. and
390 move to the first HDU that contains 'interesting' data, if the primary
391 array contains a null image (i.e., NAXIS = 0).
392 */
393 {
394 if (*status > 0)
395 return(*status);
396
397 *status = SKIP_NULL_PRIMARY;
398
399 ffopen(fptr, name, mode, status);
400
401 return(*status);
402 }
403 /*--------------------------------------------------------------------------*/
ffeopn(fitsfile ** fptr,const char * name,int mode,char * extlist,int * hdutype,int * status)404 int ffeopn(fitsfile **fptr, /* O - FITS file pointer */
405 const char *name, /* I - full name of file to open */
406 int mode, /* I - 0 = open readonly; 1 = read/write */
407 char *extlist, /* I - list of 'good' extensions to move to */
408 int *hdutype, /* O - type of extension that is moved to */
409 int *status) /* IO - error status */
410 /*
411 Open an existing FITS file with either readonly or read/write access. and
412 if the primary array contains a null image (i.e., NAXIS = 0) then attempt to
413 move to the first extension named in the extlist of extension names. If
414 none are found, then simply move to the 2nd extension.
415 */
416 {
417 int hdunum, naxis, thdutype, gotext=0;
418 char *ext, *textlist;
419 char *saveptr;
420
421 if (*status > 0)
422 return(*status);
423
424 if (ffopen(fptr, name, mode, status) > 0)
425 return(*status);
426
427 fits_get_hdu_num(*fptr, &hdunum);
428 fits_get_img_dim(*fptr, &naxis, status);
429
430 if( (hdunum == 1) && (naxis == 0) ){
431 /* look through the extension list */
432 if( extlist ){
433 gotext = 0;
434 textlist = malloc(strlen(extlist) + 1);
435 if (!textlist) {
436 *status = MEMORY_ALLOCATION;
437 return(*status);
438 }
439
440 strcpy(textlist, extlist);
441 for(ext=(char *)ffstrtok(textlist, " ",&saveptr); ext != NULL;
442 ext=(char *)ffstrtok(NULL," ",&saveptr)){
443 fits_movnam_hdu(*fptr, ANY_HDU, ext, 0, status);
444 if( *status == 0 ){
445 gotext = 1;
446 break;
447 } else {
448 *status = 0;
449 }
450 }
451 free(textlist);
452 }
453 if( !gotext ){
454 /* if all else fails, move to extension #2 and hope for the best */
455 fits_movabs_hdu(*fptr, 2, &thdutype, status);
456 }
457 }
458 fits_get_hdu_type(*fptr, hdutype, status);
459 return(*status);
460 }
461 /*--------------------------------------------------------------------------*/
fftopn(fitsfile ** fptr,const char * name,int mode,int * status)462 int fftopn(fitsfile **fptr, /* O - FITS file pointer */
463 const char *name, /* I - full name of file to open */
464 int mode, /* I - 0 = open readonly; 1 = read/write */
465 int *status) /* IO - error status */
466 /*
467 Open an existing FITS file with either readonly or read/write access. and
468 move to the first HDU that contains 'interesting' table (not an image).
469 */
470 {
471 int hdutype;
472
473 if (*status > 0)
474 return(*status);
475
476 *status = SKIP_IMAGE;
477
478 ffopen(fptr, name, mode, status);
479
480 if (ffghdt(*fptr, &hdutype, status) <= 0) {
481 if (hdutype == IMAGE_HDU)
482 *status = NOT_TABLE;
483 }
484
485 return(*status);
486 }
487 /*--------------------------------------------------------------------------*/
ffiopn(fitsfile ** fptr,const char * name,int mode,int * status)488 int ffiopn(fitsfile **fptr, /* O - FITS file pointer */
489 const char *name, /* I - full name of file to open */
490 int mode, /* I - 0 = open readonly; 1 = read/write */
491 int *status) /* IO - error status */
492 /*
493 Open an existing FITS file with either readonly or read/write access. and
494 move to the first HDU that contains 'interesting' image (not an table).
495 */
496 {
497 int hdutype;
498
499 if (*status > 0)
500 return(*status);
501
502 *status = SKIP_TABLE;
503
504 ffopen(fptr, name, mode, status);
505
506 if (ffghdt(*fptr, &hdutype, status) <= 0) {
507 if (hdutype != IMAGE_HDU)
508 *status = NOT_IMAGE;
509 }
510
511 return(*status);
512 }
513 /*--------------------------------------------------------------------------*/
ffopentest(int soname,fitsfile ** fptr,const char * name,int mode,int * status)514 int ffopentest(int soname, /* I - CFITSIO shared library version */
515 /* application program (fitsio.h file) */
516 fitsfile **fptr, /* O - FITS file pointer */
517 const char *name, /* I - full name of file to open */
518 int mode, /* I - 0 = open readonly; 1 = read/write */
519 int *status) /* IO - error status */
520 /*
521 Open an existing FITS file with either readonly or read/write access.
522 First test that the SONAME of fitsio.h used to build the CFITSIO library
523 is the same as was used in compiling the application program that
524 links to the library.
525 */
526 {
527 if (soname != CFITSIO_SONAME)
528 {
529 printf("\nERROR: Mismatch in the CFITSIO_SONAME value in the fitsio.h include file\n");
530 printf("that was used to build the CFITSIO library, and the value in the include file\n");
531 printf("that was used when compiling the application program:\n");
532 printf(" Version used to build the CFITSIO library = %d\n",CFITSIO_SONAME);
533 printf(" Version included by the application program = %d\n",soname);
534 printf("\nFix this by recompiling and then relinking this application program \n");
535 printf("with the CFITSIO library.\n");
536
537 *status = FILE_NOT_OPENED;
538 return(*status);
539 }
540
541 /* now call the normal file open routine */
542 ffopen(fptr, name, mode, status);
543 return(*status);
544 }
545 /*--------------------------------------------------------------------------*/
ffopen(fitsfile ** fptr,const char * name,int mode,int * status)546 int ffopen(fitsfile **fptr, /* O - FITS file pointer */
547 const char *name, /* I - full name of file to open */
548 int mode, /* I - 0 = open readonly; 1 = read/write */
549 int *status) /* IO - error status */
550 /*
551 Open an existing FITS file with either readonly or read/write access.
552 */
553 {
554 fitsfile *newptr;
555 int ii, driver, hdutyp, hdunum, slen, writecopy, isopen;
556 LONGLONG filesize;
557 long rownum, nrows, goodrows;
558 int extnum, extvers, handle, movetotype, tstatus = 0, only_one = 0;
559 char urltype[MAX_PREFIX_LEN], infile[FLEN_FILENAME], outfile[FLEN_FILENAME];
560 char origurltype[MAX_PREFIX_LEN], extspec[FLEN_FILENAME];
561 char extname[FLEN_VALUE], rowfilter[FLEN_FILENAME], tblname[FLEN_VALUE];
562 char imagecolname[FLEN_VALUE], rowexpress[FLEN_FILENAME];
563 char binspec[FLEN_FILENAME], colspec[FLEN_FILENAME], pixfilter[FLEN_FILENAME];
564 char histfilename[FLEN_FILENAME];
565 char filtfilename[FLEN_FILENAME], compspec[FLEN_FILENAME];
566 char wtcol[FLEN_VALUE];
567 char minname[4][FLEN_VALUE], maxname[4][FLEN_VALUE];
568 char binname[4][FLEN_VALUE];
569
570 char *url;
571 double minin[4], maxin[4], binsizein[4], weight;
572 int imagetype, naxis = 1, haxis, recip;
573 int skip_null = 0, skip_image = 0, skip_table = 0, open_disk_file = 0;
574 char colname[4][FLEN_VALUE];
575 char errmsg[FLEN_ERRMSG];
576 char *hdtype[3] = {"IMAGE", "TABLE", "BINTABLE"};
577 char *rowselect = 0;
578
579 if (*status > 0)
580 return(*status);
581
582 if (*status == SKIP_NULL_PRIMARY)
583 {
584 /* this special status value is used as a flag by ffdopn to tell */
585 /* ffopen to skip over a null primary array when opening the file. */
586
587 skip_null = 1;
588 *status = 0;
589 }
590 else if (*status == SKIP_IMAGE)
591 {
592 /* this special status value is used as a flag by fftopn to tell */
593 /* ffopen to move to 1st significant table when opening the file. */
594
595 skip_image = 1;
596 *status = 0;
597 }
598 else if (*status == SKIP_TABLE)
599 {
600 /* this special status value is used as a flag by ffiopn to tell */
601 /* ffopen to move to 1st significant image when opening the file. */
602
603 skip_table = 1;
604 *status = 0;
605 }
606 else if (*status == OPEN_DISK_FILE)
607 {
608 /* this special status value is used as a flag by ffdkopn to tell */
609 /* ffopen to not interpret the input filename using CFITSIO's */
610 /* extended filename syntax, and simply open the specified disk file */
611
612 open_disk_file = 1;
613 *status = 0;
614 }
615
616 *fptr = 0; /* initialize null file pointer */
617 writecopy = 0; /* have we made a write-able copy of the input file? */
618
619 if (need_to_initialize) { /* this is called only once */
620 *status = fits_init_cfitsio();
621 }
622
623 if (*status > 0)
624 return(*status);
625
626 url = (char *) name;
627 while (*url == ' ') /* ignore leading spaces in the filename */
628 url++;
629
630 if (*url == '\0')
631 {
632 ffpmsg("Name of file to open is blank. (ffopen)");
633 return(*status = FILE_NOT_OPENED);
634 }
635
636 if (open_disk_file)
637 {
638 /* treat the input URL literally as the name of the file to open */
639 /* and don't try to parse the URL using the extended filename syntax */
640
641 if (strlen(url) > FLEN_FILENAME - 1) {
642 ffpmsg("Name of file to open is too long. (ffopen)");
643 return(*status = FILE_NOT_OPENED);
644 }
645
646 strcpy(infile,url);
647 strcpy(urltype, "file://");
648 outfile[0] = '\0';
649 extspec[0] = '\0';
650 binspec[0] = '\0';
651 colspec[0] = '\0';
652 rowfilter[0] = '\0';
653 pixfilter[0] = '\0';
654 compspec[0] = '\0';
655 }
656 else
657 {
658 /* parse the input file specification */
659
660 /* NOTE: This routine tests that all the strings do not */
661 /* overflow the standard buffer sizes (FLEN_FILENAME, etc.) */
662 /* therefore in general we do not have to worry about buffer */
663 /* overflow of any of the returned strings. */
664
665 /* call the newer version of this parsing routine that supports 'compspec' */
666 ffifile2(url, urltype, infile, outfile, extspec,
667 rowfilter, binspec, colspec, pixfilter, compspec, status);
668 }
669
670 if (*status > 0)
671 {
672 ffpmsg("could not parse the input filename: (ffopen)");
673 ffpmsg(url);
674 return(*status);
675 }
676
677 imagecolname[0] = '\0';
678 rowexpress[0] = '\0';
679
680 if (*extspec)
681 {
682 slen = strlen(extspec);
683 if (extspec[slen - 1] == '#') { /* special symbol to mean only copy this extension */
684 extspec[slen - 1] = '\0';
685 only_one = 1;
686 }
687
688 /* parse the extension specifier into individual parameters */
689 ffexts(extspec, &extnum,
690 extname, &extvers, &movetotype, imagecolname, rowexpress, status);
691
692 if (*status > 0)
693 return(*status);
694 }
695
696 /*-------------------------------------------------------------------*/
697 /* special cases: */
698 /*-------------------------------------------------------------------*/
699
700 histfilename[0] = '\0';
701 filtfilename[0] = '\0';
702 if (*outfile && (*binspec || *imagecolname || *pixfilter))
703 {
704 /* if binspec or imagecolumn are specified, then the */
705 /* output file name is intended for the final image, */
706 /* and not a copy of the input file. */
707
708 strcpy(histfilename, outfile);
709 outfile[0] = '\0';
710 }
711 else if (*outfile && (*rowfilter || *colspec))
712 {
713 /* if rowfilter or colspece are specified, then the */
714 /* output file name is intended for the filtered file */
715 /* and not a copy of the input file. */
716
717 strcpy(filtfilename, outfile);
718 outfile[0] = '\0';
719 }
720
721 /*-------------------------------------------------------------------*/
722 /* check if this same file is already open, and if so, attach to it */
723 /*-------------------------------------------------------------------*/
724
725 FFLOCK;
726 if (fits_already_open(fptr, url, urltype, infile, extspec, rowfilter,
727 binspec, colspec, mode, &isopen, status) > 0)
728 {
729 FFUNLOCK;
730 return(*status);
731 }
732 FFUNLOCK;
733
734 if (isopen) {
735 goto move2hdu;
736 }
737
738 /* get the driver number corresponding to this urltype */
739 *status = urltype2driver(urltype, &driver);
740
741 if (*status > 0)
742 {
743 ffpmsg("could not find driver for this file: (ffopen)");
744 ffpmsg(urltype);
745 ffpmsg(url);
746 return(*status);
747 }
748
749 /*-------------------------------------------------------------------
750 deal with all those messy special cases which may require that
751 a different driver be used:
752 - is disk file compressed?
753 - are ftp:, gsiftp:, or http: files compressed?
754 - has user requested that a local copy be made of
755 the ftp or http file?
756 -------------------------------------------------------------------*/
757
758 if (driverTable[driver].checkfile)
759 {
760 strcpy(origurltype,urltype); /* Save the urltype */
761
762 /* 'checkfile' may modify the urltype, infile and outfile strings */
763 *status = (*driverTable[driver].checkfile)(urltype, infile, outfile);
764
765 if (*status)
766 {
767 ffpmsg("checkfile failed for this file: (ffopen)");
768 ffpmsg(url);
769 return(*status);
770 }
771
772 if (strcmp(origurltype, urltype)) /* did driver changed on us? */
773 {
774 *status = urltype2driver(urltype, &driver);
775 if (*status > 0)
776 {
777 ffpmsg("could not change driver for this file: (ffopen)");
778 ffpmsg(url);
779 ffpmsg(urltype);
780 return(*status);
781 }
782 }
783 }
784
785 /* call appropriate driver to open the file */
786 if (driverTable[driver].open)
787 {
788 FFLOCK; /* lock this while searching for vacant handle */
789 *status = (*driverTable[driver].open)(infile, mode, &handle);
790 FFUNLOCK;
791 if (*status > 0)
792 {
793 ffpmsg("failed to find or open the following file: (ffopen)");
794 ffpmsg(url);
795 return(*status);
796 }
797 }
798 else
799 {
800 ffpmsg("cannot open an existing file of this type: (ffopen)");
801 ffpmsg(url);
802 return(*status = FILE_NOT_OPENED);
803 }
804
805 /* get initial file size */
806 *status = (*driverTable[driver].size)(handle, &filesize);
807 if (*status > 0)
808 {
809 (*driverTable[driver].close)(handle); /* close the file */
810 ffpmsg("failed get the size of the following file: (ffopen)");
811 ffpmsg(url);
812 return(*status);
813 }
814
815 /* allocate fitsfile structure and initialize = 0 */
816 *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
817
818 if (!(*fptr))
819 {
820 (*driverTable[driver].close)(handle); /* close the file */
821 ffpmsg("failed to allocate structure for following file: (ffopen)");
822 ffpmsg(url);
823 return(*status = MEMORY_ALLOCATION);
824 }
825
826 /* allocate FITSfile structure and initialize = 0 */
827 (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
828
829 if (!((*fptr)->Fptr))
830 {
831 (*driverTable[driver].close)(handle); /* close the file */
832 ffpmsg("failed to allocate structure for following file: (ffopen)");
833 ffpmsg(url);
834 free(*fptr);
835 *fptr = 0;
836 return(*status = MEMORY_ALLOCATION);
837 }
838
839 slen = strlen(url) + 1;
840 slen = maxvalue(slen, 32); /* reserve at least 32 chars */
841 ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
842
843 if ( !(((*fptr)->Fptr)->filename) )
844 {
845 (*driverTable[driver].close)(handle); /* close the file */
846 ffpmsg("failed to allocate memory for filename: (ffopen)");
847 ffpmsg(url);
848 free((*fptr)->Fptr);
849 free(*fptr);
850 *fptr = 0; /* return null file pointer */
851 return(*status = MEMORY_ALLOCATION);
852 }
853
854 /* mem for headstart array */
855 ((*fptr)->Fptr)->headstart = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
856
857 if ( !(((*fptr)->Fptr)->headstart) )
858 {
859 (*driverTable[driver].close)(handle); /* close the file */
860 ffpmsg("failed to allocate memory for headstart array: (ffopen)");
861 ffpmsg(url);
862 free( ((*fptr)->Fptr)->filename);
863 free((*fptr)->Fptr);
864 free(*fptr);
865 *fptr = 0; /* return null file pointer */
866 return(*status = MEMORY_ALLOCATION);
867 }
868
869 /* mem for file I/O buffers */
870 ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
871
872 if ( !(((*fptr)->Fptr)->iobuffer) )
873 {
874 (*driverTable[driver].close)(handle); /* close the file */
875 ffpmsg("failed to allocate memory for iobuffer array: (ffopen)");
876 ffpmsg(url);
877 free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
878 free( ((*fptr)->Fptr)->filename);
879 free((*fptr)->Fptr);
880 free(*fptr);
881 *fptr = 0; /* return null file pointer */
882 return(*status = MEMORY_ALLOCATION);
883 }
884
885 /* initialize the ageindex array (relative age of the I/O buffers) */
886 /* and initialize the bufrecnum array as being empty */
887 for (ii = 0; ii < NIOBUF; ii++) {
888 ((*fptr)->Fptr)->ageindex[ii] = ii;
889 ((*fptr)->Fptr)->bufrecnum[ii] = -1;
890 }
891
892 /* store the parameters describing the file */
893 ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
894 ((*fptr)->Fptr)->filehandle = handle; /* file handle */
895 ((*fptr)->Fptr)->driver = driver; /* driver number */
896 strcpy(((*fptr)->Fptr)->filename, url); /* full input filename */
897 ((*fptr)->Fptr)->filesize = filesize; /* physical file size */
898 ((*fptr)->Fptr)->logfilesize = filesize; /* logical file size */
899 ((*fptr)->Fptr)->writemode = mode; /* read-write mode */
900 ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
901 ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
902 ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
903 ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
904 ((*fptr)->Fptr)->only_one = only_one; /* flag denoting only copy single extension */
905
906 ffldrc(*fptr, 0, REPORT_EOF, status); /* load first record */
907
908 fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
909
910 if (ffrhdu(*fptr, &hdutyp, status) > 0) /* determine HDU structure */
911 {
912 ffpmsg(
913 "ffopen could not interpret primary array header of file: ");
914 ffpmsg(url);
915
916 if (*status == UNKNOWN_REC)
917 ffpmsg("This does not look like a FITS file.");
918
919 ffclos(*fptr, status);
920 *fptr = 0; /* return null file pointer */
921 return(*status);
922 }
923
924 /* ------------------------------------------------------------- */
925 /* At this point, the input file has been opened. If outfile was */
926 /* specified, then we have opened a copy of the file, not the */
927 /* original file so it is safe to modify it if necessary */
928 /* ------------------------------------------------------------- */
929
930 if (*outfile)
931 writecopy = 1;
932
933 move2hdu:
934
935 /* ---------------------------------------------------------- */
936 /* move to desired extension, if specified as part of the URL */
937 /* ---------------------------------------------------------- */
938
939 if (*extspec)
940 {
941 if (extnum) /* extension number was specified */
942 {
943 ffmahd(*fptr, extnum + 1, &hdutyp, status);
944 }
945 else if (*extname) /* move to named extension, if specified */
946 {
947 ffmnhd(*fptr, movetotype, extname, extvers, status);
948 }
949
950 if (*status > 0) /* clean up after error */
951 {
952 ffpmsg("ffopen could not move to the specified extension:");
953 if (extnum > 0)
954 {
955 snprintf(errmsg, FLEN_ERRMSG,
956 " extension number %d doesn't exist or couldn't be opened.",extnum);
957 ffpmsg(errmsg);
958 }
959 else
960 {
961 snprintf(errmsg, FLEN_ERRMSG,
962 " extension with EXTNAME = %s,", extname);
963 ffpmsg(errmsg);
964
965 if (extvers)
966 {
967 snprintf(errmsg, FLEN_ERRMSG,
968 " and with EXTVERS = %d,", extvers);
969 ffpmsg(errmsg);
970 }
971
972 if (movetotype != ANY_HDU)
973 {
974 snprintf(errmsg, FLEN_ERRMSG,
975 " and with XTENSION = %s,", hdtype[movetotype]);
976 ffpmsg(errmsg);
977 }
978
979 ffpmsg(" doesn't exist or couldn't be opened.");
980 }
981
982 ffclos(*fptr, status);
983 *fptr = 0; /* return null file pointer */
984 return(*status);
985 }
986 }
987 else if (skip_null || skip_image || skip_table ||
988 (*imagecolname || *colspec || *rowfilter || *binspec))
989 {
990 /* ------------------------------------------------------------------
991
992 If no explicit extension specifier is given as part of the file
993 name, and, if a) skip_null is true (set if ffopen is called by
994 ffdopn) or b) skip_image or skip_table is true (set if ffopen is
995 called by fftopn or ffdopn) or c) other file filters are
996 specified, then CFITSIO will attempt to move to the first
997 'interesting' HDU after opening an existing FITS file (or to
998 first interesting table HDU if skip_image is true);
999
1000 An 'interesting' HDU is defined to be either an image with NAXIS
1001 > 0 (i.e., not a null array) or a table which has an EXTNAME
1002 value which does not contain any of the following strings:
1003 'GTI' - Good Time Interval extension
1004 'OBSTABLE' - used in Beppo SAX data files
1005
1006 The main purpose for this is to allow CFITSIO to skip over a null
1007 primary and other non-interesting HDUs when opening an existing
1008 file, and move directly to the first extension that contains
1009 significant data.
1010 ------------------------------------------------------------------ */
1011
1012 fits_get_hdu_num(*fptr, &hdunum);
1013 if (hdunum == 1) {
1014
1015 fits_get_img_dim(*fptr, &naxis, status);
1016
1017 if (naxis == 0 || skip_image) /* skip primary array */
1018 {
1019 while(1)
1020 {
1021 /* see if the next HDU is 'interesting' */
1022 if (fits_movrel_hdu(*fptr, 1, &hdutyp, status))
1023 {
1024 if (*status == END_OF_FILE)
1025 *status = 0; /* reset expected error */
1026
1027 /* didn't find an interesting HDU so move back to beginning */
1028 fits_movabs_hdu(*fptr, 1, &hdutyp, status);
1029 break;
1030 }
1031
1032 if (hdutyp == IMAGE_HDU && skip_image) {
1033
1034 continue; /* skip images */
1035
1036 } else if (hdutyp != IMAGE_HDU && skip_table) {
1037
1038 continue; /* skip tables */
1039
1040 } else if (hdutyp == IMAGE_HDU) {
1041
1042 fits_get_img_dim(*fptr, &naxis, status);
1043 if (naxis > 0)
1044 break; /* found a non-null image */
1045
1046 } else {
1047
1048 tstatus = 0;
1049 tblname[0] = '\0';
1050 fits_read_key(*fptr, TSTRING, "EXTNAME", tblname, NULL,&tstatus);
1051
1052 if ( (!strstr(tblname, "GTI") && !strstr(tblname, "gti")) &&
1053 fits_strncasecmp(tblname, "OBSTABLE", 8) )
1054 break; /* found an interesting table */
1055 }
1056 } /* end while */
1057 }
1058 } /* end if (hdunum==1) */
1059 }
1060
1061 if (*imagecolname)
1062 {
1063 /* ----------------------------------------------------------------- */
1064 /* we need to open an image contained in a single table cell */
1065 /* First, determine which row of the table to use. */
1066 /* ----------------------------------------------------------------- */
1067
1068 if (isdigit((int) *rowexpress)) /* is the row specification a number? */
1069 {
1070 sscanf(rowexpress, "%ld", &rownum);
1071 if (rownum < 1)
1072 {
1073 ffpmsg("illegal rownum for image cell:");
1074 ffpmsg(rowexpress);
1075 ffpmsg("Could not open the following image in a table cell:");
1076 ffpmsg(extspec);
1077 ffclos(*fptr, status);
1078 *fptr = 0; /* return null file pointer */
1079 return(*status = BAD_ROW_NUM);
1080 }
1081 }
1082 else if (fits_find_first_row(*fptr, rowexpress, &rownum, status) > 0)
1083 {
1084 ffpmsg("Failed to find row matching this expression:");
1085 ffpmsg(rowexpress);
1086 ffpmsg("Could not open the following image in a table cell:");
1087 ffpmsg(extspec);
1088 ffclos(*fptr, status);
1089 *fptr = 0; /* return null file pointer */
1090 return(*status);
1091 }
1092
1093 if (rownum == 0)
1094 {
1095 ffpmsg("row statisfying this expression doesn't exist::");
1096 ffpmsg(rowexpress);
1097 ffpmsg("Could not open the following image in a table cell:");
1098 ffpmsg(extspec);
1099 ffclos(*fptr, status);
1100 *fptr = 0; /* return null file pointer */
1101 return(*status = BAD_ROW_NUM);
1102 }
1103
1104 /* determine the name of the new file to contain copy of the image */
1105 if (*histfilename && !(*pixfilter) )
1106 strcpy(outfile, histfilename); /* the original outfile name */
1107 else
1108 strcpy(outfile, "mem://_1"); /* create image file in memory */
1109
1110 /* Copy the image into new primary array and open it as the current */
1111 /* fptr. This will close the table that contains the original image. */
1112
1113 /* create new empty file to hold copy of the image */
1114 if (ffinit(&newptr, outfile, status) > 0)
1115 {
1116 ffpmsg("failed to create file for copy of image in table cell:");
1117 ffpmsg(outfile);
1118 return(*status);
1119 }
1120
1121 if (fits_copy_cell2image(*fptr, newptr, imagecolname, rownum,
1122 status) > 0)
1123 {
1124 ffpmsg("Failed to copy table cell to new primary array:");
1125 ffpmsg(extspec);
1126 ffclos(*fptr, status);
1127 *fptr = 0; /* return null file pointer */
1128 return(*status);
1129 }
1130
1131 /* close the original file and set fptr to the new image */
1132 ffclos(*fptr, status);
1133
1134 *fptr = newptr; /* reset the pointer to the new table */
1135
1136 writecopy = 1; /* we are now dealing with a copy of the original file */
1137
1138
1139 /* leave it up to calling routine to write any HISTORY keywords */
1140 }
1141
1142 /* --------------------------------------------------------------------- */
1143 /* edit columns (and/or keywords) in the table, if specified in the URL */
1144 /* --------------------------------------------------------------------- */
1145
1146 if (*colspec)
1147 {
1148 /* the column specifier will modify the file, so make sure */
1149 /* we are already dealing with a copy, or else make a new copy */
1150
1151 if (!writecopy) /* Is the current file already a copy? */
1152 writecopy = fits_is_this_a_copy(urltype);
1153
1154 if (!writecopy)
1155 {
1156 if (*filtfilename && *outfile == '\0')
1157 strcpy(outfile, filtfilename); /* the original outfile name */
1158 else
1159 strcpy(outfile, "mem://_1"); /* will create copy in memory */
1160
1161 writecopy = 1;
1162 }
1163 else
1164 {
1165 ((*fptr)->Fptr)->writemode = READWRITE; /* we have write access */
1166 outfile[0] = '\0';
1167 }
1168
1169 if (ffedit_columns(fptr, outfile, colspec, status) > 0)
1170 {
1171 ffpmsg("editing columns in input table failed (ffopen)");
1172 ffpmsg(" while trying to perform the following operation:");
1173 ffpmsg(colspec);
1174 ffclos(*fptr, status);
1175 *fptr = 0; /* return null file pointer */
1176 return(*status);
1177 }
1178 }
1179
1180 /* ------------------------------------------------------------------- */
1181 /* select rows from the table, if specified in the URL */
1182 /* or select a subimage (if this is an image HDU and not a table) */
1183 /* ------------------------------------------------------------------- */
1184
1185 if (*rowfilter)
1186 {
1187 fits_get_hdu_type(*fptr, &hdutyp, status); /* get type of HDU */
1188 if (hdutyp == IMAGE_HDU)
1189 {
1190 /* this is an image so 'rowfilter' is an image section specification */
1191
1192 if (*filtfilename && *outfile == '\0')
1193 strcpy(outfile, filtfilename); /* the original outfile name */
1194 else if (*outfile == '\0') /* output file name not already defined? */
1195 strcpy(outfile, "mem://_2"); /* will create file in memory */
1196
1197 /* create new file containing the image section, plus a copy of */
1198 /* any other HDUs that exist in the input file. This routine */
1199 /* will close the original image file and return a pointer */
1200 /* to the new file. */
1201
1202 if (fits_select_image_section(fptr, outfile, rowfilter, status) > 0)
1203 {
1204 ffpmsg("on-the-fly selection of image section failed (ffopen)");
1205 ffpmsg(" while trying to use the following section filter:");
1206 ffpmsg(rowfilter);
1207 ffclos(*fptr, status);
1208 *fptr = 0; /* return null file pointer */
1209 return(*status);
1210 }
1211 }
1212 else
1213 {
1214 /* this is a table HDU, so the rowfilter is really a row filter */
1215
1216 if (*binspec)
1217 {
1218 /* since we are going to make a histogram of the selected rows, */
1219 /* it would be a waste of time and memory to make a whole copy of */
1220 /* the selected rows. Instead, just construct an array of TRUE */
1221 /* or FALSE values that indicate which rows are to be included */
1222 /* in the histogram and pass that to the histogram generating */
1223 /* routine */
1224
1225 fits_get_num_rows(*fptr, &nrows, status); /* get no. of rows */
1226
1227 rowselect = (char *) calloc(nrows, 1);
1228 if (!rowselect)
1229 {
1230 ffpmsg(
1231 "failed to allocate memory for selected columns array (ffopen)");
1232 ffpmsg(" while trying to select rows with the following filter:");
1233 ffpmsg(rowfilter);
1234 ffclos(*fptr, status);
1235 *fptr = 0; /* return null file pointer */
1236 return(*status = MEMORY_ALLOCATION);
1237 }
1238
1239 if (fits_find_rows(*fptr, rowfilter, 1L, nrows, &goodrows,
1240 rowselect, status) > 0)
1241 {
1242 ffpmsg("selection of rows in input table failed (ffopen)");
1243 ffpmsg(" while trying to select rows with the following filter:");
1244 ffpmsg(rowfilter);
1245 free(rowselect);
1246 ffclos(*fptr, status);
1247 *fptr = 0; /* return null file pointer */
1248 return(*status);
1249 }
1250 }
1251 else
1252 {
1253 if (!writecopy) /* Is the current file already a copy? */
1254 writecopy = fits_is_this_a_copy(urltype);
1255
1256 if (!writecopy)
1257 {
1258 if (*filtfilename && *outfile == '\0')
1259 strcpy(outfile, filtfilename); /* the original outfile name */
1260 else if (*outfile == '\0') /* output filename not already defined? */
1261 strcpy(outfile, "mem://_2"); /* will create copy in memory */
1262 }
1263 else
1264 {
1265 ((*fptr)->Fptr)->writemode = READWRITE; /* we have write access */
1266 outfile[0] = '\0';
1267 }
1268
1269 /* select rows in the table. If a copy of the input file has */
1270 /* not already been made, then this routine will make a copy */
1271 /* and then close the input file, so that the modifications will */
1272 /* only be made on the copy, not the original */
1273
1274 if (ffselect_table(fptr, outfile, rowfilter, status) > 0)
1275 {
1276 ffpmsg("on-the-fly selection of rows in input table failed (ffopen)");
1277 ffpmsg(" while trying to select rows with the following filter:");
1278 ffpmsg(rowfilter);
1279 ffclos(*fptr, status);
1280 *fptr = 0; /* return null file pointer */
1281 return(*status);
1282 }
1283
1284 /* write history records */
1285 ffphis(*fptr,
1286 "CFITSIO used the following filtering expression to create this table:",
1287 status);
1288 ffphis(*fptr, name, status);
1289
1290 } /* end of no binspec case */
1291 } /* end of table HDU case */
1292 } /* end of rowfilter exists case */
1293
1294 /* ------------------------------------------------------------------- */
1295 /* make an image histogram by binning columns, if specified in the URL */
1296 /* ------------------------------------------------------------------- */
1297
1298 if (*binspec)
1299 {
1300 if (*histfilename && !(*pixfilter) )
1301 strcpy(outfile, histfilename); /* the original outfile name */
1302 else
1303 strcpy(outfile, "mem://_3"); /* create histogram in memory */
1304 /* if not already copied the file */
1305
1306 /* parse the binning specifier into individual parameters */
1307 ffbins(binspec, &imagetype, &haxis, colname,
1308 minin, maxin, binsizein,
1309 minname, maxname, binname,
1310 &weight, wtcol, &recip, status);
1311
1312 /* Create the histogram primary array and open it as the current fptr */
1313 /* This will close the table that was used to create the histogram. */
1314 ffhist2(fptr, outfile, imagetype, haxis, colname, minin, maxin,
1315 binsizein, minname, maxname, binname,
1316 weight, wtcol, recip, rowselect, status);
1317
1318 if (rowselect)
1319 free(rowselect);
1320
1321 if (*status > 0)
1322 {
1323 ffpmsg("on-the-fly histogramming of input table failed (ffopen)");
1324 ffpmsg(" while trying to execute the following histogram specification:");
1325 ffpmsg(binspec);
1326 ffclos(*fptr, status);
1327 *fptr = 0; /* return null file pointer */
1328 return(*status);
1329 }
1330
1331 /* write history records */
1332 ffphis(*fptr,
1333 "CFITSIO used the following expression to create this histogram:",
1334 status);
1335 ffphis(*fptr, name, status);
1336 }
1337
1338 if (*pixfilter)
1339 {
1340 if (*histfilename)
1341 strcpy(outfile, histfilename); /* the original outfile name */
1342 else
1343 strcpy(outfile, "mem://_4"); /* create in memory */
1344 /* if not already copied the file */
1345
1346 /* Ensure type of HDU is consistent with pixel filtering */
1347 fits_get_hdu_type(*fptr, &hdutyp, status); /* get type of HDU */
1348 if (hdutyp == IMAGE_HDU) {
1349
1350 pixel_filter_helper(fptr, outfile, pixfilter, status);
1351
1352 if (*status > 0) {
1353 ffpmsg("pixel filtering of input image failed (ffopen)");
1354 ffpmsg(" while trying to execute the following:");
1355 ffpmsg(pixfilter);
1356 ffclos(*fptr, status);
1357 *fptr = 0; /* return null file pointer */
1358 return(*status);
1359 }
1360
1361 /* write history records */
1362 ffphis(*fptr,
1363 "CFITSIO used the following expression to create this image:",
1364 status);
1365 ffphis(*fptr, name, status);
1366 }
1367 else
1368 {
1369 ffpmsg("cannot use pixel filter on non-IMAGE HDU");
1370 ffpmsg(pixfilter);
1371 ffclos(*fptr, status);
1372 *fptr = 0; /* return null file pointer */
1373 *status = NOT_IMAGE;
1374 return(*status);
1375 }
1376 }
1377
1378 /* parse and save image compression specification, if given */
1379 if (*compspec) {
1380 ffparsecompspec(*fptr, compspec, status);
1381 }
1382
1383 return(*status);
1384 }
1385 /*--------------------------------------------------------------------------*/
ffreopen(fitsfile * openfptr,fitsfile ** newfptr,int * status)1386 int ffreopen(fitsfile *openfptr, /* I - FITS file pointer to open file */
1387 fitsfile **newfptr, /* O - pointer to new re opened file */
1388 int *status) /* IO - error status */
1389 /*
1390 Reopen an existing FITS file with either readonly or read/write access.
1391 The reopened file shares the same FITSfile structure but may point to a
1392 different HDU within the file.
1393 */
1394 {
1395 if (*status > 0)
1396 return(*status);
1397
1398 /* check that the open file pointer is valid */
1399 if (!openfptr)
1400 return(*status = NULL_INPUT_PTR);
1401 else if ((openfptr->Fptr)->validcode != VALIDSTRUC) /* check magic value */
1402 return(*status = BAD_FILEPTR);
1403
1404 /* allocate fitsfile structure and initialize = 0 */
1405 *newfptr = (fitsfile *) calloc(1, sizeof(fitsfile));
1406
1407 (*newfptr)->Fptr = openfptr->Fptr; /* both point to the same structure */
1408 (*newfptr)->HDUposition = 0; /* set initial position to primary array */
1409 (((*newfptr)->Fptr)->open_count)++; /* increment the file usage counter */
1410
1411 return(*status);
1412 }
1413 /*--------------------------------------------------------------------------*/
fits_store_Fptr(FITSfile * Fptr,int * status)1414 int fits_store_Fptr(FITSfile *Fptr, /* O - FITS file pointer */
1415 int *status) /* IO - error status */
1416 /*
1417 store the new Fptr address for future use by fits_already_open
1418 */
1419 {
1420 int ii;
1421
1422 if (*status > 0)
1423 return(*status);
1424
1425 FFLOCK;
1426 for (ii = 0; ii < NMAXFILES; ii++) {
1427 if (FptrTable[ii] == 0) {
1428 FptrTable[ii] = Fptr;
1429 break;
1430 }
1431 }
1432 FFUNLOCK;
1433 return(*status);
1434 }
1435 /*--------------------------------------------------------------------------*/
fits_clear_Fptr(FITSfile * Fptr,int * status)1436 int fits_clear_Fptr(FITSfile *Fptr, /* O - FITS file pointer */
1437 int *status) /* IO - error status */
1438 /*
1439 clear the Fptr address from the Fptr Table
1440 */
1441 {
1442 int ii;
1443
1444 FFLOCK;
1445 for (ii = 0; ii < NMAXFILES; ii++) {
1446 if (FptrTable[ii] == Fptr) {
1447 FptrTable[ii] = 0;
1448 break;
1449 }
1450 }
1451 FFUNLOCK;
1452 return(*status);
1453 }
1454 /*--------------------------------------------------------------------------*/
fits_already_open(fitsfile ** fptr,char * url,char * urltype,char * infile,char * extspec,char * rowfilter,char * binspec,char * colspec,int mode,int * isopen,int * status)1455 int fits_already_open(fitsfile **fptr, /* I/O - FITS file pointer */
1456 char *url,
1457 char *urltype,
1458 char *infile,
1459 char *extspec,
1460 char *rowfilter,
1461 char *binspec,
1462 char *colspec,
1463 int mode, /* I - 0 = open readonly; 1 = read/write */
1464 int *isopen, /* O - 1 = file is already open */
1465 int *status) /* IO - error status */
1466 /*
1467 Check if the file to be opened is already open. If so, then attach to it.
1468 */
1469
1470 /* the input strings must not exceed the standard lengths */
1471 /* of FLEN_FILENAME, MAX_PREFIX_LEN, etc. */
1472
1473 /*
1474 this function was changed so that for files of access method FILE://
1475 the file paths are compared using standard URL syntax and absolute
1476 paths (as opposed to relative paths). This eliminates some instances
1477 where a file is already opened but it is not realized because it
1478 was opened with another file path. For instance, if the CWD is
1479 /a/b/c and I open /a/b/c/foo.fits then open ./foo.fits the previous
1480 version of this function would not have reconized that the two files
1481 were the same. This version does recognize that the two files are
1482 the same.
1483 */
1484 {
1485 FITSfile *oldFptr;
1486 int ii;
1487 char oldurltype[MAX_PREFIX_LEN], oldinfile[FLEN_FILENAME];
1488 char oldextspec[FLEN_FILENAME], oldoutfile[FLEN_FILENAME];
1489 char oldrowfilter[FLEN_FILENAME];
1490 char oldbinspec[FLEN_FILENAME], oldcolspec[FLEN_FILENAME];
1491 char cwd[FLEN_FILENAME];
1492 char tmpStr[FLEN_FILENAME];
1493 char tmpinfile[FLEN_FILENAME];
1494
1495 *isopen = 0;
1496
1497 /* When opening a file with readonly access then we simply let
1498 the operating system open the file again, instead of using the CFITSIO
1499 trick of attaching to the previously opened file. This is required
1500 if CFITSIO is running in a multi-threaded environment, because 2 different
1501 threads cannot share the same FITSfile pointer.
1502
1503 If the file is opened/reopened with write access, then the file MUST
1504 only be physically opened once..
1505 */
1506 if (mode == 0)
1507 return(*status);
1508
1509 if(fits_strcasecmp(urltype,"FILE://") == 0)
1510 {
1511 if (fits_path2url(infile,FLEN_FILENAME,tmpinfile,status))
1512 return (*status);
1513
1514 if(tmpinfile[0] != '/')
1515 {
1516 fits_get_cwd(cwd,status);
1517 strcat(cwd,"/");
1518
1519 if (strlen(cwd) + strlen(tmpinfile) > FLEN_FILENAME-1) {
1520 ffpmsg("File name is too long. (fits_already_open)");
1521 return(*status = FILE_NOT_OPENED);
1522 }
1523
1524 strcat(cwd,tmpinfile);
1525 fits_clean_url(cwd,tmpinfile,status);
1526 }
1527 }
1528 else
1529 strcpy(tmpinfile,infile);
1530
1531 for (ii = 0; ii < NMAXFILES; ii++) /* check every buffer */
1532 {
1533 if (FptrTable[ii] != 0)
1534 {
1535 oldFptr = FptrTable[ii];
1536
1537 fits_parse_input_url(oldFptr->filename, oldurltype,
1538 oldinfile, oldoutfile, oldextspec, oldrowfilter,
1539 oldbinspec, oldcolspec, status);
1540
1541 if (*status > 0)
1542 {
1543 ffpmsg("could not parse the previously opened filename: (ffopen)");
1544 ffpmsg(oldFptr->filename);
1545 return(*status);
1546 }
1547
1548 if(fits_strcasecmp(oldurltype,"FILE://") == 0)
1549 {
1550 if(fits_path2url(oldinfile,FLEN_FILENAME,tmpStr,status))
1551 return(*status);
1552
1553 if(tmpStr[0] != '/')
1554 {
1555 fits_get_cwd(cwd,status);
1556 strcat(cwd,"/");
1557
1558
1559 strcat(cwd,tmpStr);
1560 fits_clean_url(cwd,tmpStr,status);
1561 }
1562
1563 strcpy(oldinfile,tmpStr);
1564 }
1565
1566 if (!strcmp(urltype, oldurltype) && !strcmp(tmpinfile, oldinfile) )
1567 {
1568 /* identical type of file and root file name */
1569
1570 if ( (!rowfilter[0] && !oldrowfilter[0] &&
1571 !binspec[0] && !oldbinspec[0] &&
1572 !colspec[0] && !oldcolspec[0])
1573
1574 /* no filtering or binning specs for either file, so */
1575 /* this is a case where the same file is being reopened. */
1576 /* It doesn't matter if the extensions are different */
1577
1578 || /* or */
1579
1580 (!strcmp(rowfilter, oldrowfilter) &&
1581 !strcmp(binspec, oldbinspec) &&
1582 !strcmp(colspec, oldcolspec) &&
1583 !strcmp(extspec, oldextspec) ) )
1584
1585 /* filtering specs are given and are identical, and */
1586 /* the same extension is specified */
1587
1588 {
1589 if (mode == READWRITE && oldFptr->writemode == READONLY)
1590 {
1591 /*
1592 cannot assume that a file previously opened with READONLY
1593 can now be written to (e.g., files on CDROM, or over the
1594 the network, or STDIN), so return with an error.
1595 */
1596
1597 ffpmsg(
1598 "cannot reopen file READWRITE when previously opened READONLY");
1599 ffpmsg(url);
1600 return(*status = FILE_NOT_OPENED);
1601 }
1602
1603 *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
1604
1605 if (!(*fptr))
1606 {
1607 ffpmsg(
1608 "failed to allocate structure for following file: (ffopen)");
1609 ffpmsg(url);
1610 return(*status = MEMORY_ALLOCATION);
1611 }
1612
1613 (*fptr)->Fptr = oldFptr; /* point to the structure */
1614 (*fptr)->HDUposition = 0; /* set initial position */
1615 (((*fptr)->Fptr)->open_count)++; /* increment usage counter */
1616
1617 if (binspec[0]) /* if binning specified, don't move */
1618 extspec[0] = '\0';
1619
1620 /* all the filtering has already been applied, so ignore */
1621 rowfilter[0] = '\0';
1622 binspec[0] = '\0';
1623 colspec[0] = '\0';
1624
1625 *isopen = 1;
1626 }
1627 }
1628 }
1629 }
1630 return(*status);
1631 }
1632 /*--------------------------------------------------------------------------*/
fits_is_this_a_copy(char * urltype)1633 int fits_is_this_a_copy(char *urltype) /* I - type of file */
1634 /*
1635 specialized routine that returns 1 if the file is known to be a temporary
1636 copy of the originally opened file. Otherwise it returns 0.
1637 */
1638 {
1639 int iscopy;
1640
1641 if (!strncmp(urltype, "mem", 3) )
1642 iscopy = 1; /* file copy is in memory */
1643 else if (!strncmp(urltype, "compress", 8) )
1644 iscopy = 1; /* compressed diskfile that is uncompressed in memory */
1645 else if (!strncmp(urltype, "http", 4) )
1646 iscopy = 1; /* copied file using http protocol */
1647 else if (!strncmp(urltype, "ftp", 3) )
1648 iscopy = 1; /* copied file using ftp protocol */
1649 else if (!strncmp(urltype, "gsiftp", 6) )
1650 iscopy = 1; /* copied file using gsiftp protocol */
1651 else if (!strncpy(urltype, "stdin", 5) )
1652 iscopy = 1; /* piped stdin has been copied to memory */
1653 else
1654 iscopy = 0; /* file is not known to be a copy */
1655
1656 return(iscopy);
1657 }
1658 /*--------------------------------------------------------------------------*/
find_quote(char ** string)1659 static int find_quote(char **string)
1660
1661 /*
1662 look for the closing single quote character in the input string
1663 */
1664 {
1665 char *tstr;
1666
1667 tstr = *string;
1668
1669 while (*tstr) {
1670 if (*tstr == '\'') { /* found the closing quote */
1671 *string = tstr + 1; /* set pointer to next char */
1672 return(0);
1673 } else { /* skip over any other character */
1674 tstr++;
1675 }
1676 }
1677 return(1); /* opps, didn't find the closing character */
1678 }
1679 /*--------------------------------------------------------------------------*/
find_doublequote(char ** string)1680 static int find_doublequote(char **string)
1681
1682 /*
1683 look for the closing double quote character in the input string
1684 */
1685 {
1686 char *tstr;
1687
1688 tstr = *string;
1689
1690 while (*tstr) {
1691 if (*tstr == '"') { /* found the closing quote */
1692 *string = tstr + 1; /* set pointer to next char */
1693 return(0);
1694 } else { /* skip over any other character */
1695 tstr++;
1696 }
1697 }
1698 return(1); /* opps, didn't find the closing character */
1699 }
1700
1701 /*--------------------------------------------------------------------------*/
find_paren(char ** string)1702 static int find_paren(char **string)
1703
1704 /*
1705 look for the closing parenthesis character in the input string
1706 */
1707 {
1708 char *tstr;
1709
1710 tstr = *string;
1711
1712 while (*tstr) {
1713
1714 if (*tstr == ')') { /* found the closing parens */
1715 *string = tstr + 1; /* set pointer to next char */
1716 return(0);
1717 } else if (*tstr == '(') { /* found another level of parens */
1718 tstr++;
1719 if (find_paren(&tstr)) return(1);
1720 } else if (*tstr == '[') {
1721 tstr++;
1722 if (find_bracket(&tstr)) return(1);
1723 } else if (*tstr == '{') {
1724 tstr++;
1725 if (find_curlybracket(&tstr)) return(1);
1726 } else if (*tstr == '"') {
1727 tstr++;
1728 if (find_doublequote(&tstr)) return(1);
1729 } else if (*tstr == '\'') {
1730 tstr++;
1731 if (find_quote(&tstr)) return(1);
1732 } else {
1733 tstr++;
1734 }
1735 }
1736 return(1); /* opps, didn't find the closing character */
1737 }
1738 /*--------------------------------------------------------------------------*/
find_bracket(char ** string)1739 static int find_bracket(char **string)
1740
1741 /*
1742 look for the closing bracket character in the input string
1743 */
1744 {
1745 char *tstr;
1746
1747 tstr = *string;
1748
1749 while (*tstr) {
1750 if (*tstr == ']') { /* found the closing bracket */
1751 *string = tstr + 1; /* set pointer to next char */
1752 return(0);
1753 } else if (*tstr == '(') { /* found another level of parens */
1754 tstr++;
1755 if (find_paren(&tstr)) return(1);
1756 } else if (*tstr == '[') {
1757 tstr++;
1758 if (find_bracket(&tstr)) return(1);
1759 } else if (*tstr == '{') {
1760 tstr++;
1761 if (find_curlybracket(&tstr)) return(1);
1762 } else if (*tstr == '"') {
1763 tstr++;
1764 if (find_doublequote(&tstr)) return(1);
1765 } else if (*tstr == '\'') {
1766 tstr++;
1767 if (find_quote(&tstr)) return(1);
1768 } else {
1769 tstr++;
1770 }
1771 }
1772 return(1); /* opps, didn't find the closing character */
1773 }
1774 /*--------------------------------------------------------------------------*/
find_curlybracket(char ** string)1775 static int find_curlybracket(char **string)
1776
1777 /*
1778 look for the closing curly bracket character in the input string
1779 */
1780 {
1781 char *tstr;
1782
1783 tstr = *string;
1784
1785 while (*tstr) {
1786 if (*tstr == '}') { /* found the closing curly bracket */
1787 *string = tstr + 1; /* set pointer to next char */
1788 return(0);
1789 } else if (*tstr == '(') { /* found another level of parens */
1790 tstr++;
1791 if (find_paren(&tstr)) return(1);
1792 } else if (*tstr == '[') {
1793 tstr++;
1794 if (find_bracket(&tstr)) return(1);
1795 } else if (*tstr == '{') {
1796 tstr++;
1797 if (find_curlybracket(&tstr)) return(1);
1798 } else if (*tstr == '"') {
1799 tstr++;
1800 if (find_doublequote(&tstr)) return(1);
1801 } else if (*tstr == '\'') {
1802 tstr++;
1803 if (find_quote(&tstr)) return(1);
1804 } else {
1805 tstr++;
1806 }
1807 }
1808 return(1); /* opps, didn't find the closing character */
1809 }
1810 /*--------------------------------------------------------------------------*/
comma2semicolon(char * string)1811 int comma2semicolon(char *string)
1812
1813 /*
1814 replace commas with semicolons, unless the comma is within a quoted or bracketed expression
1815 */
1816 {
1817 char *tstr;
1818
1819 tstr = string;
1820
1821 while (*tstr) {
1822
1823 if (*tstr == ',') { /* found a comma */
1824 *tstr = ';';
1825 tstr++;
1826 } else if (*tstr == '(') { /* found another level of parens */
1827 tstr++;
1828 if (find_paren(&tstr)) return(1);
1829 } else if (*tstr == '[') {
1830 tstr++;
1831 if (find_bracket(&tstr)) return(1);
1832 } else if (*tstr == '{') {
1833 tstr++;
1834 if (find_curlybracket(&tstr)) return(1);
1835 } else if (*tstr == '"') {
1836 tstr++;
1837 if (find_doublequote(&tstr)) return(1);
1838 } else if (*tstr == '\'') {
1839 tstr++;
1840 if (find_quote(&tstr)) return(1);
1841 } else {
1842 tstr++;
1843 }
1844 }
1845 return(0); /* reached end of string */
1846 }
1847 /*--------------------------------------------------------------------------*/
ffedit_columns(fitsfile ** fptr,char * outfile,char * expr,int * status)1848 int ffedit_columns(
1849 fitsfile **fptr, /* IO - pointer to input table; on output it */
1850 /* points to the new selected rows table */
1851 char *outfile, /* I - name for output file */
1852 char *expr, /* I - column edit expression */
1853 int *status)
1854 /*
1855 modify columns in a table and/or header keywords in the HDU
1856 */
1857 {
1858 fitsfile *newptr;
1859 int ii, hdunum, slen, colnum = -1, testnum, deletecol = 0, savecol = 0;
1860 int numcols = 0, *colindex = 0, tstatus = 0;
1861 char *tstbuff=0, *cptr, *cptr2, *cptr3, *clause = NULL, keyname[FLEN_KEYWORD];
1862 char colname[FLEN_VALUE], oldname[FLEN_VALUE], colformat[FLEN_VALUE];
1863 char *file_expr = NULL, testname[FLEN_VALUE], card[FLEN_CARD];
1864
1865 if (*outfile)
1866 {
1867 /* create new empty file in to hold the selected rows */
1868 if (ffinit(&newptr, outfile, status) > 0)
1869 {
1870 ffpmsg("failed to create file for copy (ffedit_columns)");
1871 return(*status);
1872 }
1873
1874 fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
1875
1876 /* copy all HDUs to the output copy, if the 'only_one' flag is not set */
1877 if (!((*fptr)->Fptr)->only_one) {
1878 for (ii = 1; 1; ii++)
1879 {
1880 if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
1881 break;
1882
1883 fits_copy_hdu(*fptr, newptr, 0, status);
1884 }
1885
1886 if (*status == END_OF_FILE)
1887 {
1888 *status = 0; /* got the expected EOF error; reset = 0 */
1889 }
1890 else if (*status > 0)
1891 {
1892 ffclos(newptr, status);
1893 ffpmsg("failed to copy all HDUs from input file (ffedit_columns)");
1894 return(*status);
1895 }
1896
1897
1898 } else {
1899 /* only copy the primary array and the designated table extension */
1900 fits_movabs_hdu(*fptr, 1, NULL, status);
1901 fits_copy_hdu(*fptr, newptr, 0, status);
1902 fits_movabs_hdu(*fptr, hdunum, NULL, status);
1903 fits_copy_hdu(*fptr, newptr, 0, status);
1904 if (*status > 0)
1905 {
1906 ffclos(newptr, status);
1907 ffpmsg("failed to copy all HDUs from input file (ffedit_columns)");
1908 return(*status);
1909 }
1910 hdunum = 2;
1911 }
1912
1913 /* close the original file and return ptr to the new image */
1914 ffclos(*fptr, status);
1915
1916 *fptr = newptr; /* reset the pointer to the new table */
1917
1918 /* move back to the selected table HDU */
1919 if (fits_movabs_hdu(*fptr, hdunum, NULL, status) > 0)
1920 {
1921 ffpmsg("failed to copy the input file (ffedit_columns)");
1922 return(*status);
1923 }
1924 }
1925
1926 /* remove the "col " from the beginning of the column edit expression */
1927 cptr = expr + 4;
1928
1929 while (*cptr == ' ')
1930 cptr++; /* skip leading white space */
1931
1932 /* Check if need to import expression from a file */
1933
1934 if( *cptr=='@' ) {
1935 if( ffimport_file( cptr+1, &file_expr, status ) ) return(*status);
1936 cptr = file_expr;
1937 while (*cptr == ' ')
1938 cptr++; /* skip leading white space... again */
1939 }
1940
1941 tstatus = 0;
1942 ffgncl(*fptr, &numcols, &tstatus); /* get initial # of cols */
1943
1944 /* as of July 2012, the CFITSIO column filter syntax was modified */
1945 /* so that commas may be used to separate clauses, as well as semi-colons. */
1946 /* This was done because users cannot enter the semi-colon in the HEASARC's */
1947 /* Hera on-line data processing system for computer security reasons. */
1948 /* Therefore, we must convert those commas back to semi-colons here, but we */
1949 /* must not convert any columns that occur within parenthesies. */
1950
1951 if (comma2semicolon(cptr)) {
1952 ffpmsg("parsing error in column filter expression");
1953 ffpmsg(cptr);
1954 if( file_expr ) free( file_expr );
1955 *status = PARSE_SYNTAX_ERR;
1956 return(*status);
1957 }
1958
1959 /* parse expression and get first clause, if more than 1 */
1960 while ((slen = fits_get_token2(&cptr, ";", &clause, NULL, status)) > 0 )
1961 {
1962 if( *cptr==';' ) cptr++;
1963 clause[slen] = '\0';
1964
1965 if (clause[0] == '!' || clause[0] == '-')
1966 {
1967 char *clause1 = clause+1;
1968 int clen = clause1[0] ? strlen(clause1) : 0;
1969 /* ===================================== */
1970 /* Case I. delete this column or keyword */
1971 /* ===================================== */
1972
1973 /* Case Ia. delete column names with 0-or-more wildcard
1974 -COLNAME+ - delete repeated columns with exact name
1975 -COLNAM*+ - delete columns matching patterns
1976 */
1977 if (*status == 0 &&
1978 clen > 1 && clause1[0] != '#' &&
1979 clause1[clen-1] == '+') {
1980
1981 clause1[clen-1] = 0; clen--;
1982
1983 /* Note that this is a delete 0 or more specification,
1984 which means that no matching columns is not an error. */
1985 do {
1986 int status_del = 0;
1987
1988 /* Have to set status=0 so we can reset the search at
1989 start column. Because we are deleting columns on
1990 the fly here, we have to reset the search every
1991 time. The only penalty here is execution time
1992 because leaving *status == COL_NOT_UNIQUE is merely
1993 an optimization for tables assuming the tables do
1994 not change from one call to the next. (an
1995 assumption broken in this loop) */
1996 *status = 0;
1997 ffgcno(*fptr, CASEINSEN, clause1, &colnum, status);
1998 /* ffgcno returns COL_NOT_UNIQUE if there are multiple columns,
1999 and COL_NOT_FOUND after the last column is found, and
2000 COL_NOT_FOUND if no matches were found */
2001 if (*status != 0 && *status != COL_NOT_UNIQUE) break;
2002
2003 if (ffdcol(*fptr, colnum, &status_del) > 0) {
2004 ffpmsg("failed to delete column in input file:");
2005 ffpmsg(clause);
2006 if( colindex ) free( colindex );
2007 if( file_expr ) free( file_expr );
2008 if( clause ) free(clause);
2009 return (*status = status_del);
2010 }
2011 deletecol = 1; /* set flag that at least one col was deleted */
2012 numcols--;
2013 } while (*status == COL_NOT_UNIQUE);
2014
2015 *status = 0; /* No matches are still successful */
2016 colnum = -1; /* Ignore the column we found */
2017
2018 /* Case Ib. delete column names with wildcard or not
2019 -COLNAME - deleted exact column
2020 -COLNAM* - delete first column that matches pattern
2021 Note no leading '#'
2022 */
2023 } else if (clause1[0] && clause1[0] != '#' &&
2024 ffgcno(*fptr, CASEINSEN, clause1, &colnum, status) <= 0)
2025 {
2026 /* a column with this name exists, so try to delete it */
2027 if (ffdcol(*fptr, colnum, status) > 0)
2028 {
2029 ffpmsg("failed to delete column in input file:");
2030 ffpmsg(clause);
2031 if( colindex ) free( colindex );
2032 if( file_expr ) free( file_expr );
2033 if( clause ) free(clause);
2034 return(*status);
2035 }
2036 deletecol = 1; /* set flag that at least one col was deleted */
2037 numcols--;
2038 colnum = -1;
2039 }
2040 /* Case Ic. delete keyword(s)
2041 -KEYNAME,#KEYNAME - delete exact keyword (first match)
2042 -KEYNAM*,#KEYNAM* - delete first matching keyword
2043 -KEYNAME+,-#KEYNAME+ - delete 0-or-more exact matches of exact keyword
2044 -KEYNAM*+,-#KEYNAM*+ - delete 0-or-more wildcard matches
2045 Note the preceding # is optional if no conflicting column name exists
2046 and that wildcard patterns are described in "colfilter" section of
2047 documentation.
2048 */
2049 else
2050 {
2051 int delall = 0;
2052 int haswild = 0;
2053 ffcmsg(); /* clear previous error message from ffgcno */
2054 /* try deleting a keyword with this name */
2055 *status = 0;
2056 /* skip past leading '#' if any */
2057 if (clause1[0] == '#') clause1++;
2058 clen = strlen(clause1);
2059
2060 /* Repeat deletion of keyword if requested with trailing '+' */
2061 if (clen > 1 && clause1[clen-1] == '+') {
2062 delall = 1;
2063 clause1[clen-1] = 0;
2064 }
2065 /* Determine if this pattern has wildcards */
2066 if (strchr(clause1,'?') || strchr(clause1,'*') || strchr(clause1,'#')) {
2067 haswild = 1;
2068 }
2069
2070 if (haswild) {
2071 /* ffdkey() behaves differently if the pattern has a wildcard:
2072 it only checks from the "current" header position to the end, and doesn't
2073 check before the "current" header position. Therefore, for the
2074 case of wildcards we will have to reset to the beginning. */
2075 ffmaky(*fptr, 1, status); /* reset pointer to beginning of header */
2076 }
2077
2078 /* Single or repeated deletions until done */
2079 do {
2080 if (ffdkey(*fptr, clause1, status) > 0)
2081 {
2082 if (delall && *status == KEY_NO_EXIST) {
2083 /* Found last wildcard item. Stop deleting */
2084 ffcmsg();
2085 *status = 0;
2086 delall = 0; /* Force end of this loop */
2087 } else {
2088 /* This was not a wildcard deletion, or it resulted in
2089 another kind of error */
2090 ffpmsg("column or keyword to be deleted does not exist:");
2091 ffpmsg(clause1);
2092 if( colindex ) free( colindex );
2093 if( file_expr ) free( file_expr );
2094 if( clause ) free(clause);
2095 return(*status);
2096 }
2097 }
2098 } while(delall); /* end do{} */
2099 }
2100 }
2101 else
2102 {
2103 /* ===================================================== */
2104 /* Case II:
2105 this is either a column name, (case 1)
2106
2107 or a new column name followed by double = ("==") followed
2108 by the old name which is to be renamed. (case 2A)
2109
2110 or a column or keyword name followed by a single "=" and a
2111 calculation expression (case 2B) */
2112 /* ===================================================== */
2113 cptr2 = clause;
2114 slen = fits_get_token2(&cptr2, "( =", &tstbuff, NULL, status);
2115
2116 if (slen == 0 || *status)
2117 {
2118 ffpmsg("error: column or keyword name is blank (ffedit_columns):");
2119 ffpmsg(clause);
2120 if( colindex ) free( colindex );
2121 if( file_expr ) free( file_expr );
2122 if (clause) free(clause);
2123 if (*status==0)
2124 *status=URL_PARSE_ERROR;
2125 return(*status);
2126 }
2127 if (strlen(tstbuff) > FLEN_VALUE-1)
2128 {
2129 ffpmsg("error: column or keyword name is too long (ffedit_columns):");
2130 ffpmsg(clause);
2131 if( colindex ) free( colindex );
2132 if( file_expr ) free( file_expr );
2133 if (clause) free(clause);
2134 free(tstbuff);
2135 return(*status= URL_PARSE_ERROR);
2136 }
2137 strcpy(colname, tstbuff);
2138 free(tstbuff);
2139 tstbuff=0;
2140
2141 /* If this is a keyword of the form
2142 #KEYWORD#
2143 then transform to the form
2144 #KEYWORDn
2145 where n is the previously used column number
2146 */
2147 if (colname[0] == '#' &&
2148 strstr(colname+1, "#") == (colname + strlen(colname) - 1))
2149 {
2150 if (colnum <= 0)
2151 {
2152 ffpmsg("The keyword name:");
2153 ffpmsg(colname);
2154 ffpmsg("is invalid unless a column has been previously");
2155 ffpmsg("created or editted by a calculator command");
2156 if( file_expr ) free( file_expr );
2157 if (clause) free(clause);
2158 return(*status = URL_PARSE_ERROR);
2159 }
2160 colname[strlen(colname)-1] = '\0';
2161 /* Make keyword name and put it in oldname */
2162 ffkeyn(colname+1, colnum, oldname, status);
2163 if (*status) return (*status);
2164 /* Re-copy back into colname */
2165 strcpy(colname+1,oldname);
2166 }
2167 else if (strstr(colname, "#") == (colname + strlen(colname) - 1))
2168 {
2169 /* colname is of the form "NAME#"; if
2170 a) colnum is defined, and
2171 b) a column with literal name "NAME#" does not exist, and
2172 c) a keyword with name "NAMEn" (where n=colnum) exists, then
2173 transfrom the colname string to "NAMEn", otherwise
2174 do nothing.
2175 */
2176 if (colnum > 0) { /* colnum must be defined */
2177 tstatus = 0;
2178 ffgcno(*fptr, CASEINSEN, colname, &testnum, &tstatus);
2179 if (tstatus != 0 && tstatus != COL_NOT_UNIQUE)
2180 {
2181 /* OK, column doesn't exist, now see if keyword exists */
2182 ffcmsg(); /* clear previous error message from ffgcno */
2183 strcpy(testname, colname);
2184 testname[strlen(testname)-1] = '\0';
2185 /* Make keyword name and put it in oldname */
2186 ffkeyn(testname, colnum, oldname, status);
2187 if (*status) {
2188 if( file_expr ) free( file_expr );
2189 if (clause) free(clause);
2190 return (*status);
2191 }
2192
2193 tstatus = 0;
2194 if (!fits_read_card(*fptr, oldname, card, &tstatus)) {
2195 /* Keyword does exist; copy real name back into colname */
2196 strcpy(colname,oldname);
2197 }
2198 }
2199 }
2200 }
2201
2202 /* if we encountered an opening parenthesis, then we need to */
2203 /* find the closing parenthesis, and concatinate the 2 strings */
2204 /* This supports expressions like:
2205 [col #EXTNAME(Extension name)="GTI"]
2206 */
2207 if (*cptr2 == '(')
2208 {
2209 if (fits_get_token2(&cptr2, ")", &tstbuff, NULL, status)==0)
2210 {
2211 strcat(colname,")");
2212 }
2213 else
2214 {
2215 if ((strlen(tstbuff) + strlen(colname) + 1) >
2216 FLEN_VALUE-1)
2217 {
2218 ffpmsg("error: column name is too long (ffedit_columns):");
2219 if( file_expr ) free( file_expr );
2220 if (clause) free(clause);
2221 free(tstbuff);
2222 *status=URL_PARSE_ERROR;
2223 return (*status);
2224 }
2225 strcat(colname, tstbuff);
2226 strcat(colname, ")");
2227 free(tstbuff);
2228 tstbuff=0;
2229 }
2230 cptr2++;
2231 }
2232
2233 while (*cptr2 == ' ')
2234 cptr2++; /* skip white space */
2235
2236 if (*cptr2 != '=')
2237 {
2238 /* ------------------------------------ */
2239 /* case 1 - simply the name of a column */
2240 /* ------------------------------------ */
2241
2242 /* look for matching column */
2243 ffgcno(*fptr, CASEINSEN, colname, &testnum, status);
2244
2245 while (*status == COL_NOT_UNIQUE)
2246 {
2247 /* the column name contained wild cards, and it */
2248 /* matches more than one column in the table. */
2249
2250 colnum = testnum;
2251
2252 /* keep this column in the output file */
2253 savecol = 1;
2254
2255 if (!colindex)
2256 colindex = (int *) calloc(999, sizeof(int));
2257
2258 colindex[colnum - 1] = 1; /* flag this column number */
2259
2260 /* look for other matching column names */
2261 ffgcno(*fptr, CASEINSEN, colname, &testnum, status);
2262
2263 if (*status == COL_NOT_FOUND)
2264 *status = 999; /* temporary status flag value */
2265 }
2266
2267 if (*status <= 0)
2268 {
2269 colnum = testnum;
2270
2271 /* keep this column in the output file */
2272 savecol = 1;
2273
2274 if (!colindex)
2275 colindex = (int *) calloc(999, sizeof(int));
2276
2277 colindex[colnum - 1] = 1; /* flag this column number */
2278 }
2279 else if (*status == 999)
2280 {
2281 /* this special flag value does not represent an error */
2282 *status = 0;
2283 }
2284 else
2285 {
2286 ffpmsg("Syntax error in columns specifier in input URL:");
2287 ffpmsg(cptr2);
2288 if( colindex ) free( colindex );
2289 if( file_expr ) free( file_expr );
2290 if (clause) free(clause);
2291 return(*status = URL_PARSE_ERROR);
2292 }
2293 }
2294 else
2295 {
2296 /* ----------------------------------------------- */
2297 /* case 2 where the token ends with an equals sign */
2298 /* ----------------------------------------------- */
2299
2300 cptr2++; /* skip over the first '=' */
2301
2302 if (*cptr2 == '=')
2303 {
2304 /*................................................. */
2305 /* Case A: rename a column or keyword; syntax is
2306 "new_name == old_name" */
2307 /*................................................. */
2308
2309 cptr2++; /* skip the 2nd '=' */
2310 while (*cptr2 == ' ')
2311 cptr2++; /* skip white space */
2312
2313 if (fits_get_token2(&cptr2, " ", &tstbuff, NULL, status)==0)
2314 {
2315 oldname[0]=0;
2316 }
2317 else
2318 {
2319 if (strlen(tstbuff) > FLEN_VALUE-1)
2320 {
2321 ffpmsg("error: column name syntax is too long (ffedit_columns):");
2322 if( file_expr ) free( file_expr );
2323 if (clause) free(clause);
2324 free(tstbuff);
2325 *status=URL_PARSE_ERROR;
2326 return (*status);
2327 }
2328 strcpy(oldname, tstbuff);
2329 free(tstbuff);
2330 tstbuff=0;
2331 }
2332 /* get column number of the existing column */
2333 if (ffgcno(*fptr, CASEINSEN, oldname, &colnum, status) <= 0)
2334 {
2335 /* modify the TTYPEn keyword value with the new name */
2336 ffkeyn("TTYPE", colnum, keyname, status);
2337
2338 if (ffmkys(*fptr, keyname, colname, NULL, status) > 0)
2339 {
2340 ffpmsg("failed to rename column in input file");
2341 ffpmsg(" oldname =");
2342 ffpmsg(oldname);
2343 ffpmsg(" newname =");
2344 ffpmsg(colname);
2345 if( colindex ) free( colindex );
2346 if( file_expr ) free( file_expr );
2347 if (clause) free(clause);
2348 return(*status);
2349 }
2350 /* keep this column in the output file */
2351 savecol = 1;
2352 if (!colindex)
2353 colindex = (int *) calloc(999, sizeof(int));
2354
2355 colindex[colnum - 1] = 1; /* flag this column number */
2356 }
2357 else
2358 {
2359 /* try renaming a keyword */
2360 ffcmsg(); /* clear error message stack */
2361 *status = 0;
2362 if (ffmnam(*fptr, oldname, colname, status) > 0)
2363 {
2364 ffpmsg("column or keyword to be renamed does not exist:");
2365 ffpmsg(clause);
2366 if( colindex ) free( colindex );
2367 if( file_expr ) free( file_expr );
2368 if (clause) free(clause);
2369 return(*status);
2370 }
2371 }
2372 }
2373 else
2374 {
2375 /*...................................................... */
2376 /* Case B: */
2377 /* this must be a general column/keyword calc expression */
2378 /* "name = expression" or "colname(TFORM) = expression" */
2379 /*...................................................... */
2380
2381 /* parse the name and TFORM values, if present */
2382 colformat[0] = '\0';
2383 cptr3 = colname;
2384
2385 if (fits_get_token2(&cptr3, "(", &tstbuff, NULL, status)==0)
2386 {
2387 oldname[0]=0;
2388 }
2389 else
2390 {
2391 if (strlen(tstbuff) > FLEN_VALUE-1)
2392 {
2393 ffpmsg("column expression is too long (ffedit_columns)");
2394 if( colindex ) free( colindex );
2395 if( file_expr ) free( file_expr );
2396 if (clause) free(clause);
2397 free(tstbuff);
2398 *status=URL_PARSE_ERROR;
2399 return(*status);
2400 }
2401 strcpy(oldname, tstbuff);
2402 free(tstbuff);
2403 tstbuff=0;
2404 }
2405 if (cptr3[0] == '(' )
2406 {
2407 cptr3++; /* skip the '(' */
2408 if (fits_get_token2(&cptr3, ")", &tstbuff, NULL, status)==0)
2409 {
2410 colformat[0]=0;
2411 }
2412 else
2413 {
2414 if (strlen(tstbuff) > FLEN_VALUE-1)
2415 {
2416 ffpmsg("column expression is too long (ffedit_columns)");
2417 if( colindex ) free( colindex );
2418 if( file_expr ) free( file_expr );
2419 if (clause) free(clause);
2420 free(tstbuff);
2421 *status=URL_PARSE_ERROR;
2422 return(*status);
2423 }
2424 strcpy(colformat, tstbuff);
2425 free(tstbuff);
2426 tstbuff=0;
2427 }
2428 }
2429
2430 /* calculate values for the column or keyword */
2431 /* cptr2 = the expression to be calculated */
2432 /* oldname = name of the column or keyword */
2433 /* colformat = column format, or keyword comment string */
2434 if (fits_calculator(*fptr, cptr2, *fptr, oldname, colformat,
2435 status) > 0) {
2436
2437 ffpmsg("Unable to calculate expression");
2438 if( colindex ) free( colindex );
2439 if( file_expr ) free( file_expr );
2440 if (clause) free(clause);
2441 return(*status);
2442 }
2443
2444 /* test if this is a column and not a keyword */
2445 tstatus = 0;
2446 ffgcno(*fptr, CASEINSEN, oldname, &testnum, &tstatus);
2447 if (tstatus == 0)
2448 {
2449 /* keep this column in the output file */
2450 colnum = testnum;
2451 savecol = 1;
2452
2453 if (!colindex)
2454 colindex = (int *) calloc(999, sizeof(int));
2455
2456 colindex[colnum - 1] = 1;
2457 if (colnum > numcols)numcols++;
2458 }
2459 else
2460 {
2461 ffcmsg(); /* clear the error message stack */
2462 }
2463 }
2464 }
2465 }
2466 if (clause) free(clause); /* free old clause before getting new one */
2467 clause = NULL;
2468 }
2469
2470 if (savecol && !deletecol)
2471 {
2472 /* need to delete all but the specified columns */
2473 for (ii = numcols; ii > 0; ii--)
2474 {
2475 if (!colindex[ii-1]) /* delete this column */
2476 {
2477 if (ffdcol(*fptr, ii, status) > 0)
2478 {
2479 ffpmsg("failed to delete column in input file:");
2480 ffpmsg(clause);
2481 if( colindex ) free( colindex );
2482 if( file_expr ) free( file_expr );
2483 if (clause) free(clause);
2484 return(*status);
2485 }
2486 }
2487 }
2488 }
2489
2490 if( colindex ) free( colindex );
2491 if( file_expr ) free( file_expr );
2492 if (clause) free(clause);
2493
2494 return(*status);
2495 }
2496 /*--------------------------------------------------------------------------*/
fits_copy_cell2image(fitsfile * fptr,fitsfile * newptr,char * colname,long rownum,int * status)2497 int fits_copy_cell2image(
2498 fitsfile *fptr, /* I - point to input table */
2499 fitsfile *newptr, /* O - existing output file; new image HDU
2500 will be appended to it */
2501 char *colname, /* I - column name / number containing the image*/
2502 long rownum, /* I - number of the row containing the image */
2503 int *status) /* IO - error status */
2504
2505 /*
2506 Copy a table cell of a given row and column into an image extension.
2507 The output file must already have been created. A new image
2508 extension will be created in that file.
2509
2510 This routine was written by Craig Markwardt, GSFC
2511 */
2512
2513 {
2514 unsigned char buffer[30000];
2515 int hdutype, colnum, typecode, bitpix, naxis, maxelem, tstatus;
2516 LONGLONG naxes[9], nbytes, firstbyte, ntodo;
2517 LONGLONG repeat, startpos, elemnum, rowlen, tnull;
2518 long twidth, incre;
2519 double scale, zero;
2520 char tform[20];
2521 char card[FLEN_CARD];
2522 char templt[FLEN_CARD] = "";
2523
2524 /* Table-to-image keyword translation table */
2525 /* INPUT OUTPUT */
2526 /* 01234567 01234567 */
2527 char *patterns[][2] = {{"TSCALn", "BSCALE" }, /* Standard FITS keywords */
2528 {"TZEROn", "BZERO" },
2529 {"TUNITn", "BUNIT" },
2530 {"TNULLn", "BLANK" },
2531 {"TDMINn", "DATAMIN" },
2532 {"TDMAXn", "DATAMAX" },
2533 {"iCTYPn", "CTYPEi" }, /* Coordinate labels */
2534 {"iCTYna", "CTYPEia" },
2535 {"iCUNIn", "CUNITi" }, /* Coordinate units */
2536 {"iCUNna", "CUNITia" },
2537 {"iCRVLn", "CRVALi" }, /* WCS keywords */
2538 {"iCRVna", "CRVALia" },
2539 {"iCDLTn", "CDELTi" },
2540 {"iCDEna", "CDELTia" },
2541 {"iCRPXn", "CRPIXi" },
2542 {"iCRPna", "CRPIXia" },
2543 {"ijPCna", "PCi_ja" },
2544 {"ijCDna", "CDi_ja" },
2545 {"iVn_ma", "PVi_ma" },
2546 {"iSn_ma", "PSi_ma" },
2547 {"iCRDna", "CRDERia" },
2548 {"iCSYna", "CSYERia" },
2549 {"iCROTn", "CROTAi" },
2550 {"WCAXna", "WCSAXESa"},
2551 {"WCSNna", "WCSNAMEa"},
2552
2553 {"LONPna", "LONPOLEa"},
2554 {"LATPna", "LATPOLEa"},
2555 {"EQUIna", "EQUINOXa"},
2556 {"MJDOBn", "MJD-OBS" },
2557 {"MJDAn", "MJD-AVG" },
2558 {"RADEna", "RADESYSa"},
2559 {"iCNAna", "CNAMEia" },
2560 {"DAVGn", "DATE-AVG"},
2561
2562 /* Delete table keywords related to other columns */
2563 {"T????#a", "-" },
2564 {"TC??#a", "-" },
2565 {"TWCS#a", "-" },
2566 {"TDIM#", "-" },
2567 {"iCTYPm", "-" },
2568 {"iCUNIm", "-" },
2569 {"iCRVLm", "-" },
2570 {"iCDLTm", "-" },
2571 {"iCRPXm", "-" },
2572 {"iCTYma", "-" },
2573 {"iCUNma", "-" },
2574 {"iCRVma", "-" },
2575 {"iCDEma", "-" },
2576 {"iCRPma", "-" },
2577 {"ijPCma", "-" },
2578 {"ijCDma", "-" },
2579 {"iVm_ma", "-" },
2580 {"iSm_ma", "-" },
2581 {"iCRDma", "-" },
2582 {"iCSYma", "-" },
2583 {"iCROTm", "-" },
2584 {"WCAXma", "-" },
2585 {"WCSNma", "-" },
2586
2587 {"LONPma", "-" },
2588 {"LATPma", "-" },
2589 {"EQUIma", "-" },
2590 {"MJDOBm", "-" },
2591 {"MJDAm", "-" },
2592 {"RADEma", "-" },
2593 {"iCNAma", "-" },
2594 {"DAVGm", "-" },
2595
2596 {"EXTNAME", "-" }, /* Remove structural keywords*/
2597 {"EXTVER", "-" },
2598 {"EXTLEVEL","-" },
2599 {"CHECKSUM","-" },
2600 {"DATASUM", "-" },
2601
2602 {"*", "+" }}; /* copy all other keywords */
2603 int npat;
2604
2605 if (*status > 0)
2606 return(*status);
2607
2608 /* get column number */
2609 if (ffgcno(fptr, CASEINSEN, colname, &colnum, status) > 0)
2610 {
2611 ffpmsg("column containing image in table cell does not exist:");
2612 ffpmsg(colname);
2613 return(*status);
2614 }
2615
2616 /*---------------------------------------------------*/
2617 /* Check input and get parameters about the column: */
2618 /*---------------------------------------------------*/
2619 if ( ffgcprll(fptr, colnum, rownum, 1L, 1L, 0, &scale, &zero,
2620 tform, &twidth, &typecode, &maxelem, &startpos, &elemnum, &incre,
2621 &repeat, &rowlen, &hdutype, &tnull, (char *) buffer, status) > 0 )
2622 return(*status);
2623
2624 /* get the actual column name, in case a column number was given */
2625 ffkeyn("", colnum, templt, &tstatus);
2626 ffgcnn(fptr, CASEINSEN, templt, colname, &colnum, &tstatus);
2627
2628 if (hdutype != BINARY_TBL)
2629 {
2630 ffpmsg("This extension is not a binary table.");
2631 ffpmsg(" Cannot open the image in a binary table cell.");
2632 return(*status = NOT_BTABLE);
2633 }
2634
2635 if (typecode < 0)
2636 {
2637 /* variable length array */
2638 typecode *= -1;
2639
2640 /* variable length arrays are 1-dimensional by default */
2641 naxis = 1;
2642 naxes[0] = repeat;
2643 }
2644 else
2645 {
2646 /* get the dimensions of the image */
2647 ffgtdmll(fptr, colnum, 9, &naxis, naxes, status);
2648 }
2649
2650 if (*status > 0)
2651 {
2652 ffpmsg("Error getting the dimensions of the image");
2653 return(*status);
2654 }
2655
2656 /* determine BITPIX value for the image */
2657 if (typecode == TBYTE)
2658 {
2659 bitpix = BYTE_IMG;
2660 nbytes = repeat;
2661 }
2662 else if (typecode == TSHORT)
2663 {
2664 bitpix = SHORT_IMG;
2665 nbytes = repeat * 2;
2666 }
2667 else if (typecode == TLONG)
2668 {
2669 bitpix = LONG_IMG;
2670 nbytes = repeat * 4;
2671 }
2672 else if (typecode == TFLOAT)
2673 {
2674 bitpix = FLOAT_IMG;
2675 nbytes = repeat * 4;
2676 }
2677 else if (typecode == TDOUBLE)
2678 {
2679 bitpix = DOUBLE_IMG;
2680 nbytes = repeat * 8;
2681 }
2682 else if (typecode == TLONGLONG)
2683 {
2684 bitpix = LONGLONG_IMG;
2685 nbytes = repeat * 8;
2686 }
2687 else if (typecode == TLOGICAL)
2688 {
2689 bitpix = BYTE_IMG;
2690 nbytes = repeat;
2691 }
2692 else
2693 {
2694 ffpmsg("Error: the following image column has invalid datatype:");
2695 ffpmsg(colname);
2696 ffpmsg(tform);
2697 ffpmsg("Cannot open an image in a single row of this column.");
2698 return(*status = BAD_TFORM);
2699 }
2700
2701 /* create new image in output file */
2702 if (ffcrimll(newptr, bitpix, naxis, naxes, status) > 0)
2703 {
2704 ffpmsg("failed to write required primary array keywords in the output file");
2705 return(*status);
2706 }
2707
2708 npat = sizeof(patterns)/sizeof(patterns[0][0])/2;
2709
2710 /* skip over the first 8 keywords, starting just after TFIELDS */
2711 fits_translate_keywords(fptr, newptr, 9, patterns, npat,
2712 colnum, 0, 0, status);
2713
2714 /* add some HISTORY */
2715 snprintf(card,FLEN_CARD,"HISTORY This image was copied from row %ld of column '%s',",
2716 rownum, colname);
2717 /* disable this; leave it up to the caller to write history if needed.
2718 ffprec(newptr, card, status);
2719 */
2720 /* the use of ffread routine, below, requires that any 'dirty' */
2721 /* buffers in memory be flushed back to the file first */
2722
2723 ffflsh(fptr, FALSE, status);
2724
2725 /* finally, copy the data, one buffer size at a time */
2726 ffmbyt(fptr, startpos, TRUE, status);
2727 firstbyte = 1;
2728
2729 /* the upper limit on the number of bytes must match the declaration */
2730 /* read up to the first 30000 bytes in the normal way with ffgbyt */
2731
2732 ntodo = minvalue(30000, nbytes);
2733 ffgbyt(fptr, ntodo, buffer, status);
2734 ffptbb(newptr, 1, firstbyte, ntodo, buffer, status);
2735
2736 nbytes -= ntodo;
2737 firstbyte += ntodo;
2738
2739 /* read any additional bytes with low-level ffread routine, for speed */
2740 while (nbytes && (*status <= 0) )
2741 {
2742 ntodo = minvalue(30000, nbytes);
2743 ffread((fptr)->Fptr, (long) ntodo, buffer, status);
2744 ffptbb(newptr, 1, firstbyte, ntodo, buffer, status);
2745 nbytes -= ntodo;
2746 firstbyte += ntodo;
2747 }
2748
2749 /* Re-scan the header so that CFITSIO knows about all the new keywords */
2750 ffrdef(newptr,status);
2751
2752 return(*status);
2753 }
2754 /*--------------------------------------------------------------------------*/
fits_copy_image2cell(fitsfile * fptr,fitsfile * newptr,char * colname,long rownum,int copykeyflag,int * status)2755 int fits_copy_image2cell(
2756 fitsfile *fptr, /* I - pointer to input image extension */
2757 fitsfile *newptr, /* I - pointer to output table */
2758 char *colname, /* I - name of column containing the image */
2759 long rownum, /* I - number of the row containing the image */
2760 int copykeyflag, /* I - controls which keywords to copy */
2761 int *status) /* IO - error status */
2762
2763 /*
2764 Copy an image extension into a table cell at a given row and
2765 column. The table must have already been created. If the "colname"
2766 column exists, it will be used, otherwise a new column will be created
2767 in the table.
2768
2769 The "copykeyflag" parameter controls which keywords to copy from the
2770 input image to the output table header (with any appropriate translation).
2771
2772 copykeyflag = 0 -- no keywords will be copied
2773 copykeyflag = 1 -- essentially all keywords will be copied
2774 copykeyflag = 2 -- copy only the WCS related keywords
2775
2776 This routine was written by Craig Markwardt, GSFC
2777
2778 */
2779 {
2780 tcolumn *colptr;
2781 unsigned char buffer[30000];
2782 int ii, hdutype, colnum, typecode, bitpix, naxis, ncols, hdunum;
2783 char tformchar, tform[20], card[FLEN_CARD];
2784 LONGLONG imgstart, naxes[9], nbytes, repeat, ntodo,firstbyte;
2785 char filename[FLEN_FILENAME+20];
2786
2787 int npat;
2788
2789 int naxis1;
2790 LONGLONG naxes1[9] = {0,0,0,0,0,0,0,0,0}, repeat1, width1;
2791 int typecode1;
2792 unsigned char dummy = 0;
2793
2794 LONGLONG headstart, datastart, dataend;
2795
2796 /* Image-to-table keyword translation table */
2797 /* INPUT OUTPUT */
2798 /* 01234567 01234567 */
2799 char *patterns[][2] = {{"BSCALE", "TSCALn" }, /* Standard FITS keywords */
2800 {"BZERO", "TZEROn" },
2801 {"BUNIT", "TUNITn" },
2802 {"BLANK", "TNULLn" },
2803 {"DATAMIN", "TDMINn" },
2804 {"DATAMAX", "TDMAXn" },
2805 {"CTYPEi", "iCTYPn" }, /* Coordinate labels */
2806 {"CTYPEia", "iCTYna" },
2807 {"CUNITi", "iCUNIn" }, /* Coordinate units */
2808 {"CUNITia", "iCUNna" },
2809 {"CRVALi", "iCRVLn" }, /* WCS keywords */
2810 {"CRVALia", "iCRVna" },
2811 {"CDELTi", "iCDLTn" },
2812 {"CDELTia", "iCDEna" },
2813 {"CRPIXj", "jCRPXn" },
2814 {"CRPIXja", "jCRPna" },
2815 {"PCi_ja", "ijPCna" },
2816 {"CDi_ja", "ijCDna" },
2817 {"PVi_ma", "iVn_ma" },
2818 {"PSi_ma", "iSn_ma" },
2819 {"WCSAXESa","WCAXna" },
2820 {"WCSNAMEa","WCSNna" },
2821 {"CRDERia", "iCRDna" },
2822 {"CSYERia", "iCSYna" },
2823 {"CROTAi", "iCROTn" },
2824
2825 {"LONPOLEa","LONPna"},
2826 {"LATPOLEa","LATPna"},
2827 {"EQUINOXa","EQUIna"},
2828 {"MJD-OBS", "MJDOBn" },
2829 {"MJD-AVG", "MJDAn" },
2830 {"RADESYSa","RADEna"},
2831 {"CNAMEia", "iCNAna" },
2832 {"DATE-AVG","DAVGn"},
2833
2834 {"NAXISi", "-" }, /* Remove structural keywords*/
2835 {"PCOUNT", "-" },
2836 {"GCOUNT", "-" },
2837 {"EXTEND", "-" },
2838 {"EXTNAME", "-" },
2839 {"EXTVER", "-" },
2840 {"EXTLEVEL","-" },
2841 {"CHECKSUM","-" },
2842 {"DATASUM", "-" },
2843 {"*", "+" }}; /* copy all other keywords */
2844
2845
2846 if (*status > 0)
2847 return(*status);
2848
2849 if (fptr == 0 || newptr == 0) return (*status = NULL_INPUT_PTR);
2850
2851 if (ffghdt(fptr, &hdutype, status) > 0) {
2852 ffpmsg("could not get input HDU type");
2853 return (*status);
2854 }
2855
2856 if (hdutype != IMAGE_HDU) {
2857 ffpmsg("The input extension is not an image.");
2858 ffpmsg(" Cannot open the image.");
2859 return(*status = NOT_IMAGE);
2860 }
2861
2862 if (ffghdt(newptr, &hdutype, status) > 0) {
2863 ffpmsg("could not get output HDU type");
2864 return (*status);
2865 }
2866
2867 if (hdutype != BINARY_TBL) {
2868 ffpmsg("The output extension is not a table.");
2869 return(*status = NOT_BTABLE);
2870 }
2871
2872
2873 if (ffgiprll(fptr, 9, &bitpix, &naxis, naxes, status) > 0) {
2874 ffpmsg("Could not read image parameters.");
2875 return (*status);
2876 }
2877
2878 /* Determine total number of pixels in the image */
2879 repeat = 1;
2880 for (ii = 0; ii < naxis; ii++) repeat *= naxes[ii];
2881
2882 /* Determine the TFORM value for the table cell */
2883 if (bitpix == BYTE_IMG) {
2884 typecode = TBYTE;
2885 tformchar = 'B';
2886 nbytes = repeat;
2887 } else if (bitpix == SHORT_IMG) {
2888 typecode = TSHORT;
2889 tformchar = 'I';
2890 nbytes = repeat*2;
2891 } else if (bitpix == LONG_IMG) {
2892 typecode = TLONG;
2893 tformchar = 'J';
2894 nbytes = repeat*4;
2895 } else if (bitpix == FLOAT_IMG) {
2896 typecode = TFLOAT;
2897 tformchar = 'E';
2898 nbytes = repeat*4;
2899 } else if (bitpix == DOUBLE_IMG) {
2900 typecode = TDOUBLE;
2901 tformchar = 'D';
2902 nbytes = repeat*8;
2903 } else if (bitpix == LONGLONG_IMG) {
2904 typecode = TLONGLONG;
2905 tformchar = 'K';
2906 nbytes = repeat*8;
2907 } else {
2908 ffpmsg("Error: the image has an invalid datatype.");
2909 return (*status = BAD_BITPIX);
2910 }
2911
2912 /* get column number */
2913 ffpmrk();
2914 ffgcno(newptr, CASEINSEN, colname, &colnum, status);
2915 ffcmrk();
2916
2917 /* Column does not exist; create it */
2918 if (*status) {
2919
2920 *status = 0;
2921 snprintf(tform, 20, "%.0f%c", (double) repeat, tformchar);
2922 ffgncl(newptr, &ncols, status);
2923 colnum = ncols+1;
2924 fficol(newptr, colnum, colname, tform, status);
2925 ffptdmll(newptr, colnum, naxis, naxes, status);
2926
2927 if (*status) {
2928 ffpmsg("Could not insert new column into output table.");
2929 return *status;
2930 }
2931
2932 } else {
2933
2934 ffgtdmll(newptr, colnum, 9, &naxis1, naxes1, status);
2935 if (*status > 0 || naxis != naxis1) {
2936 ffpmsg("Input image dimensions and output table cell dimensions do not match.");
2937 return (*status = BAD_DIMEN);
2938 }
2939 for (ii=0; ii<naxis; ii++) if (naxes[ii] != naxes1[ii]) {
2940 ffpmsg("Input image dimensions and output table cell dimensions do not match.");
2941 return (*status = BAD_DIMEN);
2942 }
2943
2944 ffgtclll(newptr, colnum, &typecode1, &repeat1, &width1, status);
2945 if ((*status > 0) || (typecode1 != typecode) || (repeat1 != repeat)) {
2946 ffpmsg("Input image data type does not match output table cell type.");
2947 return (*status = BAD_TFORM);
2948 }
2949 }
2950
2951 /* copy keywords from input image to output table, if required */
2952
2953 if (copykeyflag) {
2954
2955 npat = sizeof(patterns)/sizeof(patterns[0][0])/2;
2956
2957 if (copykeyflag == 2) { /* copy only the WCS-related keywords */
2958 patterns[npat-1][1] = "-";
2959 }
2960
2961 /* The 3rd parameter value = 5 means skip the first 4 keywords in the image */
2962 fits_translate_keywords(fptr, newptr, 5, patterns, npat,
2963 colnum, 0, 0, status);
2964 }
2965
2966 /* Here is all the code to compute offsets:
2967 * * byte offset from start of row to column (dest table)
2968 * * byte offset from start of file to image data (source image)
2969 */
2970
2971 /* Force the writing of the row of the table by writing the last byte of
2972 the array, which grows the table, and/or shifts following extensions */
2973 ffpcl(newptr, TBYTE, colnum, rownum, repeat, 1, &dummy, status);
2974
2975 /* byte offset within the row to the start of the image column */
2976 colptr = (newptr->Fptr)->tableptr; /* point to first column */
2977 colptr += (colnum - 1); /* offset to correct column structure */
2978 firstbyte = colptr->tbcol + 1;
2979
2980 /* get starting address of input image to be read */
2981 ffghadll(fptr, &headstart, &datastart, &dataend, status);
2982 imgstart = datastart;
2983
2984 snprintf(card, FLEN_CARD, "HISTORY Table column '%s' row %ld copied from image",
2985 colname, rownum);
2986 /*
2987 Don't automatically write History keywords; leave this up to the caller.
2988 ffprec(newptr, card, status);
2989 */
2990
2991 /* write HISTORY keyword with the file name (this is now disabled)*/
2992
2993 filename[0] = '\0'; hdunum = 0;
2994 strcpy(filename, "HISTORY ");
2995 ffflnm(fptr, filename+strlen(filename), status);
2996 ffghdn(fptr, &hdunum);
2997 snprintf(filename+strlen(filename),FLEN_FILENAME+20-strlen(filename),"[%d]", hdunum-1);
2998 /*
2999 ffprec(newptr, filename, status);
3000 */
3001
3002 /* the use of ffread routine, below, requires that any 'dirty' */
3003 /* buffers in memory be flushed back to the file first */
3004
3005 ffflsh(fptr, FALSE, status);
3006
3007 /* move to the first byte of the input image */
3008 ffmbyt(fptr, imgstart, TRUE, status);
3009
3010 ntodo = minvalue(30000L, nbytes);
3011 ffgbyt(fptr, ntodo, buffer, status); /* read input image */
3012 ffptbb(newptr, rownum, firstbyte, ntodo, buffer, status); /* write to table */
3013
3014 nbytes -= ntodo;
3015 firstbyte += ntodo;
3016
3017
3018 /* read any additional bytes with low-level ffread routine, for speed */
3019 while (nbytes && (*status <= 0) )
3020 {
3021 ntodo = minvalue(30000L, nbytes);
3022 ffread(fptr->Fptr, (long) ntodo, buffer, status);
3023 ffptbb(newptr, rownum, firstbyte, ntodo, buffer, status);
3024 nbytes -= ntodo;
3025 firstbyte += ntodo;
3026 }
3027
3028 /* Re-scan the header so that CFITSIO knows about all the new keywords */
3029 ffrdef(newptr,status);
3030
3031 return(*status);
3032 }
3033 /*--------------------------------------------------------------------------*/
fits_select_image_section(fitsfile ** fptr,char * outfile,char * expr,int * status)3034 int fits_select_image_section(
3035 fitsfile **fptr, /* IO - pointer to input image; on output it */
3036 /* points to the new subimage */
3037 char *outfile, /* I - name for output file */
3038 char *expr, /* I - Image section expression */
3039 int *status)
3040 {
3041 /*
3042 copies an image section from the input file to a new output file.
3043 Any HDUs preceding or following the image are also copied to the
3044 output file.
3045 */
3046
3047 fitsfile *newptr;
3048 int ii, hdunum;
3049
3050 /* create new empty file to hold the image section */
3051 if (ffinit(&newptr, outfile, status) > 0)
3052 {
3053 ffpmsg(
3054 "failed to create output file for image section:");
3055 ffpmsg(outfile);
3056 return(*status);
3057 }
3058
3059 fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
3060
3061 /* copy all preceding extensions to the output file, if 'only_one' flag not set */
3062 if (!(((*fptr)->Fptr)->only_one)) {
3063 for (ii = 1; ii < hdunum; ii++)
3064 {
3065 fits_movabs_hdu(*fptr, ii, NULL, status);
3066 if (fits_copy_hdu(*fptr, newptr, 0, status) > 0)
3067 {
3068 ffclos(newptr, status);
3069 return(*status);
3070 }
3071 }
3072
3073 /* move back to the original HDU position */
3074 fits_movabs_hdu(*fptr, hdunum, NULL, status);
3075 }
3076
3077 if (fits_copy_image_section(*fptr, newptr, expr, status) > 0)
3078 {
3079 ffclos(newptr, status);
3080 return(*status);
3081 }
3082
3083 /* copy any remaining HDUs to the output file, if 'only_one' flag not set */
3084
3085 if (!(((*fptr)->Fptr)->only_one)) {
3086 for (ii = hdunum + 1; 1; ii++)
3087 {
3088 if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
3089 break;
3090
3091 fits_copy_hdu(*fptr, newptr, 0, status);
3092 }
3093
3094 if (*status == END_OF_FILE)
3095 *status = 0; /* got the expected EOF error; reset = 0 */
3096 else if (*status > 0)
3097 {
3098 ffclos(newptr, status);
3099 return(*status);
3100 }
3101 } else {
3102 ii = hdunum + 1; /* this value of ii is required below */
3103 }
3104
3105 /* close the original file and return ptr to the new image */
3106 ffclos(*fptr, status);
3107
3108 *fptr = newptr; /* reset the pointer to the new table */
3109
3110 /* move back to the image subsection */
3111 if (ii - 1 != hdunum)
3112 fits_movabs_hdu(*fptr, hdunum, NULL, status);
3113 else
3114 {
3115 /* may have to reset BSCALE and BZERO pixel scaling, */
3116 /* since the keywords were previously turned off */
3117
3118 if (ffrdef(*fptr, status) > 0)
3119 {
3120 ffclos(*fptr, status);
3121 return(*status);
3122 }
3123
3124 }
3125
3126 return(*status);
3127 }
3128 /*--------------------------------------------------------------------------*/
fits_copy_image_section(fitsfile * fptr,fitsfile * newptr,char * expr,int * status)3129 int fits_copy_image_section(
3130 fitsfile *fptr, /* I - pointer to input image */
3131 fitsfile *newptr, /* I - pointer to output image */
3132 char *expr, /* I - Image section expression */
3133 int *status)
3134 {
3135 /*
3136 copies an image section from the input file to a new output HDU
3137 */
3138
3139 int bitpix, naxis, numkeys, nkey;
3140 long naxes[] = {1,1,1,1,1,1,1,1,1}, smin, smax, sinc;
3141 long fpixels[] = {1,1,1,1,1,1,1,1,1};
3142 long lpixels[] = {1,1,1,1,1,1,1,1,1};
3143 long incs[] = {1,1,1,1,1,1,1,1,1};
3144 char *cptr, keyname[FLEN_KEYWORD], card[FLEN_CARD];
3145 int ii, tstatus, anynull;
3146 long minrow, maxrow, minslice, maxslice, mincube, maxcube;
3147 long firstpix;
3148 long ncubeiter, nsliceiter, nrowiter, kiter, jiter, iiter;
3149 int klen, kk, jj;
3150 long outnaxes[9], outsize, buffsize;
3151 double *buffer, crpix, cdelt;
3152
3153 if (*status > 0)
3154 return(*status);
3155
3156 /* get the size of the input image */
3157 fits_get_img_type(fptr, &bitpix, status);
3158 fits_get_img_dim(fptr, &naxis, status);
3159 if (fits_get_img_size(fptr, naxis, naxes, status) > 0)
3160 return(*status);
3161
3162 if (naxis < 1 || naxis > 4)
3163 {
3164 ffpmsg(
3165 "Input image either had NAXIS = 0 (NULL image) or has > 4 dimensions");
3166 return(*status = BAD_NAXIS);
3167 }
3168
3169 /* create output image with same size and type as the input image */
3170 /* Will update the size later */
3171 fits_create_img(newptr, bitpix, naxis, naxes, status);
3172
3173 /* copy all other non-structural keywords from the input to output file */
3174 fits_get_hdrspace(fptr, &numkeys, NULL, status);
3175
3176 for (nkey = 4; nkey <= numkeys; nkey++) /* skip the first few keywords */
3177 {
3178 fits_read_record(fptr, nkey, card, status);
3179
3180 if (fits_get_keyclass(card) > TYP_CMPRS_KEY)
3181 {
3182 /* write the record to the output file */
3183 fits_write_record(newptr, card, status);
3184 }
3185 }
3186
3187 if (*status > 0)
3188 {
3189 ffpmsg("error copying header from input image to output image");
3190 return(*status);
3191 }
3192
3193 /* parse the section specifier to get min, max, and inc for each axis */
3194 /* and the size of each output image axis */
3195
3196 cptr = expr;
3197 for (ii=0; ii < naxis; ii++)
3198 {
3199 if (fits_get_section_range(&cptr, &smin, &smax, &sinc, status) > 0)
3200 {
3201 ffpmsg("error parsing the following image section specifier:");
3202 ffpmsg(expr);
3203 return(*status);
3204 }
3205
3206 if (smax == 0)
3207 smax = naxes[ii]; /* use whole axis by default */
3208 else if (smin == 0)
3209 smin = naxes[ii]; /* use inverted whole axis */
3210
3211 if (smin > naxes[ii] || smax > naxes[ii])
3212 {
3213 ffpmsg("image section exceeds dimensions of input image:");
3214 ffpmsg(expr);
3215 return(*status = BAD_NAXIS);
3216 }
3217
3218 fpixels[ii] = smin;
3219 lpixels[ii] = smax;
3220 incs[ii] = sinc;
3221
3222 if (smin <= smax)
3223 outnaxes[ii] = (smax - smin + sinc) / sinc;
3224 else
3225 outnaxes[ii] = (smin - smax + sinc) / sinc;
3226
3227 /* modify the NAXISn keyword */
3228 fits_make_keyn("NAXIS", ii + 1, keyname, status);
3229 fits_modify_key_lng(newptr, keyname, outnaxes[ii], NULL, status);
3230
3231 /* modify the WCS keywords if necessary */
3232
3233 if (fpixels[ii] != 1 || incs[ii] != 1)
3234 {
3235 for (kk=-1;kk<26; kk++) /* modify any alternate WCS keywords */
3236 {
3237 /* read the CRPIXn keyword if it exists in the input file */
3238 fits_make_keyn("CRPIX", ii + 1, keyname, status);
3239
3240 if (kk != -1) {
3241 klen = strlen(keyname);
3242 keyname[klen]='A' + kk;
3243 keyname[klen + 1] = '\0';
3244 }
3245
3246 tstatus = 0;
3247 if (fits_read_key(fptr, TDOUBLE, keyname,
3248 &crpix, NULL, &tstatus) == 0)
3249 {
3250 /* calculate the new CRPIXn value */
3251 if (fpixels[ii] <= lpixels[ii]) {
3252 crpix = (crpix - (fpixels[ii])) / incs[ii] + 1.0;
3253 /* crpix = (crpix - (fpixels[ii] - 1.0) - .5) / incs[ii] + 0.5; */
3254 } else {
3255 crpix = (fpixels[ii] - crpix) / incs[ii] + 1.0;
3256 /* crpix = (fpixels[ii] - (crpix - 1.0) - .5) / incs[ii] + 0.5; */
3257 }
3258
3259 /* modify the value in the output file */
3260 fits_modify_key_dbl(newptr, keyname, crpix, 15, NULL, status);
3261
3262 if (incs[ii] != 1 || fpixels[ii] > lpixels[ii])
3263 {
3264 /* read the CDELTn keyword if it exists in the input file */
3265 fits_make_keyn("CDELT", ii + 1, keyname, status);
3266
3267 if (kk != -1) {
3268 klen = strlen(keyname);
3269 keyname[klen]='A' + kk;
3270 keyname[klen + 1] = '\0';
3271 }
3272
3273 tstatus = 0;
3274 if (fits_read_key(fptr, TDOUBLE, keyname,
3275 &cdelt, NULL, &tstatus) == 0)
3276 {
3277 /* calculate the new CDELTn value */
3278 if (fpixels[ii] <= lpixels[ii])
3279 cdelt = cdelt * incs[ii];
3280 else
3281 cdelt = cdelt * (-incs[ii]);
3282
3283 /* modify the value in the output file */
3284 fits_modify_key_dbl(newptr, keyname, cdelt, 15, NULL, status);
3285 }
3286
3287 /* modify the CDi_j keywords if they exist in the input file */
3288
3289 fits_make_keyn("CD1_", ii + 1, keyname, status);
3290
3291 if (kk != -1) {
3292 klen = strlen(keyname);
3293 keyname[klen]='A' + kk;
3294 keyname[klen + 1] = '\0';
3295 }
3296
3297 for (jj=0; jj < 9; jj++) /* look for up to 9 dimensions */
3298 {
3299 keyname[2] = '1' + jj;
3300
3301 tstatus = 0;
3302 if (fits_read_key(fptr, TDOUBLE, keyname,
3303 &cdelt, NULL, &tstatus) == 0)
3304 {
3305 /* calculate the new CDi_j value */
3306 if (fpixels[ii] <= lpixels[ii])
3307 cdelt = cdelt * incs[ii];
3308 else
3309 cdelt = cdelt * (-incs[ii]);
3310
3311 /* modify the value in the output file */
3312 fits_modify_key_dbl(newptr, keyname, cdelt, 15, NULL, status);
3313 }
3314 }
3315
3316 } /* end of if (incs[ii]... loop */
3317 } /* end of fits_read_key loop */
3318 } /* end of for (kk loop */
3319 }
3320 } /* end of main NAXIS loop */
3321
3322 if (ffrdef(newptr, status) > 0) /* force the header to be scanned */
3323 {
3324 return(*status);
3325 }
3326
3327 /* turn off any scaling of the pixel values */
3328 fits_set_bscale(fptr, 1.0, 0.0, status);
3329 fits_set_bscale(newptr, 1.0, 0.0, status);
3330
3331 /* to reduce memory foot print, just read/write image 1 row at a time */
3332
3333 outsize = outnaxes[0];
3334 buffsize = (abs(bitpix) / 8) * outsize;
3335
3336 buffer = (double *) malloc(buffsize); /* allocate memory for the image row */
3337 if (!buffer)
3338 {
3339 ffpmsg("fits_copy_image_section: no memory for image section");
3340 return(*status = MEMORY_ALLOCATION);
3341 }
3342
3343 /* read the image section then write it to the output file */
3344
3345 minrow = fpixels[1];
3346 maxrow = lpixels[1];
3347 if (minrow > maxrow) {
3348 nrowiter = (minrow - maxrow + incs[1]) / incs[1];
3349 } else {
3350 nrowiter = (maxrow - minrow + incs[1]) / incs[1];
3351 }
3352
3353 minslice = fpixels[2];
3354 maxslice = lpixels[2];
3355 if (minslice > maxslice) {
3356 nsliceiter = (minslice - maxslice + incs[2]) / incs[2];
3357 } else {
3358 nsliceiter = (maxslice - minslice + incs[2]) / incs[2];
3359 }
3360
3361 mincube = fpixels[3];
3362 maxcube = lpixels[3];
3363 if (mincube > maxcube) {
3364 ncubeiter = (mincube - maxcube + incs[3]) / incs[3];
3365 } else {
3366 ncubeiter = (maxcube - mincube + incs[3]) / incs[3];
3367 }
3368
3369 firstpix = 1;
3370 for (kiter = 0; kiter < ncubeiter; kiter++)
3371 {
3372 if (mincube > maxcube) {
3373 fpixels[3] = mincube - (kiter * incs[3]);
3374 } else {
3375 fpixels[3] = mincube + (kiter * incs[3]);
3376 }
3377
3378 lpixels[3] = fpixels[3];
3379
3380 for (jiter = 0; jiter < nsliceiter; jiter++)
3381 {
3382 if (minslice > maxslice) {
3383 fpixels[2] = minslice - (jiter * incs[2]);
3384 } else {
3385 fpixels[2] = minslice + (jiter * incs[2]);
3386 }
3387
3388 lpixels[2] = fpixels[2];
3389
3390 for (iiter = 0; iiter < nrowiter; iiter++)
3391 {
3392 if (minrow > maxrow) {
3393 fpixels[1] = minrow - (iiter * incs[1]);
3394 } else {
3395 fpixels[1] = minrow + (iiter * incs[1]);
3396 }
3397
3398 lpixels[1] = fpixels[1];
3399
3400 if (bitpix == 8)
3401 {
3402 ffgsvb(fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
3403 (unsigned char *) buffer, &anynull, status);
3404
3405 ffpprb(newptr, 1, firstpix, outsize, (unsigned char *) buffer, status);
3406 }
3407 else if (bitpix == 16)
3408 {
3409 ffgsvi(fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
3410 (short *) buffer, &anynull, status);
3411
3412 ffppri(newptr, 1, firstpix, outsize, (short *) buffer, status);
3413 }
3414 else if (bitpix == 32)
3415 {
3416 ffgsvk(fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
3417 (int *) buffer, &anynull, status);
3418
3419 ffpprk(newptr, 1, firstpix, outsize, (int *) buffer, status);
3420 }
3421 else if (bitpix == -32)
3422 {
3423 ffgsve(fptr, 1, naxis, naxes, fpixels, lpixels, incs, FLOATNULLVALUE,
3424 (float *) buffer, &anynull, status);
3425
3426 ffppne(newptr, 1, firstpix, outsize, (float *) buffer, FLOATNULLVALUE, status);
3427 }
3428 else if (bitpix == -64)
3429 {
3430 ffgsvd(fptr, 1, naxis, naxes, fpixels, lpixels, incs, DOUBLENULLVALUE,
3431 buffer, &anynull, status);
3432
3433 ffppnd(newptr, 1, firstpix, outsize, buffer, DOUBLENULLVALUE,
3434 status);
3435 }
3436 else if (bitpix == 64)
3437 {
3438 ffgsvjj(fptr, 1, naxis, naxes, fpixels, lpixels, incs, 0,
3439 (LONGLONG *) buffer, &anynull, status);
3440
3441 ffpprjj(newptr, 1, firstpix, outsize, (LONGLONG *) buffer, status);
3442 }
3443
3444 firstpix += outsize;
3445 }
3446 }
3447 }
3448
3449 free(buffer); /* finished with the memory */
3450
3451 if (*status > 0)
3452 {
3453 ffpmsg("fits_copy_image_section: error copying image section");
3454 return(*status);
3455 }
3456
3457 return(*status);
3458 }
3459 /*--------------------------------------------------------------------------*/
fits_get_section_range(char ** ptr,long * secmin,long * secmax,long * incre,int * status)3460 int fits_get_section_range(char **ptr,
3461 long *secmin,
3462 long *secmax,
3463 long *incre,
3464 int *status)
3465 /*
3466 Parse the input image section specification string, returning
3467 the min, max and increment values.
3468 Typical string = "1:512:2" or "1:512"
3469 */
3470 {
3471 int slen, isanumber;
3472 char token[FLEN_VALUE], *tstbuff=0;
3473
3474 if (*status > 0)
3475 return(*status);
3476
3477 slen = fits_get_token2(ptr, " ,:", &tstbuff, &isanumber, status); /* get 1st token */
3478 if (slen==0)
3479 {
3480 /* support [:2,:2] type syntax, where the leading * is implied */
3481 strcpy(token,"*");
3482 }
3483 else
3484 {
3485 if (strlen(tstbuff) > FLEN_VALUE-1)
3486 {
3487 ffpmsg("Error: image section string too long (fits_get_section_range)");
3488 free(tstbuff);
3489 *status = URL_PARSE_ERROR;
3490 return(*status);
3491 }
3492 strcpy(token, tstbuff);
3493 free(tstbuff);
3494 tstbuff=0;
3495 }
3496
3497 if (*token == '*') /* wild card means to use the whole range */
3498 {
3499 *secmin = 1;
3500 *secmax = 0;
3501 }
3502 else if (*token == '-' && *(token+1) == '*' ) /* invert the whole range */
3503 {
3504 *secmin = 0;
3505 *secmax = 1;
3506 }
3507 else
3508 {
3509 if (slen == 0 || !isanumber || **ptr != ':')
3510 return(*status = URL_PARSE_ERROR);
3511
3512 /* the token contains the min value */
3513 *secmin = atol(token);
3514
3515 (*ptr)++; /* skip the colon between the min and max values */
3516 slen = fits_get_token2(ptr, " ,:", &tstbuff, &isanumber, status); /* get token */
3517 if (slen == 0 || !isanumber)
3518 {
3519 if (tstbuff)
3520 free(tstbuff);
3521 return(*status = URL_PARSE_ERROR);
3522 }
3523 if (strlen(tstbuff) > FLEN_VALUE-1)
3524 {
3525 ffpmsg("Error: image section string too long (fits_get_section_range)");
3526 free(tstbuff);
3527 *status = URL_PARSE_ERROR;
3528 return(*status);
3529 }
3530 strcpy(token, tstbuff);
3531 free(tstbuff);
3532 tstbuff=0;
3533
3534 /* the token contains the max value */
3535 *secmax = atol(token);
3536 }
3537
3538 if (**ptr == ':')
3539 {
3540 (*ptr)++; /* skip the colon between the max and incre values */
3541 slen = fits_get_token2(ptr, " ,", &tstbuff, &isanumber, status); /* get token */
3542 if (slen == 0 || !isanumber)
3543 {
3544 if (tstbuff)
3545 free(tstbuff);
3546 return(*status = URL_PARSE_ERROR);
3547 }
3548 if (strlen(tstbuff) > FLEN_VALUE-1)
3549 {
3550 ffpmsg("Error: image section string too long (fits_get_section_range)");
3551 free(tstbuff);
3552 *status = URL_PARSE_ERROR;
3553 return(*status);
3554 }
3555 strcpy(token, tstbuff);
3556 free(tstbuff);
3557 tstbuff=0;
3558
3559
3560 *incre = atol(token);
3561 }
3562 else
3563 *incre = 1; /* default increment if none is supplied */
3564
3565 if (**ptr == ',')
3566 (*ptr)++;
3567
3568 while (**ptr == ' ') /* skip any trailing blanks */
3569 (*ptr)++;
3570
3571 if (*secmin < 0 || *secmax < 0 || *incre < 1)
3572 *status = URL_PARSE_ERROR;
3573
3574 return(*status);
3575 }
3576 /*--------------------------------------------------------------------------*/
ffselect_table(fitsfile ** fptr,char * outfile,char * expr,int * status)3577 int ffselect_table(
3578 fitsfile **fptr, /* IO - pointer to input table; on output it */
3579 /* points to the new selected rows table */
3580 char *outfile, /* I - name for output file */
3581 char *expr, /* I - Boolean expression */
3582 int *status)
3583 {
3584 fitsfile *newptr;
3585 int ii, hdunum;
3586
3587 if (*outfile)
3588 {
3589 /* create new empty file in to hold the selected rows */
3590 if (ffinit(&newptr, outfile, status) > 0)
3591 {
3592 ffpmsg(
3593 "failed to create file for selected rows from input table");
3594 ffpmsg(outfile);
3595 return(*status);
3596 }
3597
3598 fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
3599
3600 /* copy all preceding extensions to the output file, if the 'only_one' flag is not set */
3601 if (!((*fptr)->Fptr)->only_one) {
3602 for (ii = 1; ii < hdunum; ii++)
3603 {
3604 fits_movabs_hdu(*fptr, ii, NULL, status);
3605 if (fits_copy_hdu(*fptr, newptr, 0, status) > 0)
3606 {
3607 ffclos(newptr, status);
3608 return(*status);
3609 }
3610 }
3611 } else {
3612 /* just copy the primary array */
3613 fits_movabs_hdu(*fptr, 1, NULL, status);
3614 if (fits_copy_hdu(*fptr, newptr, 0, status) > 0)
3615 {
3616 ffclos(newptr, status);
3617 return(*status);
3618 }
3619 }
3620
3621 fits_movabs_hdu(*fptr, hdunum, NULL, status);
3622
3623 /* copy all the header keywords from the input to output file */
3624 if (fits_copy_header(*fptr, newptr, status) > 0)
3625 {
3626 ffclos(newptr, status);
3627 return(*status);
3628 }
3629
3630 /* set number of rows = 0 */
3631 fits_modify_key_lng(newptr, "NAXIS2", 0, NULL,status);
3632 (newptr->Fptr)->numrows = 0;
3633 (newptr->Fptr)->origrows = 0;
3634
3635 if (ffrdef(newptr, status) > 0) /* force the header to be scanned */
3636 {
3637 ffclos(newptr, status);
3638 return(*status);
3639 }
3640 }
3641 else
3642 newptr = *fptr; /* will delete rows in place in the table */
3643
3644 /* copy rows which satisfy the selection expression to the output table */
3645 /* or delete the nonqualifying rows if *fptr = newptr. */
3646 if (fits_select_rows(*fptr, newptr, expr, status) > 0)
3647 {
3648 if (*outfile)
3649 ffclos(newptr, status);
3650
3651 return(*status);
3652 }
3653
3654 if (*outfile)
3655 {
3656 /* copy any remaining HDUs to the output copy */
3657
3658 if (!((*fptr)->Fptr)->only_one) {
3659 for (ii = hdunum + 1; 1; ii++)
3660 {
3661 if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
3662 break;
3663
3664 fits_copy_hdu(*fptr, newptr, 0, status);
3665 }
3666
3667 if (*status == END_OF_FILE)
3668 *status = 0; /* got the expected EOF error; reset = 0 */
3669 else if (*status > 0)
3670 {
3671 ffclos(newptr, status);
3672 return(*status);
3673 }
3674 } else {
3675 hdunum = 2;
3676 }
3677
3678 /* close the original file and return ptr to the new image */
3679 ffclos(*fptr, status);
3680
3681 *fptr = newptr; /* reset the pointer to the new table */
3682
3683 /* move back to the selected table HDU */
3684 fits_movabs_hdu(*fptr, hdunum, NULL, status);
3685 }
3686
3687 return(*status);
3688 }
3689 /*--------------------------------------------------------------------------*/
ffparsecompspec(fitsfile * fptr,char * compspec,int * status)3690 int ffparsecompspec(fitsfile *fptr, /* I - FITS file pointer */
3691 char *compspec, /* I - image compression specification */
3692 int *status) /* IO - error status */
3693 /*
3694 Parse the image compression specification that was give in square brackets
3695 following the output FITS file name, as in these examples:
3696
3697 myfile.fits[compress] - default Rice compression, row by row
3698 myfile.fits[compress TYPE] - the first letter of TYPE defines the
3699 compression algorithm:
3700 R = Rice
3701 G = GZIP
3702 H = HCOMPRESS
3703 HS = HCOMPRESS (with smoothing)
3704 B - BZIP2
3705 P = PLIO
3706
3707 myfile.fits[compress TYPE 100,100] - the numbers give the dimensions
3708 of the compression tiles. Default
3709 is NAXIS1, 1, 1, ...
3710
3711 other optional parameters may be specified following a semi-colon
3712
3713 myfile.fits[compress; q 8.0] q specifies the floating point
3714 mufile.fits[compress TYPE; q -.0002] quantization level;
3715 myfile.fits[compress TYPE 100,100; q 10, s 25] s specifies the HCOMPRESS
3716 integer scaling parameter
3717
3718 The compression parameters are saved in the fptr->Fptr structure for use
3719 when writing FITS images.
3720
3721 */
3722 {
3723 char *ptr1;
3724
3725 /* initialize with default values */
3726 int ii, compresstype = RICE_1, smooth = 0;
3727 int quantize_method = SUBTRACTIVE_DITHER_1;
3728 long tilesize[MAX_COMPRESS_DIM] = {0,0,0,0,0,0};
3729 float qlevel = -99., scale = 0.;
3730
3731 ptr1 = compspec;
3732 while (*ptr1 == ' ') /* ignore leading blanks */
3733 ptr1++;
3734
3735 if (strncmp(ptr1, "compress", 8) && strncmp(ptr1, "COMPRESS", 8) )
3736 {
3737 /* apparently this string does not specify compression parameters */
3738 return(*status = URL_PARSE_ERROR);
3739 }
3740
3741 ptr1 += 8;
3742 while (*ptr1 == ' ') /* ignore leading blanks */
3743 ptr1++;
3744
3745 /* ========================= */
3746 /* look for compression type */
3747 /* ========================= */
3748
3749 if (*ptr1 == 'r' || *ptr1 == 'R')
3750 {
3751 compresstype = RICE_1;
3752 while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
3753 ptr1++;
3754 }
3755 else if (*ptr1 == 'g' || *ptr1 == 'G')
3756 {
3757 compresstype = GZIP_1;
3758 while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
3759 ptr1++;
3760
3761 }
3762 /*
3763 else if (*ptr1 == 'b' || *ptr1 == 'B')
3764 {
3765 compresstype = BZIP2_1;
3766 while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
3767 ptr1++;
3768
3769 }
3770 */
3771 else if (*ptr1 == 'p' || *ptr1 == 'P')
3772 {
3773 compresstype = PLIO_1;
3774 while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
3775 ptr1++;
3776 }
3777 else if (*ptr1 == 'h' || *ptr1 == 'H')
3778 {
3779 compresstype = HCOMPRESS_1;
3780 ptr1++;
3781 if (*ptr1 == 's' || *ptr1 == 'S')
3782 smooth = 1; /* apply smoothing when uncompressing HCOMPRESSed image */
3783
3784 while (*ptr1 != ' ' && *ptr1 != ';' && *ptr1 != '\0')
3785 ptr1++;
3786 }
3787
3788 /* ======================== */
3789 /* look for tile dimensions */
3790 /* ======================== */
3791
3792 while (*ptr1 == ' ') /* ignore leading blanks */
3793 ptr1++;
3794
3795 ii = 0;
3796 while (isdigit( (int) *ptr1) && ii < 9)
3797 {
3798 tilesize[ii] = atol(ptr1); /* read the integer value */
3799 ii++;
3800
3801 while (isdigit((int) *ptr1)) /* skip over the integer */
3802 ptr1++;
3803
3804 if (*ptr1 == ',')
3805 ptr1++; /* skip over the comma */
3806
3807 while (*ptr1 == ' ') /* ignore leading blanks */
3808 ptr1++;
3809 }
3810
3811 /* ========================================================= */
3812 /* look for semi-colon, followed by other optional parameters */
3813 /* ========================================================= */
3814
3815 if (*ptr1 == ';') {
3816 ptr1++;
3817 while (*ptr1 == ' ') /* ignore leading blanks */
3818 ptr1++;
3819
3820 while (*ptr1 != 0) { /* haven't reached end of string yet */
3821
3822 if (*ptr1 == 's' || *ptr1 == 'S') {
3823 /* this should be the HCOMPRESS "scale" parameter; default = 1 */
3824
3825 ptr1++;
3826 while (*ptr1 == ' ') /* ignore leading blanks */
3827 ptr1++;
3828
3829 scale = (float) strtod(ptr1, &ptr1);
3830
3831 while (*ptr1 == ' ' || *ptr1 == ',') /* skip over blanks or comma */
3832 ptr1++;
3833
3834 } else if (*ptr1 == 'q' || *ptr1 == 'Q') {
3835 /* this should be the floating point quantization parameter */
3836
3837 ptr1++;
3838 if (*ptr1 == 'z' || *ptr1 == 'Z') {
3839 /* use the subtractive_dither_2 option */
3840 quantize_method = SUBTRACTIVE_DITHER_2;
3841 ptr1++;
3842 } else if (*ptr1 == '0') {
3843 /* do not dither */
3844 quantize_method = NO_DITHER;
3845 ptr1++;
3846 }
3847
3848 while (*ptr1 == ' ') /* ignore leading blanks */
3849 ptr1++;
3850
3851 qlevel = (float) strtod(ptr1, &ptr1);
3852
3853 while (*ptr1 == ' ' || *ptr1 == ',') /* skip over blanks or comma */
3854 ptr1++;
3855
3856 } else {
3857 return(*status = URL_PARSE_ERROR);
3858 }
3859 }
3860 }
3861
3862 /* ================================= */
3863 /* finished parsing; save the values */
3864 /* ================================= */
3865
3866 fits_set_compression_type(fptr, compresstype, status);
3867 fits_set_tile_dim(fptr, MAX_COMPRESS_DIM, tilesize, status);
3868
3869 if (compresstype == HCOMPRESS_1) {
3870 fits_set_hcomp_scale (fptr, scale, status);
3871 fits_set_hcomp_smooth(fptr, smooth, status);
3872 }
3873
3874 if (qlevel != -99.) {
3875 fits_set_quantize_level(fptr, qlevel, status);
3876 fits_set_quantize_method(fptr, quantize_method, status);
3877 }
3878
3879 return(*status);
3880 }
3881 /*--------------------------------------------------------------------------*/
ffdkinit(fitsfile ** fptr,const char * name,int * status)3882 int ffdkinit(fitsfile **fptr, /* O - FITS file pointer */
3883 const char *name, /* I - name of file to create */
3884 int *status) /* IO - error status */
3885 /*
3886 Create and initialize a new FITS file on disk. This routine differs
3887 from ffinit in that the input 'name' is literally taken as the name
3888 of the disk file to be created, and it does not support CFITSIO's
3889 extended filename syntax.
3890 */
3891 {
3892 *fptr = 0; /* initialize null file pointer, */
3893 /* regardless of the value of *status */
3894 if (*status > 0)
3895 return(*status);
3896
3897 *status = CREATE_DISK_FILE;
3898
3899 ffinit(fptr, name,status);
3900
3901 return(*status);
3902 }
3903 /*--------------------------------------------------------------------------*/
ffinit(fitsfile ** fptr,const char * name,int * status)3904 int ffinit(fitsfile **fptr, /* O - FITS file pointer */
3905 const char *name, /* I - name of file to create */
3906 int *status) /* IO - error status */
3907 /*
3908 Create and initialize a new FITS file.
3909 */
3910 {
3911 int ii, driver, slen, clobber = 0;
3912 char *url;
3913 char urltype[MAX_PREFIX_LEN], outfile[FLEN_FILENAME];
3914 char tmplfile[FLEN_FILENAME], compspec[80];
3915 int handle, create_disk_file = 0;
3916
3917 *fptr = 0; /* initialize null file pointer, */
3918 /* regardless of the value of *status */
3919 if (*status > 0)
3920 return(*status);
3921
3922 if (*status == CREATE_DISK_FILE)
3923 {
3924 create_disk_file = 1;
3925 *status = 0;
3926 }
3927
3928 if (need_to_initialize) { /* this is called only once */
3929 *status = fits_init_cfitsio();
3930 }
3931
3932 if (*status > 0)
3933 return(*status);
3934
3935 url = (char *) name;
3936 while (*url == ' ') /* ignore leading spaces in the filename */
3937 url++;
3938
3939 if (*url == '\0')
3940 {
3941 ffpmsg("Name of file to create is blank. (ffinit)");
3942 return(*status = FILE_NOT_CREATED);
3943 }
3944
3945 if (create_disk_file)
3946 {
3947 if (strlen(url) > FLEN_FILENAME - 1)
3948 {
3949 ffpmsg("Filename is too long. (ffinit)");
3950 return(*status = FILE_NOT_CREATED);
3951 }
3952
3953 strcpy(outfile, url);
3954 strcpy(urltype, "file://");
3955 tmplfile[0] = '\0';
3956 compspec[0] = '\0';
3957 }
3958 else
3959 {
3960
3961 /* check for clobber symbol, i.e, overwrite existing file */
3962 if (*url == '!')
3963 {
3964 clobber = TRUE;
3965 url++;
3966 }
3967 else
3968 clobber = FALSE;
3969
3970 /* parse the output file specification */
3971 /* this routine checks that the strings will not overflow */
3972 ffourl(url, urltype, outfile, tmplfile, compspec, status);
3973
3974 if (*status > 0)
3975 {
3976 ffpmsg("could not parse the output filename: (ffinit)");
3977 ffpmsg(url);
3978 return(*status);
3979 }
3980 }
3981
3982 /* find which driver corresponds to the urltype */
3983 *status = urltype2driver(urltype, &driver);
3984
3985 if (*status)
3986 {
3987 ffpmsg("could not find driver for this file: (ffinit)");
3988 ffpmsg(url);
3989 return(*status);
3990 }
3991
3992 /* delete pre-existing file, if asked to do so */
3993 if (clobber)
3994 {
3995 if (driverTable[driver].remove)
3996 (*driverTable[driver].remove)(outfile);
3997 }
3998
3999 /* call appropriate driver to create the file */
4000 if (driverTable[driver].create)
4001 {
4002
4003 FFLOCK; /* lock this while searching for vacant handle */
4004 *status = (*driverTable[driver].create)(outfile, &handle);
4005 FFUNLOCK;
4006
4007 if (*status)
4008 {
4009 ffpmsg("failed to create new file (already exists?):");
4010 ffpmsg(url);
4011 return(*status);
4012 }
4013 }
4014 else
4015 {
4016 ffpmsg("cannot create a new file of this type: (ffinit)");
4017 ffpmsg(url);
4018 return(*status = FILE_NOT_CREATED);
4019 }
4020
4021 /* allocate fitsfile structure and initialize = 0 */
4022 *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
4023
4024 if (!(*fptr))
4025 {
4026 (*driverTable[driver].close)(handle); /* close the file */
4027 ffpmsg("failed to allocate structure for following file: (ffopen)");
4028 ffpmsg(url);
4029 return(*status = MEMORY_ALLOCATION);
4030 }
4031
4032 /* allocate FITSfile structure and initialize = 0 */
4033 (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
4034
4035 if (!((*fptr)->Fptr))
4036 {
4037 (*driverTable[driver].close)(handle); /* close the file */
4038 ffpmsg("failed to allocate structure for following file: (ffopen)");
4039 ffpmsg(url);
4040 free(*fptr);
4041 *fptr = 0;
4042 return(*status = MEMORY_ALLOCATION);
4043 }
4044
4045 slen = strlen(url) + 1;
4046 slen = maxvalue(slen, 32); /* reserve at least 32 chars */
4047 ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
4048
4049 if ( !(((*fptr)->Fptr)->filename) )
4050 {
4051 (*driverTable[driver].close)(handle); /* close the file */
4052 ffpmsg("failed to allocate memory for filename: (ffinit)");
4053 ffpmsg(url);
4054 free((*fptr)->Fptr);
4055 free(*fptr);
4056 *fptr = 0; /* return null file pointer */
4057 return(*status = FILE_NOT_CREATED);
4058 }
4059
4060 /* mem for headstart array */
4061 ((*fptr)->Fptr)->headstart = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
4062
4063 if ( !(((*fptr)->Fptr)->headstart) )
4064 {
4065 (*driverTable[driver].close)(handle); /* close the file */
4066 ffpmsg("failed to allocate memory for headstart array: (ffinit)");
4067 ffpmsg(url);
4068 free( ((*fptr)->Fptr)->filename);
4069 free((*fptr)->Fptr);
4070 free(*fptr);
4071 *fptr = 0; /* return null file pointer */
4072 return(*status = MEMORY_ALLOCATION);
4073 }
4074
4075 /* mem for file I/O buffers */
4076 ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
4077
4078 if ( !(((*fptr)->Fptr)->iobuffer) )
4079 {
4080 (*driverTable[driver].close)(handle); /* close the file */
4081 ffpmsg("failed to allocate memory for iobuffer array: (ffinit)");
4082 ffpmsg(url);
4083 free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
4084 free( ((*fptr)->Fptr)->filename);
4085 free((*fptr)->Fptr);
4086 free(*fptr);
4087 *fptr = 0; /* return null file pointer */
4088 return(*status = MEMORY_ALLOCATION);
4089 }
4090
4091 /* initialize the ageindex array (relative age of the I/O buffers) */
4092 /* and initialize the bufrecnum array as being empty */
4093 for (ii = 0; ii < NIOBUF; ii++) {
4094 ((*fptr)->Fptr)->ageindex[ii] = ii;
4095 ((*fptr)->Fptr)->bufrecnum[ii] = -1;
4096 }
4097
4098 /* store the parameters describing the file */
4099 ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
4100 ((*fptr)->Fptr)->filehandle = handle; /* store the file pointer */
4101 ((*fptr)->Fptr)->driver = driver; /* driver number */
4102 strcpy(((*fptr)->Fptr)->filename, url); /* full input filename */
4103 ((*fptr)->Fptr)->filesize = 0; /* physical file size */
4104 ((*fptr)->Fptr)->logfilesize = 0; /* logical file size */
4105 ((*fptr)->Fptr)->writemode = 1; /* read-write mode */
4106 ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
4107 ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
4108 ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
4109 ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
4110
4111 ffldrc(*fptr, 0, IGNORE_EOF, status); /* initialize first record */
4112
4113 fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
4114
4115 /* if template file was given, use it to define structure of new file */
4116
4117 if (tmplfile[0])
4118 ffoptplt(*fptr, tmplfile, status);
4119
4120 /* parse and save image compression specification, if given */
4121 if (compspec[0])
4122 ffparsecompspec(*fptr, compspec, status);
4123
4124 return(*status); /* successful return */
4125 }
4126 /*--------------------------------------------------------------------------*/
4127 /* ffimem == fits_create_memfile */
4128
ffimem(fitsfile ** fptr,void ** buffptr,size_t * buffsize,size_t deltasize,void * (* mem_realloc)(void * p,size_t newsize),int * status)4129 int ffimem(fitsfile **fptr, /* O - FITS file pointer */
4130 void **buffptr, /* I - address of memory pointer */
4131 size_t *buffsize, /* I - size of buffer, in bytes */
4132 size_t deltasize, /* I - increment for future realloc's */
4133 void *(*mem_realloc)(void *p, size_t newsize), /* function */
4134 int *status) /* IO - error status */
4135
4136 /*
4137 Create and initialize a new FITS file in memory
4138 */
4139 {
4140 int ii, driver, slen;
4141 char urltype[MAX_PREFIX_LEN];
4142 int handle;
4143
4144 if (*status > 0)
4145 return(*status);
4146
4147 *fptr = 0; /* initialize null file pointer */
4148
4149 if (need_to_initialize) { /* this is called only once */
4150 *status = fits_init_cfitsio();
4151 }
4152
4153 if (*status > 0)
4154 return(*status);
4155
4156 strcpy(urltype, "memkeep://"); /* URL type for pre-existing memory file */
4157
4158 *status = urltype2driver(urltype, &driver);
4159
4160 if (*status > 0)
4161 {
4162 ffpmsg("could not find driver for pre-existing memory file: (ffimem)");
4163 return(*status);
4164 }
4165
4166 /* call driver routine to "open" the memory file */
4167 FFLOCK; /* lock this while searching for vacant handle */
4168 *status = mem_openmem( buffptr, buffsize, deltasize,
4169 mem_realloc, &handle);
4170 FFUNLOCK;
4171
4172 if (*status > 0)
4173 {
4174 ffpmsg("failed to open pre-existing memory file: (ffimem)");
4175 return(*status);
4176 }
4177
4178 /* allocate fitsfile structure and initialize = 0 */
4179 *fptr = (fitsfile *) calloc(1, sizeof(fitsfile));
4180
4181 if (!(*fptr))
4182 {
4183 (*driverTable[driver].close)(handle); /* close the file */
4184 ffpmsg("failed to allocate structure for memory file: (ffimem)");
4185 return(*status = MEMORY_ALLOCATION);
4186 }
4187
4188 /* allocate FITSfile structure and initialize = 0 */
4189 (*fptr)->Fptr = (FITSfile *) calloc(1, sizeof(FITSfile));
4190
4191 if (!((*fptr)->Fptr))
4192 {
4193 (*driverTable[driver].close)(handle); /* close the file */
4194 ffpmsg("failed to allocate structure for memory file: (ffimem)");
4195 free(*fptr);
4196 *fptr = 0;
4197 return(*status = MEMORY_ALLOCATION);
4198 }
4199
4200 slen = 32; /* reserve at least 32 chars */
4201 ((*fptr)->Fptr)->filename = (char *) malloc(slen); /* mem for file name */
4202
4203 if ( !(((*fptr)->Fptr)->filename) )
4204 {
4205 (*driverTable[driver].close)(handle); /* close the file */
4206 ffpmsg("failed to allocate memory for filename: (ffimem)");
4207 free((*fptr)->Fptr);
4208 free(*fptr);
4209 *fptr = 0; /* return null file pointer */
4210 return(*status = MEMORY_ALLOCATION);
4211 }
4212
4213 /* mem for headstart array */
4214 ((*fptr)->Fptr)->headstart = (LONGLONG *) calloc(1001, sizeof(LONGLONG));
4215
4216 if ( !(((*fptr)->Fptr)->headstart) )
4217 {
4218 (*driverTable[driver].close)(handle); /* close the file */
4219 ffpmsg("failed to allocate memory for headstart array: (ffimem)");
4220 free( ((*fptr)->Fptr)->filename);
4221 free((*fptr)->Fptr);
4222 free(*fptr);
4223 *fptr = 0; /* return null file pointer */
4224 return(*status = MEMORY_ALLOCATION);
4225 }
4226
4227 /* mem for file I/O buffers */
4228 ((*fptr)->Fptr)->iobuffer = (char *) calloc(NIOBUF, IOBUFLEN);
4229
4230 if ( !(((*fptr)->Fptr)->iobuffer) )
4231 {
4232 (*driverTable[driver].close)(handle); /* close the file */
4233 ffpmsg("failed to allocate memory for iobuffer array: (ffimem)");
4234 free( ((*fptr)->Fptr)->headstart); /* free memory for headstart array */
4235 free( ((*fptr)->Fptr)->filename);
4236 free((*fptr)->Fptr);
4237 free(*fptr);
4238 *fptr = 0; /* return null file pointer */
4239 return(*status = MEMORY_ALLOCATION);
4240 }
4241
4242 /* initialize the ageindex array (relative age of the I/O buffers) */
4243 /* and initialize the bufrecnum array as being empty */
4244 for (ii = 0; ii < NIOBUF; ii++) {
4245 ((*fptr)->Fptr)->ageindex[ii] = ii;
4246 ((*fptr)->Fptr)->bufrecnum[ii] = -1;
4247 }
4248
4249 /* store the parameters describing the file */
4250 ((*fptr)->Fptr)->MAXHDU = 1000; /* initial size of headstart */
4251 ((*fptr)->Fptr)->filehandle = handle; /* file handle */
4252 ((*fptr)->Fptr)->driver = driver; /* driver number */
4253 strcpy(((*fptr)->Fptr)->filename, "memfile"); /* dummy filename */
4254 ((*fptr)->Fptr)->filesize = *buffsize; /* physical file size */
4255 ((*fptr)->Fptr)->logfilesize = *buffsize; /* logical file size */
4256 ((*fptr)->Fptr)->writemode = 1; /* read-write mode */
4257 ((*fptr)->Fptr)->datastart = DATA_UNDEFINED; /* unknown start of data */
4258 ((*fptr)->Fptr)->curbuf = -1; /* undefined current IO buffer */
4259 ((*fptr)->Fptr)->open_count = 1; /* structure is currently used once */
4260 ((*fptr)->Fptr)->validcode = VALIDSTRUC; /* flag denoting valid structure */
4261
4262 ffldrc(*fptr, 0, IGNORE_EOF, status); /* initialize first record */
4263 fits_store_Fptr( (*fptr)->Fptr, status); /* store Fptr address */
4264 return(*status);
4265 }
4266 /*--------------------------------------------------------------------------*/
fits_init_cfitsio(void)4267 int fits_init_cfitsio(void)
4268 /*
4269 initialize anything that is required before using the CFITSIO routines
4270 */
4271 {
4272 int status;
4273
4274 union u_tag {
4275 short ival;
4276 char cval[2];
4277 } u;
4278
4279 fitsio_init_lock();
4280
4281 FFLOCK; /* lockout other threads while executing this critical */
4282 /* section of code */
4283
4284 if (need_to_initialize == 0) { /* already initialized? */
4285 FFUNLOCK;
4286 return(0);
4287 }
4288
4289 /* test for correct byteswapping. */
4290
4291 u.ival = 1;
4292 if ((BYTESWAPPED && u.cval[0] != 1) ||
4293 (BYTESWAPPED == FALSE && u.cval[1] != 1) )
4294 {
4295 printf ("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
4296 printf(" Byteswapping is not being done correctly on this system.\n");
4297 printf(" Check the MACHINE and BYTESWAPPED definitions in fitsio2.h\n");
4298 printf(" Please report this problem to the CFITSIO developers.\n");
4299 printf( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
4300 FFUNLOCK;
4301 return(1);
4302 }
4303
4304
4305 /* test that LONGLONG is an 8 byte integer */
4306
4307 if (sizeof(LONGLONG) != 8)
4308 {
4309 printf ("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
4310 printf(" CFITSIO did not find an 8-byte long integer data type.\n");
4311 printf(" sizeof(LONGLONG) = %d\n",(int)sizeof(LONGLONG));
4312 printf(" Please report this problem to the CFITSIO developers.\n");
4313 printf( "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
4314 FFUNLOCK;
4315 return(1);
4316 }
4317
4318 /* register the standard I/O drivers that are always available */
4319
4320 /* 1--------------------disk file driver-----------------------*/
4321 status = fits_register_driver("file://",
4322 file_init,
4323 file_shutdown,
4324 file_setoptions,
4325 file_getoptions,
4326 file_getversion,
4327 file_checkfile,
4328 file_open,
4329 file_create,
4330 #ifdef HAVE_FTRUNCATE
4331 file_truncate,
4332 #else
4333 NULL, /* no file truncate function */
4334 #endif
4335 file_close,
4336 file_remove,
4337 file_size,
4338 file_flush,
4339 file_seek,
4340 file_read,
4341 file_write);
4342
4343 if (status)
4344 {
4345 ffpmsg("failed to register the file:// driver (init_cfitsio)");
4346 FFUNLOCK;
4347 return(status);
4348 }
4349
4350 /* 2------------ output temporary memory file driver ----------------*/
4351 status = fits_register_driver("mem://",
4352 mem_init,
4353 mem_shutdown,
4354 mem_setoptions,
4355 mem_getoptions,
4356 mem_getversion,
4357 NULL, /* checkfile not needed */
4358 NULL, /* open function not allowed */
4359 mem_create,
4360 mem_truncate,
4361 mem_close_free,
4362 NULL, /* remove function not required */
4363 mem_size,
4364 NULL, /* flush function not required */
4365 mem_seek,
4366 mem_read,
4367 mem_write);
4368
4369
4370 if (status)
4371 {
4372 ffpmsg("failed to register the mem:// driver (init_cfitsio)");
4373 FFUNLOCK;
4374 return(status);
4375 }
4376
4377 /* 3--------------input pre-existing memory file driver----------------*/
4378 status = fits_register_driver("memkeep://",
4379 NULL,
4380 mem_shutdown,
4381 mem_setoptions,
4382 mem_getoptions,
4383 mem_getversion,
4384 NULL, /* checkfile not needed */
4385 NULL, /* file open driver function is not used */
4386 NULL, /* create function not allowed */
4387 mem_truncate,
4388 mem_close_keep,
4389 NULL, /* remove function not required */
4390 mem_size,
4391 NULL, /* flush function not required */
4392 mem_seek,
4393 mem_read,
4394 mem_write);
4395
4396
4397 if (status)
4398 {
4399 ffpmsg("failed to register the memkeep:// driver (init_cfitsio)");
4400 FFUNLOCK;
4401 return(status);
4402 }
4403
4404 /* 4-------------------stdin stream driver----------------------*/
4405 /* the stdin stream is copied to memory then opened in memory */
4406
4407 status = fits_register_driver("stdin://",
4408 NULL,
4409 mem_shutdown,
4410 mem_setoptions,
4411 mem_getoptions,
4412 mem_getversion,
4413 stdin_checkfile,
4414 stdin_open,
4415 NULL, /* create function not allowed */
4416 mem_truncate,
4417 mem_close_free,
4418 NULL, /* remove function not required */
4419 mem_size,
4420 NULL, /* flush function not required */
4421 mem_seek,
4422 mem_read,
4423 mem_write);
4424
4425 if (status)
4426 {
4427 ffpmsg("failed to register the stdin:// driver (init_cfitsio)");
4428 FFUNLOCK;
4429 return(status);
4430 }
4431
4432 /* 5-------------------stdin file stream driver----------------------*/
4433 /* the stdin stream is copied to a disk file then the disk file is opened */
4434
4435 status = fits_register_driver("stdinfile://",
4436 NULL,
4437 mem_shutdown,
4438 mem_setoptions,
4439 mem_getoptions,
4440 mem_getversion,
4441 NULL, /* checkfile not needed */
4442 stdin_open,
4443 NULL, /* create function not allowed */
4444 #ifdef HAVE_FTRUNCATE
4445 file_truncate,
4446 #else
4447 NULL, /* no file truncate function */
4448 #endif
4449 file_close,
4450 file_remove,
4451 file_size,
4452 file_flush,
4453 file_seek,
4454 file_read,
4455 file_write);
4456
4457 if (status)
4458 {
4459 ffpmsg("failed to register the stdinfile:// driver (init_cfitsio)");
4460 FFUNLOCK;
4461 return(status);
4462 }
4463
4464
4465 /* 6-----------------------stdout stream driver------------------*/
4466 status = fits_register_driver("stdout://",
4467 NULL,
4468 mem_shutdown,
4469 mem_setoptions,
4470 mem_getoptions,
4471 mem_getversion,
4472 NULL, /* checkfile not needed */
4473 NULL, /* open function not required */
4474 mem_create,
4475 mem_truncate,
4476 stdout_close,
4477 NULL, /* remove function not required */
4478 mem_size,
4479 NULL, /* flush function not required */
4480 mem_seek,
4481 mem_read,
4482 mem_write);
4483
4484 if (status)
4485 {
4486 ffpmsg("failed to register the stdout:// driver (init_cfitsio)");
4487 FFUNLOCK;
4488 return(status);
4489 }
4490
4491 /* 7------------------iraf disk file to memory driver -----------*/
4492 status = fits_register_driver("irafmem://",
4493 NULL,
4494 mem_shutdown,
4495 mem_setoptions,
4496 mem_getoptions,
4497 mem_getversion,
4498 NULL, /* checkfile not needed */
4499 mem_iraf_open,
4500 NULL, /* create function not required */
4501 mem_truncate,
4502 mem_close_free,
4503 NULL, /* remove function not required */
4504 mem_size,
4505 NULL, /* flush function not required */
4506 mem_seek,
4507 mem_read,
4508 mem_write);
4509
4510 if (status)
4511 {
4512 ffpmsg("failed to register the irafmem:// driver (init_cfitsio)");
4513 FFUNLOCK;
4514 return(status);
4515 }
4516
4517 /* 8------------------raw binary file to memory driver -----------*/
4518 status = fits_register_driver("rawfile://",
4519 NULL,
4520 mem_shutdown,
4521 mem_setoptions,
4522 mem_getoptions,
4523 mem_getversion,
4524 NULL, /* checkfile not needed */
4525 mem_rawfile_open,
4526 NULL, /* create function not required */
4527 mem_truncate,
4528 mem_close_free,
4529 NULL, /* remove function not required */
4530 mem_size,
4531 NULL, /* flush function not required */
4532 mem_seek,
4533 mem_read,
4534 mem_write);
4535
4536 if (status)
4537 {
4538 ffpmsg("failed to register the rawfile:// driver (init_cfitsio)");
4539 FFUNLOCK;
4540 return(status);
4541 }
4542
4543 /* 9------------------compressed disk file to memory driver -----------*/
4544 status = fits_register_driver("compress://",
4545 NULL,
4546 mem_shutdown,
4547 mem_setoptions,
4548 mem_getoptions,
4549 mem_getversion,
4550 NULL, /* checkfile not needed */
4551 mem_compress_open,
4552 NULL, /* create function not required */
4553 mem_truncate,
4554 mem_close_free,
4555 NULL, /* remove function not required */
4556 mem_size,
4557 NULL, /* flush function not required */
4558 mem_seek,
4559 mem_read,
4560 mem_write);
4561
4562 if (status)
4563 {
4564 ffpmsg("failed to register the compress:// driver (init_cfitsio)");
4565 FFUNLOCK;
4566 return(status);
4567 }
4568
4569 /* 10------------------compressed disk file to memory driver -----------*/
4570 /* Identical to compress://, except it allows READWRITE access */
4571
4572 status = fits_register_driver("compressmem://",
4573 NULL,
4574 mem_shutdown,
4575 mem_setoptions,
4576 mem_getoptions,
4577 mem_getversion,
4578 NULL, /* checkfile not needed */
4579 mem_compress_openrw,
4580 NULL, /* create function not required */
4581 mem_truncate,
4582 mem_close_free,
4583 NULL, /* remove function not required */
4584 mem_size,
4585 NULL, /* flush function not required */
4586 mem_seek,
4587 mem_read,
4588 mem_write);
4589
4590 if (status)
4591 {
4592 ffpmsg("failed to register the compressmem:// driver (init_cfitsio)");
4593 FFUNLOCK;
4594 return(status);
4595 }
4596
4597 /* 11------------------compressed disk file to disk file driver -------*/
4598 status = fits_register_driver("compressfile://",
4599 NULL,
4600 file_shutdown,
4601 file_setoptions,
4602 file_getoptions,
4603 file_getversion,
4604 NULL, /* checkfile not needed */
4605 file_compress_open,
4606 file_create,
4607 #ifdef HAVE_FTRUNCATE
4608 file_truncate,
4609 #else
4610 NULL, /* no file truncate function */
4611 #endif
4612 file_close,
4613 file_remove,
4614 file_size,
4615 file_flush,
4616 file_seek,
4617 file_read,
4618 file_write);
4619
4620 if (status)
4621 {
4622 ffpmsg("failed to register the compressfile:// driver (init_cfitsio)");
4623 FFUNLOCK;
4624 return(status);
4625 }
4626
4627 /* 12---create file in memory, then compress it to disk file on close--*/
4628 status = fits_register_driver("compressoutfile://",
4629 NULL,
4630 mem_shutdown,
4631 mem_setoptions,
4632 mem_getoptions,
4633 mem_getversion,
4634 NULL, /* checkfile not needed */
4635 NULL, /* open function not allowed */
4636 mem_create_comp,
4637 mem_truncate,
4638 mem_close_comp,
4639 file_remove, /* delete existing compressed disk file */
4640 mem_size,
4641 NULL, /* flush function not required */
4642 mem_seek,
4643 mem_read,
4644 mem_write);
4645
4646
4647 if (status)
4648 {
4649 ffpmsg(
4650 "failed to register the compressoutfile:// driver (init_cfitsio)");
4651 FFUNLOCK;
4652 return(status);
4653 }
4654
4655 /* Register Optional drivers */
4656
4657 #ifdef HAVE_NET_SERVICES
4658
4659 /* 13--------------------root driver-----------------------*/
4660
4661 status = fits_register_driver("root://",
4662 root_init,
4663 root_shutdown,
4664 root_setoptions,
4665 root_getoptions,
4666 root_getversion,
4667 NULL, /* checkfile not needed */
4668 root_open,
4669 root_create,
4670 NULL, /* No truncate possible */
4671 root_close,
4672 NULL, /* No remove possible */
4673 root_size, /* no size possible */
4674 root_flush,
4675 root_seek, /* Though will always succeed */
4676 root_read,
4677 root_write);
4678
4679 if (status)
4680 {
4681 ffpmsg("failed to register the root:// driver (init_cfitsio)");
4682 FFUNLOCK;
4683 return(status);
4684 }
4685
4686 /* 14--------------------http driver-----------------------*/
4687 status = fits_register_driver("http://",
4688 NULL,
4689 mem_shutdown,
4690 mem_setoptions,
4691 mem_getoptions,
4692 mem_getversion,
4693 http_checkfile,
4694 http_open,
4695 NULL, /* create function not required */
4696 mem_truncate,
4697 mem_close_free,
4698 NULL, /* remove function not required */
4699 mem_size,
4700 NULL, /* flush function not required */
4701 mem_seek,
4702 mem_read,
4703 mem_write);
4704
4705 if (status)
4706 {
4707 ffpmsg("failed to register the http:// driver (init_cfitsio)");
4708 FFUNLOCK;
4709 return(status);
4710 }
4711
4712 /* 15--------------------http file driver-----------------------*/
4713
4714 status = fits_register_driver("httpfile://",
4715 NULL,
4716 file_shutdown,
4717 file_setoptions,
4718 file_getoptions,
4719 file_getversion,
4720 NULL, /* checkfile not needed */
4721 http_file_open,
4722 file_create,
4723 #ifdef HAVE_FTRUNCATE
4724 file_truncate,
4725 #else
4726 NULL, /* no file truncate function */
4727 #endif
4728 file_close,
4729 file_remove,
4730 file_size,
4731 file_flush,
4732 file_seek,
4733 file_read,
4734 file_write);
4735
4736 if (status)
4737 {
4738 ffpmsg("failed to register the httpfile:// driver (init_cfitsio)");
4739 FFUNLOCK;
4740 return(status);
4741 }
4742
4743 /* 16--------------------http memory driver-----------------------*/
4744 /* same as http:// driver, except memory file can be opened READWRITE */
4745 status = fits_register_driver("httpmem://",
4746 NULL,
4747 mem_shutdown,
4748 mem_setoptions,
4749 mem_getoptions,
4750 mem_getversion,
4751 http_checkfile,
4752 http_file_open, /* this will simply call http_open */
4753 NULL, /* create function not required */
4754 mem_truncate,
4755 mem_close_free,
4756 NULL, /* remove function not required */
4757 mem_size,
4758 NULL, /* flush function not required */
4759 mem_seek,
4760 mem_read,
4761 mem_write);
4762
4763 if (status)
4764 {
4765 ffpmsg("failed to register the httpmem:// driver (init_cfitsio)");
4766 FFUNLOCK;
4767 return(status);
4768 }
4769
4770 /* 17--------------------httpcompress file driver-----------------------*/
4771
4772 status = fits_register_driver("httpcompress://",
4773 NULL,
4774 mem_shutdown,
4775 mem_setoptions,
4776 mem_getoptions,
4777 mem_getversion,
4778 NULL, /* checkfile not needed */
4779 http_compress_open,
4780 NULL, /* create function not required */
4781 mem_truncate,
4782 mem_close_free,
4783 NULL, /* remove function not required */
4784 mem_size,
4785 NULL, /* flush function not required */
4786 mem_seek,
4787 mem_read,
4788 mem_write);
4789
4790 if (status)
4791 {
4792 ffpmsg("failed to register the httpcompress:// driver (init_cfitsio)");
4793 FFUNLOCK;
4794 return(status);
4795 }
4796
4797
4798 /* 18--------------------ftp driver-----------------------*/
4799 status = fits_register_driver("ftp://",
4800 NULL,
4801 mem_shutdown,
4802 mem_setoptions,
4803 mem_getoptions,
4804 mem_getversion,
4805 ftp_checkfile,
4806 ftp_open,
4807 NULL, /* create function not required */
4808 mem_truncate,
4809 mem_close_free,
4810 NULL, /* remove function not required */
4811 mem_size,
4812 NULL, /* flush function not required */
4813 mem_seek,
4814 mem_read,
4815 mem_write);
4816
4817 if (status)
4818 {
4819 ffpmsg("failed to register the ftp:// driver (init_cfitsio)");
4820 FFUNLOCK;
4821 return(status);
4822 }
4823
4824 /* 19--------------------ftp file driver-----------------------*/
4825 status = fits_register_driver("ftpfile://",
4826 NULL,
4827 file_shutdown,
4828 file_setoptions,
4829 file_getoptions,
4830 file_getversion,
4831 NULL, /* checkfile not needed */
4832 ftp_file_open,
4833 file_create,
4834 #ifdef HAVE_FTRUNCATE
4835 file_truncate,
4836 #else
4837 NULL, /* no file truncate function */
4838 #endif
4839 file_close,
4840 file_remove,
4841 file_size,
4842 file_flush,
4843 file_seek,
4844 file_read,
4845 file_write);
4846
4847 if (status)
4848 {
4849 ffpmsg("failed to register the ftpfile:// driver (init_cfitsio)");
4850 FFUNLOCK;
4851 return(status);
4852 }
4853
4854 /* 20--------------------ftp mem driver-----------------------*/
4855 /* same as ftp:// driver, except memory file can be opened READWRITE */
4856 status = fits_register_driver("ftpmem://",
4857 NULL,
4858 mem_shutdown,
4859 mem_setoptions,
4860 mem_getoptions,
4861 mem_getversion,
4862 ftp_checkfile,
4863 ftp_file_open, /* this will simply call ftp_open */
4864 NULL, /* create function not required */
4865 mem_truncate,
4866 mem_close_free,
4867 NULL, /* remove function not required */
4868 mem_size,
4869 NULL, /* flush function not required */
4870 mem_seek,
4871 mem_read,
4872 mem_write);
4873
4874 if (status)
4875 {
4876 ffpmsg("failed to register the ftpmem:// driver (init_cfitsio)");
4877 FFUNLOCK;
4878 return(status);
4879 }
4880
4881 /* 21--------------------ftp compressed file driver------------------*/
4882 status = fits_register_driver("ftpcompress://",
4883 NULL,
4884 mem_shutdown,
4885 mem_setoptions,
4886 mem_getoptions,
4887 mem_getversion,
4888 NULL, /* checkfile not needed */
4889 ftp_compress_open,
4890 0, /* create function not required */
4891 mem_truncate,
4892 mem_close_free,
4893 0, /* remove function not required */
4894 mem_size,
4895 0, /* flush function not required */
4896 mem_seek,
4897 mem_read,
4898 mem_write);
4899
4900 if (status)
4901 {
4902 ffpmsg("failed to register the ftpcompress:// driver (init_cfitsio)");
4903 FFUNLOCK;
4904 return(status);
4905 }
4906 /* === End of net drivers section === */
4907 #endif
4908
4909 /* ==================== SHARED MEMORY DRIVER SECTION ======================= */
4910
4911 #ifdef HAVE_SHMEM_SERVICES
4912
4913 /* 22--------------------shared memory driver-----------------------*/
4914 status = fits_register_driver("shmem://",
4915 smem_init,
4916 smem_shutdown,
4917 smem_setoptions,
4918 smem_getoptions,
4919 smem_getversion,
4920 NULL, /* checkfile not needed */
4921 smem_open,
4922 smem_create,
4923 NULL, /* truncate file not supported yet */
4924 smem_close,
4925 smem_remove,
4926 smem_size,
4927 smem_flush,
4928 smem_seek,
4929 smem_read,
4930 smem_write );
4931
4932 if (status)
4933 {
4934 ffpmsg("failed to register the shmem:// driver (init_cfitsio)");
4935 FFUNLOCK;
4936 return(status);
4937 }
4938
4939 #endif
4940 /* ==================== END OF SHARED MEMORY DRIVER SECTION ================ */
4941
4942
4943 #ifdef HAVE_GSIFTP
4944 /* 23--------------------gsiftp driver-----------------------*/
4945 status = fits_register_driver("gsiftp://",
4946 gsiftp_init,
4947 gsiftp_shutdown,
4948 gsiftp_setoptions,
4949 gsiftp_getoptions,
4950 gsiftp_getversion,
4951 gsiftp_checkfile,
4952 gsiftp_open,
4953 gsiftp_create,
4954 #ifdef HAVE_FTRUNCATE
4955 gsiftp_truncate,
4956 #else
4957 NULL,
4958 #endif
4959 gsiftp_close,
4960 NULL, /* remove function not yet implemented */
4961 gsiftp_size,
4962 gsiftp_flush,
4963 gsiftp_seek,
4964 gsiftp_read,
4965 gsiftp_write);
4966
4967 if (status)
4968 {
4969 ffpmsg("failed to register the gsiftp:// driver (init_cfitsio)");
4970 FFUNLOCK;
4971 return(status);
4972 }
4973
4974 #endif
4975
4976 /* 24---------------stdin and stdout stream driver-------------------*/
4977 status = fits_register_driver("stream://",
4978 NULL,
4979 NULL,
4980 NULL,
4981 NULL,
4982 NULL,
4983 NULL,
4984 stream_open,
4985 stream_create,
4986 NULL, /* no stream truncate function */
4987 stream_close,
4988 NULL, /* no stream remove */
4989 stream_size,
4990 stream_flush,
4991 stream_seek,
4992 stream_read,
4993 stream_write);
4994
4995 if (status)
4996 {
4997 ffpmsg("failed to register the stream:// driver (init_cfitsio)");
4998 FFUNLOCK;
4999 return(status);
5000 }
5001
5002 #ifdef HAVE_NET_SERVICES
5003
5004 /* 25--------------------https driver-----------------------*/
5005 status = fits_register_driver("https://",
5006 NULL,
5007 mem_shutdown,
5008 mem_setoptions,
5009 mem_getoptions,
5010 mem_getversion,
5011 https_checkfile,
5012 https_open,
5013 NULL, /* create function not required */
5014 mem_truncate,
5015 mem_close_free,
5016 NULL, /* remove function not required */
5017 mem_size,
5018 NULL, /* flush function not required */
5019 mem_seek,
5020 mem_read,
5021 mem_write);
5022
5023 if (status)
5024 {
5025 ffpmsg("failed to register the https:// driver (init_cfitsio)");
5026 FFUNLOCK;
5027 return(status);
5028 }
5029
5030 /* 26--------------------https file driver-----------------------*/
5031
5032 status = fits_register_driver("httpsfile://",
5033 NULL,
5034 file_shutdown,
5035 file_setoptions,
5036 file_getoptions,
5037 file_getversion,
5038 NULL, /* checkfile not needed */
5039 https_file_open,
5040 file_create,
5041 #ifdef HAVE_FTRUNCATE
5042 file_truncate,
5043 #else
5044 NULL, /* no file truncate function */
5045 #endif
5046 file_close,
5047 file_remove,
5048 file_size,
5049 file_flush,
5050 file_seek,
5051 file_read,
5052 file_write);
5053
5054 if (status)
5055 {
5056 ffpmsg("failed to register the httpsfile:// driver (init_cfitsio)");
5057 FFUNLOCK;
5058 return(status);
5059 }
5060
5061 /* 27--------------------https memory driver-----------------------*/
5062 /* same as https:// driver, except memory file can be opened READWRITE */
5063 status = fits_register_driver("httpsmem://",
5064 NULL,
5065 mem_shutdown,
5066 mem_setoptions,
5067 mem_getoptions,
5068 mem_getversion,
5069 https_checkfile,
5070 https_file_open, /* this will simply call https_open */
5071 NULL, /* create function not required */
5072 mem_truncate,
5073 mem_close_free,
5074 NULL, /* remove function not required */
5075 mem_size,
5076 NULL, /* flush function not required */
5077 mem_seek,
5078 mem_read,
5079 mem_write);
5080
5081 if (status)
5082 {
5083 ffpmsg("failed to register the httpsmem:// driver (init_cfitsio)");
5084 FFUNLOCK;
5085 return(status);
5086 }
5087 /* === End of https net drivers section === */
5088
5089 /* 28--------------------ftps driver-----------------------*/
5090 status = fits_register_driver("ftps://",
5091 NULL,
5092 mem_shutdown,
5093 mem_setoptions,
5094 mem_getoptions,
5095 mem_getversion,
5096 ftps_checkfile,
5097 ftps_open,
5098 NULL,
5099 mem_truncate,
5100 mem_close_free,
5101 NULL,
5102 mem_size,
5103 NULL,
5104 mem_seek,
5105 mem_read,
5106 mem_write);
5107
5108 if (status)
5109 {
5110 ffpmsg("failed to register the ftps:// driver (init_cfitsio)");
5111 FFUNLOCK;
5112 return(status);
5113 }
5114
5115 /* 29--------------------ftps file driver-----------------------*/
5116
5117 status = fits_register_driver("ftpsfile://",
5118 NULL,
5119 file_shutdown,
5120 file_setoptions,
5121 file_getoptions,
5122 file_getversion,
5123 NULL,
5124 ftps_file_open,
5125 file_create,
5126 #ifdef HAVE_FTRUNCATE
5127 file_truncate,
5128 #else
5129 NULL,
5130 #endif
5131 file_close,
5132 file_remove,
5133 file_size,
5134 file_flush,
5135 file_seek,
5136 file_read,
5137 file_write);
5138
5139 if (status)
5140 {
5141 ffpmsg("failed to register the ftpsfile:// driver (init_cfitsio)");
5142 FFUNLOCK;
5143 return(status);
5144 }
5145
5146 /* 30--------------------ftps memory driver-----------------------*/
5147 /* same as ftps:// driver, except memory file can be opened READWRITE */
5148 status = fits_register_driver("ftpsmem://",
5149 NULL,
5150 mem_shutdown,
5151 mem_setoptions,
5152 mem_getoptions,
5153 mem_getversion,
5154 ftps_checkfile,
5155 ftps_file_open,
5156 NULL,
5157 mem_truncate,
5158 mem_close_free,
5159 NULL,
5160 mem_size,
5161 NULL,
5162 mem_seek,
5163 mem_read,
5164 mem_write);
5165
5166 if (status)
5167 {
5168 ffpmsg("failed to register the ftpsmem:// driver (init_cfitsio)");
5169 FFUNLOCK;
5170 return(status);
5171 }
5172
5173 /* 31--------------------ftps compressed file driver------------------*/
5174 status = fits_register_driver("ftpscompress://",
5175 NULL,
5176 mem_shutdown,
5177 mem_setoptions,
5178 mem_getoptions,
5179 mem_getversion,
5180 NULL, /* checkfile not needed */
5181 ftps_compress_open,
5182 0, /* create function not required */
5183 mem_truncate,
5184 mem_close_free,
5185 0, /* remove function not required */
5186 mem_size,
5187 0, /* flush function not required */
5188 mem_seek,
5189 mem_read,
5190 mem_write);
5191
5192 if (status)
5193 {
5194 ffpmsg("failed to register the ftpscompress:// driver (init_cfitsio)");
5195 FFUNLOCK;
5196 return(status);
5197 }
5198 #endif
5199
5200
5201 /* reset flag. Any other threads will now not need to call this routine */
5202 need_to_initialize = 0;
5203
5204 FFUNLOCK;
5205 return(status);
5206 }
5207 /*--------------------------------------------------------------------------*/
fits_register_driver(char * prefix,int (* init)(void),int (* shutdown)(void),int (* setoptions)(int option),int (* getoptions)(int * options),int (* getversion)(int * version),int (* checkfile)(char * urltype,char * infile,char * outfile),int (* open)(char * filename,int rwmode,int * driverhandle),int (* create)(char * filename,int * driverhandle),int (* truncate)(int driverhandle,LONGLONG filesize),int (* close)(int driverhandle),int (* fremove)(char * filename),int (* size)(int driverhandle,LONGLONG * sizex),int (* flush)(int driverhandle),int (* seek)(int driverhandle,LONGLONG offset),int (* read)(int driverhandle,void * buffer,long nbytes),int (* write)(int driverhandle,void * buffer,long nbytes))5208 int fits_register_driver(char *prefix,
5209 int (*init)(void),
5210 int (*shutdown)(void),
5211 int (*setoptions)(int option),
5212 int (*getoptions)(int *options),
5213 int (*getversion)(int *version),
5214 int (*checkfile) (char *urltype, char *infile, char *outfile),
5215 int (*open)(char *filename, int rwmode, int *driverhandle),
5216 int (*create)(char *filename, int *driverhandle),
5217 int (*truncate)(int driverhandle, LONGLONG filesize),
5218 int (*close)(int driverhandle),
5219 int (*fremove)(char *filename),
5220 int (*size)(int driverhandle, LONGLONG *sizex),
5221 int (*flush)(int driverhandle),
5222 int (*seek)(int driverhandle, LONGLONG offset),
5223 int (*read) (int driverhandle, void *buffer, long nbytes),
5224 int (*write)(int driverhandle, void *buffer, long nbytes) )
5225 /*
5226 register all the functions needed to support an I/O driver
5227 */
5228 {
5229 int status;
5230
5231 if (no_of_drivers < 0 ) {
5232 /* This is bad. looks like memory has been corrupted. */
5233 ffpmsg("Vital CFITSIO parameters held in memory have been corrupted!!");
5234 ffpmsg("Fatal condition detected in fits_register_driver.");
5235 return(TOO_MANY_DRIVERS);
5236 }
5237
5238 if (no_of_drivers + 1 > MAX_DRIVERS)
5239 return(TOO_MANY_DRIVERS);
5240
5241 if (prefix == NULL)
5242 return(BAD_URL_PREFIX);
5243
5244
5245 if (init != NULL)
5246 {
5247 status = (*init)(); /* initialize the driver */
5248 if (status)
5249 return(status);
5250 }
5251
5252 /* fill in data in table */
5253 strncpy(driverTable[no_of_drivers].prefix, prefix, MAX_PREFIX_LEN);
5254 driverTable[no_of_drivers].prefix[MAX_PREFIX_LEN - 1] = 0;
5255 driverTable[no_of_drivers].init = init;
5256 driverTable[no_of_drivers].shutdown = shutdown;
5257 driverTable[no_of_drivers].setoptions = setoptions;
5258 driverTable[no_of_drivers].getoptions = getoptions;
5259 driverTable[no_of_drivers].getversion = getversion;
5260 driverTable[no_of_drivers].checkfile = checkfile;
5261 driverTable[no_of_drivers].open = open;
5262 driverTable[no_of_drivers].create = create;
5263 driverTable[no_of_drivers].truncate = truncate;
5264 driverTable[no_of_drivers].close = close;
5265 driverTable[no_of_drivers].remove = fremove;
5266 driverTable[no_of_drivers].size = size;
5267 driverTable[no_of_drivers].flush = flush;
5268 driverTable[no_of_drivers].seek = seek;
5269 driverTable[no_of_drivers].read = read;
5270 driverTable[no_of_drivers].write = write;
5271
5272 no_of_drivers++; /* increment the number of drivers */
5273 return(0);
5274 }
5275 /*--------------------------------------------------------------------------*/
5276 /* fits_parse_input_url */
ffiurl(char * url,char * urltype,char * infilex,char * outfile,char * extspec,char * rowfilterx,char * binspec,char * colspec,int * status)5277 int ffiurl(char *url, /* input filename */
5278 char *urltype, /* e.g., 'file://', 'http://', 'mem://' */
5279 char *infilex, /* root filename (may be complete path) */
5280 char *outfile, /* optional output file name */
5281 char *extspec, /* extension spec: +n or [extname, extver] */
5282 char *rowfilterx, /* boolean row filter expression */
5283 char *binspec, /* histogram binning specifier */
5284 char *colspec, /* column or keyword modifier expression */
5285 int *status)
5286 /*
5287 parse the input URL into its basic components.
5288 This routine does not support the pixfilter or compspec components.
5289 */
5290 {
5291 return ffifile2(url, urltype, infilex, outfile,
5292 extspec, rowfilterx, binspec, colspec, 0, 0, status);
5293 }
5294 /*--------------------------------------------------------------------------*/
5295 /* fits_parse_input_file */
ffifile(char * url,char * urltype,char * infilex,char * outfile,char * extspec,char * rowfilterx,char * binspec,char * colspec,char * pixfilter,int * status)5296 int ffifile(char *url, /* input filename */
5297 char *urltype, /* e.g., 'file://', 'http://', 'mem://' */
5298 char *infilex, /* root filename (may be complete path) */
5299 char *outfile, /* optional output file name */
5300 char *extspec, /* extension spec: +n or [extname, extver] */
5301 char *rowfilterx, /* boolean row filter expression */
5302 char *binspec, /* histogram binning specifier */
5303 char *colspec, /* column or keyword modifier expression */
5304 char *pixfilter, /* pixel filter expression */
5305 int *status)
5306 /*
5307 fits_parse_input_filename
5308 parse the input URL into its basic components.
5309 This routine does not support the compspec component.
5310 */
5311 {
5312 return ffifile2(url, urltype, infilex, outfile,
5313 extspec, rowfilterx, binspec, colspec, pixfilter, 0, status);
5314
5315 }
5316 /*--------------------------------------------------------------------------*/
ffifile2(char * url,char * urltype,char * infilex,char * outfile,char * extspec,char * rowfilterx,char * binspec,char * colspec,char * pixfilter,char * compspec,int * status)5317 int ffifile2(char *url, /* input filename */
5318 char *urltype, /* e.g., 'file://', 'http://', 'mem://' */
5319 char *infilex, /* root filename (may be complete path) */
5320 char *outfile, /* optional output file name */
5321 char *extspec, /* extension spec: +n or [extname, extver] */
5322 char *rowfilterx, /* boolean row filter expression */
5323 char *binspec, /* histogram binning specifier */
5324 char *colspec, /* column or keyword modifier expression */
5325 char *pixfilter, /* pixel filter expression */
5326 char *compspec, /* image compression specification */
5327 int *status)
5328 /*
5329 fits_parse_input_filename
5330 parse the input URL into its basic components.
5331 This routine is big and ugly and should be redesigned someday!
5332 */
5333 {
5334 int ii, jj, slen, infilelen, plus_ext = 0, collen;
5335 char *ptr1, *ptr2, *ptr3, *ptr4, *tmptr;
5336 int hasAt, hasDot, hasOper, followingOper, spaceTerm, rowFilter;
5337 int colStart, binStart, pixStart, compStart;
5338
5339
5340 /* must have temporary variable for these, in case inputs are NULL */
5341 char *infile;
5342 char *rowfilter;
5343 char *tmpstr;
5344
5345 if (*status > 0)
5346 return(*status);
5347
5348 /* Initialize null strings */
5349 if (infilex) *infilex = '\0';
5350 if (urltype) *urltype = '\0';
5351 if (outfile) *outfile = '\0';
5352 if (extspec) *extspec = '\0';
5353 if (binspec) *binspec = '\0';
5354 if (colspec) *colspec = '\0';
5355 if (rowfilterx) *rowfilterx = '\0';
5356 if (pixfilter) *pixfilter = '\0';
5357 if (compspec) *compspec = '\0';
5358 slen = strlen(url);
5359
5360 if (slen == 0) /* blank filename ?? */
5361 return(*status);
5362
5363 /* allocate memory for 3 strings, each as long as the input url */
5364 infile = (char *) calloc(3, slen + 1);
5365 if (!infile)
5366 return(*status = MEMORY_ALLOCATION);
5367
5368 rowfilter = &infile[slen + 1];
5369 tmpstr = &rowfilter[slen + 1];
5370
5371 ptr1 = url;
5372
5373 /* -------------------------------------------------------- */
5374 /* get urltype (e.g., file://, ftp://, http://, etc.) */
5375 /* --------------------------------------------------------- */
5376
5377 if (*ptr1 == '-' && ( *(ptr1 +1) == 0 || *(ptr1 +1) == ' ' ||
5378 *(ptr1 +1) == '[' || *(ptr1 +1) == '(' ) )
5379 {
5380 /* "-" means read file from stdin. Also support "- ", */
5381 /* "-[extname]" and '-(outfile.fits)" but exclude disk file */
5382 /* names that begin with a minus sign, e.g., "-55d33m.fits" */
5383
5384 if (urltype)
5385 strcat(urltype, "stdin://");
5386 ptr1++;
5387 }
5388 else if (!fits_strncasecmp(ptr1, "stdin", 5))
5389 {
5390 if (urltype)
5391 strcat(urltype, "stdin://");
5392 ptr1 = ptr1 + 5;
5393 }
5394 else
5395 {
5396 ptr2 = strstr(ptr1, "://");
5397 ptr3 = strstr(ptr1, "(" );
5398
5399 if (ptr3 && (ptr3 < ptr2) )
5400 {
5401 /* the urltype follows a '(' character, so it must apply */
5402 /* to the output file, and is not the urltype of the input file */
5403 ptr2 = 0; /* so reset pointer to zero */
5404 }
5405
5406 if (ptr2) /* copy the explicit urltype string */
5407 {
5408 if (ptr2-ptr1+3 >= MAX_PREFIX_LEN)
5409 {
5410 ffpmsg("Name of urltype is too long.");
5411 return(*status = URL_PARSE_ERROR);
5412 }
5413 if (urltype)
5414 strncat(urltype, ptr1, ptr2 - ptr1 + 3);
5415 ptr1 = ptr2 + 3;
5416 }
5417 else if (!strncmp(ptr1, "ftp:", 4) )
5418 { /* the 2 //'s are optional */
5419 if (urltype)
5420 strcat(urltype, "ftp://");
5421 ptr1 += 4;
5422 }
5423 else if (!strncmp(ptr1, "gsiftp:", 7) )
5424 { /* the 2 //'s are optional */
5425 if (urltype)
5426 strcat(urltype, "gsiftp://");
5427 ptr1 += 7;
5428 }
5429 else if (!strncmp(ptr1, "http:", 5) )
5430 { /* the 2 //'s are optional */
5431 if (urltype)
5432 strcat(urltype, "http://");
5433 ptr1 += 5;
5434 }
5435 else if (!strncmp(ptr1, "mem:", 4) )
5436 { /* the 2 //'s are optional */
5437 if (urltype)
5438 strcat(urltype, "mem://");
5439 ptr1 += 4;
5440 }
5441 else if (!strncmp(ptr1, "shmem:", 6) )
5442 { /* the 2 //'s are optional */
5443 if (urltype)
5444 strcat(urltype, "shmem://");
5445 ptr1 += 6;
5446 }
5447 else if (!strncmp(ptr1, "file:", 5) )
5448 { /* the 2 //'s are optional */
5449 if (urltype)
5450 strcat(urltype, "file://");
5451 ptr1 += 5;
5452 }
5453 else /* assume file driver */
5454 {
5455 if (urltype)
5456 strcat(urltype, "file://");
5457 }
5458 }
5459
5460 /* ----------------------------------------------------------
5461 If this is a http:// type file, then the cgi file name could
5462 include the '[' character, which should not be interpreted
5463 as part of CFITSIO's Extended File Name Syntax. Test for this
5464 case by seeing if the last character is a ']' or ')'. If it
5465 is not, then just treat the whole input string as the file name
5466 and do not attempt to interprete the name using the extended
5467 filename syntax.
5468 ----------------------------------------------------------- */
5469
5470 if (urltype && !strncmp(urltype, "http://", 7) )
5471 {
5472 /* test for opening parenthesis or bracket in the file name */
5473 if( strchr(ptr1, '(' ) || strchr(ptr1, '[' ) )
5474 {
5475 slen = strlen(ptr1);
5476 ptr3 = ptr1 + slen - 1;
5477 while (*ptr3 == ' ') /* ignore trailing blanks */
5478 ptr3--;
5479
5480 if (*ptr3 != ']' && *ptr3 != ')' )
5481 {
5482 /* name doesn't end with a ']' or ')' so don't try */
5483 /* to parse this unusual string (may be cgi string) */
5484 if (infilex) {
5485
5486 if (strlen(ptr1) > FLEN_FILENAME - 1) {
5487 ffpmsg("Name of file is too long.");
5488 return(*status = URL_PARSE_ERROR);
5489 }
5490
5491 strcpy(infilex, ptr1);
5492 }
5493
5494 free(infile);
5495 return(*status);
5496 }
5497 }
5498 }
5499
5500 /* ----------------------------------------------------------
5501 Look for VMS style filenames like:
5502 disk:[directory.subdirectory]filename.ext, or
5503 [directory.subdirectory]filename.ext
5504
5505 Check if the first character is a '[' and urltype != stdin
5506 or if there is a ':[' string in the remaining url string. If
5507 so, then need to move past this bracket character before
5508 search for the opening bracket of a filter specification.
5509 ----------------------------------------------------------- */
5510
5511 tmptr = ptr1;
5512 if (*ptr1 == '[')
5513 {
5514 if (*url != '-')
5515 tmptr = ptr1 + 1; /* this bracket encloses a VMS directory name */
5516 }
5517 else
5518 {
5519 tmptr = strstr(ptr1, ":[");
5520 if (tmptr) /* these 2 chars are part of the VMS disk and directory */
5521 tmptr += 2;
5522 else
5523 tmptr = ptr1;
5524 }
5525
5526 /* ------------------------ */
5527 /* get the input file name */
5528 /* ------------------------ */
5529
5530 ptr2 = strchr(tmptr, '('); /* search for opening parenthesis ( */
5531 ptr3 = strchr(tmptr, '['); /* search for opening bracket [ */
5532
5533 if (ptr2 == ptr3) /* simple case: no [ or ( in the file name */
5534 {
5535 strcat(infile, ptr1);
5536 }
5537 else if (!ptr3 || /* no bracket, so () enclose output file name */
5538 (ptr2 && (ptr2 < ptr3)) ) /* () enclose output name before bracket */
5539 {
5540 strncat(infile, ptr1, ptr2 - ptr1);
5541 ptr2++;
5542
5543 ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
5544 if (!ptr1)
5545 {
5546 free(infile);
5547 return(*status = URL_PARSE_ERROR); /* error, no closing ) */
5548 }
5549
5550 if (outfile) {
5551
5552 if (ptr1 - ptr2 > FLEN_FILENAME - 1)
5553 {
5554 free(infile);
5555 return(*status = URL_PARSE_ERROR);
5556 }
5557
5558 strncat(outfile, ptr2, ptr1 - ptr2);
5559 }
5560
5561 /* the opening [ could have been part of output name, */
5562 /* e.g., file(out[compress])[3][#row > 5] */
5563 /* so search again for opening bracket following the closing ) */
5564 ptr3 = strchr(ptr1, '[');
5565
5566 }
5567 else /* bracket comes first, so there is no output name */
5568 {
5569 strncat(infile, ptr1, ptr3 - ptr1);
5570 }
5571
5572 /* strip off any trailing blanks in the names */
5573
5574 slen = strlen(infile);
5575 while ( (--slen) > 0 && infile[slen] == ' ')
5576 infile[slen] = '\0';
5577
5578 if (outfile)
5579 {
5580 slen = strlen(outfile);
5581 while ( (--slen) > 0 && outfile[slen] == ' ')
5582 outfile[slen] = '\0';
5583 }
5584
5585 /* --------------------------------------------- */
5586 /* check if this is an IRAF file (.imh extension */
5587 /* --------------------------------------------- */
5588
5589 ptr4 = strstr(infile, ".imh");
5590
5591 /* did the infile name end with ".imh" ? */
5592 if (ptr4 && (*(ptr4 + 4) == '\0'))
5593 {
5594 if (urltype)
5595 strcpy(urltype, "irafmem://");
5596 }
5597
5598 /* --------------------------------------------- */
5599 /* check if the 'filename+n' convention has been */
5600 /* used to specifiy which HDU number to open */
5601 /* --------------------------------------------- */
5602
5603 jj = strlen(infile);
5604
5605 for (ii = jj - 1; ii >= 0; ii--)
5606 {
5607 if (infile[ii] == '+') /* search backwards for '+' sign */
5608 break;
5609 }
5610
5611 if (ii > 0 && (jj - ii) < 7) /* limit extension numbers to 5 digits */
5612 {
5613 infilelen = ii;
5614 ii++;
5615 ptr1 = infile+ii; /* pointer to start of sequence */
5616
5617 for (; ii < jj; ii++)
5618 {
5619 if (!isdigit((int) infile[ii] ) ) /* are all the chars digits? */
5620 break;
5621 }
5622
5623 if (ii == jj)
5624 {
5625 /* yes, the '+n' convention was used. Copy */
5626 /* the digits to the output extspec string. */
5627 plus_ext = 1;
5628
5629 if (extspec) {
5630 if (jj - infilelen > FLEN_FILENAME - 1)
5631 {
5632 free(infile);
5633 return(*status = URL_PARSE_ERROR);
5634 }
5635
5636 strncpy(extspec, ptr1, jj - infilelen);
5637 }
5638
5639 infile[infilelen] = '\0'; /* delete the extension number */
5640 }
5641 }
5642
5643 /* -------------------------------------------------------------------- */
5644 /* if '*' was given for the output name expand it to the root file name */
5645 /* -------------------------------------------------------------------- */
5646
5647 if (outfile && outfile[0] == '*')
5648 {
5649 /* scan input name backwards to the first '/' character */
5650 for (ii = jj - 1; ii >= 0; ii--)
5651 {
5652 if (infile[ii] == '/' || ii == 0)
5653 {
5654 if (strlen(&infile[ii + 1]) > FLEN_FILENAME - 1)
5655 {
5656 free(infile);
5657 return(*status = URL_PARSE_ERROR);
5658 }
5659
5660 strcpy(outfile, &infile[ii + 1]);
5661 break;
5662 }
5663 }
5664 }
5665
5666 /* ------------------------------------------ */
5667 /* copy strings from local copy to the output */
5668 /* ------------------------------------------ */
5669 if (infilex) {
5670 if (strlen(infile) > FLEN_FILENAME - 1)
5671 {
5672 free(infile);
5673 return(*status = URL_PARSE_ERROR);
5674 }
5675
5676 strcpy(infilex, infile);
5677 }
5678 /* ---------------------------------------------------------- */
5679 /* if no '[' character in the input string, then we are done. */
5680 /* ---------------------------------------------------------- */
5681 if (!ptr3)
5682 {
5683 free(infile);
5684 return(*status);
5685 }
5686
5687 /* ------------------------------------------- */
5688 /* see if [ extension specification ] is given */
5689 /* ------------------------------------------- */
5690
5691 if (!plus_ext) /* extension no. not already specified? Then */
5692 /* first brackets must enclose extension name or # */
5693 /* or it encloses a image subsection specification */
5694 /* or a raw binary image specifier */
5695 /* or a image compression specifier */
5696
5697 /* Or, the extension specification may have been */
5698 /* omitted and we have to guess what the user intended */
5699 {
5700 ptr1 = ptr3 + 1; /* pointer to first char after the [ */
5701
5702 ptr2 = strchr(ptr1, ']' ); /* search for closing ] */
5703 if (!ptr2)
5704 {
5705 ffpmsg("input file URL is missing closing bracket ']'");
5706 free(infile);
5707 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
5708 }
5709
5710 /* ---------------------------------------------- */
5711 /* First, test if this is a rawfile specifier */
5712 /* which looks something like: '[ib512,512:2880]' */
5713 /* Test if first character is b,i,j,d,r,f, or u, */
5714 /* and optional second character is b or l, */
5715 /* followed by one or more digits, */
5716 /* finally followed by a ',', ':', or ']' */
5717 /* ---------------------------------------------- */
5718
5719 if (*ptr1 == 'b' || *ptr1 == 'B' || *ptr1 == 'i' || *ptr1 == 'I' ||
5720 *ptr1 == 'j' || *ptr1 == 'J' || *ptr1 == 'd' || *ptr1 == 'D' ||
5721 *ptr1 == 'r' || *ptr1 == 'R' || *ptr1 == 'f' || *ptr1 == 'F' ||
5722 *ptr1 == 'u' || *ptr1 == 'U')
5723 {
5724 /* next optional character may be a b or l (for Big or Little) */
5725 ptr1++;
5726 if (*ptr1 == 'b' || *ptr1 == 'B' || *ptr1 == 'l' || *ptr1 == 'L')
5727 ptr1++;
5728
5729 if (isdigit((int) *ptr1)) /* must have at least 1 digit */
5730 {
5731 while (isdigit((int) *ptr1))
5732 ptr1++; /* skip over digits */
5733
5734 if (*ptr1 == ',' || *ptr1 == ':' || *ptr1 == ']' )
5735 {
5736 /* OK, this looks like a rawfile specifier */
5737
5738 if (urltype)
5739 {
5740 if (strstr(urltype, "stdin") )
5741 strcpy(urltype, "rawstdin://");
5742 else
5743 strcpy(urltype, "rawfile://");
5744 }
5745
5746 /* append the raw array specifier to infilex */
5747 if (infilex)
5748 {
5749
5750 if (strlen(infilex) + strlen(ptr3) > FLEN_FILENAME - 1)
5751 {
5752 free(infile);
5753 return(*status = URL_PARSE_ERROR);
5754 }
5755
5756 strcat(infilex, ptr3);
5757 ptr1 = strchr(infilex, ']'); /* find the closing ] char */
5758 if (ptr1)
5759 *(ptr1 + 1) = '\0'; /* terminate string after the ] */
5760 }
5761
5762 if (extspec)
5763 strcpy(extspec, "0"); /* the 0 ext number is implicit */
5764
5765 tmptr = strchr(ptr2 + 1, '[' ); /* search for another [ char */
5766
5767 /* copy any remaining characters into rowfilterx */
5768 if (tmptr && rowfilterx)
5769 {
5770
5771
5772 if (strlen(rowfilterx) + strlen(tmptr + 1) > FLEN_FILENAME -1)
5773 {
5774 free(infile);
5775 return(*status = URL_PARSE_ERROR);
5776 }
5777
5778 strcat(rowfilterx, tmptr + 1);
5779
5780 tmptr = strchr(rowfilterx, ']' ); /* search for closing ] */
5781 if (tmptr)
5782 *tmptr = '\0'; /* overwrite the ] with null terminator */
5783 }
5784
5785 free(infile); /* finished parsing, so return */
5786 return(*status);
5787 }
5788 }
5789 } /* end of rawfile specifier test */
5790
5791 /* -------------------------------------------------------- */
5792 /* Not a rawfile, so next, test if this is an image section */
5793 /* i.e., an integer followed by a ':' or a '*' or '-*' */
5794 /* -------------------------------------------------------- */
5795
5796 ptr1 = ptr3 + 1; /* reset pointer to first char after the [ */
5797 tmptr = ptr1;
5798
5799 while (*tmptr == ' ')
5800 tmptr++; /* skip leading blanks */
5801
5802 while (isdigit((int) *tmptr))
5803 tmptr++; /* skip over leading digits */
5804
5805 if (*tmptr == ':' || *tmptr == '*' || *tmptr == '-')
5806 {
5807 /* this is an image section specifier */
5808 strcat(rowfilter, ptr3);
5809 /*
5810 don't want to assume 0 extension any more; may imply an image extension.
5811 if (extspec)
5812 strcpy(extspec, "0");
5813 */
5814 }
5815 else
5816 {
5817 /* -----------------------------------------------------------------
5818 Not an image section or rawfile spec so may be an extension spec.
5819
5820 Examples of valid extension specifiers:
5821 [3] - 3rd extension; 0 = primary array
5822 [events] - events extension
5823 [events, 2] - events extension, with EXTVER = 2
5824 [events,2] - spaces are optional
5825 [events, 3, b] - same as above, plus XTENSION = 'BINTABLE'
5826 [PICS; colName(12)] - an image in row 12 of the colName column
5827 in the PICS table extension
5828 [PICS; colName(exposure > 1000)] - as above, but find image in
5829 first row with with exposure column value > 1000.
5830 [Rate Table] - extension name can contain spaces!
5831 [Rate Table;colName(exposure>1000)]
5832
5833 Examples of other types of specifiers (Not extension specifiers)
5834
5835 [bin] !!! this is ambiguous, and can't be distinguished from
5836 a valid extension specifier
5837 [bini X=1:512:16] (also binb, binj, binr, and bind are allowed)
5838 [binr (X,Y) = 5]
5839 [bin @binfilter.txt]
5840
5841 [col Time;rate]
5842 [col PI=PHA * 1.1]
5843 [col -Time; status]
5844
5845 [X > 5]
5846 [X>5]
5847 [@filter.txt]
5848 [StatusCol] !!! this is ambiguous, and can't be distinguished
5849 from a valid extension specifier
5850 [StatusCol==0]
5851 [StatusCol || x>6]
5852 [gtifilter()]
5853 [regfilter("region.reg")]
5854
5855 [compress Rice]
5856
5857 There will always be some ambiguity between an extension name and
5858 a boolean row filtering expression, (as in a couple of the above
5859 examples). If there is any doubt, the expression should be treated
5860 as an extension specification; The user can always add an explicit
5861 expression specifier to override this interpretation.
5862
5863 The following decision logic will be used:
5864
5865 1) locate the first token, terminated with a space, comma,
5866 semi-colon, or closing bracket.
5867
5868 2) the token is not part of an extension specifier if any of
5869 the following is true:
5870
5871 - if the token begins with '@' and contains a '.'
5872 - if the token contains an operator: = > < || &&
5873 - if the token begins with "gtifilter(" or "regfilter("
5874 - if the token is terminated by a space and is followed by
5875 additional characters (not a ']') AND any of the following:
5876 - the token is 'col'
5877 - the token is 3 or 4 chars long and begins with 'bin'
5878 - the second token begins with an operator:
5879 ! = < > | & + - * / %
5880
5881
5882 3) otherwise, the string is assumed to be an extension specifier
5883
5884 ----------------------------------------------------------------- */
5885
5886 tmptr = ptr1;
5887 while(*tmptr == ' ')
5888 tmptr++;
5889
5890 hasAt = 0;
5891 hasDot = 0;
5892 hasOper = 0;
5893 followingOper = 0;
5894 spaceTerm = 0;
5895 rowFilter = 0;
5896 colStart = 0;
5897 binStart = 0;
5898 pixStart = 0;
5899 compStart = 0;
5900
5901 if (*tmptr == '@') /* test for leading @ symbol */
5902 hasAt = 1;
5903
5904 if ( !fits_strncasecmp(tmptr, "col ", 4) )
5905 colStart = 1;
5906
5907 if ( !fits_strncasecmp(tmptr, "bin", 3) )
5908 binStart = 1;
5909
5910 if ( !fits_strncasecmp(tmptr, "pix", 3) )
5911 pixStart = 1;
5912
5913 if ( !fits_strncasecmp(tmptr, "compress ", 9) ||
5914 !fits_strncasecmp(tmptr, "compress]", 9) )
5915 compStart = 1;
5916
5917 if ( !fits_strncasecmp(tmptr, "gtifilter(", 10) ||
5918 !fits_strncasecmp(tmptr, "regfilter(", 10) )
5919 {
5920 rowFilter = 1;
5921 }
5922 else
5923 {
5924 /* parse the first token of the expression */
5925 for (ii = 0; ii < ptr2 - ptr1 + 1; ii++, tmptr++)
5926 {
5927 if (*tmptr == '.')
5928 hasDot = 1;
5929 else if (*tmptr == '=' || *tmptr == '>' || *tmptr == '<' ||
5930 (*tmptr == '|' && *(tmptr+1) == '|') ||
5931 (*tmptr == '&' && *(tmptr+1) == '&') )
5932 hasOper = 1;
5933
5934 else if (*tmptr == ',' || *tmptr == ';' || *tmptr == ']')
5935 {
5936 break;
5937 }
5938 else if (*tmptr == ' ') /* a space char? */
5939 {
5940 while(*tmptr == ' ') /* skip spaces */
5941 tmptr++;
5942
5943 if (*tmptr == ']') /* is this the end? */
5944 break;
5945
5946 spaceTerm = 1; /* 1st token is terminated by space */
5947
5948 /* test if this is a column or binning specifier */
5949 if (colStart || (ii <= 4 && (binStart || pixStart)) )
5950 rowFilter = 1;
5951 else
5952 {
5953
5954 /* check if next character is an operator */
5955 if (*tmptr == '=' || *tmptr == '>' || *tmptr == '<' ||
5956 *tmptr == '|' || *tmptr == '&' || *tmptr == '!' ||
5957 *tmptr == '+' || *tmptr == '-' || *tmptr == '*' ||
5958 *tmptr == '/' || *tmptr == '%')
5959 followingOper = 1;
5960 }
5961 break;
5962 }
5963 }
5964 }
5965
5966 /* test if this is NOT an extension specifier */
5967 if ( rowFilter || (pixStart && spaceTerm) ||
5968 (hasAt && hasDot) ||
5969 hasOper ||
5970 compStart ||
5971 (spaceTerm && followingOper) )
5972 {
5973 /* this is (probably) not an extension specifier */
5974 /* so copy all chars to filter spec string */
5975 strcat(rowfilter, ptr3);
5976 }
5977 else
5978 {
5979 /* this appears to be a legit extension specifier */
5980 /* copy the extension specification */
5981 if (extspec) {
5982 if (ptr2 - ptr1 > FLEN_FILENAME - 1) {
5983 free(infile);
5984 return(*status = URL_PARSE_ERROR);
5985 }
5986 strncat(extspec, ptr1, ptr2 - ptr1);
5987 }
5988
5989 /* copy any remaining chars to filter spec string */
5990 strcat(rowfilter, ptr2 + 1);
5991 }
5992 }
5993 } /* end of if (!plus_ext) */
5994 else
5995 {
5996 /* ------------------------------------------------------------------ */
5997 /* already have extension, so this must be a filter spec of some sort */
5998 /* ------------------------------------------------------------------ */
5999
6000 strcat(rowfilter, ptr3);
6001 }
6002
6003 /* strip off any trailing blanks from filter */
6004 slen = strlen(rowfilter);
6005 while ( (--slen) >= 0 && rowfilter[slen] == ' ')
6006 rowfilter[slen] = '\0';
6007
6008 if (!rowfilter[0])
6009 {
6010 free(infile);
6011 return(*status); /* nothing left to parse */
6012 }
6013
6014 /* ------------------------------------------------ */
6015 /* does the filter contain a binning specification? */
6016 /* ------------------------------------------------ */
6017
6018 ptr1 = strstr(rowfilter, "[bin"); /* search for "[bin" */
6019 if (!ptr1)
6020 ptr1 = strstr(rowfilter, "[BIN"); /* search for "[BIN" */
6021 if (!ptr1)
6022 ptr1 = strstr(rowfilter, "[Bin"); /* search for "[Bin" */
6023
6024 if (ptr1)
6025 {
6026 ptr2 = ptr1 + 4; /* end of the '[bin' string */
6027 if (*ptr2 == 'b' || *ptr2 == 'i' || *ptr2 == 'j' ||
6028 *ptr2 == 'r' || *ptr2 == 'd')
6029 ptr2++; /* skip the datatype code letter */
6030
6031
6032 if ( *ptr2 != ' ' && *ptr2 != ']')
6033 ptr1 = NULL; /* bin string must be followed by space or ] */
6034 }
6035
6036 if (ptr1)
6037 {
6038 /* found the binning string */
6039 if (binspec)
6040 {
6041 if (strlen(ptr1 +1) > FLEN_FILENAME - 1)
6042 {
6043 free(infile);
6044 return(*status = URL_PARSE_ERROR);
6045 }
6046
6047 strcpy(binspec, ptr1 + 1);
6048 ptr2 = strchr(binspec, ']');
6049
6050 if (ptr2) /* terminate the binning filter */
6051 {
6052 *ptr2 = '\0';
6053
6054 if ( *(--ptr2) == ' ') /* delete trailing spaces */
6055 *ptr2 = '\0';
6056 }
6057 else
6058 {
6059 ffpmsg("input file URL is missing closing bracket ']'");
6060 ffpmsg(rowfilter);
6061 free(infile);
6062 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6063 }
6064 }
6065
6066 /* delete the binning spec from the row filter string */
6067 ptr2 = strchr(ptr1, ']');
6068 strcpy(tmpstr, ptr2+1); /* copy any chars after the binspec */
6069 strcpy(ptr1, tmpstr); /* overwrite binspec */
6070 }
6071
6072 /* --------------------------------------------------------- */
6073 /* does the filter contain a column selection specification? */
6074 /* --------------------------------------------------------- */
6075
6076 ptr1 = strstr(rowfilter, "[col ");
6077 if (!ptr1)
6078 {
6079 ptr1 = strstr(rowfilter, "[COL ");
6080
6081 if (!ptr1)
6082 ptr1 = strstr(rowfilter, "[Col ");
6083 }
6084
6085 if (ptr1)
6086 { /* find the end of the column specifier */
6087 ptr2 = ptr1 + 5;
6088 while (*ptr2 != ']')
6089 {
6090 if (*ptr2 == '\0')
6091 {
6092 ffpmsg("input file URL is missing closing bracket ']'");
6093 free(infile);
6094 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6095 }
6096
6097 if (*ptr2 == '\'') /* start of a literal string */
6098 {
6099 ptr2 = strchr(ptr2 + 1, '\''); /* find closing quote */
6100 if (!ptr2)
6101 {
6102 ffpmsg
6103 ("literal string in input file URL is missing closing single quote");
6104 free(infile);
6105 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6106 }
6107 }
6108
6109 if (*ptr2 == '[') /* set of nested square brackets */
6110 {
6111 ptr2 = strchr(ptr2 + 1, ']'); /* find closing bracket */
6112 if (!ptr2)
6113 {
6114 ffpmsg
6115 ("nested brackets in input file URL is missing closing bracket");
6116 free(infile);
6117 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6118 }
6119 }
6120
6121 ptr2++; /* continue search for the closing bracket character */
6122 }
6123
6124 collen = ptr2 - ptr1 - 1;
6125
6126 if (colspec) /* copy the column specifier to output string */
6127 {
6128 if (collen > FLEN_FILENAME - 1) {
6129 free(infile);
6130 return(*status = URL_PARSE_ERROR);
6131 }
6132
6133 strncpy(colspec, ptr1 + 1, collen);
6134 colspec[collen] = '\0';
6135
6136 while (colspec[--collen] == ' ')
6137 colspec[collen] = '\0'; /* strip trailing blanks */
6138 }
6139
6140 /* delete the column selection spec from the row filter string */
6141 strcpy(tmpstr, ptr2 + 1); /* copy any chars after the colspec */
6142 strcpy(ptr1, tmpstr); /* overwrite binspec */
6143 }
6144
6145 /* --------------------------------------------------------- */
6146 /* does the filter contain a pixel filter specification? */
6147 /* --------------------------------------------------------- */
6148
6149 ptr1 = strstr(rowfilter, "[pix");
6150 if (!ptr1)
6151 {
6152 ptr1 = strstr(rowfilter, "[PIX");
6153
6154 if (!ptr1)
6155 ptr1 = strstr(rowfilter, "[Pix");
6156 }
6157
6158 if (ptr1)
6159 {
6160 ptr2 = ptr1 + 4; /* end of the '[pix' string */
6161 if (*ptr2 == 'b' || *ptr2 == 'i' || *ptr2 == 'j' || *ptr2 == 'B' ||
6162 *ptr2 == 'I' || *ptr2 == 'J' || *ptr2 == 'r' || *ptr2 == 'd' ||
6163 *ptr2 == 'R' || *ptr2 == 'D')
6164 ptr2++; /* skip the datatype code letter */
6165
6166 if (*ptr2 == '1')
6167 ptr2++; /* skip the single HDU indicator */
6168
6169 if ( *ptr2 != ' ')
6170 ptr1 = NULL; /* pix string must be followed by space */
6171 }
6172
6173 if (ptr1)
6174 { /* find the end of the pixel filter */
6175 while (*ptr2 != ']')
6176 {
6177 if (*ptr2 == '\0')
6178 {
6179 ffpmsg("input file URL is missing closing bracket ']'");
6180 free(infile);
6181 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6182 }
6183
6184 if (*ptr2 == '\'') /* start of a literal string */
6185 {
6186 ptr2 = strchr(ptr2 + 1, '\''); /* find closing quote */
6187 if (!ptr2)
6188 {
6189 ffpmsg
6190 ("literal string in input file URL is missing closing single quote");
6191 free(infile);
6192 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6193 }
6194 }
6195
6196 if (*ptr2 == '[') /* set of nested square brackets */
6197 {
6198 ptr2 = strchr(ptr2 + 1, ']'); /* find closing bracket */
6199 if (!ptr2)
6200 {
6201 ffpmsg
6202 ("nested brackets in input file URL is missing closing bracket");
6203 free(infile);
6204 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6205 }
6206 }
6207
6208 ptr2++; /* continue search for the closing bracket character */
6209 }
6210
6211 collen = ptr2 - ptr1 - 1;
6212
6213 if (pixfilter) /* copy the column specifier to output string */
6214 {
6215 if (collen > FLEN_FILENAME - 1) {
6216 free(infile);
6217 return(*status = URL_PARSE_ERROR);
6218 }
6219
6220 strncpy(pixfilter, ptr1 + 1, collen);
6221 pixfilter[collen] = '\0';
6222
6223 while (pixfilter[--collen] == ' ')
6224 pixfilter[collen] = '\0'; /* strip trailing blanks */
6225 }
6226
6227 /* delete the pixel filter from the row filter string */
6228 strcpy(tmpstr, ptr2 + 1); /* copy any chars after the pixel filter */
6229 strcpy(ptr1, tmpstr); /* overwrite binspec */
6230 }
6231
6232 /* ------------------------------------------------------------ */
6233 /* does the filter contain an image compression specification? */
6234 /* ------------------------------------------------------------ */
6235
6236 ptr1 = strstr(rowfilter, "[compress");
6237
6238 if (ptr1)
6239 {
6240 ptr2 = ptr1 + 9; /* end of the '[compress' string */
6241
6242 if ( *ptr2 != ' ' && *ptr2 != ']')
6243 ptr1 = NULL; /* compress string must be followed by space or ] */
6244 }
6245
6246 if (ptr1)
6247 {
6248 /* found the compress string */
6249 if (compspec)
6250 {
6251 if (strlen(ptr1 +1) > FLEN_FILENAME - 1)
6252 {
6253 free(infile);
6254 return(*status = URL_PARSE_ERROR);
6255 }
6256
6257 strcpy(compspec, ptr1 + 1);
6258 ptr2 = strchr(compspec, ']');
6259
6260 if (ptr2) /* terminate the binning filter */
6261 {
6262 *ptr2 = '\0';
6263
6264 if ( *(--ptr2) == ' ') /* delete trailing spaces */
6265 *ptr2 = '\0';
6266 }
6267 else
6268 {
6269 ffpmsg("input file URL is missing closing bracket ']'");
6270 ffpmsg(rowfilter);
6271 free(infile);
6272 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6273 }
6274 }
6275
6276 /* delete the compression spec from the row filter string */
6277 ptr2 = strchr(ptr1, ']');
6278 strcpy(tmpstr, ptr2+1); /* copy any chars after the binspec */
6279 strcpy(ptr1, tmpstr); /* overwrite binspec */
6280 }
6281
6282 /* copy the remaining string to the rowfilter output... should only */
6283 /* contain a rowfilter expression of the form "[expr]" */
6284
6285 if (rowfilterx && rowfilter[0]) {
6286 ptr2 = rowfilter + strlen(rowfilter) - 1;
6287 if( rowfilter[0]=='[' && *ptr2==']' ) {
6288 *ptr2 = '\0';
6289
6290 if (strlen(rowfilter + 1) > FLEN_FILENAME - 1)
6291 {
6292 free(infile);
6293 return(*status = URL_PARSE_ERROR);
6294 }
6295
6296 strcpy(rowfilterx, rowfilter+1);
6297 } else {
6298 ffpmsg("input file URL lacks valid row filter expression");
6299 *status = URL_PARSE_ERROR;
6300 }
6301 }
6302
6303 free(infile);
6304 return(*status);
6305 }
6306 /*--------------------------------------------------------------------------*/
ffexist(const char * infile,int * exists,int * status)6307 int ffexist(const char *infile, /* I - input filename or URL */
6308 int *exists, /* O - 2 = a compressed version of file exists */
6309 /* 1 = yes, disk file exists */
6310 /* 0 = no, disk file could not be found */
6311 /* -1 = infile is not a disk file (could */
6312 /* be a http, ftp, gsiftp, smem, or stdin file) */
6313 int *status) /* I/O status */
6314
6315 /*
6316 test if the input file specifier is an existing file on disk
6317 If the specified file can't be found, it then searches for a
6318 compressed version of the file.
6319 */
6320 {
6321 FILE *diskfile;
6322 char rootname[FLEN_FILENAME];
6323 char *ptr1;
6324
6325 if (*status > 0)
6326 return(*status);
6327
6328 /* strip off any extname or filters from the name */
6329 ffrtnm( (char *)infile, rootname, status);
6330
6331 ptr1 = strstr(rootname, "://");
6332
6333 if (ptr1 || *rootname == '-') {
6334 if (!strncmp(rootname, "file", 4) ) {
6335 ptr1 = ptr1 + 3; /* pointer to start of the disk file name */
6336 } else {
6337 *exists = -1; /* this is not a disk file */
6338 return (*status);
6339 }
6340 } else {
6341 ptr1 = rootname;
6342 }
6343
6344 /* see if the disk file exists */
6345 if (file_openfile(ptr1, 0, &diskfile)) {
6346
6347 /* no, couldn't open file, so see if there is a compressed version */
6348 if (file_is_compressed(ptr1) ) {
6349 *exists = 2; /* a compressed version of the file exists */
6350 } else {
6351 *exists = 0; /* neither file nor compressed version exist */
6352 }
6353
6354 } else {
6355
6356 /* yes, file exists */
6357 *exists = 1;
6358 fclose(diskfile);
6359 }
6360
6361 return(*status);
6362 }
6363 /*--------------------------------------------------------------------------*/
ffrtnm(char * url,char * rootname,int * status)6364 int ffrtnm(char *url,
6365 char *rootname,
6366 int *status)
6367 /*
6368 parse the input URL, returning the root name (filetype://basename).
6369 */
6370
6371 {
6372 int ii, jj, slen, infilelen;
6373 char *ptr1, *ptr2, *ptr3;
6374 char urltype[MAX_PREFIX_LEN];
6375 char infile[FLEN_FILENAME];
6376
6377 if (*status > 0)
6378 return(*status);
6379
6380 ptr1 = url;
6381 *rootname = '\0';
6382 *urltype = '\0';
6383 *infile = '\0';
6384
6385 /* get urltype (e.g., file://, ftp://, http://, etc.) */
6386 if (*ptr1 == '-') /* "-" means read file from stdin */
6387 {
6388 strcat(urltype, "-");
6389 ptr1++;
6390 }
6391 else if (!strncmp(ptr1, "stdin", 5) || !strncmp(ptr1, "STDIN", 5))
6392 {
6393 strcat(urltype, "-");
6394 ptr1 = ptr1 + 5;
6395 }
6396 else
6397 {
6398 ptr2 = strstr(ptr1, "://");
6399 ptr3 = strstr(ptr1, "(" );
6400
6401 if (ptr3 && (ptr3 < ptr2) )
6402 {
6403 /* the urltype follows a '(' character, so it must apply */
6404 /* to the output file, and is not the urltype of the input file */
6405 ptr2 = 0; /* so reset pointer to zero */
6406 }
6407
6408
6409 if (ptr2) /* copy the explicit urltype string */
6410 {
6411
6412 if (ptr2 - ptr1 + 3 > MAX_PREFIX_LEN - 1)
6413 {
6414 return(*status = URL_PARSE_ERROR);
6415 }
6416 strncat(urltype, ptr1, ptr2 - ptr1 + 3);
6417 ptr1 = ptr2 + 3;
6418 }
6419 else if (!strncmp(ptr1, "ftp:", 4) )
6420 { /* the 2 //'s are optional */
6421 strcat(urltype, "ftp://");
6422 ptr1 += 4;
6423 }
6424 else if (!strncmp(ptr1, "gsiftp:", 7) )
6425 { /* the 2 //'s are optional */
6426 strcat(urltype, "gsiftp://");
6427 ptr1 += 7;
6428 }
6429 else if (!strncmp(ptr1, "http:", 5) )
6430 { /* the 2 //'s are optional */
6431 strcat(urltype, "http://");
6432 ptr1 += 5;
6433 }
6434 else if (!strncmp(ptr1, "mem:", 4) )
6435 { /* the 2 //'s are optional */
6436 strcat(urltype, "mem://");
6437 ptr1 += 4;
6438 }
6439 else if (!strncmp(ptr1, "shmem:", 6) )
6440 { /* the 2 //'s are optional */
6441 strcat(urltype, "shmem://");
6442 ptr1 += 6;
6443 }
6444 else if (!strncmp(ptr1, "file:", 5) )
6445 { /* the 2 //'s are optional */
6446 ptr1 += 5;
6447 }
6448
6449 /* else assume file driver */
6450 }
6451
6452 /* get the input file name */
6453 ptr2 = strchr(ptr1, '('); /* search for opening parenthesis ( */
6454 ptr3 = strchr(ptr1, '['); /* search for opening bracket [ */
6455
6456 if (ptr2 == ptr3) /* simple case: no [ or ( in the file name */
6457 {
6458
6459 if (strlen(ptr1) > FLEN_FILENAME - 1)
6460 {
6461 return(*status = URL_PARSE_ERROR);
6462 }
6463
6464 strcat(infile, ptr1);
6465 }
6466 else if (!ptr3) /* no bracket, so () enclose output file name */
6467 {
6468
6469 if (ptr2 - ptr1 > FLEN_FILENAME - 1)
6470 {
6471 return(*status = URL_PARSE_ERROR);
6472 }
6473
6474 strncat(infile, ptr1, ptr2 - ptr1);
6475 ptr2++;
6476
6477 ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
6478 if (!ptr1)
6479 return(*status = URL_PARSE_ERROR); /* error, no closing ) */
6480
6481 }
6482 else if (ptr2 && (ptr2 < ptr3)) /* () enclose output name before bracket */
6483 {
6484
6485 if (ptr2 - ptr1 > FLEN_FILENAME - 1)
6486 {
6487 return(*status = URL_PARSE_ERROR);
6488 }
6489
6490 strncat(infile, ptr1, ptr2 - ptr1);
6491 ptr2++;
6492
6493 ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
6494 if (!ptr1)
6495 return(*status = URL_PARSE_ERROR); /* error, no closing ) */
6496 }
6497 else /* bracket comes first, so there is no output name */
6498 {
6499 if (ptr3 - ptr1 > FLEN_FILENAME - 1)
6500 {
6501 return(*status = URL_PARSE_ERROR);
6502 }
6503
6504 strncat(infile, ptr1, ptr3 - ptr1);
6505 }
6506
6507 /* strip off any trailing blanks in the names */
6508 slen = strlen(infile);
6509 for (ii = slen - 1; ii > 0; ii--)
6510 {
6511 if (infile[ii] == ' ')
6512 infile[ii] = '\0';
6513 else
6514 break;
6515 }
6516
6517 /* --------------------------------------------- */
6518 /* check if the 'filename+n' convention has been */
6519 /* used to specifiy which HDU number to open */
6520 /* --------------------------------------------- */
6521
6522 jj = strlen(infile);
6523
6524 for (ii = jj - 1; ii >= 0; ii--)
6525 {
6526 if (infile[ii] == '+') /* search backwards for '+' sign */
6527 break;
6528 }
6529
6530 if (ii > 0 && (jj - ii) < 5) /* limit extension numbers to 4 digits */
6531 {
6532 infilelen = ii;
6533 ii++;
6534
6535
6536 for (; ii < jj; ii++)
6537 {
6538 if (!isdigit((int) infile[ii] ) ) /* are all the chars digits? */
6539 break;
6540 }
6541
6542 if (ii == jj)
6543 {
6544 /* yes, the '+n' convention was used. */
6545
6546 infile[infilelen] = '\0'; /* delete the extension number */
6547 }
6548 }
6549
6550 if (strlen(urltype) + strlen(infile) > FLEN_FILENAME - 1)
6551 {
6552 return(*status = URL_PARSE_ERROR);
6553 }
6554
6555 strcat(rootname, urltype); /* construct the root name */
6556 strcat(rootname, infile);
6557
6558 return(*status);
6559 }
6560 /*--------------------------------------------------------------------------*/
ffourl(char * url,char * urltype,char * outfile,char * tpltfile,char * compspec,int * status)6561 int ffourl(char *url, /* I - full input URL */
6562 char *urltype, /* O - url type */
6563 char *outfile, /* O - base file name */
6564 char *tpltfile, /* O - template file name, if any */
6565 char *compspec, /* O - compression specification, if any */
6566 int *status)
6567 /*
6568 parse the output URL into its basic components.
6569 */
6570
6571 {
6572 char *ptr1, *ptr2, *ptr3;
6573
6574 if (*status > 0)
6575 return(*status);
6576
6577 if (urltype)
6578 *urltype = '\0';
6579 if (outfile)
6580 *outfile = '\0';
6581 if (tpltfile)
6582 *tpltfile = '\0';
6583 if (compspec)
6584 *compspec = '\0';
6585
6586 ptr1 = url;
6587 while (*ptr1 == ' ') /* ignore leading blanks */
6588 ptr1++;
6589
6590 if ( ( (*ptr1 == '-') && ( *(ptr1 +1) == 0 || *(ptr1 +1) == ' ' ) )
6591 || !strcmp(ptr1, "stdout")
6592 || !strcmp(ptr1, "STDOUT"))
6593
6594 /* "-" means write to stdout; also support "- " */
6595 /* but exclude disk file names that begin with a minus sign */
6596 /* e.g., "-55d33m.fits" */
6597 {
6598 if (urltype)
6599 strcpy(urltype, "stdout://");
6600 }
6601 else
6602 {
6603 /* not writing to stdout */
6604 /* get urltype (e.g., file://, ftp://, http://, etc.) */
6605
6606 ptr2 = strstr(ptr1, "://");
6607 if (ptr2) /* copy the explicit urltype string */
6608 {
6609 if (urltype) {
6610 if (ptr2 - ptr1 + 3 > MAX_PREFIX_LEN - 1)
6611 {
6612 return(*status = URL_PARSE_ERROR);
6613 }
6614
6615 strncat(urltype, ptr1, ptr2 - ptr1 + 3);
6616 }
6617
6618 ptr1 = ptr2 + 3;
6619 }
6620 else /* assume file driver */
6621 {
6622 if (urltype)
6623 strcat(urltype, "file://");
6624 }
6625
6626 /* look for template file name, enclosed in parenthesis */
6627 ptr2 = strchr(ptr1, '(');
6628
6629 /* look for image compression parameters, enclosed in sq. brackets */
6630 ptr3 = strchr(ptr1, '[');
6631
6632 if (outfile)
6633 {
6634 if (ptr2) { /* template file was specified */
6635 if (ptr2 - ptr1 > FLEN_FILENAME - 1)
6636 {
6637 return(*status = URL_PARSE_ERROR);
6638 }
6639
6640 strncat(outfile, ptr1, ptr2 - ptr1);
6641 } else if (ptr3) { /* compression was specified */
6642 if (ptr3 - ptr1 > FLEN_FILENAME - 1)
6643 {
6644 return(*status = URL_PARSE_ERROR);
6645 }
6646 strncat(outfile, ptr1, ptr3 - ptr1);
6647
6648 } else { /* no template file or compression */
6649 if (strlen(ptr1) > FLEN_FILENAME - 1)
6650 {
6651 return(*status = URL_PARSE_ERROR);
6652 }
6653 strcpy(outfile, ptr1);
6654 }
6655 }
6656
6657
6658 if (ptr2) /* template file was specified */
6659 {
6660 ptr2++;
6661
6662 ptr1 = strchr(ptr2, ')' ); /* search for closing ) */
6663
6664 if (!ptr1)
6665 {
6666 return(*status = URL_PARSE_ERROR); /* error, no closing ) */
6667 }
6668
6669 if (tpltfile) {
6670 if (ptr1 - ptr2 > FLEN_FILENAME - 1)
6671 {
6672 return(*status = URL_PARSE_ERROR);
6673 }
6674 strncat(tpltfile, ptr2, ptr1 - ptr2);
6675 }
6676 }
6677
6678 if (ptr3) /* compression was specified */
6679 {
6680 ptr3++;
6681
6682 ptr1 = strchr(ptr3, ']' ); /* search for closing ] */
6683
6684 if (!ptr1)
6685 {
6686 return(*status = URL_PARSE_ERROR); /* error, no closing ] */
6687 }
6688
6689 if (compspec) {
6690
6691 if (ptr1 - ptr3 > FLEN_FILENAME - 1)
6692 {
6693 return(*status = URL_PARSE_ERROR);
6694 }
6695
6696 strncat(compspec, ptr3, ptr1 - ptr3);
6697 }
6698 }
6699
6700 /* check if a .gz compressed output file is to be created */
6701 /* by seeing if the filename ends in '.gz' */
6702 if (urltype && outfile)
6703 {
6704 if (!strcmp(urltype, "file://") )
6705 {
6706 ptr1 = strstr(outfile, ".gz");
6707 if (ptr1)
6708 { /* make sure the ".gz" is at the end of the file name */
6709 ptr1 += 3;
6710 if (*ptr1 == 0 || *ptr1 == ' ' )
6711 strcpy(urltype, "compressoutfile://");
6712 }
6713 }
6714 }
6715 }
6716 return(*status);
6717 }
6718 /*--------------------------------------------------------------------------*/
ffexts(char * extspec,int * extnum,char * extname,int * extvers,int * hdutype,char * imagecolname,char * rowexpress,int * status)6719 int ffexts(char *extspec,
6720 int *extnum,
6721 char *extname,
6722 int *extvers,
6723 int *hdutype,
6724 char *imagecolname,
6725 char *rowexpress,
6726 int *status)
6727 {
6728 /*
6729 Parse the input extension specification string, returning either the
6730 extension number or the values of the EXTNAME, EXTVERS, and XTENSION
6731 keywords in desired extension. Also return the name of the column containing
6732 an image, and an expression to be used to determine which row to use,
6733 if present.
6734 */
6735 char *ptr1, *ptr2;
6736 int slen, nvals;
6737 int notint = 1; /* initially assume specified extname is not an integer */
6738 char tmpname[FLEN_VALUE], *loc;
6739
6740 *extnum = 0;
6741 *extname = '\0';
6742 *extvers = 0;
6743 *hdutype = ANY_HDU;
6744 *imagecolname = '\0';
6745 *rowexpress = '\0';
6746
6747 if (*status > 0)
6748 return(*status);
6749
6750 ptr1 = extspec; /* pointer to first char */
6751
6752 while (*ptr1 == ' ') /* skip over any leading blanks */
6753 ptr1++;
6754
6755 if (isdigit((int) *ptr1)) /* is the extension specification a number? */
6756 {
6757 notint = 0; /* looks like extname may actually be the ext. number */
6758 errno = 0; /* reset this prior to calling strtol */
6759 *extnum = strtol(ptr1, &loc, 10); /* read the string as an integer */
6760
6761 while (*loc == ' ') /* skip over trailing blanks */
6762 loc++;
6763
6764 /* check for read error, or junk following the integer */
6765 if ((*loc != '\0' && *loc != ';' ) || (errno == ERANGE) )
6766 {
6767 *extnum = 0;
6768 notint = 1; /* no, extname was not a simple integer after all */
6769 errno = 0; /* reset error condition flag if it was set */
6770 }
6771
6772 if ( *extnum < 0 || *extnum > 99999)
6773 {
6774 *extnum = 0; /* this is not a reasonable extension number */
6775 ffpmsg("specified extension number is out of range:");
6776 ffpmsg(extspec);
6777 return(*status = URL_PARSE_ERROR);
6778 }
6779 }
6780
6781
6782 /* This logic was too simple, and failed on extnames like '1000TEMP'
6783 where it would try to move to the 1000th extension
6784
6785 if (isdigit((int) *ptr1))
6786 {
6787 sscanf(ptr1, "%d", extnum);
6788 if (*extnum < 0 || *extnum > 9999)
6789 {
6790 *extnum = 0;
6791 ffpmsg("specified extension number is out of range:");
6792 ffpmsg(extspec);
6793 return(*status = URL_PARSE_ERROR);
6794 }
6795 }
6796 */
6797
6798 if (notint)
6799 {
6800 /* not a number, so EXTNAME must be specified, followed by */
6801 /* optional EXTVERS and XTENSION values */
6802
6803 /* don't use space char as end indicator, because there */
6804 /* may be imbedded spaces in the EXTNAME value */
6805 slen = strcspn(ptr1, ",:;"); /* length of EXTNAME */
6806
6807 if (slen > FLEN_VALUE - 1)
6808 {
6809 return(*status = URL_PARSE_ERROR);
6810 }
6811
6812 strncat(extname, ptr1, slen); /* EXTNAME value */
6813
6814 /* now remove any trailing blanks */
6815 while (slen > 0 && *(extname + slen -1) == ' ')
6816 {
6817 *(extname + slen -1) = '\0';
6818 slen--;
6819 }
6820
6821 ptr1 += slen;
6822 slen = strspn(ptr1, " ,:"); /* skip delimiter characters */
6823 ptr1 += slen;
6824
6825 slen = strcspn(ptr1, " ,:;"); /* length of EXTVERS */
6826 if (slen)
6827 {
6828 nvals = sscanf(ptr1, "%d", extvers); /* EXTVERS value */
6829 if (nvals != 1)
6830 {
6831 ffpmsg("illegal EXTVER value in input URL:");
6832 ffpmsg(extspec);
6833 return(*status = URL_PARSE_ERROR);
6834 }
6835
6836 ptr1 += slen;
6837 slen = strspn(ptr1, " ,:"); /* skip delimiter characters */
6838 ptr1 += slen;
6839
6840 slen = strcspn(ptr1, ";"); /* length of HDUTYPE */
6841 if (slen)
6842 {
6843 if (*ptr1 == 'b' || *ptr1 == 'B')
6844 *hdutype = BINARY_TBL;
6845 else if (*ptr1 == 't' || *ptr1 == 'T' ||
6846 *ptr1 == 'a' || *ptr1 == 'A')
6847 *hdutype = ASCII_TBL;
6848 else if (*ptr1 == 'i' || *ptr1 == 'I')
6849 *hdutype = IMAGE_HDU;
6850 else
6851 {
6852 ffpmsg("unknown type of HDU in input URL:");
6853 ffpmsg(extspec);
6854 return(*status = URL_PARSE_ERROR);
6855 }
6856 }
6857 }
6858 else
6859 {
6860 strcpy(tmpname, extname);
6861 ffupch(tmpname);
6862 if (!strcmp(tmpname, "PRIMARY") || !strcmp(tmpname, "P") )
6863 *extname = '\0'; /* return extnum = 0 */
6864 }
6865 }
6866
6867 ptr1 = strchr(ptr1, ';');
6868 if (ptr1)
6869 {
6870 /* an image is to be opened; the image is contained in a single */
6871 /* cell of a binary table. A column name and an expression to */
6872 /* determine which row to use has been entered. */
6873
6874 ptr1++; /* skip over the ';' delimiter */
6875 while (*ptr1 == ' ') /* skip over any leading blanks */
6876 ptr1++;
6877
6878 ptr2 = strchr(ptr1, '(');
6879 if (!ptr2)
6880 {
6881 ffpmsg("illegal specification of image in table cell in input URL:");
6882 ffpmsg(" did not find a row expression enclosed in ( )");
6883 ffpmsg(extspec);
6884 return(*status = URL_PARSE_ERROR);
6885 }
6886
6887 if (ptr2 - ptr1 > FLEN_FILENAME - 1)
6888 {
6889 return(*status = URL_PARSE_ERROR);
6890 }
6891
6892 strncat(imagecolname, ptr1, ptr2 - ptr1); /* copy column name */
6893
6894 ptr2++; /* skip over the '(' delimiter */
6895 while (*ptr2 == ' ') /* skip over any leading blanks */
6896 ptr2++;
6897
6898
6899 ptr1 = strchr(ptr2, ')');
6900 if (!ptr2)
6901 {
6902 ffpmsg("illegal specification of image in table cell in input URL:");
6903 ffpmsg(" missing closing ')' character in row expression");
6904 ffpmsg(extspec);
6905 return(*status = URL_PARSE_ERROR);
6906 }
6907
6908 if (ptr1 - ptr2 > FLEN_FILENAME - 1)
6909 {
6910 return(*status = URL_PARSE_ERROR);
6911 }
6912
6913 strncat(rowexpress, ptr2, ptr1 - ptr2); /* row expression */
6914 }
6915
6916 return(*status);
6917 }
6918 /*--------------------------------------------------------------------------*/
ffextn(char * url,int * extension_num,int * status)6919 int ffextn(char *url, /* I - input filename/URL */
6920 int *extension_num, /* O - returned extension number */
6921 int *status)
6922 {
6923 /*
6924 Parse the input url string and return the number of the extension that
6925 CFITSIO would automatically move to if CFITSIO were to open this input URL.
6926 The extension numbers are one's based, so 1 = the primary array, 2 = the
6927 first extension, etc.
6928
6929 The extension number that gets returned is determined by the following
6930 algorithm:
6931
6932 1. If the input URL includes a binning specification (e.g.
6933 'myfile.fits[3][bin X,Y]') then the returned extension number
6934 will always = 1, since CFITSIO would create a temporary primary
6935 image on the fly in this case. The same is true if an image
6936 within a single cell of a binary table is opened.
6937
6938 2. Else if the input URL specifies an extension number (e.g.,
6939 'myfile.fits[3]' or 'myfile.fits+3') then the specified extension
6940 number (+ 1) is returned.
6941
6942 3. Else if the extension name is specified in brackets
6943 (e.g., this 'myfile.fits[EVENTS]') then the file will be opened and searched
6944 for the extension number. If the input URL is '-' (reading from the stdin
6945 file stream) this is not possible and an error will be returned.
6946
6947 4. Else if the URL does not specify an extension (e.g. 'myfile.fits') then
6948 a special extension number = -99 will be returned to signal that no
6949 extension was specified. This feature is mainly for compatibility with
6950 existing FTOOLS software. CFITSIO would open the primary array by default
6951 (extension_num = 1) in this case.
6952
6953 */
6954 fitsfile *fptr;
6955 char urltype[20];
6956 char infile[FLEN_FILENAME];
6957 char outfile[FLEN_FILENAME];
6958 char extspec[FLEN_FILENAME];
6959 char extname[FLEN_FILENAME];
6960 char rowfilter[FLEN_FILENAME];
6961 char binspec[FLEN_FILENAME];
6962 char colspec[FLEN_FILENAME];
6963 char imagecolname[FLEN_VALUE], rowexpress[FLEN_FILENAME];
6964 char *cptr;
6965 int extnum, extvers, hdutype, tstatus = 0;
6966
6967 if (*status > 0)
6968 return(*status);
6969
6970 /* parse the input URL into its basic components */
6971 fits_parse_input_url(url, urltype, infile, outfile,
6972 extspec, rowfilter,binspec, colspec, status);
6973
6974 if (*status > 0)
6975 return(*status);
6976
6977 if (*binspec) /* is there a binning specification? */
6978 {
6979 *extension_num = 1; /* a temporary primary array image is created */
6980 return(*status);
6981 }
6982
6983 if (*extspec) /* is an extension specified? */
6984 {
6985 ffexts(extspec, &extnum,
6986 extname, &extvers, &hdutype, imagecolname, rowexpress, status);
6987
6988 if (*status > 0)
6989 return(*status);
6990
6991 if (*imagecolname) /* is an image within a table cell being opened? */
6992 {
6993 *extension_num = 1; /* a temporary primary array image is created */
6994 return(*status);
6995 }
6996
6997 if (*extname)
6998 {
6999 /* have to open the file to search for the extension name (curses!) */
7000
7001 if (!strcmp(urltype, "stdin://"))
7002 /* opening stdin would destroying it! */
7003 return(*status = URL_PARSE_ERROR);
7004
7005 /* First, strip off any filtering specification */
7006 infile[0] = '\0';
7007 strncat(infile, url, FLEN_FILENAME -1);
7008
7009 cptr = strchr(infile, ']'); /* locate the closing bracket */
7010 if (!cptr)
7011 {
7012 return(*status = URL_PARSE_ERROR);
7013 }
7014 else
7015 {
7016 cptr++;
7017 *cptr = '\0'; /* terminate URl after the extension spec */
7018 }
7019
7020 if (ffopen(&fptr, infile, READONLY, status) > 0) /* open the file */
7021 {
7022 ffclos(fptr, &tstatus);
7023 return(*status);
7024 }
7025
7026 ffghdn(fptr, &extnum); /* where am I in the file? */
7027 *extension_num = extnum;
7028 ffclos(fptr, status);
7029
7030 return(*status);
7031 }
7032 else
7033 {
7034 *extension_num = extnum + 1; /* return the specified number (+ 1) */
7035 return(*status);
7036 }
7037 }
7038 else
7039 {
7040 *extension_num = -99; /* no specific extension was specified */
7041 /* defaults to primary array */
7042 return(*status);
7043 }
7044 }
7045 /*--------------------------------------------------------------------------*/
7046
ffurlt(fitsfile * fptr,char * urlType,int * status)7047 int ffurlt(fitsfile *fptr, char *urlType, int *status)
7048 /*
7049 return the prefix string associated with the driver in use by the
7050 fitsfile pointer fptr
7051 */
7052
7053 {
7054 strcpy(urlType, driverTable[fptr->Fptr->driver].prefix);
7055 return(*status);
7056 }
7057
7058 /*--------------------------------------------------------------------------*/
ffimport_file(char * filename,char ** contents,int * status)7059 int ffimport_file( char *filename, /* Text file to read */
7060 char **contents, /* Pointer to pointer to hold file */
7061 int *status ) /* CFITSIO error code */
7062 /*
7063 Read and concatenate all the lines from the given text file. User
7064 must free the pointer returned in contents. Pointer is guaranteed
7065 to hold 2 characters more than the length of the text... allows the
7066 calling routine to append (or prepend) a newline (or quotes?) without
7067 reallocating memory.
7068 */
7069 {
7070 int allocLen, totalLen, llen, eoline = 1;
7071 char *lines,line[256];
7072 FILE *aFile;
7073
7074 if( *status > 0 ) return( *status );
7075
7076 totalLen = 0;
7077 allocLen = 1024;
7078 lines = (char *)malloc( allocLen * sizeof(char) );
7079 if( !lines ) {
7080 ffpmsg("Couldn't allocate memory to hold ASCII file contents.");
7081 return(*status = MEMORY_ALLOCATION );
7082 }
7083 lines[0] = '\0';
7084
7085 if( (aFile = fopen( filename, "r" ))==NULL ) {
7086 snprintf(line,256,"Could not open ASCII file %s.",filename);
7087 ffpmsg(line);
7088 free( lines );
7089 return(*status = FILE_NOT_OPENED);
7090 }
7091
7092 while( fgets(line,256,aFile)!=NULL ) {
7093 llen = strlen(line);
7094 if ( eoline && (llen > 1) && (line[0] == '/' && line[1] == '/'))
7095 continue; /* skip comment lines begging with // */
7096
7097 eoline = 0;
7098
7099 /* replace CR and newline chars at end of line with nulls */
7100 if ((llen > 0) && (line[llen-1]=='\n' || line[llen-1] == '\r')) {
7101 line[--llen] = '\0';
7102 eoline = 1; /* found an end of line character */
7103
7104 if ((llen > 0) && (line[llen-1]=='\n' || line[llen-1] == '\r')) {
7105 line[--llen] = '\0';
7106 }
7107 }
7108
7109 if( totalLen + llen + 3 >= allocLen ) {
7110 allocLen += 256;
7111 lines = (char *)realloc(lines, allocLen * sizeof(char) );
7112 if( ! lines ) {
7113 ffpmsg("Couldn't allocate memory to hold ASCII file contents.");
7114 *status = MEMORY_ALLOCATION;
7115 break;
7116 }
7117 }
7118 strcpy( lines+totalLen, line );
7119 totalLen += llen;
7120
7121 if (eoline) {
7122 strcpy( lines+totalLen, " "); /* add a space between lines */
7123 totalLen += 1;
7124 }
7125 }
7126 fclose(aFile);
7127
7128 *contents = lines;
7129 return( *status );
7130 }
7131
7132 /*--------------------------------------------------------------------------*/
fits_get_token(char ** ptr,char * delimiter,char * token,int * isanumber)7133 int fits_get_token(char **ptr,
7134 char *delimiter,
7135 char *token,
7136 int *isanumber) /* O - is this token a number? */
7137 /*
7138 parse off the next token, delimited by a character in 'delimiter',
7139 from the input ptr string; increment *ptr to the end of the token.
7140 Returns the length of the token, not including the delimiter char;
7141 */
7142 {
7143 char *loc, tval[73];
7144 int slen;
7145 double dval;
7146
7147 *token = '\0';
7148
7149 while (**ptr == ' ') /* skip over leading blanks */
7150 (*ptr)++;
7151
7152 slen = strcspn(*ptr, delimiter); /* length of next token */
7153 if (slen)
7154 {
7155 strncat(token, *ptr, slen); /* copy token */
7156
7157 (*ptr) += slen; /* skip over the token */
7158
7159 if (isanumber) /* check if token is a number */
7160 {
7161 *isanumber = 1;
7162
7163 if (strchr(token, 'D')) {
7164 strncpy(tval, token, 72);
7165 tval[72] = '\0';
7166
7167 /* The C language does not support a 'D'; replace with 'E' */
7168 if ((loc = strchr(tval, 'D'))) *loc = 'E';
7169
7170 dval = strtod(tval, &loc);
7171 } else {
7172 dval = strtod(token, &loc);
7173 }
7174
7175 /* check for read error, or junk following the value */
7176 if (*loc != '\0' && *loc != ' ' ) *isanumber = 0;
7177 if (errno == ERANGE) *isanumber = 0;
7178 }
7179 }
7180
7181 return(slen);
7182 }
7183 /*--------------------------------------------------------------------------*/
fits_get_token2(char ** ptr,char * delimiter,char ** token,int * isanumber,int * status)7184 int fits_get_token2(char **ptr,
7185 char *delimiter,
7186 char **token,
7187 int *isanumber, /* O - is this token a number? */
7188 int *status)
7189
7190 /*
7191 parse off the next token, delimited by a character in 'delimiter',
7192 from the input ptr string; increment *ptr to the end of the token.
7193 Returns the length of the token, not including the delimiter char;
7194
7195 This routine allocates the *token string; the calling routine must free it
7196 */
7197 {
7198 char *loc, tval[73];
7199 int slen;
7200 double dval;
7201
7202 if (*status)
7203 return(0);
7204
7205 while (**ptr == ' ') /* skip over leading blanks */
7206 (*ptr)++;
7207
7208 slen = strcspn(*ptr, delimiter); /* length of next token */
7209 if (slen)
7210 {
7211 *token = (char *) calloc(slen + 1, 1);
7212 if (!(*token)) {
7213 ffpmsg("Couldn't allocate memory to hold token string (fits_get_token2).");
7214 *status = MEMORY_ALLOCATION ;
7215 return(0);
7216 }
7217
7218 strncat(*token, *ptr, slen); /* copy token */
7219 (*ptr) += slen; /* skip over the token */
7220
7221 if (isanumber) /* check if token is a number */
7222 {
7223 *isanumber = 1;
7224
7225 if (strchr(*token, 'D')) {
7226 strncpy(tval, *token, 72);
7227 tval[72] = '\0';
7228
7229 /* The C language does not support a 'D'; replace with 'E' */
7230 if ((loc = strchr(tval, 'D'))) *loc = 'E';
7231
7232 dval = strtod(tval, &loc);
7233 } else {
7234 dval = strtod(*token, &loc);
7235 }
7236
7237 /* check for read error, or junk following the value */
7238 if (*loc != '\0' && *loc != ' ' ) *isanumber = 0;
7239 if (errno == ERANGE) *isanumber = 0;
7240 }
7241 }
7242
7243 return(slen);
7244 }
7245 /*---------------------------------------------------------------------------*/
fits_split_names(char * list)7246 char *fits_split_names(
7247 char *list) /* I - input list of names */
7248 {
7249 /*
7250 A sequence of calls to fits_split_names will split the input string
7251 into name tokens. The string typically contains a list of file or
7252 column names. The names must be delimited by a comma and/or spaces.
7253 This routine ignores spaces and commas that occur within parentheses,
7254 brackets, or curly brackets. It also strips any leading and trailing
7255 blanks from the returned name.
7256
7257 This routine is similar to the ANSI C 'strtok' function:
7258
7259 The first call to fits_split_names has a non-null input string.
7260 It finds the first name in the string and terminates it by
7261 overwriting the next character of the string with a '\0' and returns
7262 a pointer to the name. Each subsequent call, indicated by a NULL
7263 value of the input string, returns the next name, searching from
7264 just past the end of the previous name. It returns NULL when no
7265 further names are found.
7266
7267 The following line illustrates how a string would be split into 3 names:
7268 myfile[1][bin (x,y)=4], file2.fits file3.fits
7269 ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^
7270 1st name 2nd name 3rd name
7271
7272
7273 NOTE: This routine is not thread-safe.
7274 This routine is simply provided as a utility routine for other external
7275 software. It is not used by any CFITSIO routine.
7276
7277 */
7278 int depth = 0;
7279 char *start;
7280 static char *ptr;
7281
7282 if (list) /* reset ptr if a string is given */
7283 ptr = list;
7284
7285 while (*ptr == ' ')ptr++; /* skip leading white space */
7286
7287 if (*ptr == '\0')return(0); /* no remaining file names */
7288
7289 start = ptr;
7290
7291 while (*ptr != '\0') {
7292 if ((*ptr == '[') || (*ptr == '(') || (*ptr == '{')) depth ++;
7293 else if ((*ptr == '}') || (*ptr == ')') || (*ptr == ']')) depth --;
7294 else if ((depth == 0) && (*ptr == ',' || *ptr == ' ')) {
7295 *ptr = '\0'; /* terminate the filename here */
7296 ptr++; /* save pointer to start of next filename */
7297 break;
7298 }
7299 ptr++;
7300 }
7301
7302 return(start);
7303 }
7304 /*--------------------------------------------------------------------------*/
urltype2driver(char * urltype,int * driver)7305 int urltype2driver(char *urltype, int *driver)
7306 /*
7307 compare input URL with list of known drivers, returning the
7308 matching driver numberL.
7309 */
7310
7311 {
7312 int ii;
7313
7314 /* find matching driver; search most recent drivers first */
7315
7316 for (ii=no_of_drivers - 1; ii >= 0; ii--)
7317 {
7318 if (0 == strcmp(driverTable[ii].prefix, urltype))
7319 {
7320 *driver = ii;
7321 return(0);
7322 }
7323 }
7324
7325 return(NO_MATCHING_DRIVER);
7326 }
7327 /*--------------------------------------------------------------------------*/
ffclos(fitsfile * fptr,int * status)7328 int ffclos(fitsfile *fptr, /* I - FITS file pointer */
7329 int *status) /* IO - error status */
7330 /*
7331 close the FITS file by completing the current HDU, flushing it to disk,
7332 then calling the system dependent routine to physically close the FITS file
7333 */
7334 {
7335 int tstatus = NO_CLOSE_ERROR, zerostatus = 0;
7336
7337 if (!fptr)
7338 return(*status = NULL_INPUT_PTR);
7339 else if ((fptr->Fptr)->validcode != VALIDSTRUC) /* check for magic value */
7340 return(*status = BAD_FILEPTR);
7341
7342 /* close and flush the current HDU */
7343 if (*status > 0)
7344 ffchdu(fptr, &tstatus); /* turn off the error message from ffchdu */
7345 else
7346 ffchdu(fptr, status);
7347
7348 ((fptr->Fptr)->open_count)--; /* decrement usage counter */
7349
7350 if ((fptr->Fptr)->open_count == 0) /* if no other files use structure */
7351 {
7352 ffflsh(fptr, TRUE, status); /* flush and disassociate IO buffers */
7353
7354 /* call driver function to actually close the file */
7355 if ((*driverTable[(fptr->Fptr)->driver].close)((fptr->Fptr)->filehandle))
7356 {
7357 if (*status <= 0)
7358 {
7359 *status = FILE_NOT_CLOSED; /* report if no previous error */
7360
7361 ffpmsg("failed to close the following file: (ffclos)");
7362 ffpmsg((fptr->Fptr)->filename);
7363 }
7364 }
7365
7366 fits_clear_Fptr( fptr->Fptr, status); /* clear Fptr address */
7367 free((fptr->Fptr)->iobuffer); /* free memory for I/O buffers */
7368 free((fptr->Fptr)->headstart); /* free memory for headstart array */
7369 free((fptr->Fptr)->filename); /* free memory for the filename */
7370 (fptr->Fptr)->filename = 0;
7371 (fptr->Fptr)->validcode = 0; /* magic value to indicate invalid fptr */
7372 free(fptr->Fptr); /* free memory for the FITS file structure */
7373 free(fptr); /* free memory for the FITS file structure */
7374 }
7375 else
7376 {
7377 /*
7378 to minimize the fallout from any previous error (e.g., trying to
7379 open a non-existent extension in a already opened file),
7380 always call ffflsh with status = 0.
7381 */
7382 /* just flush the buffers, don't disassociate them */
7383 if (*status > 0)
7384 ffflsh(fptr, FALSE, &zerostatus);
7385 else
7386 ffflsh(fptr, FALSE, status);
7387
7388 free(fptr); /* free memory for the FITS file structure */
7389 }
7390
7391 return(*status);
7392 }
7393 /*--------------------------------------------------------------------------*/
ffdelt(fitsfile * fptr,int * status)7394 int ffdelt(fitsfile *fptr, /* I - FITS file pointer */
7395 int *status) /* IO - error status */
7396 /*
7397 close and DELETE the FITS file.
7398 */
7399 {
7400 char *basename;
7401 int slen, tstatus = NO_CLOSE_ERROR, zerostatus = 0;
7402
7403 if (!fptr)
7404 return(*status = NULL_INPUT_PTR);
7405 else if ((fptr->Fptr)->validcode != VALIDSTRUC) /* check for magic value */
7406 return(*status = BAD_FILEPTR);
7407
7408 if (*status > 0)
7409 ffchdu(fptr, &tstatus); /* turn off the error message from ffchdu */
7410 else
7411 ffchdu(fptr, status);
7412
7413 ffflsh(fptr, TRUE, status); /* flush and disassociate IO buffers */
7414
7415 /* call driver function to actually close the file */
7416 if ( (*driverTable[(fptr->Fptr)->driver].close)((fptr->Fptr)->filehandle) )
7417 {
7418 if (*status <= 0)
7419 {
7420 *status = FILE_NOT_CLOSED; /* report error if no previous error */
7421
7422 ffpmsg("failed to close the following file: (ffdelt)");
7423 ffpmsg((fptr->Fptr)->filename);
7424 }
7425 }
7426
7427 /* call driver function to actually delete the file */
7428 if ( (driverTable[(fptr->Fptr)->driver].remove) )
7429 {
7430 /* parse the input URL to get the base filename */
7431 slen = strlen((fptr->Fptr)->filename);
7432 basename = (char *) malloc(slen +1);
7433 if (!basename)
7434 return(*status = MEMORY_ALLOCATION);
7435
7436 fits_parse_input_url((fptr->Fptr)->filename, NULL, basename, NULL, NULL, NULL, NULL,
7437 NULL, &zerostatus);
7438
7439 if ((*driverTable[(fptr->Fptr)->driver].remove)(basename))
7440 {
7441 ffpmsg("failed to delete the following file: (ffdelt)");
7442 ffpmsg((fptr->Fptr)->filename);
7443 if (!(*status))
7444 *status = FILE_NOT_CLOSED;
7445 }
7446 free(basename);
7447 }
7448
7449 fits_clear_Fptr( fptr->Fptr, status); /* clear Fptr address */
7450 free((fptr->Fptr)->iobuffer); /* free memory for I/O buffers */
7451 free((fptr->Fptr)->headstart); /* free memory for headstart array */
7452 free((fptr->Fptr)->filename); /* free memory for the filename */
7453 (fptr->Fptr)->filename = 0;
7454 (fptr->Fptr)->validcode = 0; /* magic value to indicate invalid fptr */
7455 free(fptr->Fptr); /* free memory for the FITS file structure */
7456 free(fptr); /* free memory for the FITS file structure */
7457
7458 return(*status);
7459 }
7460 /*--------------------------------------------------------------------------*/
fftrun(fitsfile * fptr,LONGLONG filesize,int * status)7461 int fftrun( fitsfile *fptr, /* I - FITS file pointer */
7462 LONGLONG filesize, /* I - size to truncate the file */
7463 int *status) /* O - error status */
7464 /*
7465 low level routine to truncate a file to a new smaller size.
7466 */
7467 {
7468 if (driverTable[(fptr->Fptr)->driver].truncate)
7469 {
7470 ffflsh(fptr, FALSE, status); /* flush all the buffers first */
7471 (fptr->Fptr)->filesize = filesize;
7472 (fptr->Fptr)->io_pos = filesize;
7473 (fptr->Fptr)->logfilesize = filesize;
7474 (fptr->Fptr)->bytepos = filesize;
7475 ffbfeof(fptr, status); /* eliminate any buffers beyond current EOF */
7476 return (*status =
7477 (*driverTable[(fptr->Fptr)->driver].truncate)((fptr->Fptr)->filehandle,
7478 filesize) );
7479 }
7480 else
7481 return(*status);
7482 }
7483 /*--------------------------------------------------------------------------*/
ffflushx(FITSfile * fptr)7484 int ffflushx( FITSfile *fptr) /* I - FITS file pointer */
7485 /*
7486 low level routine to flush internal file buffers to the file.
7487 */
7488 {
7489 if (driverTable[fptr->driver].flush)
7490 return ( (*driverTable[fptr->driver].flush)(fptr->filehandle) );
7491 else
7492 return(0); /* no flush function defined for this driver */
7493 }
7494 /*--------------------------------------------------------------------------*/
ffseek(FITSfile * fptr,LONGLONG position)7495 int ffseek( FITSfile *fptr, /* I - FITS file pointer */
7496 LONGLONG position) /* I - byte position to seek to */
7497 /*
7498 low level routine to seek to a position in a file.
7499 */
7500 {
7501 return( (*driverTable[fptr->driver].seek)(fptr->filehandle, position) );
7502 }
7503 /*--------------------------------------------------------------------------*/
ffwrite(FITSfile * fptr,long nbytes,void * buffer,int * status)7504 int ffwrite( FITSfile *fptr, /* I - FITS file pointer */
7505 long nbytes, /* I - number of bytes to write */
7506 void *buffer, /* I - buffer to write */
7507 int *status) /* O - error status */
7508 /*
7509 low level routine to write bytes to a file.
7510 */
7511 {
7512 if ( (*driverTable[fptr->driver].write)(fptr->filehandle, buffer, nbytes) )
7513 {
7514 ffpmsg("Error writing data buffer to file:");
7515 ffpmsg(fptr->filename);
7516
7517 *status = WRITE_ERROR;
7518 }
7519 return(*status);
7520 }
7521 /*--------------------------------------------------------------------------*/
ffread(FITSfile * fptr,long nbytes,void * buffer,int * status)7522 int ffread( FITSfile *fptr, /* I - FITS file pointer */
7523 long nbytes, /* I - number of bytes to read */
7524 void *buffer, /* O - buffer to read into */
7525 int *status) /* O - error status */
7526 /*
7527 low level routine to read bytes from a file.
7528 */
7529 {
7530 int readstatus;
7531
7532 readstatus = (*driverTable[fptr->driver].read)(fptr->filehandle,
7533 buffer, nbytes);
7534
7535 if (readstatus == END_OF_FILE)
7536 *status = END_OF_FILE;
7537 else if (readstatus > 0)
7538 {
7539 ffpmsg("Error reading data buffer from file:");
7540 ffpmsg(fptr->filename);
7541
7542 *status = READ_ERROR;
7543 }
7544
7545 return(*status);
7546 }
7547 /*--------------------------------------------------------------------------*/
fftplt(fitsfile ** fptr,const char * filename,const char * tempname,int * status)7548 int fftplt(fitsfile **fptr, /* O - FITS file pointer */
7549 const char *filename, /* I - name of file to create */
7550 const char *tempname, /* I - name of template file */
7551 int *status) /* IO - error status */
7552 /*
7553 Create and initialize a new FITS file based on a template file.
7554 Uses C fopen and fgets functions.
7555 */
7556 {
7557 *fptr = 0; /* initialize null file pointer, */
7558 /* regardless of the value of *status */
7559 if (*status > 0)
7560 return(*status);
7561
7562 if ( ffinit(fptr, filename, status) ) /* create empty file */
7563 return(*status);
7564
7565 ffoptplt(*fptr, tempname, status); /* open and use template */
7566
7567 return(*status);
7568 }
7569 /*--------------------------------------------------------------------------*/
ffoptplt(fitsfile * fptr,const char * tempname,int * status)7570 int ffoptplt(fitsfile *fptr, /* O - FITS file pointer */
7571 const char *tempname, /* I - name of template file */
7572 int *status) /* IO - error status */
7573 /*
7574 open template file and use it to create new file
7575 */
7576 {
7577 fitsfile *tptr;
7578 int tstatus = 0, nkeys, nadd, ii;
7579 char card[FLEN_CARD];
7580
7581 if (*status > 0)
7582 return(*status);
7583
7584 if (tempname == NULL || *tempname == '\0') /* no template file? */
7585 return(*status);
7586
7587 /* try opening template */
7588 ffopen(&tptr, (char *) tempname, READONLY, &tstatus);
7589
7590 if (tstatus) /* not a FITS file, so treat it as an ASCII template */
7591 {
7592 ffxmsg(2, card); /* clear the error message */
7593 fits_execute_template(fptr, (char *) tempname, status);
7594
7595 ffmahd(fptr, 1, 0, status); /* move back to the primary array */
7596 return(*status);
7597 }
7598 else /* template is a valid FITS file */
7599 {
7600 ffmahd(tptr, 1, NULL, status); /* make sure we are at the beginning */
7601 while (*status <= 0)
7602 {
7603 ffghsp(tptr, &nkeys, &nadd, status); /* get no. of keywords */
7604
7605 for (ii = 1; ii <= nkeys; ii++) /* copy keywords */
7606 {
7607 ffgrec(tptr, ii, card, status);
7608
7609 /* must reset the PCOUNT keyword to zero in the new output file */
7610 if (strncmp(card, "PCOUNT ",8) == 0) { /* the PCOUNT keyword? */
7611 if (strncmp(card+25, " 0", 5)) { /* non-zero value? */
7612 strncpy(card, "PCOUNT = 0", 30);
7613 }
7614 }
7615
7616 ffprec(fptr, card, status);
7617 }
7618
7619 ffmrhd(tptr, 1, 0, status); /* move to next HDU until error */
7620 ffcrhd(fptr, status); /* create empty new HDU in output file */
7621 }
7622
7623 if (*status == END_OF_FILE)
7624 {
7625 *status = 0; /* expected error condition */
7626 }
7627 ffclos(tptr, status); /* close the template file */
7628 }
7629
7630 ffmahd(fptr, 1, 0, status); /* move to the primary array */
7631 return(*status);
7632 }
7633 /*--------------------------------------------------------------------------*/
ffrprt(FILE * stream,int status)7634 void ffrprt( FILE *stream, int status)
7635 /*
7636 Print out report of cfitsio error status and messages on the error stack.
7637 Uses C FILE stream.
7638 */
7639 {
7640 char status_str[FLEN_STATUS], errmsg[FLEN_ERRMSG];
7641
7642 if (status)
7643 {
7644
7645 fits_get_errstatus(status, status_str); /* get the error description */
7646 fprintf(stream, "\nFITSIO status = %d: %s\n", status, status_str);
7647
7648 while ( fits_read_errmsg(errmsg) ) /* get error stack messages */
7649 fprintf(stream, "%s\n", errmsg);
7650 }
7651 return;
7652 }
7653 /*--------------------------------------------------------------------------*/
pixel_filter_helper(fitsfile ** fptr,char * outfile,char * expr,int * status)7654 int pixel_filter_helper(
7655 fitsfile **fptr, /* IO - pointer to input image; on output it */
7656 /* points to the new image */
7657 char *outfile, /* I - name for output file */
7658 char *expr, /* I - Image filter expression */
7659 int *status)
7660 {
7661 PixelFilter filter = { 0 };
7662 char * DEFAULT_TAG = "X";
7663 int ii, hdunum;
7664 int singleHDU = 0;
7665
7666 filter.count = 1;
7667 filter.ifptr = fptr;
7668 filter.tag = &DEFAULT_TAG;
7669
7670 /* create new empty file for result */
7671 if (ffinit(&filter.ofptr, outfile, status) > 0)
7672 {
7673 ffpmsg("failed to create output file for pixel filter:");
7674 ffpmsg(outfile);
7675 return(*status);
7676 }
7677
7678 fits_get_hdu_num(*fptr, &hdunum); /* current HDU number in input file */
7679
7680 expr += 3; /* skip 'pix' */
7681 switch (expr[0]) {
7682 case 'b':
7683 case 'B': filter.bitpix = BYTE_IMG; break;
7684 case 'i':
7685 case 'I': filter.bitpix = SHORT_IMG; break;
7686 case 'j':
7687 case 'J': filter.bitpix = LONG_IMG; break;
7688 case 'r':
7689 case 'R': filter.bitpix = FLOAT_IMG; break;
7690 case 'd':
7691 case 'D': filter.bitpix = DOUBLE_IMG; break;
7692 }
7693 if (filter.bitpix) /* skip bitpix indicator */
7694 ++expr;
7695
7696 if (*expr == '1') {
7697 ++expr;
7698 singleHDU = 1;
7699 }
7700
7701 if (((*fptr)->Fptr)->only_one)
7702 singleHDU = 1;
7703
7704 if (*expr != ' ') {
7705 ffpmsg("pixel filtering expression not space separated:");
7706 ffpmsg(expr);
7707 }
7708 while (*expr == ' ')
7709 ++expr;
7710
7711 /* copy all preceding extensions to the output file */
7712 for (ii = 1; !singleHDU && ii < hdunum; ii++)
7713 {
7714 fits_movabs_hdu(*fptr, ii, NULL, status);
7715 if (fits_copy_hdu(*fptr, filter.ofptr, 0, status) > 0)
7716 {
7717 ffclos(filter.ofptr, status);
7718 return(*status);
7719 }
7720 }
7721
7722 /* move back to the original HDU position */
7723 fits_movabs_hdu(*fptr, hdunum, NULL, status);
7724
7725 filter.expression = expr;
7726 if (fits_pixel_filter(&filter, status)) {
7727 ffpmsg("failed to execute image filter:");
7728 ffpmsg(expr);
7729 ffclos(filter.ofptr, status);
7730 return(*status);
7731 }
7732
7733
7734 /* copy any remaining HDUs to the output file */
7735
7736 for (ii = hdunum + 1; !singleHDU; ii++)
7737 {
7738 if (fits_movabs_hdu(*fptr, ii, NULL, status) > 0)
7739 break;
7740
7741 fits_copy_hdu(*fptr, filter.ofptr, 0, status);
7742 }
7743
7744 if (*status == END_OF_FILE)
7745 *status = 0; /* got the expected EOF error; reset = 0 */
7746 else if (*status > 0)
7747 {
7748 ffclos(filter.ofptr, status);
7749 return(*status);
7750 }
7751
7752 /* close the original file and return ptr to the new image */
7753 ffclos(*fptr, status);
7754
7755 *fptr = filter.ofptr; /* reset the pointer to the new table */
7756
7757 /* move back to the image subsection */
7758 if (ii - 1 != hdunum)
7759 fits_movabs_hdu(*fptr, hdunum, NULL, status);
7760
7761 return(*status);
7762 }
7763
7764 /*-------------------------------------------------------------------*/
ffihtps(void)7765 int ffihtps(void)
7766 {
7767 /* Wrapper function for global initialization of curl library.
7768 This is NOT THREAD-SAFE */
7769 int status=0;
7770 #ifdef CFITSIO_HAVE_CURL
7771 if (curl_global_init(CURL_GLOBAL_ALL))
7772 /* Do we want to define a new CFITSIO error code for this? */
7773 status = -1;
7774 #endif
7775 return status;
7776 }
7777
7778 /*-------------------------------------------------------------------*/
ffchtps(void)7779 int ffchtps(void)
7780 {
7781 /* Wrapper function for global cleanup of curl library.
7782 This is NOT THREAD-SAFE */
7783 #ifdef CFITSIO_HAVE_CURL
7784 curl_global_cleanup();
7785 #endif
7786 return 0;
7787 }
7788
7789 /*-------------------------------------------------------------------*/
ffvhtps(int flag)7790 void ffvhtps(int flag)
7791 {
7792 /* Turn libcurl's verbose output on (1) or off (0).
7793 This is NOT THREAD-SAFE */
7794 #ifdef HAVE_NET_SERVICES
7795
7796 https_set_verbose(flag);
7797 #endif
7798 }
7799
7800 /*-------------------------------------------------------------------*/
ffshdwn(int flag)7801 void ffshdwn(int flag)
7802 {
7803 /* Display download status bar (to stderr), where applicable.
7804 This is NOT THREAD-SAFE */
7805 #ifdef HAVE_NET_SERVICES
7806 fits_dwnld_prog_bar(flag);
7807 #endif
7808 }
7809
7810 /*-------------------------------------------------------------------*/
ffgtmo(void)7811 int ffgtmo(void)
7812 {
7813 int timeout=0;
7814 #ifdef HAVE_NET_SERVICES
7815 timeout = fits_net_timeout(-1);
7816 #endif
7817 return timeout;
7818 }
7819
7820 /*-------------------------------------------------------------------*/
ffstmo(int sec,int * status)7821 int ffstmo(int sec, int *status)
7822 {
7823 if (*status > 0)
7824 return (*status);
7825
7826 #ifdef HAVE_NET_SERVICES
7827 if (sec <= 0)
7828 {
7829 *status = BAD_NETTIMEOUT;
7830 ffpmsg("Bad value for net timeout setting (fits_set_timeout).");
7831 return(*status);
7832 }
7833 fits_net_timeout(sec);
7834 #endif
7835 return(*status);
7836 }
7837