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