1 /* This file, getkey.c, contains routines that read keywords from */
2 /* a FITS header. */
3
4 /* The FITSIO software was written by William Pence at the High Energy */
5 /* Astrophysic Science Archive Research Center (HEASARC) at the NASA */
6 /* Goddard Space Flight Center. */
7
8 #include <string.h>
9 #include <limits.h>
10 #include <stdlib.h>
11 #include <ctype.h>
12 /* stddef.h is apparently needed to define size_t */
13 #include <stddef.h>
14 #include "fitsio2.h"
15
16 /*--------------------------------------------------------------------------*/
ffghsp(fitsfile * fptr,int * nexist,int * nmore,int * status)17 int ffghsp(fitsfile *fptr, /* I - FITS file pointer */
18 int *nexist, /* O - number of existing keywords in header */
19 int *nmore, /* O - how many more keywords will fit */
20 int *status) /* IO - error status */
21 /*
22 returns the number of existing keywords (not counting the END keyword)
23 and the number of more keyword that will fit in the current header
24 without having to insert more FITS blocks.
25 */
26 {
27 if (*status > 0)
28 return(*status);
29
30 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
31 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
32
33 if (nexist)
34 *nexist = (int) (( ((fptr->Fptr)->headend) -
35 ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) ) / 80);
36
37 if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
38 {
39 if (nmore)
40 *nmore = -1; /* data not written yet, so room for any keywords */
41 }
42 else
43 {
44 /* calculate space available between the data and the END card */
45 if (nmore)
46 *nmore = (int) (((fptr->Fptr)->datastart - (fptr->Fptr)->headend) / 80 - 1);
47 }
48
49 return(*status);
50 }
51 /*--------------------------------------------------------------------------*/
ffghps(fitsfile * fptr,int * nexist,int * position,int * status)52 int ffghps(fitsfile *fptr, /* I - FITS file pointer */
53 int *nexist, /* O - number of existing keywords in header */
54 int *position, /* O - position of next keyword to be read */
55 int *status) /* IO - error status */
56 /*
57 return the number of existing keywords and the position of the next
58 keyword that will be read.
59 */
60 {
61 if (*status > 0)
62 return(*status);
63
64 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
65 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
66
67 if (nexist)
68 *nexist = (int) (( ((fptr->Fptr)->headend) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) ) / 80);
69
70 if (position)
71 *position = (int) (( ((fptr->Fptr)->nextkey) - ((fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) ) / 80 + 1);
72
73 return(*status);
74 }
75 /*--------------------------------------------------------------------------*/
ffnchk(fitsfile * fptr,int * status)76 int ffnchk(fitsfile *fptr, /* I - FITS file pointer */
77 int *status) /* IO - error status */
78 /*
79 function returns the position of the first null character (ASCII 0), if
80 any, in the current header. Null characters are illegal, but the other
81 CFITSIO routines that read the header will not detect this error, because
82 the null gets interpreted as a normal end of string character.
83 */
84 {
85 long ii, nblock;
86 LONGLONG bytepos;
87 int length, nullpos;
88 char block[2881];
89
90 if (*status > 0)
91 return(*status);
92
93 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
94 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
95
96 if ((fptr->Fptr)->datastart == DATA_UNDEFINED)
97 {
98 return(0); /* Don't check a file that is just being created. */
99 /* It cannot contain nulls since CFITSIO wrote it. */
100 }
101 else
102 {
103 /* calculate number of blocks in the header */
104 nblock = (long) (( (fptr->Fptr)->datastart -
105 (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] ) / 2880);
106 }
107
108 bytepos = (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu];
109 ffmbyt(fptr, bytepos, REPORT_EOF, status); /* move to read pos. */
110
111 block[2880] = '\0';
112 for (ii = 0; ii < nblock; ii++)
113 {
114 if (ffgbyt(fptr, 2880, block, status) > 0)
115 return(0); /* read error of some sort */
116
117 length = strlen(block);
118 if (length != 2880)
119 {
120 nullpos = (ii * 2880) + length + 1;
121 return(nullpos);
122 }
123 }
124
125 return(0);
126 }
127 /*--------------------------------------------------------------------------*/
ffmaky(fitsfile * fptr,int nrec,int * status)128 int ffmaky(fitsfile *fptr, /* I - FITS file pointer */
129 int nrec, /* I - one-based keyword number to move to */
130 int *status) /* IO - error status */
131 {
132 /*
133 move pointer to the specified absolute keyword position. E.g. this keyword
134 will then be read by the next call to ffgnky.
135 */
136 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
137 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
138
139 (fptr->Fptr)->nextkey = (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] + ( (nrec - 1) * 80);
140
141 return(*status);
142 }
143 /*--------------------------------------------------------------------------*/
ffmrky(fitsfile * fptr,int nmove,int * status)144 int ffmrky(fitsfile *fptr, /* I - FITS file pointer */
145 int nmove, /* I - relative number of keywords to move */
146 int *status) /* IO - error status */
147 {
148 /*
149 move pointer to the specified keyword position relative to the current
150 position. E.g. this keyword will then be read by the next call to ffgnky.
151 */
152
153 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
154 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
155
156 (fptr->Fptr)->nextkey += (nmove * 80);
157
158 return(*status);
159 }
160 /*--------------------------------------------------------------------------*/
ffgnky(fitsfile * fptr,char * card,int * status)161 int ffgnky(fitsfile *fptr, /* I - FITS file pointer */
162 char *card, /* O - card string */
163 int *status) /* IO - error status */
164 /*
165 read the next keyword from the header - used internally by cfitsio
166 */
167 {
168 int jj, nrec;
169 LONGLONG bytepos, endhead;
170 char message[FLEN_ERRMSG];
171
172 if (*status > 0)
173 return(*status);
174
175 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
176 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
177
178 card[0] = '\0'; /* make sure card is terminated, even affer read error */
179
180 /*
181 Check that nextkey points to a legal keyword position. Note that headend
182 is the current end of the header, i.e., the position where a new keyword
183 would be appended, however, if there are more than 1 FITS block worth of
184 blank keywords at the end of the header (36 keywords per 2880 byte block)
185 then the actual physical END card must be located at a starting position
186 which is just 2880 bytes prior to the start of the data unit.
187 */
188
189 bytepos = (fptr->Fptr)->nextkey;
190 endhead = maxvalue( ((fptr->Fptr)->headend), ((fptr->Fptr)->datastart - 2880) );
191
192 /* nextkey must be < endhead and > than headstart */
193 if (bytepos > endhead ||
194 bytepos < (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu] )
195 {
196 nrec= (int) ((bytepos - (fptr->Fptr)->headstart[(fptr->Fptr)->curhdu]) / 80 + 1);
197 snprintf(message, FLEN_ERRMSG,"Cannot get keyword number %d. It does not exist.",
198 nrec);
199 ffpmsg(message);
200 return(*status = KEY_OUT_BOUNDS);
201 }
202
203 ffmbyt(fptr, bytepos, REPORT_EOF, status); /* move to read pos. */
204
205 card[80] = '\0'; /* make sure card is terminate, even if ffgbyt fails */
206
207 if (ffgbyt(fptr, 80, card, status) <= 0)
208 {
209 (fptr->Fptr)->nextkey += 80; /* increment pointer to next keyword */
210
211 /* strip off trailing blanks with terminated string */
212 jj = 79;
213 while (jj >= 0 && card[jj] == ' ')
214 jj--;
215
216 card[jj + 1] = '\0';
217 }
218 return(*status);
219 }
220 /*--------------------------------------------------------------------------*/
ffgnxk(fitsfile * fptr,char ** inclist,int ninc,char ** exclist,int nexc,char * card,int * status)221 int ffgnxk( fitsfile *fptr, /* I - FITS file pointer */
222 char **inclist, /* I - list of included keyword names */
223 int ninc, /* I - number of names in inclist */
224 char **exclist, /* I - list of excluded keyword names */
225 int nexc, /* I - number of names in exclist */
226 char *card, /* O - first matching keyword */
227 int *status) /* IO - error status */
228 /*
229 Return the next keyword that matches one of the names in inclist
230 but does not match any of the names in exclist. The search
231 goes from the current position to the end of the header, only.
232 Wild card characters may be used in the name lists ('*', '?' and '#').
233 */
234 {
235 int casesn, match, exact, namelen;
236 long ii, jj;
237 char keybuf[FLEN_CARD], keyname[FLEN_KEYWORD];
238
239 card[0] = '\0';
240 if (*status > 0)
241 return(*status);
242
243 casesn = FALSE;
244
245 /* get next card, and return with an error if hit end of header */
246 while( ffgcrd(fptr, "*", keybuf, status) <= 0)
247 {
248 ffgknm(keybuf, keyname, &namelen, status); /* get the keyword name */
249
250 /* does keyword match any names in the include list? */
251 for (ii = 0; ii < ninc; ii++)
252 {
253 ffcmps(inclist[ii], keyname, casesn, &match, &exact);
254 if (match)
255 {
256 /* does keyword match any names in the exclusion list? */
257 jj = -1;
258 while ( ++jj < nexc )
259 {
260 ffcmps(exclist[jj], keyname, casesn, &match, &exact);
261 if (match)
262 break;
263 }
264
265 if (jj >= nexc)
266 {
267 /* not in exclusion list, so return this keyword */
268 strcat(card, keybuf);
269 return(*status);
270 }
271 }
272 }
273 }
274 return(*status);
275 }
276 /*--------------------------------------------------------------------------*/
ffgky(fitsfile * fptr,int datatype,const char * keyname,void * value,char * comm,int * status)277 int ffgky( fitsfile *fptr, /* I - FITS file pointer */
278 int datatype, /* I - datatype of the value */
279 const char *keyname, /* I - name of keyword to read */
280 void *value, /* O - keyword value */
281 char *comm, /* O - keyword comment */
282 int *status) /* IO - error status */
283 /*
284 Read (get) the keyword value and comment from the FITS header.
285 Reads a keyword value with the datatype specified by the 2nd argument.
286 */
287 {
288 LONGLONG longval;
289 ULONGLONG ulongval;
290 double doubleval;
291
292 if (*status > 0) /* inherit input status value if > 0 */
293 return(*status);
294
295 if (datatype == TSTRING)
296 {
297 ffgkys(fptr, keyname, (char *) value, comm, status);
298 }
299 else if (datatype == TBYTE)
300 {
301 if (ffgkyjj(fptr, keyname, &longval, comm, status) <= 0)
302 {
303 if (longval > UCHAR_MAX || longval < 0)
304 *status = NUM_OVERFLOW;
305 else
306 *(unsigned char *) value = (unsigned char) longval;
307 }
308 }
309 else if (datatype == TSBYTE)
310 {
311 if (ffgkyjj(fptr, keyname, &longval, comm, status) <= 0)
312 {
313 if (longval > 127 || longval < -128)
314 *status = NUM_OVERFLOW;
315 else
316 *(signed char *) value = (signed char) longval;
317 }
318 }
319 else if (datatype == TUSHORT)
320 {
321 if (ffgkyjj(fptr, keyname, &longval, comm, status) <= 0)
322 {
323 if (longval > (long) USHRT_MAX || longval < 0)
324 *status = NUM_OVERFLOW;
325 else
326 *(unsigned short *) value = (unsigned short) longval;
327 }
328 }
329 else if (datatype == TSHORT)
330 {
331 if (ffgkyjj(fptr, keyname, &longval, comm, status) <= 0)
332 {
333 if (longval > SHRT_MAX || longval < SHRT_MIN)
334 *status = NUM_OVERFLOW;
335 else
336 *(short *) value = (short) longval;
337 }
338 }
339 else if (datatype == TUINT)
340 {
341 if (ffgkyjj(fptr, keyname, &longval, comm, status) <= 0)
342 {
343 if (longval > (long) UINT_MAX || longval < 0)
344 *status = NUM_OVERFLOW;
345 else
346 *(unsigned int *) value = longval;
347 }
348 }
349 else if (datatype == TINT)
350 {
351 if (ffgkyjj(fptr, keyname, &longval, comm, status) <= 0)
352 {
353 if (longval > INT_MAX || longval < INT_MIN)
354 *status = NUM_OVERFLOW;
355 else
356 *(int *) value = longval;
357 }
358 }
359 else if (datatype == TLOGICAL)
360 {
361 ffgkyl(fptr, keyname, (int *) value, comm, status);
362 }
363 else if (datatype == TULONG)
364 {
365 if (ffgkyujj(fptr, keyname, &ulongval, comm, status) <= 0)
366 {
367 if (ulongval > ULONG_MAX)
368 *status = NUM_OVERFLOW;
369 else
370 *(unsigned long *) value = ulongval;
371 }
372 }
373 else if (datatype == TLONG)
374 {
375 if (ffgkyjj(fptr, keyname, &longval, comm, status) <= 0)
376 {
377 if (longval > LONG_MAX || longval < LONG_MIN)
378 *status = NUM_OVERFLOW;
379 else
380 *(int *) value = longval;
381 }
382 ffgkyj(fptr, keyname, (long *) value, comm, status);
383 }
384 else if (datatype == TULONGLONG)
385 {
386 ffgkyujj(fptr, keyname, (ULONGLONG *) value, comm, status);
387 }
388 else if (datatype == TLONGLONG)
389 {
390 ffgkyjj(fptr, keyname, (LONGLONG *) value, comm, status);
391 }
392 else if (datatype == TFLOAT)
393 {
394 ffgkye(fptr, keyname, (float *) value, comm, status);
395 }
396 else if (datatype == TDOUBLE)
397 {
398 ffgkyd(fptr, keyname, (double *) value, comm, status);
399 }
400 else if (datatype == TCOMPLEX)
401 {
402 ffgkyc(fptr, keyname, (float *) value, comm, status);
403 }
404 else if (datatype == TDBLCOMPLEX)
405 {
406 ffgkym(fptr, keyname, (double *) value, comm, status);
407 }
408 else
409 *status = BAD_DATATYPE;
410
411 return(*status);
412 }
413 /*--------------------------------------------------------------------------*/
ffgkey(fitsfile * fptr,const char * keyname,char * keyval,char * comm,int * status)414 int ffgkey( fitsfile *fptr, /* I - FITS file pointer */
415 const char *keyname, /* I - name of keyword to read */
416 char *keyval, /* O - keyword value */
417 char *comm, /* O - keyword comment */
418 int *status) /* IO - error status */
419 /*
420 Read (get) the named keyword, returning the keyword value and comment.
421 The value is just the literal string of characters in the value field
422 of the keyword. In the case of a string valued keyword, the returned
423 value includes the leading and closing quote characters. The value may be
424 up to 70 characters long, and the comment may be up to 72 characters long.
425 If the keyword has no value (no equal sign in column 9) then a null value
426 is returned.
427 */
428 {
429 char card[FLEN_CARD];
430
431 keyval[0] = '\0';
432 if (comm)
433 comm[0] = '\0';
434
435 if (*status > 0)
436 return(*status);
437
438 if (ffgcrd(fptr, keyname, card, status) > 0) /* get the 80-byte card */
439 return(*status);
440
441 ffpsvc(card, keyval, comm, status); /* parse the value and comment */
442
443 return(*status);
444 }
445 /*--------------------------------------------------------------------------*/
ffgrec(fitsfile * fptr,int nrec,char * card,int * status)446 int ffgrec( fitsfile *fptr, /* I - FITS file pointer */
447 int nrec, /* I - number of keyword to read */
448 char *card, /* O - keyword card */
449 int *status) /* IO - error status */
450 /*
451 Read (get) the nrec-th keyword, returning the entire keyword card up to
452 80 characters long. The first keyword in the header has nrec = 1, not 0.
453 The returned card value is null terminated with any trailing blank
454 characters removed. If nrec = 0, then this routine simply moves the
455 current header pointer to the top of the header.
456 */
457 {
458 if (*status > 0)
459 return(*status);
460
461 if (nrec == 0)
462 {
463 ffmaky(fptr, 1, status); /* simply move to beginning of header */
464 if (card)
465 card[0] = '\0'; /* and return null card */
466 }
467 else if (nrec > 0)
468 {
469 ffmaky(fptr, nrec, status);
470 ffgnky(fptr, card, status);
471 }
472
473 return(*status);
474 }
475 /*--------------------------------------------------------------------------*/
ffgcrd(fitsfile * fptr,const char * name,char * card,int * status)476 int ffgcrd( fitsfile *fptr, /* I - FITS file pointer */
477 const char *name, /* I - name of keyword to read */
478 char *card, /* O - keyword card */
479 int *status) /* IO - error status */
480 /*
481 Read (get) the named keyword, returning the entire keyword card up to
482 80 characters long.
483 The returned card value is null terminated with any trailing blank
484 characters removed.
485
486 If the input name contains wild cards ('?' matches any single char
487 and '*' matches any sequence of chars, # matches any string of decimal
488 digits) then the search ends once the end of header is reached and does
489 not automatically resume from the top of the header.
490 */
491 {
492 int nkeys, nextkey, ntodo, namelen, namelen_limit, namelenminus1, cardlen;
493 int ii = 0, jj, kk, wild, match, exact, hier = 0;
494 char keyname[FLEN_KEYWORD], cardname[FLEN_KEYWORD];
495 char *ptr1, *ptr2, *gotstar;
496
497 if (*status > 0)
498 return(*status);
499
500 *keyname = '\0';
501
502 while (name[ii] == ' ') /* skip leading blanks in name */
503 ii++;
504
505 strncat(keyname, &name[ii], FLEN_KEYWORD - 1);
506
507 namelen = strlen(keyname);
508
509 while (namelen > 0 && keyname[namelen - 1] == ' ')
510 namelen--; /* ignore trailing blanks in name */
511
512 keyname[namelen] = '\0'; /* terminate the name */
513
514 for (ii=0; ii < namelen; ii++)
515 keyname[ii] = toupper(keyname[ii]); /* make upper case */
516
517 if (FSTRNCMP("HIERARCH", keyname, 8) == 0)
518 {
519 if (namelen == 8)
520 {
521 /* special case: just looking for any HIERARCH keyword */
522 hier = 1;
523 }
524 else
525 {
526 /* ignore the leading HIERARCH and look for the 'real' name */
527 /* starting with first non-blank character following HIERARCH */
528 ptr1 = keyname;
529 ptr2 = &keyname[8];
530
531 while(*ptr2 == ' ')
532 ptr2++;
533
534 namelen = 0;
535 while(*ptr2)
536 {
537 *ptr1 = *ptr2;
538 ptr1++;
539 ptr2++;
540 namelen++;
541 }
542 *ptr1 = '\0';
543 }
544 }
545
546 /* does input name contain wild card chars? ('?', '*', or '#') */
547 /* wild cards are currently not supported with HIERARCH keywords */
548
549 namelen_limit = namelen;
550 gotstar = 0;
551 if (namelen < 9 &&
552 (strchr(keyname,'?') || (gotstar = strchr(keyname,'*')) ||
553 strchr(keyname,'#')) )
554 {
555 wild = 1;
556
557 /* if we found a '*' wild card in the name, there might be */
558 /* more than one. Support up to 2 '*' in the template. */
559 /* Thus we need to compare keywords whose names have at least */
560 /* namelen - 2 characters. */
561 if (gotstar)
562 namelen_limit -= 2;
563 }
564 else
565 wild = 0;
566
567 ffghps(fptr, &nkeys, &nextkey, status); /* get no. keywords and position */
568
569 namelenminus1 = maxvalue(namelen - 1, 1);
570 ntodo = nkeys - nextkey + 1; /* first, read from next keyword to end */
571 for (jj=0; jj < 2; jj++)
572 {
573 for (kk = 0; kk < ntodo; kk++)
574 {
575 ffgnky(fptr, card, status); /* get next keyword */
576
577 if (hier)
578 {
579 if (FSTRNCMP("HIERARCH", card, 8) == 0)
580 return(*status); /* found a HIERARCH keyword */
581 }
582 else
583 {
584 ffgknm(card, cardname, &cardlen, status); /* get the keyword name */
585
586 if (cardlen >= namelen_limit) /* can't match if card < name */
587 {
588 /* if there are no wild cards, lengths must be the same */
589 if (!( !wild && cardlen != namelen) )
590 {
591 for (ii=0; ii < cardlen; ii++)
592 {
593 /* make sure keyword is in uppercase */
594 if (cardname[ii] > 96)
595 {
596 /* This assumes the ASCII character set in which */
597 /* upper case characters start at ASCII(97) */
598 /* Timing tests showed that this is 20% faster */
599 /* than calling the isupper function. */
600
601 cardname[ii] = toupper(cardname[ii]); /* make upper case */
602 }
603 }
604
605 if (wild)
606 {
607 ffcmps(keyname, cardname, 1, &match, &exact);
608 if (match)
609 return(*status); /* found a matching keyword */
610 }
611 else if (keyname[namelenminus1] == cardname[namelenminus1])
612 {
613 /* test the last character of the keyword name first, on */
614 /* the theory that it is less likely to match then the first */
615 /* character since many keywords begin with 'T', for example */
616
617 if (FSTRNCMP(keyname, cardname, namelenminus1) == 0)
618 {
619 return(*status); /* found the matching keyword */
620 }
621 }
622 else if (namelen == 0 && cardlen == 0)
623 {
624 /* matched a blank keyword */
625 return(*status);
626 }
627 }
628 }
629 }
630 }
631
632 if (wild || jj == 1)
633 break; /* stop at end of header if template contains wildcards */
634
635 ffmaky(fptr, 1, status); /* reset pointer to beginning of header */
636 ntodo = nextkey - 1; /* number of keyword to read */
637 }
638
639 return(*status = KEY_NO_EXIST); /* couldn't find the keyword */
640 }
641 /*--------------------------------------------------------------------------*/
ffgstr(fitsfile * fptr,const char * string,char * card,int * status)642 int ffgstr( fitsfile *fptr, /* I - FITS file pointer */
643 const char *string, /* I - string to match */
644 char *card, /* O - keyword card */
645 int *status) /* IO - error status */
646 /*
647 Read (get) the next keyword record that contains the input character string,
648 returning the entire keyword card up to 80 characters long.
649 The returned card value is null terminated with any trailing blank
650 characters removed.
651 */
652 {
653 int nkeys, nextkey, ntodo, stringlen;
654 int jj, kk;
655
656 if (*status > 0)
657 return(*status);
658
659 stringlen = strlen(string);
660 if (stringlen > 80) {
661 return(*status = KEY_NO_EXIST); /* matching string is too long to exist */
662 }
663
664 ffghps(fptr, &nkeys, &nextkey, status); /* get no. keywords and position */
665 ntodo = nkeys - nextkey + 1; /* first, read from next keyword to end */
666
667 for (jj=0; jj < 2; jj++)
668 {
669 for (kk = 0; kk < ntodo; kk++)
670 {
671 ffgnky(fptr, card, status); /* get next keyword */
672 if (strstr(card, string) != 0) {
673 return(*status); /* found the matching string */
674 }
675 }
676
677 ffmaky(fptr, 1, status); /* reset pointer to beginning of header */
678 ntodo = nextkey - 1; /* number of keyword to read */
679 }
680
681 return(*status = KEY_NO_EXIST); /* couldn't find the keyword */
682 }
683 /*--------------------------------------------------------------------------*/
ffgknm(char * card,char * name,int * length,int * status)684 int ffgknm( char *card, /* I - keyword card */
685 char *name, /* O - name of the keyword */
686 int *length, /* O - length of the keyword name */
687 int *status) /* IO - error status */
688
689 /*
690 Return the name of the keyword, and the name length. This supports the
691 ESO HIERARCH convention where keyword names may be > 8 characters long.
692 */
693 {
694 char *ptr1, *ptr2;
695 int ii, namelength;
696
697 namelength = FLEN_KEYWORD - 1;
698 *name = '\0';
699 *length = 0;
700
701 /* support for ESO HIERARCH keywords; find the '=' */
702 if (FSTRNCMP(card, "HIERARCH ", 9) == 0)
703 {
704 ptr2 = strchr(card, '=');
705
706 if (!ptr2) /* no value indicator ??? */
707 {
708 /* this probably indicates an error, so just return FITS name */
709 strcat(name, "HIERARCH");
710 *length = 8;
711 return(*status);
712 }
713
714 /* find the start and end of the HIERARCH name */
715 ptr1 = &card[9];
716 while (*ptr1 == ' ') /* skip spaces */
717 ptr1++;
718
719 strncat(name, ptr1, ptr2 - ptr1);
720 ii = ptr2 - ptr1;
721
722 while (ii > 0 && name[ii - 1] == ' ') /* remove trailing spaces */
723 ii--;
724
725 name[ii] = '\0';
726 *length = ii;
727 }
728 else
729 {
730 for (ii = 0; ii < namelength; ii++)
731 {
732 /* look for string terminator, or a blank */
733 if (*(card+ii) != ' ' && *(card+ii) != '=' && *(card+ii) !='\0')
734 {
735 *(name+ii) = *(card+ii);
736 }
737 else
738 {
739 name[ii] = '\0';
740 *length = ii;
741 return(*status);
742 }
743 }
744
745 /* if we got here, keyword is namelength characters long */
746 name[namelength] = '\0';
747 *length = namelength;
748 }
749
750 return(*status);
751 }
752 /*--------------------------------------------------------------------------*/
ffgunt(fitsfile * fptr,const char * keyname,char * unit,int * status)753 int ffgunt( fitsfile *fptr, /* I - FITS file pointer */
754 const char *keyname, /* I - name of keyword to read */
755 char *unit, /* O - keyword units */
756 int *status) /* IO - error status */
757 /*
758 Read (get) the units string from the comment field of the existing
759 keyword. This routine uses a local FITS convention (not defined in the
760 official FITS standard) in which the units are enclosed in
761 square brackets following the '/' comment field delimiter, e.g.:
762
763 KEYWORD = 12 / [kpc] comment string goes here
764 */
765 {
766 char valstring[FLEN_VALUE];
767 char comm[FLEN_COMMENT];
768 char *loc;
769
770 if (*status > 0)
771 return(*status);
772
773 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
774
775 if (comm[0] == '[')
776 {
777 loc = strchr(comm, ']'); /* find the closing bracket */
778 if (loc)
779 *loc = '\0'; /* terminate the string */
780
781 strcpy(unit, &comm[1]); /* copy the string */
782 }
783 else
784 unit[0] = '\0';
785
786 return(*status);
787 }
788 /*--------------------------------------------------------------------------*/
ffgkys(fitsfile * fptr,const char * keyname,char * value,char * comm,int * status)789 int ffgkys( fitsfile *fptr, /* I - FITS file pointer */
790 const char *keyname, /* I - name of keyword to read */
791 char *value, /* O - keyword value */
792 char *comm, /* O - keyword comment */
793 int *status) /* IO - error status */
794 /*
795 Get KeYword with a String value:
796 Read (get) a simple string valued keyword. The returned value may be up to
797 68 chars long ( + 1 null terminator char). The routine does not support the
798 HEASARC convention for continuing long string values over multiple keywords.
799 The ffgkls routine may be used to read long continued strings. The returned
800 comment string may be up to 69 characters long (including null terminator).
801 */
802 {
803 char valstring[FLEN_VALUE];
804
805 if (*status > 0)
806 return(*status);
807
808 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
809 value[0] = '\0';
810 ffc2s(valstring, value, status); /* remove quotes from string */
811
812 return(*status);
813 }
814 /*--------------------------------------------------------------------------*/
ffgksl(fitsfile * fptr,const char * keyname,int * length,int * status)815 int ffgksl( fitsfile *fptr, /* I - FITS file pointer */
816 const char *keyname, /* I - name of keyword to read */
817 int *length, /* O - length of the string value */
818 int *status) /* IO - error status */
819 /*
820 Get the length of the keyword value string.
821 This routine explicitly supports the CONTINUE convention for long string values.
822 */
823 {
824 char valstring[FLEN_VALUE], value[FLEN_VALUE];
825 int position, contin, len;
826
827 if (*status > 0)
828 return(*status);
829
830 ffgkey(fptr, keyname, valstring, NULL, status); /* read the keyword */
831
832 if (*status > 0)
833 return(*status);
834
835 ffghps(fptr, NULL, &position, status); /* save the current header position */
836
837 if (!valstring[0]) { /* null value string? */
838 *length = 0;
839 } else {
840 ffc2s(valstring, value, status); /* in case string contains "/" char */
841 *length = strlen(value);
842
843 /* If last character is a & then value may be continued on next keyword */
844 contin = 1;
845 while (contin)
846 {
847 len = strlen(value);
848
849 if (len && *(value+len-1) == '&') /* is last char an anpersand? */
850 {
851 ffgcnt(fptr, value, NULL, status);
852 if (*value) /* a null valstring indicates no continuation */
853 {
854 *length += strlen(value) - 1;
855 }
856 else
857 {
858 contin = 0;
859 }
860 }
861 else
862 {
863 contin = 0;
864 }
865 }
866 }
867
868 ffmaky(fptr, position - 1, status); /* reset header pointer to the keyword */
869 /* since in many cases the program will read */
870 /* the string value after getting the length */
871
872 return(*status);
873 }
874 /*--------------------------------------------------------------------------*/
ffgkls(fitsfile * fptr,const char * keyname,char ** value,char * comm,int * status)875 int ffgkls( fitsfile *fptr, /* I - FITS file pointer */
876 const char *keyname, /* I - name of keyword to read */
877 char **value, /* O - pointer to keyword value */
878 char *comm, /* O - keyword comment (may be NULL) */
879 int *status) /* IO - error status */
880 /*
881 This is the original routine for reading long string keywords that use
882 the CONTINUE keyword convention. In 2016 a new routine called
883 ffgsky / fits_read_string_key was added, which may provide a more
884 convenient user interface for most applications.
885
886 Get Keyword with possible Long String value:
887 Read (get) the named keyword, returning the value and comment.
888 The returned value string may be arbitrarily long (by using the HEASARC
889 convention for continuing long string values over multiple keywords) so
890 this routine allocates the required memory for the returned string value.
891 It is up to the calling routine to free the memory once it is finished
892 with the value string. The returned comment string may be up to 69
893 characters long.
894 */
895 {
896 char valstring[FLEN_VALUE], nextcomm[FLEN_COMMENT];
897 int contin, commspace = 0;
898 size_t len;
899
900 if (*status > 0)
901 return(*status);
902
903 *value = NULL; /* initialize a null pointer in case of error */
904
905 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
906
907 if (*status > 0)
908 return(*status);
909
910 if (comm)
911 {
912 /* remaining space in comment string */
913 commspace = FLEN_COMMENT - strlen(comm) - 2;
914 }
915
916 if (!valstring[0]) /* null value string? */
917 {
918 *value = (char *) malloc(1); /* allocate and return a null string */
919 **value = '\0';
920 }
921 else
922 {
923 /* allocate space, plus 1 for null */
924 *value = (char *) malloc(strlen(valstring) + 1);
925
926 ffc2s(valstring, *value, status); /* convert string to value */
927 len = strlen(*value);
928
929 /* If last character is a & then value may be continued on next keyword */
930 contin = 1;
931 while (contin)
932 {
933 if (len && *(*value+len-1) == '&') /* is last char an ampersand? */
934 {
935 ffgcnt(fptr, valstring, nextcomm, status);
936 if (*valstring) /* a null valstring indicates no continuation */
937 {
938 *(*value+len-1) = '\0'; /* erase the trailing & char */
939 len += strlen(valstring) - 1;
940 *value = (char *) realloc(*value, len + 1); /* increase size */
941 strcat(*value, valstring); /* append the continued chars */
942 }
943 else
944 {
945 contin = 0;
946 /* Without this, for case of a last CONTINUE statement ending
947 with a '&', nextcomm would retain the same string from
948 from the previous loop iteration and the comment
949 would get concantenated twice. */
950 nextcomm[0] = 0;
951 }
952
953 /* concantenate comment strings (if any) */
954 if ((commspace > 0) && (*nextcomm != 0))
955 {
956 strcat(comm, " ");
957 strncat(comm, nextcomm, commspace);
958 commspace = FLEN_COMMENT - strlen(comm) - 2;
959 }
960 }
961 else
962 {
963 contin = 0;
964 }
965 }
966 }
967 return(*status);
968 }
969 /*--------------------------------------------------------------------------*/
ffgsky(fitsfile * fptr,const char * keyname,int firstchar,int maxchar,char * value,int * valuelen,char * comm,int * status)970 int ffgsky( fitsfile *fptr, /* I - FITS file pointer */
971 const char *keyname, /* I - name of keyword to read */
972 int firstchar, /* I - first character of string to return */
973 int maxchar, /* I - maximum length of string to return */
974 /* (string will be null terminated) */
975 char *value, /* O - pointer to keyword value */
976 int *valuelen, /* O - total length of the keyword value string */
977 /* The returned 'value' string may only */
978 /* contain a piece of the total string, depending */
979 /* on the value of firstchar and maxchar */
980 char *comm, /* O - keyword comment (may be NULL) */
981 int *status) /* IO - error status */
982 /*
983 Read and return the value of the specified string-valued keyword.
984
985 This new routine was added in 2016 to provide a more convenient user
986 interface than the older ffgkls routine.
987
988 Read a string keyword, returning up to 'naxchars' characters of the value
989 starting with the 'firstchar' character.
990 The input 'value' string must be allocated at least 1 char bigger to
991 allow for the terminating null character.
992
993 This routine may be used to read continued string keywords that use
994 the CONTINUE keyword convention, as well as normal string keywords
995 that are contained within a single header record.
996
997 This routine differs from the ffkls routine in that it does not
998 internally allocate memory for the returned value string, and consequently
999 the calling routine does not need to call fffree to free the memory.
1000 */
1001 {
1002 char valstring[FLEN_VALUE], nextcomm[FLEN_COMMENT];
1003 char *tempstring;
1004 int contin, commspace = 0;
1005 size_t len;
1006
1007 if (*status > 0)
1008 return(*status);
1009
1010 tempstring = NULL; /* initialize in case of error */
1011 *value = '\0';
1012 if (valuelen) *valuelen = 0;
1013
1014 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1015
1016 if (*status > 0)
1017 return(*status);
1018
1019 if (comm)
1020 {
1021 /* remaining space in comment string */
1022 commspace = FLEN_COMMENT - strlen(comm) - 2;
1023 }
1024
1025 if (!valstring[0]) /* null value string? */
1026 {
1027 tempstring = (char *) malloc(1); /* allocate and return a null string */
1028 *tempstring = '\0';
1029 }
1030 else
1031 {
1032 /* allocate space, plus 1 for null */
1033 tempstring = (char *) malloc(strlen(valstring) + 1);
1034
1035 ffc2s(valstring, tempstring, status); /* convert string to value */
1036 len = strlen(tempstring);
1037
1038 /* If last character is a & then value may be continued on next keyword */
1039 contin = 1;
1040 while (contin && *status <= 0)
1041 {
1042 if (len && *(tempstring+len-1) == '&') /* is last char an anpersand? */
1043 {
1044 ffgcnt(fptr, valstring, nextcomm, status);
1045 if (*valstring) /* a null valstring indicates no continuation */
1046 {
1047 *(tempstring+len-1) = '\0'; /* erase the trailing & char */
1048 len += strlen(valstring) - 1;
1049 tempstring = (char *) realloc(tempstring, len + 1); /* increase size */
1050 strcat(tempstring, valstring); /* append the continued chars */
1051 }
1052 else
1053 {
1054 contin = 0;
1055 /* Without this, for case of a last CONTINUE statement ending
1056 with a '&', nextcomm would retain the same string from
1057 from the previous loop iteration and the comment
1058 would get concantenated twice. */
1059 nextcomm[0] = 0;
1060 }
1061
1062 /* concantenate comment strings (if any) */
1063 if ((commspace > 0) && (*nextcomm != 0))
1064 {
1065 strcat(comm, " ");
1066 strncat(comm, nextcomm, commspace);
1067 commspace = FLEN_COMMENT - strlen(comm) - 2;
1068 }
1069 }
1070 else
1071 {
1072 contin = 0;
1073 }
1074 }
1075 }
1076
1077 if (tempstring)
1078 {
1079 len = strlen(tempstring);
1080 if (firstchar <= len)
1081 strncat(value, tempstring + (firstchar - 1), maxchar);
1082 free(tempstring);
1083 if (valuelen) *valuelen = len; /* total length of the keyword value */
1084 }
1085
1086 return(*status);
1087 }
1088 /*--------------------------------------------------------------------------*/
fffree(void * value,int * status)1089 int fffree( void *value, /* I - pointer to keyword value */
1090 int *status) /* IO - error status */
1091 /*
1092 Free the memory that was previously allocated by CFITSIO,
1093 such as by ffgkls or fits_hdr2str
1094 */
1095 {
1096 if (*status > 0)
1097 return(*status);
1098
1099 if (value)
1100 free(value);
1101
1102 return(*status);
1103 }
1104 /*--------------------------------------------------------------------------*/
ffgcnt(fitsfile * fptr,char * value,char * comm,int * status)1105 int ffgcnt( fitsfile *fptr, /* I - FITS file pointer */
1106 char *value, /* O - continued string value */
1107 char *comm, /* O - continued comment string */
1108 int *status) /* IO - error status */
1109 /*
1110 Attempt to read the next keyword, returning the string value
1111 if it is a continuation of the previous string keyword value.
1112 This uses the HEASARC convention for continuing long string values
1113 over multiple keywords. Each continued string is terminated with a
1114 backslash character, and the continuation follows on the next keyword
1115 which must have the name CONTINUE without an equal sign in column 9
1116 of the card. If the next card is not a continuation, then the returned
1117 value string will be null.
1118 */
1119 {
1120 int tstatus;
1121 char card[FLEN_CARD], strval[FLEN_VALUE];
1122
1123 if (*status > 0)
1124 return(*status);
1125
1126 tstatus = 0;
1127 value[0] = '\0';
1128
1129 if (ffgnky(fptr, card, &tstatus) > 0) /* read next keyword */
1130 return(*status); /* hit end of header */
1131
1132 if (strncmp(card, "CONTINUE ", 10) == 0) /* a continuation card? */
1133 {
1134 strncpy(card, "D2345678= ", 10); /* overwrite a dummy keyword name */
1135 ffpsvc(card, strval, comm, &tstatus); /* get the string value & comment */
1136 ffc2s(strval, value, &tstatus); /* remove the surrounding quotes */
1137
1138 if (tstatus) /* return null if error status was returned */
1139 value[0] = '\0';
1140 }
1141 else
1142 ffmrky(fptr, -1, status); /* reset the keyword pointer */
1143
1144 return(*status);
1145 }
1146 /*--------------------------------------------------------------------------*/
ffgkyl(fitsfile * fptr,const char * keyname,int * value,char * comm,int * status)1147 int ffgkyl( fitsfile *fptr, /* I - FITS file pointer */
1148 const char *keyname, /* I - name of keyword to read */
1149 int *value, /* O - keyword value */
1150 char *comm, /* O - keyword comment */
1151 int *status) /* IO - error status */
1152 /*
1153 Read (get) the named keyword, returning the value and comment.
1154 The returned value = 1 if the keyword is true, else = 0 if false.
1155 The comment may be up to 69 characters long.
1156 */
1157 {
1158 char valstring[FLEN_VALUE];
1159
1160 if (*status > 0)
1161 return(*status);
1162
1163 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1164 ffc2l(valstring, value, status); /* convert string to value */
1165
1166 return(*status);
1167 }
1168 /*--------------------------------------------------------------------------*/
ffgkyj(fitsfile * fptr,const char * keyname,long * value,char * comm,int * status)1169 int ffgkyj( fitsfile *fptr, /* I - FITS file pointer */
1170 const char *keyname, /* I - name of keyword to read */
1171 long *value, /* O - keyword value */
1172 char *comm, /* O - keyword comment */
1173 int *status) /* IO - error status */
1174 /*
1175 Read (get) the named keyword, returning the value and comment.
1176 The value will be implicitly converted to a (long) integer if it not
1177 already of this datatype. The comment may be up to 69 characters long.
1178 */
1179 {
1180 char valstring[FLEN_VALUE];
1181
1182 if (*status > 0)
1183 return(*status);
1184
1185 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1186 ffc2i(valstring, value, status); /* convert string to value */
1187
1188 return(*status);
1189 }
1190 /*--------------------------------------------------------------------------*/
ffgkyjj(fitsfile * fptr,const char * keyname,LONGLONG * value,char * comm,int * status)1191 int ffgkyjj( fitsfile *fptr, /* I - FITS file pointer */
1192 const char *keyname, /* I - name of keyword to read */
1193 LONGLONG *value, /* O - keyword value */
1194 char *comm, /* O - keyword comment */
1195 int *status) /* IO - error status */
1196 /*
1197 Read (get) the named keyword, returning the value and comment.
1198 The value will be implicitly converted to a (LONGLONG) integer if it not
1199 already of this datatype. The comment may be up to 69 characters long.
1200 */
1201 {
1202 char valstring[FLEN_VALUE];
1203
1204 if (*status > 0)
1205 return(*status);
1206
1207 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1208 ffc2j(valstring, value, status); /* convert string to value */
1209
1210 return(*status);
1211 }
1212 /*--------------------------------------------------------------------------*/
ffgkyujj(fitsfile * fptr,const char * keyname,ULONGLONG * value,char * comm,int * status)1213 int ffgkyujj( fitsfile *fptr, /* I - FITS file pointer */
1214 const char *keyname, /* I - name of keyword to read */
1215 ULONGLONG *value, /* O - keyword value */
1216 char *comm, /* O - keyword comment */
1217 int *status) /* IO - error status */
1218 /*
1219 Read (get) the named keyword, returning the value and comment.
1220 The value will be implicitly converted to a (ULONGLONG) integer if it not
1221 already of this datatype. The comment may be up to 69 characters long.
1222 */
1223 {
1224 char valstring[FLEN_VALUE];
1225
1226 if (*status > 0)
1227 return(*status);
1228
1229 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1230 ffc2uj(valstring, value, status); /* convert string to value */
1231
1232 return(*status);
1233 }
1234 /*--------------------------------------------------------------------------*/
ffgkye(fitsfile * fptr,const char * keyname,float * value,char * comm,int * status)1235 int ffgkye( fitsfile *fptr, /* I - FITS file pointer */
1236 const char *keyname, /* I - name of keyword to read */
1237 float *value, /* O - keyword value */
1238 char *comm, /* O - keyword comment */
1239 int *status) /* IO - error status */
1240 /*
1241 Read (get) the named keyword, returning the value and comment.
1242 The value will be implicitly converted to a float if it not
1243 already of this datatype. The comment may be up to 69 characters long.
1244 */
1245 {
1246 char valstring[FLEN_VALUE];
1247
1248 if (*status > 0)
1249 return(*status);
1250
1251 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1252 ffc2r(valstring, value, status); /* convert string to value */
1253
1254 return(*status);
1255 }
1256 /*--------------------------------------------------------------------------*/
ffgkyd(fitsfile * fptr,const char * keyname,double * value,char * comm,int * status)1257 int ffgkyd( fitsfile *fptr, /* I - FITS file pointer */
1258 const char *keyname, /* I - name of keyword to read */
1259 double *value, /* O - keyword value */
1260 char *comm, /* O - keyword comment */
1261 int *status) /* IO - error status */
1262 /*
1263 Read (get) the named keyword, returning the value and comment.
1264 The value will be implicitly converted to a double if it not
1265 already of this datatype. The comment may be up to 69 characters long.
1266 */
1267 {
1268 char valstring[FLEN_VALUE];
1269
1270 if (*status > 0)
1271 return(*status);
1272
1273 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1274 ffc2d(valstring, value, status); /* convert string to value */
1275
1276 return(*status);
1277 }
1278 /*--------------------------------------------------------------------------*/
ffgkyc(fitsfile * fptr,const char * keyname,float * value,char * comm,int * status)1279 int ffgkyc( fitsfile *fptr, /* I - FITS file pointer */
1280 const char *keyname, /* I - name of keyword to read */
1281 float *value, /* O - keyword value (real,imag) */
1282 char *comm, /* O - keyword comment */
1283 int *status) /* IO - error status */
1284 /*
1285 Read (get) the named keyword, returning the value and comment.
1286 The keyword must have a complex value. No implicit data conversion
1287 will be performed.
1288 */
1289 {
1290 char valstring[FLEN_VALUE], message[FLEN_ERRMSG];
1291 int len;
1292
1293 if (*status > 0)
1294 return(*status);
1295
1296 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1297
1298 if (valstring[0] != '(' ) /* test that this is a complex keyword */
1299 {
1300 snprintf(message, FLEN_ERRMSG, "keyword %s does not have a complex value (ffgkyc):",
1301 keyname);
1302 ffpmsg(message);
1303 ffpmsg(valstring);
1304 return(*status = BAD_C2F);
1305 }
1306
1307 valstring[0] = ' '; /* delete the opening parenthesis */
1308 len = strcspn(valstring, ")" );
1309 valstring[len] = '\0'; /* delete the closing parenthesis */
1310
1311 len = strcspn(valstring, ",");
1312 valstring[len] = '\0';
1313
1314 ffc2r(valstring, &value[0], status); /* convert the real part */
1315 ffc2r(&valstring[len + 1], &value[1], status); /* convert imag. part */
1316 return(*status);
1317 }
1318 /*--------------------------------------------------------------------------*/
ffgkym(fitsfile * fptr,const char * keyname,double * value,char * comm,int * status)1319 int ffgkym( fitsfile *fptr, /* I - FITS file pointer */
1320 const char *keyname, /* I - name of keyword to read */
1321 double *value, /* O - keyword value (real,imag) */
1322 char *comm, /* O - keyword comment */
1323 int *status) /* IO - error status */
1324 /*
1325 Read (get) the named keyword, returning the value and comment.
1326 The keyword must have a complex value. No implicit data conversion
1327 will be performed.
1328 */
1329 {
1330 char valstring[FLEN_VALUE], message[FLEN_ERRMSG];
1331 int len;
1332
1333 if (*status > 0)
1334 return(*status);
1335
1336 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1337
1338 if (valstring[0] != '(' ) /* test that this is a complex keyword */
1339 {
1340 snprintf(message, FLEN_ERRMSG, "keyword %s does not have a complex value (ffgkym):",
1341 keyname);
1342 ffpmsg(message);
1343 ffpmsg(valstring);
1344 return(*status = BAD_C2D);
1345 }
1346
1347 valstring[0] = ' '; /* delete the opening parenthesis */
1348 len = strcspn(valstring, ")" );
1349 valstring[len] = '\0'; /* delete the closing parenthesis */
1350
1351 len = strcspn(valstring, ",");
1352 valstring[len] = '\0';
1353
1354 ffc2d(valstring, &value[0], status); /* convert the real part */
1355 ffc2d(&valstring[len + 1], &value[1], status); /* convert the imag. part */
1356
1357 return(*status);
1358 }
1359 /*--------------------------------------------------------------------------*/
ffgkyt(fitsfile * fptr,const char * keyname,long * ivalue,double * fraction,char * comm,int * status)1360 int ffgkyt( fitsfile *fptr, /* I - FITS file pointer */
1361 const char *keyname, /* I - name of keyword to read */
1362 long *ivalue, /* O - integer part of keyword value */
1363 double *fraction, /* O - fractional part of keyword value */
1364 char *comm, /* O - keyword comment */
1365 int *status) /* IO - error status */
1366 /*
1367 Read (get) the named keyword, returning the value and comment.
1368 The integer and fractional parts of the value are returned in separate
1369 variables, to allow more numerical precision to be passed. This
1370 effectively passes a 'triple' precision value, with a 4-byte integer
1371 and an 8-byte fraction. The comment may be up to 69 characters long.
1372 */
1373 {
1374 char valstring[FLEN_VALUE];
1375 char *loc;
1376
1377 if (*status > 0)
1378 return(*status);
1379
1380 ffgkey(fptr, keyname, valstring, comm, status); /* read the keyword */
1381
1382 /* read the entire value string as a double, to get the integer part */
1383 ffc2d(valstring, fraction, status);
1384
1385 *ivalue = (long) *fraction;
1386
1387 *fraction = *fraction - *ivalue;
1388
1389 /* see if we need to read the fractional part again with more precision */
1390 /* look for decimal point, without an exponential E or D character */
1391
1392 loc = strchr(valstring, '.');
1393 if (loc)
1394 {
1395 if (!strchr(valstring, 'E') && !strchr(valstring, 'D'))
1396 ffc2d(loc, fraction, status);
1397 }
1398
1399 return(*status);
1400 }
1401 /*--------------------------------------------------------------------------*/
ffgkyn(fitsfile * fptr,int nkey,char * keyname,char * value,char * comm,int * status)1402 int ffgkyn( fitsfile *fptr, /* I - FITS file pointer */
1403 int nkey, /* I - number of the keyword to read */
1404 char *keyname, /* O - name of the keyword */
1405 char *value, /* O - keyword value */
1406 char *comm, /* O - keyword comment */
1407 int *status) /* IO - error status */
1408 /*
1409 Read (get) the nkey-th keyword returning the keyword name, value and comment.
1410 The value is just the literal string of characters in the value field
1411 of the keyword. In the case of a string valued keyword, the returned
1412 value includes the leading and closing quote characters. The value may be
1413 up to 70 characters long, and the comment may be up to 72 characters long.
1414 If the keyword has no value (no equal sign in column 9) then a null value
1415 is returned. If comm = NULL, then do not return the comment string.
1416 */
1417 {
1418 char card[FLEN_CARD], sbuff[FLEN_CARD];
1419 int namelen;
1420
1421 keyname[0] = '\0';
1422 value[0] = '\0';
1423 if (comm)
1424 comm[0] = '\0';
1425
1426 if (*status > 0)
1427 return(*status);
1428
1429 if (ffgrec(fptr, nkey, card, status) > 0 ) /* get the 80-byte card */
1430 return(*status);
1431
1432 ffgknm(card, keyname, &namelen, status); /* get the keyword name */
1433
1434 if (ffpsvc(card, value, comm, status) > 0) /* parse value and comment */
1435 return(*status);
1436
1437 if (fftrec(keyname, status) > 0) /* test keyword name; catches no END */
1438 {
1439 snprintf(sbuff, FLEN_CARD, "Name of keyword no. %d contains illegal character(s): %s",
1440 nkey, keyname);
1441 ffpmsg(sbuff);
1442
1443 if (nkey % 36 == 0) /* test if at beginning of 36-card FITS record */
1444 ffpmsg(" (This may indicate a missing END keyword).");
1445 }
1446 return(*status);
1447 }
1448 /*--------------------------------------------------------------------------*/
ffgkns(fitsfile * fptr,const char * keyname,int nstart,int nmax,char * value[],int * nfound,int * status)1449 int ffgkns( fitsfile *fptr, /* I - FITS file pointer */
1450 const char *keyname, /* I - root name of keywords to read */
1451 int nstart, /* I - starting index number */
1452 int nmax, /* I - maximum number of keywords to return */
1453 char *value[], /* O - array of pointers to keyword values */
1454 int *nfound, /* O - number of values that were returned */
1455 int *status) /* IO - error status */
1456 /*
1457 Read (get) an indexed array of keywords with index numbers between
1458 NSTART and (NSTART + NMAX -1) inclusive.
1459 This routine does NOT support the HEASARC long string convention.
1460 */
1461 {
1462 int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
1463 long ival;
1464 char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
1465 char svalue[FLEN_VALUE], comm[FLEN_COMMENT], *equalssign;
1466
1467 if (*status > 0)
1468 return(*status);
1469
1470 *nfound = 0;
1471 nend = nstart + nmax - 1;
1472
1473 keyroot[0] = '\0';
1474 strncat(keyroot, keyname, FLEN_KEYWORD - 1);
1475
1476 lenroot = strlen(keyroot);
1477
1478 if (lenroot == 0) /* root must be at least 1 char long */
1479 return(*status);
1480
1481 for (ii=0; ii < lenroot; ii++) /* make sure upper case */
1482 keyroot[ii] = toupper(keyroot[ii]);
1483
1484 ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
1485
1486 undefinedval = FALSE;
1487 for (ii=3; ii <= nkeys; ii++)
1488 {
1489 if (ffgrec(fptr, ii, card, status) > 0) /* get next keyword */
1490 return(*status);
1491
1492 if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
1493 {
1494 keyindex[0] = '\0';
1495 equalssign = strchr(card, '=');
1496 if (equalssign == 0) continue; /* keyword has no value */
1497
1498 if (equalssign - card - lenroot > 7)
1499 {
1500 return (*status=BAD_KEYCHAR);
1501 }
1502 strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */
1503 tstatus = 0;
1504 if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
1505 {
1506 if (ival <= nend && ival >= nstart)
1507 {
1508 ffpsvc(card, svalue, comm, status); /* parse the value */
1509 ffc2s(svalue, value[ival-nstart], status); /* convert */
1510 if (ival - nstart + 1 > *nfound)
1511 *nfound = ival - nstart + 1; /* max found */
1512
1513 if (*status == VALUE_UNDEFINED)
1514 {
1515 undefinedval = TRUE;
1516 *status = 0; /* reset status to read remaining values */
1517 }
1518 }
1519 }
1520 }
1521 }
1522 if (undefinedval && (*status <= 0) )
1523 *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
1524
1525 return(*status);
1526 }
1527 /*--------------------------------------------------------------------------*/
ffgknl(fitsfile * fptr,const char * keyname,int nstart,int nmax,int * value,int * nfound,int * status)1528 int ffgknl( fitsfile *fptr, /* I - FITS file pointer */
1529 const char *keyname, /* I - root name of keywords to read */
1530 int nstart, /* I - starting index number */
1531 int nmax, /* I - maximum number of keywords to return */
1532 int *value, /* O - array of keyword values */
1533 int *nfound, /* O - number of values that were returned */
1534 int *status) /* IO - error status */
1535 /*
1536 Read (get) an indexed array of keywords with index numbers between
1537 NSTART and (NSTART + NMAX -1) inclusive.
1538 The returned value = 1 if the keyword is true, else = 0 if false.
1539 */
1540 {
1541 int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
1542 long ival;
1543 char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
1544 char svalue[FLEN_VALUE], comm[FLEN_COMMENT], *equalssign;
1545
1546 if (*status > 0)
1547 return(*status);
1548
1549 *nfound = 0;
1550 nend = nstart + nmax - 1;
1551
1552 keyroot[0] = '\0';
1553 strncat(keyroot, keyname, FLEN_KEYWORD - 1);
1554
1555 lenroot = strlen(keyroot);
1556
1557 if (lenroot == 0) /* root must be at least 1 char long */
1558 return(*status);
1559
1560 for (ii=0; ii < lenroot; ii++) /* make sure upper case */
1561 keyroot[ii] = toupper(keyroot[ii]);
1562
1563 ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
1564
1565 ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
1566
1567 undefinedval = FALSE;
1568 for (ii=3; ii <= nkeys; ii++)
1569 {
1570 if (ffgnky(fptr, card, status) > 0) /* get next keyword */
1571 return(*status);
1572
1573 if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
1574 {
1575 keyindex[0] = '\0';
1576 equalssign = strchr(card, '=');
1577 if (equalssign == 0) continue; /* keyword has no value */
1578
1579 if (equalssign - card - lenroot > 7)
1580 {
1581 return (*status=BAD_KEYCHAR);
1582 }
1583 strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */
1584
1585 tstatus = 0;
1586 if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
1587 {
1588 if (ival <= nend && ival >= nstart)
1589 {
1590 ffpsvc(card, svalue, comm, status); /* parse the value */
1591 ffc2l(svalue, &value[ival-nstart], status); /* convert*/
1592 if (ival - nstart + 1 > *nfound)
1593 *nfound = ival - nstart + 1; /* max found */
1594
1595 if (*status == VALUE_UNDEFINED)
1596 {
1597 undefinedval = TRUE;
1598 *status = 0; /* reset status to read remaining values */
1599 }
1600 }
1601 }
1602 }
1603 }
1604 if (undefinedval && (*status <= 0) )
1605 *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
1606
1607 return(*status);
1608 }
1609 /*--------------------------------------------------------------------------*/
ffgknj(fitsfile * fptr,const char * keyname,int nstart,int nmax,long * value,int * nfound,int * status)1610 int ffgknj( fitsfile *fptr, /* I - FITS file pointer */
1611 const char *keyname, /* I - root name of keywords to read */
1612 int nstart, /* I - starting index number */
1613 int nmax, /* I - maximum number of keywords to return */
1614 long *value, /* O - array of keyword values */
1615 int *nfound, /* O - number of values that were returned */
1616 int *status) /* IO - error status */
1617 /*
1618 Read (get) an indexed array of keywords with index numbers between
1619 NSTART and (NSTART + NMAX -1) inclusive.
1620 */
1621 {
1622 int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
1623 long ival;
1624 char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
1625 char svalue[FLEN_VALUE], comm[FLEN_COMMENT], *equalssign;
1626
1627 if (*status > 0)
1628 return(*status);
1629
1630 *nfound = 0;
1631 nend = nstart + nmax - 1;
1632
1633 keyroot[0] = '\0';
1634 strncat(keyroot, keyname, FLEN_KEYWORD - 1);
1635
1636 lenroot = strlen(keyroot);
1637
1638 if (lenroot == 0) /* root must be at least 1 char long */
1639 return(*status);
1640
1641 for (ii=0; ii < lenroot; ii++) /* make sure upper case */
1642 keyroot[ii] = toupper(keyroot[ii]);
1643
1644 ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
1645
1646 ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
1647
1648 undefinedval = FALSE;
1649 for (ii=3; ii <= nkeys; ii++)
1650 {
1651 if (ffgnky(fptr, card, status) > 0) /* get next keyword */
1652 return(*status);
1653
1654 if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
1655 {
1656 keyindex[0] = '\0';
1657 equalssign = strchr(card, '=');
1658 if (equalssign == 0) continue; /* keyword has no value */
1659
1660 if (equalssign - card - lenroot > 7)
1661 {
1662 return (*status=BAD_KEYCHAR);
1663 }
1664 strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */
1665
1666 tstatus = 0;
1667 if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
1668 {
1669 if (ival <= nend && ival >= nstart)
1670 {
1671 ffpsvc(card, svalue, comm, status); /* parse the value */
1672 ffc2i(svalue, &value[ival-nstart], status); /* convert */
1673 if (ival - nstart + 1 > *nfound)
1674 *nfound = ival - nstart + 1; /* max found */
1675
1676 if (*status == VALUE_UNDEFINED)
1677 {
1678 undefinedval = TRUE;
1679 *status = 0; /* reset status to read remaining values */
1680 }
1681 }
1682 }
1683 }
1684 }
1685 if (undefinedval && (*status <= 0) )
1686 *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
1687
1688 return(*status);
1689 }
1690 /*--------------------------------------------------------------------------*/
ffgknjj(fitsfile * fptr,const char * keyname,int nstart,int nmax,LONGLONG * value,int * nfound,int * status)1691 int ffgknjj( fitsfile *fptr, /* I - FITS file pointer */
1692 const char *keyname, /* I - root name of keywords to read */
1693 int nstart, /* I - starting index number */
1694 int nmax, /* I - maximum number of keywords to return */
1695 LONGLONG *value, /* O - array of keyword values */
1696 int *nfound, /* O - number of values that were returned */
1697 int *status) /* IO - error status */
1698 /*
1699 Read (get) an indexed array of keywords with index numbers between
1700 NSTART and (NSTART + NMAX -1) inclusive.
1701 */
1702 {
1703 int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
1704 long ival;
1705 char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
1706 char svalue[FLEN_VALUE], comm[FLEN_COMMENT], *equalssign;
1707
1708 if (*status > 0)
1709 return(*status);
1710
1711 *nfound = 0;
1712 nend = nstart + nmax - 1;
1713
1714 keyroot[0] = '\0';
1715 strncat(keyroot, keyname, FLEN_KEYWORD - 1);
1716
1717 lenroot = strlen(keyroot);
1718
1719 if (lenroot == 0) /* root must be at least 1 char long */
1720 return(*status);
1721
1722 for (ii=0; ii < lenroot; ii++) /* make sure upper case */
1723 keyroot[ii] = toupper(keyroot[ii]);
1724
1725 ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
1726
1727 ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
1728
1729 undefinedval = FALSE;
1730 for (ii=3; ii <= nkeys; ii++)
1731 {
1732 if (ffgnky(fptr, card, status) > 0) /* get next keyword */
1733 return(*status);
1734
1735 if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
1736 {
1737 keyindex[0] = '\0';
1738 equalssign = strchr(card, '=');
1739 if (equalssign == 0) continue; /* keyword has no value */
1740
1741 if (equalssign - card - lenroot > 7)
1742 {
1743 return (*status=BAD_KEYCHAR);
1744 }
1745 strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */
1746
1747 tstatus = 0;
1748 if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
1749 {
1750 if (ival <= nend && ival >= nstart)
1751 {
1752 ffpsvc(card, svalue, comm, status); /* parse the value */
1753 ffc2j(svalue, &value[ival-nstart], status); /* convert */
1754 if (ival - nstart + 1 > *nfound)
1755 *nfound = ival - nstart + 1; /* max found */
1756
1757 if (*status == VALUE_UNDEFINED)
1758 {
1759 undefinedval = TRUE;
1760 *status = 0; /* reset status to read remaining values */
1761 }
1762 }
1763 }
1764 }
1765 }
1766 if (undefinedval && (*status <= 0) )
1767 *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
1768
1769 return(*status);
1770 }
1771 /*--------------------------------------------------------------------------*/
ffgkne(fitsfile * fptr,const char * keyname,int nstart,int nmax,float * value,int * nfound,int * status)1772 int ffgkne( fitsfile *fptr, /* I - FITS file pointer */
1773 const char *keyname, /* I - root name of keywords to read */
1774 int nstart, /* I - starting index number */
1775 int nmax, /* I - maximum number of keywords to return */
1776 float *value, /* O - array of keyword values */
1777 int *nfound, /* O - number of values that were returned */
1778 int *status) /* IO - error status */
1779 /*
1780 Read (get) an indexed array of keywords with index numbers between
1781 NSTART and (NSTART + NMAX -1) inclusive.
1782 */
1783 {
1784 int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
1785 long ival;
1786 char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
1787 char svalue[FLEN_VALUE], comm[FLEN_COMMENT], *equalssign;
1788
1789 if (*status > 0)
1790 return(*status);
1791
1792 *nfound = 0;
1793 nend = nstart + nmax - 1;
1794
1795 keyroot[0] = '\0';
1796 strncat(keyroot, keyname, FLEN_KEYWORD - 1);
1797
1798 lenroot = strlen(keyroot);
1799
1800 if (lenroot == 0) /* root must be at least 1 char long */
1801 return(*status);
1802
1803 for (ii=0; ii < lenroot; ii++) /* make sure upper case */
1804 keyroot[ii] = toupper(keyroot[ii]);
1805
1806 ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
1807
1808 ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
1809
1810 undefinedval = FALSE;
1811 for (ii=3; ii <= nkeys; ii++)
1812 {
1813 if (ffgnky(fptr, card, status) > 0) /* get next keyword */
1814 return(*status);
1815
1816 if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
1817 {
1818 keyindex[0] = '\0';
1819 equalssign = strchr(card, '=');
1820 if (equalssign == 0) continue; /* keyword has no value */
1821
1822 if (equalssign - card - lenroot > 7)
1823 {
1824 return (*status=BAD_KEYCHAR);
1825 }
1826 strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */
1827
1828 tstatus = 0;
1829 if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
1830 {
1831 if (ival <= nend && ival >= nstart)
1832 {
1833 ffpsvc(card, svalue, comm, status); /* parse the value */
1834 ffc2r(svalue, &value[ival-nstart], status); /* convert */
1835 if (ival - nstart + 1 > *nfound)
1836 *nfound = ival - nstart + 1; /* max found */
1837
1838 if (*status == VALUE_UNDEFINED)
1839 {
1840 undefinedval = TRUE;
1841 *status = 0; /* reset status to read remaining values */
1842 }
1843 }
1844 }
1845 }
1846 }
1847 if (undefinedval && (*status <= 0) )
1848 *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
1849
1850 return(*status);
1851 }
1852 /*--------------------------------------------------------------------------*/
ffgknd(fitsfile * fptr,const char * keyname,int nstart,int nmax,double * value,int * nfound,int * status)1853 int ffgknd( fitsfile *fptr, /* I - FITS file pointer */
1854 const char *keyname, /* I - root name of keywords to read */
1855 int nstart, /* I - starting index number */
1856 int nmax, /* I - maximum number of keywords to return */
1857 double *value, /* O - array of keyword values */
1858 int *nfound, /* O - number of values that were returned */
1859 int *status) /* IO - error status */
1860 /*
1861 Read (get) an indexed array of keywords with index numbers between
1862 NSTART and (NSTART + NMAX -1) inclusive.
1863 */
1864 {
1865 int nend, lenroot, ii, nkeys, mkeys, tstatus, undefinedval;
1866 long ival;
1867 char keyroot[FLEN_KEYWORD], keyindex[8], card[FLEN_CARD];
1868 char svalue[FLEN_VALUE], comm[FLEN_COMMENT], *equalssign;
1869
1870 if (*status > 0)
1871 return(*status);
1872
1873 *nfound = 0;
1874 nend = nstart + nmax - 1;
1875
1876 keyroot[0] = '\0';
1877 strncat(keyroot, keyname, FLEN_KEYWORD - 1);
1878
1879 lenroot = strlen(keyroot);
1880
1881 if (lenroot == 0) /* root must be at least 1 char long */
1882 return(*status);
1883
1884 for (ii=0; ii < lenroot; ii++) /* make sure upper case */
1885 keyroot[ii] = toupper(keyroot[ii]);
1886
1887 ffghps(fptr, &nkeys, &mkeys, status); /* get the number of keywords */
1888
1889 ffmaky(fptr, 3, status); /* move to 3rd keyword (skip 1st 2 keywords) */
1890
1891 undefinedval = FALSE;
1892 for (ii=3; ii <= nkeys; ii++)
1893 {
1894 if (ffgnky(fptr, card, status) > 0) /* get next keyword */
1895 return(*status);
1896 if (strncmp(keyroot, card, lenroot) == 0) /* see if keyword matches */
1897 {
1898 keyindex[0] = '\0';
1899 equalssign = strchr(card, '=');
1900 if (equalssign == 0) continue; /* keyword has no value */
1901
1902 if (equalssign - card - lenroot > 7)
1903 {
1904 return (*status=BAD_KEYCHAR);
1905 }
1906 strncat(keyindex, &card[lenroot], equalssign - card - lenroot); /* copy suffix */
1907 tstatus = 0;
1908 if (ffc2ii(keyindex, &ival, &tstatus) <= 0) /* test suffix */
1909 {
1910 if (ival <= nend && ival >= nstart) /* is index within range? */
1911 {
1912 ffpsvc(card, svalue, comm, status); /* parse the value */
1913 ffc2d(svalue, &value[ival-nstart], status); /* convert */
1914 if (ival - nstart + 1 > *nfound)
1915 *nfound = ival - nstart + 1; /* max found */
1916
1917 if (*status == VALUE_UNDEFINED)
1918 {
1919 undefinedval = TRUE;
1920 *status = 0; /* reset status to read remaining values */
1921 }
1922 }
1923 }
1924 }
1925 }
1926 if (undefinedval && (*status <= 0) )
1927 *status = VALUE_UNDEFINED; /* report at least 1 value undefined */
1928
1929 return(*status);
1930 }
1931 /*--------------------------------------------------------------------------*/
ffgtdm(fitsfile * fptr,int colnum,int maxdim,int * naxis,long naxes[],int * status)1932 int ffgtdm(fitsfile *fptr, /* I - FITS file pointer */
1933 int colnum, /* I - number of the column to read */
1934 int maxdim, /* I - maximum no. of dimensions to read; */
1935 int *naxis, /* O - number of axes in the data array */
1936 long naxes[], /* O - length of each data axis */
1937 int *status) /* IO - error status */
1938 /*
1939 read and parse the TDIMnnn keyword to get the dimensionality of a column
1940 */
1941 {
1942 int tstatus = 0;
1943 char keyname[FLEN_KEYWORD], tdimstr[FLEN_VALUE];
1944
1945 if (*status > 0)
1946 return(*status);
1947
1948 ffkeyn("TDIM", colnum, keyname, status); /* construct keyword name */
1949
1950 ffgkys(fptr, keyname, tdimstr, NULL, &tstatus); /* try reading keyword */
1951
1952 ffdtdm(fptr, tdimstr, colnum, maxdim,naxis, naxes, status); /* decode it */
1953
1954 return(*status);
1955 }
1956 /*--------------------------------------------------------------------------*/
ffgtdmll(fitsfile * fptr,int colnum,int maxdim,int * naxis,LONGLONG naxes[],int * status)1957 int ffgtdmll(fitsfile *fptr, /* I - FITS file pointer */
1958 int colnum, /* I - number of the column to read */
1959 int maxdim, /* I - maximum no. of dimensions to read; */
1960 int *naxis, /* O - number of axes in the data array */
1961 LONGLONG naxes[], /* O - length of each data axis */
1962 int *status) /* IO - error status */
1963 /*
1964 read and parse the TDIMnnn keyword to get the dimensionality of a column
1965 */
1966 {
1967 int tstatus = 0;
1968 char keyname[FLEN_KEYWORD], tdimstr[FLEN_VALUE];
1969
1970 if (*status > 0)
1971 return(*status);
1972
1973 ffkeyn("TDIM", colnum, keyname, status); /* construct keyword name */
1974
1975 ffgkys(fptr, keyname, tdimstr, NULL, &tstatus); /* try reading keyword */
1976
1977 ffdtdmll(fptr, tdimstr, colnum, maxdim,naxis, naxes, status); /* decode it */
1978
1979 return(*status);
1980 }
1981 /*--------------------------------------------------------------------------*/
ffdtdm(fitsfile * fptr,char * tdimstr,int colnum,int maxdim,int * naxis,long naxes[],int * status)1982 int ffdtdm(fitsfile *fptr, /* I - FITS file pointer */
1983 char *tdimstr, /* I - TDIMn keyword value string. e.g. (10,10) */
1984 int colnum, /* I - number of the column */
1985 int maxdim, /* I - maximum no. of dimensions to read; */
1986 int *naxis, /* O - number of axes in the data array */
1987 long naxes[], /* O - length of each data axis */
1988 int *status) /* IO - error status */
1989 /*
1990 decode the TDIMnnn keyword to get the dimensionality of a column.
1991 Check that the value is legal and consistent with the TFORM value.
1992 If colnum = 0, then the validity checking is disabled.
1993 */
1994 {
1995 long dimsize, totalpix = 1;
1996 char *loc, *lastloc, message[FLEN_ERRMSG];
1997 tcolumn *colptr = 0;
1998
1999 if (*status > 0)
2000 return(*status);
2001
2002 if (colnum != 0) {
2003 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
2004 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
2005
2006 if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
2007 return(*status = BAD_COL_NUM);
2008
2009 colptr = (fptr->Fptr)->tableptr; /* set pointer to the first column */
2010 colptr += (colnum - 1); /* increment to the correct column */
2011
2012 if (!tdimstr[0]) /* TDIMn keyword doesn't exist? */
2013 {
2014 *naxis = 1; /* default = 1 dimensional */
2015 if (maxdim > 0)
2016 naxes[0] = (long) colptr->trepeat; /* default length = repeat */
2017
2018 return(*status);
2019 }
2020 }
2021
2022 *naxis = 0;
2023
2024 loc = strchr(tdimstr, '(' ); /* find the opening quote */
2025 if (!loc)
2026 {
2027 snprintf(message, FLEN_ERRMSG, "Illegal dimensions format: %s", tdimstr);
2028 return(*status = BAD_TDIM);
2029 }
2030
2031 while (loc)
2032 {
2033 loc++;
2034 dimsize = strtol(loc, &loc, 10); /* read size of next dimension */
2035 if (*naxis < maxdim)
2036 naxes[*naxis] = dimsize;
2037
2038 if (dimsize < 0)
2039 {
2040 ffpmsg("one or more dimension are less than 0 (ffdtdm)");
2041 ffpmsg(tdimstr);
2042 return(*status = BAD_TDIM);
2043 }
2044
2045 totalpix *= dimsize;
2046 (*naxis)++;
2047 lastloc = loc;
2048 loc = strchr(loc, ','); /* look for comma before next dimension */
2049 }
2050
2051 loc = strchr(lastloc, ')' ); /* check for the closing quote */
2052 if (!loc)
2053 {
2054 snprintf(message, FLEN_ERRMSG, "Illegal dimensions format: %s", tdimstr);
2055 return(*status = BAD_TDIM);
2056 }
2057
2058 if (colnum != 0) {
2059 if ((colptr->tdatatype > 0) && ((long) colptr->trepeat != totalpix))
2060 {
2061 snprintf(message, FLEN_ERRMSG,
2062 "column vector length, %ld, does not equal TDIMn array size, %ld",
2063 (long) colptr->trepeat, totalpix);
2064 ffpmsg(message);
2065 ffpmsg(tdimstr);
2066 return(*status = BAD_TDIM);
2067 }
2068 }
2069 return(*status);
2070 }
2071 /*--------------------------------------------------------------------------*/
ffdtdmll(fitsfile * fptr,char * tdimstr,int colnum,int maxdim,int * naxis,LONGLONG naxes[],int * status)2072 int ffdtdmll(fitsfile *fptr, /* I - FITS file pointer */
2073 char *tdimstr, /* I - TDIMn keyword value string. e.g. (10,10) */
2074 int colnum, /* I - number of the column */
2075 int maxdim, /* I - maximum no. of dimensions to read; */
2076 int *naxis, /* O - number of axes in the data array */
2077 LONGLONG naxes[], /* O - length of each data axis */
2078 int *status) /* IO - error status */
2079 /*
2080 decode the TDIMnnn keyword to get the dimensionality of a column.
2081 Check that the value is legal and consistent with the TFORM value.
2082 */
2083 {
2084 LONGLONG dimsize;
2085 LONGLONG totalpix = 1;
2086 char *loc, *lastloc, message[FLEN_ERRMSG];
2087 tcolumn *colptr;
2088 double doublesize;
2089
2090 if (*status > 0)
2091 return(*status);
2092
2093 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
2094 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
2095
2096 if (colnum < 1 || colnum > (fptr->Fptr)->tfield)
2097 return(*status = BAD_COL_NUM);
2098
2099 colptr = (fptr->Fptr)->tableptr; /* set pointer to the first column */
2100 colptr += (colnum - 1); /* increment to the correct column */
2101
2102 if (!tdimstr[0]) /* TDIMn keyword doesn't exist? */
2103 {
2104 *naxis = 1; /* default = 1 dimensional */
2105 if (maxdim > 0)
2106 naxes[0] = colptr->trepeat; /* default length = repeat */
2107 }
2108 else
2109 {
2110 *naxis = 0;
2111
2112 loc = strchr(tdimstr, '(' ); /* find the opening quote */
2113 if (!loc)
2114 {
2115 snprintf(message, FLEN_ERRMSG, "Illegal TDIM keyword value: %s", tdimstr);
2116 return(*status = BAD_TDIM);
2117 }
2118
2119 while (loc)
2120 {
2121 loc++;
2122
2123 /* Read value as a double because the string to 64-bit int function is */
2124 /* platform dependent (strtoll, strtol, _atoI64). This still gives */
2125 /* about 48 bits of precision, which is plenty for this purpose. */
2126
2127 doublesize = strtod(loc, &loc);
2128 dimsize = (LONGLONG) (doublesize + 0.1);
2129
2130 if (*naxis < maxdim)
2131 naxes[*naxis] = dimsize;
2132
2133 if (dimsize < 0)
2134 {
2135 ffpmsg("one or more TDIM values are less than 0 (ffdtdm)");
2136 ffpmsg(tdimstr);
2137 return(*status = BAD_TDIM);
2138 }
2139
2140 totalpix *= dimsize;
2141 (*naxis)++;
2142 lastloc = loc;
2143 loc = strchr(loc, ','); /* look for comma before next dimension */
2144 }
2145
2146 loc = strchr(lastloc, ')' ); /* check for the closing quote */
2147 if (!loc)
2148 {
2149 snprintf(message, FLEN_ERRMSG, "Illegal TDIM keyword value: %s", tdimstr);
2150 return(*status = BAD_TDIM);
2151 }
2152
2153 if ((colptr->tdatatype > 0) && (colptr->trepeat != totalpix))
2154 {
2155 snprintf(message, FLEN_ERRMSG,
2156 "column vector length, %.0f, does not equal TDIMn array size, %.0f",
2157 (double) (colptr->trepeat), (double) totalpix);
2158 ffpmsg(message);
2159 ffpmsg(tdimstr);
2160 return(*status = BAD_TDIM);
2161 }
2162 }
2163 return(*status);
2164 }
2165 /*--------------------------------------------------------------------------*/
ffghpr(fitsfile * fptr,int maxdim,int * simple,int * bitpix,int * naxis,long naxes[],long * pcount,long * gcount,int * extend,int * status)2166 int ffghpr(fitsfile *fptr, /* I - FITS file pointer */
2167 int maxdim, /* I - maximum no. of dimensions to read; */
2168 int *simple, /* O - does file conform to FITS standard? 1/0 */
2169 int *bitpix, /* O - number of bits per data value pixel */
2170 int *naxis, /* O - number of axes in the data array */
2171 long naxes[], /* O - length of each data axis */
2172 long *pcount, /* O - number of group parameters (usually 0) */
2173 long *gcount, /* O - number of random groups (usually 1 or 0) */
2174 int *extend, /* O - may FITS file haave extensions? */
2175 int *status) /* IO - error status */
2176 /*
2177 Get keywords from the Header of the PRimary array:
2178 Check that the keywords conform to the FITS standard and return the
2179 parameters which determine the size and structure of the primary array
2180 or IMAGE extension.
2181 */
2182 {
2183 int idummy, ii;
2184 LONGLONG lldummy;
2185 double ddummy;
2186 LONGLONG tnaxes[99];
2187
2188 ffgphd(fptr, maxdim, simple, bitpix, naxis, tnaxes, pcount, gcount, extend,
2189 &ddummy, &ddummy, &lldummy, &idummy, status);
2190
2191 if (naxis && naxes) {
2192 for (ii = 0; (ii < *naxis) && (ii < maxdim); ii++)
2193 naxes[ii] = (long) tnaxes[ii];
2194 } else if (naxes) {
2195 for (ii = 0; ii < maxdim; ii++)
2196 naxes[ii] = (long) tnaxes[ii];
2197 }
2198
2199 return(*status);
2200 }
2201 /*--------------------------------------------------------------------------*/
ffghprll(fitsfile * fptr,int maxdim,int * simple,int * bitpix,int * naxis,LONGLONG naxes[],long * pcount,long * gcount,int * extend,int * status)2202 int ffghprll(fitsfile *fptr, /* I - FITS file pointer */
2203 int maxdim, /* I - maximum no. of dimensions to read; */
2204 int *simple, /* O - does file conform to FITS standard? 1/0 */
2205 int *bitpix, /* O - number of bits per data value pixel */
2206 int *naxis, /* O - number of axes in the data array */
2207 LONGLONG naxes[], /* O - length of each data axis */
2208 long *pcount, /* O - number of group parameters (usually 0) */
2209 long *gcount, /* O - number of random groups (usually 1 or 0) */
2210 int *extend, /* O - may FITS file haave extensions? */
2211 int *status) /* IO - error status */
2212 /*
2213 Get keywords from the Header of the PRimary array:
2214 Check that the keywords conform to the FITS standard and return the
2215 parameters which determine the size and structure of the primary array
2216 or IMAGE extension.
2217 */
2218 {
2219 int idummy;
2220 LONGLONG lldummy;
2221 double ddummy;
2222
2223 ffgphd(fptr, maxdim, simple, bitpix, naxis, naxes, pcount, gcount, extend,
2224 &ddummy, &ddummy, &lldummy, &idummy, status);
2225
2226 return(*status);
2227 }
2228 /*--------------------------------------------------------------------------*/
ffghtb(fitsfile * fptr,int maxfield,long * naxis1,long * naxis2,int * tfields,char ** ttype,long * tbcol,char ** tform,char ** tunit,char * extnm,int * status)2229 int ffghtb(fitsfile *fptr, /* I - FITS file pointer */
2230 int maxfield, /* I - maximum no. of columns to read; */
2231 long *naxis1, /* O - length of table row in bytes */
2232 long *naxis2, /* O - number of rows in the table */
2233 int *tfields, /* O - number of columns in the table */
2234 char **ttype, /* O - name of each column */
2235 long *tbcol, /* O - byte offset in row to each column */
2236 char **tform, /* O - value of TFORMn keyword for each column */
2237 char **tunit, /* O - value of TUNITn keyword for each column */
2238 char *extnm, /* O - value of EXTNAME keyword, if any */
2239 int *status) /* IO - error status */
2240 /*
2241 Get keywords from the Header of the ASCII TaBle:
2242 Check that the keywords conform to the FITS standard and return the
2243 parameters which describe the table.
2244 */
2245 {
2246 int ii, maxf, nfound, tstatus;
2247 long fields;
2248 char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
2249 char xtension[FLEN_VALUE], message[FLEN_ERRMSG];
2250 LONGLONG llnaxis1, llnaxis2, pcount;
2251
2252 if (*status > 0)
2253 return(*status);
2254
2255 /* read the first keyword of the extension */
2256 ffgkyn(fptr, 1, name, value, comm, status);
2257
2258 if (!strcmp(name, "XTENSION"))
2259 {
2260 if (ffc2s(value, xtension, status) > 0) /* get the value string */
2261 {
2262 ffpmsg("Bad value string for XTENSION keyword:");
2263 ffpmsg(value);
2264 return(*status);
2265 }
2266
2267 /* allow the quoted string value to begin in any column and */
2268 /* allow any number of trailing blanks before the closing quote */
2269 if ( (value[0] != '\'') || /* first char must be a quote */
2270 ( strcmp(xtension, "TABLE") ) )
2271 {
2272 snprintf(message, FLEN_ERRMSG,
2273 "This is not a TABLE extension: %s", value);
2274 ffpmsg(message);
2275 return(*status = NOT_ATABLE);
2276 }
2277 }
2278
2279 else /* error: 1st keyword of extension != XTENSION */
2280 {
2281 snprintf(message, FLEN_ERRMSG,
2282 "First keyword of the extension is not XTENSION: %s", name);
2283 ffpmsg(message);
2284 return(*status = NO_XTENSION);
2285 }
2286
2287 if (ffgttb(fptr, &llnaxis1, &llnaxis2, &pcount, &fields, status) > 0)
2288 return(*status);
2289
2290 if (naxis1)
2291 *naxis1 = (long) llnaxis1;
2292
2293 if (naxis2)
2294 *naxis2 = (long) llnaxis2;
2295
2296 if (pcount != 0)
2297 {
2298 snprintf(message, FLEN_ERRMSG, "PCOUNT = %.0f is illegal in ASCII table; must = 0",
2299 (double) pcount);
2300 ffpmsg(message);
2301 return(*status = BAD_PCOUNT);
2302 }
2303
2304 if (tfields)
2305 *tfields = fields;
2306
2307 if (maxfield < 0)
2308 maxf = fields;
2309 else
2310 maxf = minvalue(maxfield, fields);
2311
2312 if (maxf > 0)
2313 {
2314 for (ii = 0; ii < maxf; ii++)
2315 { /* initialize optional keyword values */
2316 if (ttype)
2317 *ttype[ii] = '\0';
2318
2319 if (tunit)
2320 *tunit[ii] = '\0';
2321 }
2322
2323
2324 if (ttype)
2325 ffgkns(fptr, "TTYPE", 1, maxf, ttype, &nfound, status);
2326
2327 if (tunit)
2328 ffgkns(fptr, "TUNIT", 1, maxf, tunit, &nfound, status);
2329
2330 if (*status > 0)
2331 return(*status);
2332
2333 if (tbcol)
2334 {
2335 ffgknj(fptr, "TBCOL", 1, maxf, tbcol, &nfound, status);
2336
2337 if (*status > 0 || nfound != maxf)
2338 {
2339 ffpmsg(
2340 "Required TBCOL keyword(s) not found in ASCII table header (ffghtb).");
2341 return(*status = NO_TBCOL);
2342 }
2343 }
2344
2345 if (tform)
2346 {
2347 ffgkns(fptr, "TFORM", 1, maxf, tform, &nfound, status);
2348
2349 if (*status > 0 || nfound != maxf)
2350 {
2351 ffpmsg(
2352 "Required TFORM keyword(s) not found in ASCII table header (ffghtb).");
2353 return(*status = NO_TFORM);
2354 }
2355 }
2356 }
2357
2358 if (extnm)
2359 {
2360 extnm[0] = '\0';
2361
2362 tstatus = *status;
2363 ffgkys(fptr, "EXTNAME", extnm, comm, status);
2364
2365 if (*status == KEY_NO_EXIST)
2366 *status = tstatus; /* keyword not required, so ignore error */
2367 }
2368
2369 return(*status);
2370 }
2371 /*--------------------------------------------------------------------------*/
ffghtbll(fitsfile * fptr,int maxfield,LONGLONG * naxis1,LONGLONG * naxis2,int * tfields,char ** ttype,LONGLONG * tbcol,char ** tform,char ** tunit,char * extnm,int * status)2372 int ffghtbll(fitsfile *fptr, /* I - FITS file pointer */
2373 int maxfield, /* I - maximum no. of columns to read; */
2374 LONGLONG *naxis1, /* O - length of table row in bytes */
2375 LONGLONG *naxis2, /* O - number of rows in the table */
2376 int *tfields, /* O - number of columns in the table */
2377 char **ttype, /* O - name of each column */
2378 LONGLONG *tbcol, /* O - byte offset in row to each column */
2379 char **tform, /* O - value of TFORMn keyword for each column */
2380 char **tunit, /* O - value of TUNITn keyword for each column */
2381 char *extnm, /* O - value of EXTNAME keyword, if any */
2382 int *status) /* IO - error status */
2383 /*
2384 Get keywords from the Header of the ASCII TaBle:
2385 Check that the keywords conform to the FITS standard and return the
2386 parameters which describe the table.
2387 */
2388 {
2389 int ii, maxf, nfound, tstatus;
2390 long fields;
2391 char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
2392 char xtension[FLEN_VALUE], message[FLEN_ERRMSG];
2393 LONGLONG llnaxis1, llnaxis2, pcount;
2394
2395 if (*status > 0)
2396 return(*status);
2397
2398 /* read the first keyword of the extension */
2399 ffgkyn(fptr, 1, name, value, comm, status);
2400
2401 if (!strcmp(name, "XTENSION"))
2402 {
2403 if (ffc2s(value, xtension, status) > 0) /* get the value string */
2404 {
2405 ffpmsg("Bad value string for XTENSION keyword:");
2406 ffpmsg(value);
2407 return(*status);
2408 }
2409
2410 /* allow the quoted string value to begin in any column and */
2411 /* allow any number of trailing blanks before the closing quote */
2412 if ( (value[0] != '\'') || /* first char must be a quote */
2413 ( strcmp(xtension, "TABLE") ) )
2414 {
2415 snprintf(message, FLEN_ERRMSG,
2416 "This is not a TABLE extension: %s", value);
2417 ffpmsg(message);
2418 return(*status = NOT_ATABLE);
2419 }
2420 }
2421
2422 else /* error: 1st keyword of extension != XTENSION */
2423 {
2424 snprintf(message, FLEN_ERRMSG,
2425 "First keyword of the extension is not XTENSION: %s", name);
2426 ffpmsg(message);
2427 return(*status = NO_XTENSION);
2428 }
2429
2430 if (ffgttb(fptr, &llnaxis1, &llnaxis2, &pcount, &fields, status) > 0)
2431 return(*status);
2432
2433 if (naxis1)
2434 *naxis1 = llnaxis1;
2435
2436 if (naxis2)
2437 *naxis2 = llnaxis2;
2438
2439 if (pcount != 0)
2440 {
2441 snprintf(message, FLEN_ERRMSG, "PCOUNT = %.0f is illegal in ASCII table; must = 0",
2442 (double) pcount);
2443 ffpmsg(message);
2444 return(*status = BAD_PCOUNT);
2445 }
2446
2447 if (tfields)
2448 *tfields = fields;
2449
2450 if (maxfield < 0)
2451 maxf = fields;
2452 else
2453 maxf = minvalue(maxfield, fields);
2454
2455 if (maxf > 0)
2456 {
2457 for (ii = 0; ii < maxf; ii++)
2458 { /* initialize optional keyword values */
2459 if (ttype)
2460 *ttype[ii] = '\0';
2461
2462 if (tunit)
2463 *tunit[ii] = '\0';
2464 }
2465
2466
2467 if (ttype)
2468 ffgkns(fptr, "TTYPE", 1, maxf, ttype, &nfound, status);
2469
2470 if (tunit)
2471 ffgkns(fptr, "TUNIT", 1, maxf, tunit, &nfound, status);
2472
2473 if (*status > 0)
2474 return(*status);
2475
2476 if (tbcol)
2477 {
2478 ffgknjj(fptr, "TBCOL", 1, maxf, tbcol, &nfound, status);
2479
2480 if (*status > 0 || nfound != maxf)
2481 {
2482 ffpmsg(
2483 "Required TBCOL keyword(s) not found in ASCII table header (ffghtbll).");
2484 return(*status = NO_TBCOL);
2485 }
2486 }
2487
2488 if (tform)
2489 {
2490 ffgkns(fptr, "TFORM", 1, maxf, tform, &nfound, status);
2491
2492 if (*status > 0 || nfound != maxf)
2493 {
2494 ffpmsg(
2495 "Required TFORM keyword(s) not found in ASCII table header (ffghtbll).");
2496 return(*status = NO_TFORM);
2497 }
2498 }
2499 }
2500
2501 if (extnm)
2502 {
2503 extnm[0] = '\0';
2504
2505 tstatus = *status;
2506 ffgkys(fptr, "EXTNAME", extnm, comm, status);
2507
2508 if (*status == KEY_NO_EXIST)
2509 *status = tstatus; /* keyword not required, so ignore error */
2510 }
2511
2512 return(*status);
2513 }
2514 /*--------------------------------------------------------------------------*/
ffghbn(fitsfile * fptr,int maxfield,long * naxis2,int * tfields,char ** ttype,char ** tform,char ** tunit,char * extnm,long * pcount,int * status)2515 int ffghbn(fitsfile *fptr, /* I - FITS file pointer */
2516 int maxfield, /* I - maximum no. of columns to read; */
2517 long *naxis2, /* O - number of rows in the table */
2518 int *tfields, /* O - number of columns in the table */
2519 char **ttype, /* O - name of each column */
2520 char **tform, /* O - TFORMn value for each column */
2521 char **tunit, /* O - TUNITn value for each column */
2522 char *extnm, /* O - value of EXTNAME keyword, if any */
2523 long *pcount, /* O - value of PCOUNT keyword */
2524 int *status) /* IO - error status */
2525 /*
2526 Get keywords from the Header of the BiNary table:
2527 Check that the keywords conform to the FITS standard and return the
2528 parameters which describe the table.
2529 */
2530 {
2531 int ii, maxf, nfound, tstatus;
2532 long fields;
2533 char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
2534 char xtension[FLEN_VALUE], message[FLEN_ERRMSG];
2535 LONGLONG naxis1ll, naxis2ll, pcountll;
2536
2537 if (*status > 0)
2538 return(*status);
2539
2540 /* read the first keyword of the extension */
2541 ffgkyn(fptr, 1, name, value, comm, status);
2542
2543 if (!strcmp(name, "XTENSION"))
2544 {
2545 if (ffc2s(value, xtension, status) > 0) /* get the value string */
2546 {
2547 ffpmsg("Bad value string for XTENSION keyword:");
2548 ffpmsg(value);
2549 return(*status);
2550 }
2551
2552 /* allow the quoted string value to begin in any column and */
2553 /* allow any number of trailing blanks before the closing quote */
2554 if ( (value[0] != '\'') || /* first char must be a quote */
2555 ( strcmp(xtension, "BINTABLE") &&
2556 strcmp(xtension, "A3DTABLE") &&
2557 strcmp(xtension, "3DTABLE")
2558 ) )
2559 {
2560 snprintf(message, FLEN_ERRMSG,
2561 "This is not a BINTABLE extension: %s", value);
2562 ffpmsg(message);
2563 return(*status = NOT_BTABLE);
2564 }
2565 }
2566
2567 else /* error: 1st keyword of extension != XTENSION */
2568 {
2569 snprintf(message, FLEN_ERRMSG,
2570 "First keyword of the extension is not XTENSION: %s", name);
2571 ffpmsg(message);
2572 return(*status = NO_XTENSION);
2573 }
2574
2575 if (ffgttb(fptr, &naxis1ll, &naxis2ll, &pcountll, &fields, status) > 0)
2576 return(*status);
2577
2578 if (naxis2)
2579 *naxis2 = (long) naxis2ll;
2580
2581 if (pcount)
2582 *pcount = (long) pcountll;
2583
2584 if (tfields)
2585 *tfields = fields;
2586
2587 if (maxfield < 0)
2588 maxf = fields;
2589 else
2590 maxf = minvalue(maxfield, fields);
2591
2592 if (maxf > 0)
2593 {
2594 for (ii = 0; ii < maxf; ii++)
2595 { /* initialize optional keyword values */
2596 if (ttype)
2597 *ttype[ii] = '\0';
2598
2599 if (tunit)
2600 *tunit[ii] = '\0';
2601 }
2602
2603 if (ttype)
2604 ffgkns(fptr, "TTYPE", 1, maxf, ttype, &nfound, status);
2605
2606 if (tunit)
2607 ffgkns(fptr, "TUNIT", 1, maxf, tunit, &nfound, status);
2608
2609 if (*status > 0)
2610 return(*status);
2611
2612 if (tform)
2613 {
2614 ffgkns(fptr, "TFORM", 1, maxf, tform, &nfound, status);
2615
2616 if (*status > 0 || nfound != maxf)
2617 {
2618 ffpmsg(
2619 "Required TFORM keyword(s) not found in binary table header (ffghbn).");
2620 return(*status = NO_TFORM);
2621 }
2622 }
2623 }
2624
2625 if (extnm)
2626 {
2627 extnm[0] = '\0';
2628
2629 tstatus = *status;
2630 ffgkys(fptr, "EXTNAME", extnm, comm, status);
2631
2632 if (*status == KEY_NO_EXIST)
2633 *status = tstatus; /* keyword not required, so ignore error */
2634 }
2635 return(*status);
2636 }
2637 /*--------------------------------------------------------------------------*/
ffghbnll(fitsfile * fptr,int maxfield,LONGLONG * naxis2,int * tfields,char ** ttype,char ** tform,char ** tunit,char * extnm,LONGLONG * pcount,int * status)2638 int ffghbnll(fitsfile *fptr, /* I - FITS file pointer */
2639 int maxfield, /* I - maximum no. of columns to read; */
2640 LONGLONG *naxis2, /* O - number of rows in the table */
2641 int *tfields, /* O - number of columns in the table */
2642 char **ttype, /* O - name of each column */
2643 char **tform, /* O - TFORMn value for each column */
2644 char **tunit, /* O - TUNITn value for each column */
2645 char *extnm, /* O - value of EXTNAME keyword, if any */
2646 LONGLONG *pcount, /* O - value of PCOUNT keyword */
2647 int *status) /* IO - error status */
2648 /*
2649 Get keywords from the Header of the BiNary table:
2650 Check that the keywords conform to the FITS standard and return the
2651 parameters which describe the table.
2652 */
2653 {
2654 int ii, maxf, nfound, tstatus;
2655 long fields;
2656 char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
2657 char xtension[FLEN_VALUE], message[FLEN_ERRMSG];
2658 LONGLONG naxis1ll, naxis2ll, pcountll;
2659
2660 if (*status > 0)
2661 return(*status);
2662
2663 /* read the first keyword of the extension */
2664 ffgkyn(fptr, 1, name, value, comm, status);
2665
2666 if (!strcmp(name, "XTENSION"))
2667 {
2668 if (ffc2s(value, xtension, status) > 0) /* get the value string */
2669 {
2670 ffpmsg("Bad value string for XTENSION keyword:");
2671 ffpmsg(value);
2672 return(*status);
2673 }
2674
2675 /* allow the quoted string value to begin in any column and */
2676 /* allow any number of trailing blanks before the closing quote */
2677 if ( (value[0] != '\'') || /* first char must be a quote */
2678 ( strcmp(xtension, "BINTABLE") &&
2679 strcmp(xtension, "A3DTABLE") &&
2680 strcmp(xtension, "3DTABLE")
2681 ) )
2682 {
2683 snprintf(message, FLEN_ERRMSG,
2684 "This is not a BINTABLE extension: %s", value);
2685 ffpmsg(message);
2686 return(*status = NOT_BTABLE);
2687 }
2688 }
2689
2690 else /* error: 1st keyword of extension != XTENSION */
2691 {
2692 snprintf(message, FLEN_ERRMSG,
2693 "First keyword of the extension is not XTENSION: %s", name);
2694 ffpmsg(message);
2695 return(*status = NO_XTENSION);
2696 }
2697
2698 if (ffgttb(fptr, &naxis1ll, &naxis2ll, &pcountll, &fields, status) > 0)
2699 return(*status);
2700
2701 if (naxis2)
2702 *naxis2 = naxis2ll;
2703
2704 if (pcount)
2705 *pcount = pcountll;
2706
2707 if (tfields)
2708 *tfields = fields;
2709
2710 if (maxfield < 0)
2711 maxf = fields;
2712 else
2713 maxf = minvalue(maxfield, fields);
2714
2715 if (maxf > 0)
2716 {
2717 for (ii = 0; ii < maxf; ii++)
2718 { /* initialize optional keyword values */
2719 if (ttype)
2720 *ttype[ii] = '\0';
2721
2722 if (tunit)
2723 *tunit[ii] = '\0';
2724 }
2725
2726 if (ttype)
2727 ffgkns(fptr, "TTYPE", 1, maxf, ttype, &nfound, status);
2728
2729 if (tunit)
2730 ffgkns(fptr, "TUNIT", 1, maxf, tunit, &nfound, status);
2731
2732 if (*status > 0)
2733 return(*status);
2734
2735 if (tform)
2736 {
2737 ffgkns(fptr, "TFORM", 1, maxf, tform, &nfound, status);
2738
2739 if (*status > 0 || nfound != maxf)
2740 {
2741 ffpmsg(
2742 "Required TFORM keyword(s) not found in binary table header (ffghbn).");
2743 return(*status = NO_TFORM);
2744 }
2745 }
2746 }
2747
2748 if (extnm)
2749 {
2750 extnm[0] = '\0';
2751
2752 tstatus = *status;
2753 ffgkys(fptr, "EXTNAME", extnm, comm, status);
2754
2755 if (*status == KEY_NO_EXIST)
2756 *status = tstatus; /* keyword not required, so ignore error */
2757 }
2758 return(*status);
2759 }
2760 /*--------------------------------------------------------------------------*/
ffgphd(fitsfile * fptr,int maxdim,int * simple,int * bitpix,int * naxis,LONGLONG naxes[],long * pcount,long * gcount,int * extend,double * bscale,double * bzero,LONGLONG * blank,int * nspace,int * status)2761 int ffgphd(fitsfile *fptr, /* I - FITS file pointer */
2762 int maxdim, /* I - maximum no. of dimensions to read; */
2763 int *simple, /* O - does file conform to FITS standard? 1/0 */
2764 int *bitpix, /* O - number of bits per data value pixel */
2765 int *naxis, /* O - number of axes in the data array */
2766 LONGLONG naxes[], /* O - length of each data axis */
2767 long *pcount, /* O - number of group parameters (usually 0) */
2768 long *gcount, /* O - number of random groups (usually 1 or 0) */
2769 int *extend, /* O - may FITS file haave extensions? */
2770 double *bscale, /* O - array pixel linear scaling factor */
2771 double *bzero, /* O - array pixel linear scaling zero point */
2772 LONGLONG *blank, /* O - value used to represent undefined pixels */
2773 int *nspace, /* O - number of blank keywords prior to END */
2774 int *status) /* IO - error status */
2775 {
2776 /*
2777 Get the Primary HeaDer parameters. Check that the keywords conform to
2778 the FITS standard and return the parameters which determine the size and
2779 structure of the primary array or IMAGE extension.
2780 */
2781 int unknown, found_end, tstatus, ii, nextkey, namelen;
2782 long longbitpix, longnaxis;
2783 LONGLONG axislen;
2784 char message[FLEN_ERRMSG], keyword[FLEN_KEYWORD];
2785 char card[FLEN_CARD];
2786 char name[FLEN_KEYWORD], value[FLEN_VALUE], comm[FLEN_COMMENT];
2787 char xtension[FLEN_VALUE];
2788
2789 if (*status > 0)
2790 return(*status);
2791
2792 if (fptr->HDUposition != (fptr->Fptr)->curhdu)
2793 ffmahd(fptr, (fptr->HDUposition) + 1, NULL, status);
2794
2795 if (simple)
2796 *simple = 1;
2797
2798 unknown = 0;
2799
2800 /*--------------------------------------------------------------------*/
2801 /* Get 1st keyword of HDU and test whether it is SIMPLE or XTENSION */
2802 /*--------------------------------------------------------------------*/
2803 ffgkyn(fptr, 1, name, value, comm, status);
2804
2805 if ((fptr->Fptr)->curhdu == 0) /* Is this the beginning of the FITS file? */
2806 {
2807 if (!strcmp(name, "SIMPLE"))
2808 {
2809 if (value[0] == 'F')
2810 {
2811 if (simple)
2812 *simple=0; /* not a simple FITS file */
2813 }
2814 else if (value[0] != 'T')
2815 return(*status = BAD_SIMPLE);
2816 }
2817
2818 else
2819 {
2820 snprintf(message, FLEN_ERRMSG,
2821 "First keyword of the file is not SIMPLE: %s", name);
2822 ffpmsg(message);
2823 return(*status = NO_SIMPLE);
2824 }
2825 }
2826
2827 else /* not beginning of the file, so presumably an IMAGE extension */
2828 { /* or it could be a compressed image in a binary table */
2829
2830 if (!strcmp(name, "XTENSION"))
2831 {
2832 if (ffc2s(value, xtension, status) > 0) /* get the value string */
2833 {
2834 ffpmsg("Bad value string for XTENSION keyword:");
2835 ffpmsg(value);
2836 return(*status);
2837 }
2838
2839 /* allow the quoted string value to begin in any column and */
2840 /* allow any number of trailing blanks before the closing quote */
2841 if ( (value[0] != '\'') || /* first char must be a quote */
2842 ( strcmp(xtension, "IMAGE") &&
2843 strcmp(xtension, "IUEIMAGE") ) )
2844 {
2845 unknown = 1; /* unknown type of extension; press on anyway */
2846 snprintf(message, FLEN_ERRMSG,
2847 "This is not an IMAGE extension: %s", value);
2848 ffpmsg(message);
2849 }
2850 }
2851
2852 else /* error: 1st keyword of extension != XTENSION */
2853 {
2854 snprintf(message, FLEN_ERRMSG,
2855 "First keyword of the extension is not XTENSION: %s", name);
2856 ffpmsg(message);
2857 return(*status = NO_XTENSION);
2858 }
2859 }
2860
2861 if (unknown && (fptr->Fptr)->compressimg)
2862 {
2863 /* this is a compressed image, so read ZBITPIX, ZNAXIS keywords */
2864 unknown = 0; /* reset flag */
2865 ffxmsg(3, message); /* clear previous spurious error message */
2866
2867 if (bitpix)
2868 {
2869 ffgidt(fptr, bitpix, status); /* get bitpix value */
2870
2871 if (*status > 0)
2872 {
2873 ffpmsg("Error reading BITPIX value of compressed image");
2874 return(*status);
2875 }
2876 }
2877
2878 if (naxis)
2879 {
2880 ffgidm(fptr, naxis, status); /* get NAXIS value */
2881
2882 if (*status > 0)
2883 {
2884 ffpmsg("Error reading NAXIS value of compressed image");
2885 return(*status);
2886 }
2887 }
2888
2889 if (naxes)
2890 {
2891 ffgiszll(fptr, maxdim, naxes, status); /* get NAXISn value */
2892
2893 if (*status > 0)
2894 {
2895 ffpmsg("Error reading NAXISn values of compressed image");
2896 return(*status);
2897 }
2898 }
2899
2900 nextkey = 9; /* skip required table keywords in the following search */
2901 }
2902 else
2903 {
2904
2905 /*----------------------------------------------------------------*/
2906 /* Get 2nd keyword; test whether it is BITPIX with legal value */
2907 /*----------------------------------------------------------------*/
2908 ffgkyn(fptr, 2, name, value, comm, status); /* BITPIX = 2nd keyword */
2909
2910 if (strcmp(name, "BITPIX"))
2911 {
2912 snprintf(message, FLEN_ERRMSG,
2913 "Second keyword of the extension is not BITPIX: %s", name);
2914 ffpmsg(message);
2915 return(*status = NO_BITPIX);
2916 }
2917
2918 if (ffc2ii(value, &longbitpix, status) > 0)
2919 {
2920 snprintf(message, FLEN_ERRMSG,
2921 "Value of BITPIX keyword is not an integer: %s", value);
2922 ffpmsg(message);
2923 return(*status = BAD_BITPIX);
2924 }
2925 else if (longbitpix != BYTE_IMG && longbitpix != SHORT_IMG &&
2926 longbitpix != LONG_IMG && longbitpix != LONGLONG_IMG &&
2927 longbitpix != FLOAT_IMG && longbitpix != DOUBLE_IMG)
2928 {
2929 snprintf(message, FLEN_ERRMSG,
2930 "Illegal value for BITPIX keyword: %s", value);
2931 ffpmsg(message);
2932 return(*status = BAD_BITPIX);
2933 }
2934 if (bitpix)
2935 *bitpix = longbitpix; /* do explicit type conversion */
2936
2937 /*---------------------------------------------------------------*/
2938 /* Get 3rd keyword; test whether it is NAXIS with legal value */
2939 /*---------------------------------------------------------------*/
2940 ffgtkn(fptr, 3, "NAXIS", &longnaxis, status);
2941
2942 if (*status == BAD_ORDER)
2943 return(*status = NO_NAXIS);
2944 else if (*status == NOT_POS_INT || longnaxis > 999)
2945 {
2946 snprintf(message,FLEN_ERRMSG,"NAXIS = %ld is illegal", longnaxis);
2947 ffpmsg(message);
2948 return(*status = BAD_NAXIS);
2949 }
2950 else
2951 if (naxis)
2952 *naxis = longnaxis; /* do explicit type conversion */
2953
2954 /*---------------------------------------------------------*/
2955 /* Get the next NAXISn keywords and test for legal values */
2956 /*---------------------------------------------------------*/
2957 for (ii=0, nextkey=4; ii < longnaxis; ii++, nextkey++)
2958 {
2959 ffkeyn("NAXIS", ii+1, keyword, status);
2960 ffgtknjj(fptr, 4+ii, keyword, &axislen, status);
2961
2962 if (*status == BAD_ORDER)
2963 return(*status = NO_NAXES);
2964 else if (*status == NOT_POS_INT)
2965 return(*status = BAD_NAXES);
2966 else if (ii < maxdim)
2967 if (naxes)
2968 naxes[ii] = axislen;
2969 }
2970 }
2971
2972 /*---------------------------------------------------------*/
2973 /* now look for other keywords of interest: */
2974 /* BSCALE, BZERO, BLANK, PCOUNT, GCOUNT, EXTEND, and END */
2975 /*---------------------------------------------------------*/
2976
2977 /* initialize default values in case keyword is not present */
2978 if (bscale)
2979 *bscale = 1.0;
2980 if (bzero)
2981 *bzero = 0.0;
2982 if (pcount)
2983 *pcount = 0;
2984 if (gcount)
2985 *gcount = 1;
2986 if (extend)
2987 *extend = 0;
2988 if (blank)
2989 *blank = NULL_UNDEFINED; /* no default null value for BITPIX=8,16,32 */
2990
2991 *nspace = 0;
2992 found_end = 0;
2993 tstatus = *status;
2994
2995 for (; !found_end; nextkey++)
2996 {
2997 /* get next keyword */
2998 /* don't use ffgkyn here because it trys to parse the card to read */
2999 /* the value string, thus failing to read the file just because of */
3000 /* minor syntax errors in optional keywords. */
3001
3002 if (ffgrec(fptr, nextkey, card, status) > 0 ) /* get the 80-byte card */
3003 {
3004 if (*status == KEY_OUT_BOUNDS)
3005 {
3006 found_end = 1; /* simply hit the end of the header */
3007 *status = tstatus; /* reset error status */
3008 }
3009 else
3010 {
3011 ffpmsg("Failed to find the END keyword in header (ffgphd).");
3012 }
3013 }
3014 else /* got the next keyword without error */
3015 {
3016 ffgknm(card, name, &namelen, status); /* get the keyword name */
3017
3018 if (fftrec(name, status) > 0) /* test keyword name; catches no END */
3019 {
3020 snprintf(message, FLEN_ERRMSG,
3021 "Name of keyword no. %d contains illegal character(s): %s",
3022 nextkey, name);
3023 ffpmsg(message);
3024
3025 if (nextkey % 36 == 0) /* test if at beginning of 36-card record */
3026 ffpmsg(" (This may indicate a missing END keyword).");
3027 }
3028
3029 if (!strcmp(name, "BSCALE") && bscale)
3030 {
3031 *nspace = 0; /* reset count of blank keywords */
3032 ffpsvc(card, value, comm, status); /* parse value and comment */
3033
3034 if (ffc2dd(value, bscale, status) > 0) /* convert to double */
3035 {
3036 /* reset error status and continue, but still issue warning */
3037 *status = tstatus;
3038 *bscale = 1.0;
3039
3040 snprintf(message, FLEN_ERRMSG,
3041 "Error reading BSCALE keyword value as a double: %s", value);
3042 ffpmsg(message);
3043 }
3044 }
3045
3046 else if (!strcmp(name, "BZERO") && bzero)
3047 {
3048 *nspace = 0; /* reset count of blank keywords */
3049 ffpsvc(card, value, comm, status); /* parse value and comment */
3050
3051 if (ffc2dd(value, bzero, status) > 0) /* convert to double */
3052 {
3053 /* reset error status and continue, but still issue warning */
3054 *status = tstatus;
3055 *bzero = 0.0;
3056
3057 snprintf(message, FLEN_ERRMSG,
3058 "Error reading BZERO keyword value as a double: %s", value);
3059 ffpmsg(message);
3060 }
3061 }
3062
3063 else if (!strcmp(name, "BLANK") && blank)
3064 {
3065 *nspace = 0; /* reset count of blank keywords */
3066 ffpsvc(card, value, comm, status); /* parse value and comment */
3067
3068 if (ffc2jj(value, blank, status) > 0) /* convert to LONGLONG */
3069 {
3070 /* reset error status and continue, but still issue warning */
3071 *status = tstatus;
3072 *blank = NULL_UNDEFINED;
3073
3074 snprintf(message, FLEN_ERRMSG,
3075 "Error reading BLANK keyword value as an integer: %s", value);
3076 ffpmsg(message);
3077 }
3078 }
3079
3080 else if (!strcmp(name, "PCOUNT") && pcount)
3081 {
3082 *nspace = 0; /* reset count of blank keywords */
3083 ffpsvc(card, value, comm, status); /* parse value and comment */
3084
3085 if (ffc2ii(value, pcount, status) > 0) /* convert to long */
3086 {
3087 snprintf(message, FLEN_ERRMSG,
3088 "Error reading PCOUNT keyword value as an integer: %s", value);
3089 ffpmsg(message);
3090 }
3091 }
3092
3093 else if (!strcmp(name, "GCOUNT") && gcount)
3094 {
3095 *nspace = 0; /* reset count of blank keywords */
3096 ffpsvc(card, value, comm, status); /* parse value and comment */
3097
3098 if (ffc2ii(value, gcount, status) > 0) /* convert to long */
3099 {
3100 snprintf(message, FLEN_ERRMSG,
3101 "Error reading GCOUNT keyword value as an integer: %s", value);
3102 ffpmsg(message);
3103 }
3104 }
3105
3106 else if (!strcmp(name, "EXTEND") && extend)
3107 {
3108 *nspace = 0; /* reset count of blank keywords */
3109 ffpsvc(card, value, comm, status); /* parse value and comment */
3110
3111 if (ffc2ll(value, extend, status) > 0) /* convert to logical */
3112 {
3113 /* reset error status and continue, but still issue warning */
3114 *status = tstatus;
3115 *extend = 0;
3116
3117 snprintf(message, FLEN_ERRMSG,
3118 "Error reading EXTEND keyword value as a logical: %s", value);
3119 ffpmsg(message);
3120 }
3121 }
3122
3123 else if (!strcmp(name, "END"))
3124 found_end = 1;
3125
3126 else if (!card[0] )
3127 *nspace = *nspace + 1; /* this is a blank card in the header */
3128
3129 else
3130 *nspace = 0; /* reset count of blank keywords immediately
3131 before the END keyword to zero */
3132 }
3133
3134 if (*status > 0) /* exit on error after writing error message */
3135 {
3136 if ((fptr->Fptr)->curhdu == 0)
3137 ffpmsg(
3138 "Failed to read the required primary array header keywords.");
3139 else
3140 ffpmsg(
3141 "Failed to read the required image extension header keywords.");
3142
3143 return(*status);
3144 }
3145 }
3146
3147 if (unknown)
3148 *status = NOT_IMAGE;
3149
3150 return(*status);
3151 }
3152 /*--------------------------------------------------------------------------*/
ffgttb(fitsfile * fptr,LONGLONG * rowlen,LONGLONG * nrows,LONGLONG * pcount,long * tfields,int * status)3153 int ffgttb(fitsfile *fptr, /* I - FITS file pointer*/
3154 LONGLONG *rowlen, /* O - length of a table row, in bytes */
3155 LONGLONG *nrows, /* O - number of rows in the table */
3156 LONGLONG *pcount, /* O - value of PCOUNT keyword */
3157 long *tfields, /* O - number of fields in the table */
3158 int *status) /* IO - error status */
3159 {
3160 /*
3161 Get and Test TaBle;
3162 Test that this is a legal ASCII or binary table and get some keyword values.
3163 We assume that the calling routine has already tested the 1st keyword
3164 of the extension to ensure that this is really a table extension.
3165 */
3166 if (*status > 0)
3167 return(*status);
3168
3169 if (fftkyn(fptr, 2, "BITPIX", "8", status) == BAD_ORDER) /* 2nd keyword */
3170 return(*status = NO_BITPIX); /* keyword not BITPIX */
3171 else if (*status == NOT_POS_INT)
3172 return(*status = BAD_BITPIX); /* value != 8 */
3173
3174 if (fftkyn(fptr, 3, "NAXIS", "2", status) == BAD_ORDER) /* 3rd keyword */
3175 return(*status = NO_NAXIS); /* keyword not NAXIS */
3176 else if (*status == NOT_POS_INT)
3177 return(*status = BAD_NAXIS); /* value != 2 */
3178
3179 if (ffgtknjj(fptr, 4, "NAXIS1", rowlen, status) == BAD_ORDER) /* 4th key */
3180 return(*status = NO_NAXES); /* keyword not NAXIS1 */
3181 else if (*status == NOT_POS_INT)
3182 return(*status == BAD_NAXES); /* bad NAXIS1 value */
3183
3184 if (ffgtknjj(fptr, 5, "NAXIS2", nrows, status) == BAD_ORDER) /* 5th key */
3185 return(*status = NO_NAXES); /* keyword not NAXIS2 */
3186 else if (*status == NOT_POS_INT)
3187 return(*status == BAD_NAXES); /* bad NAXIS2 value */
3188
3189 if (ffgtknjj(fptr, 6, "PCOUNT", pcount, status) == BAD_ORDER) /* 6th key */
3190 return(*status = NO_PCOUNT); /* keyword not PCOUNT */
3191 else if (*status == NOT_POS_INT)
3192 return(*status = BAD_PCOUNT); /* bad PCOUNT value */
3193
3194 if (fftkyn(fptr, 7, "GCOUNT", "1", status) == BAD_ORDER) /* 7th keyword */
3195 return(*status = NO_GCOUNT); /* keyword not GCOUNT */
3196 else if (*status == NOT_POS_INT)
3197 return(*status = BAD_GCOUNT); /* value != 1 */
3198
3199 if (ffgtkn(fptr, 8, "TFIELDS", tfields, status) == BAD_ORDER) /* 8th key*/
3200 return(*status = NO_TFIELDS); /* keyword not TFIELDS */
3201 else if (*status == NOT_POS_INT || *tfields > 999)
3202 return(*status == BAD_TFIELDS); /* bad TFIELDS value */
3203
3204
3205 if (*status > 0)
3206 ffpmsg(
3207 "Error reading required keywords in the table header (FTGTTB).");
3208
3209 return(*status);
3210 }
3211 /*--------------------------------------------------------------------------*/
ffgtkn(fitsfile * fptr,int numkey,char * name,long * value,int * status)3212 int ffgtkn(fitsfile *fptr, /* I - FITS file pointer */
3213 int numkey, /* I - number of the keyword to read */
3214 char *name, /* I - expected name of the keyword */
3215 long *value, /* O - integer value of the keyword */
3216 int *status) /* IO - error status */
3217 {
3218 /*
3219 test that keyword number NUMKEY has the expected name and get the
3220 integer value of the keyword. Return an error if the keyword
3221 name does not match the input name, or if the value of the
3222 keyword is not a positive integer.
3223 */
3224 char keyname[FLEN_KEYWORD], valuestring[FLEN_VALUE];
3225 char comm[FLEN_COMMENT], message[FLEN_ERRMSG];
3226
3227 if (*status > 0)
3228 return(*status);
3229
3230 keyname[0] = '\0';
3231 valuestring[0] = '\0';
3232
3233 if (ffgkyn(fptr, numkey, keyname, valuestring, comm, status) <= 0)
3234 {
3235 if (strcmp(keyname, name) )
3236 *status = BAD_ORDER; /* incorrect keyword name */
3237
3238 else
3239 {
3240 ffc2ii(valuestring, value, status); /* convert to integer */
3241
3242 if (*status > 0 || *value < 0 )
3243 *status = NOT_POS_INT;
3244 }
3245
3246 if (*status > 0)
3247 {
3248 snprintf(message, FLEN_ERRMSG,
3249 "ffgtkn found unexpected keyword or value for keyword no. %d.",
3250 numkey);
3251 ffpmsg(message);
3252
3253 snprintf(message, FLEN_ERRMSG,
3254 " Expected positive integer keyword %s, but instead", name);
3255 ffpmsg(message);
3256
3257 snprintf(message, FLEN_ERRMSG,
3258 " found keyword %s with value %s", keyname, valuestring);
3259 ffpmsg(message);
3260 }
3261 }
3262
3263 return(*status);
3264 }
3265 /*--------------------------------------------------------------------------*/
ffgtknjj(fitsfile * fptr,int numkey,char * name,LONGLONG * value,int * status)3266 int ffgtknjj(fitsfile *fptr, /* I - FITS file pointer */
3267 int numkey, /* I - number of the keyword to read */
3268 char *name, /* I - expected name of the keyword */
3269 LONGLONG *value, /* O - integer value of the keyword */
3270 int *status) /* IO - error status */
3271 {
3272 /*
3273 test that keyword number NUMKEY has the expected name and get the
3274 integer value of the keyword. Return an error if the keyword
3275 name does not match the input name, or if the value of the
3276 keyword is not a positive integer.
3277 */
3278 char keyname[FLEN_KEYWORD], valuestring[FLEN_VALUE];
3279 char comm[FLEN_COMMENT], message[FLEN_ERRMSG];
3280
3281 if (*status > 0)
3282 return(*status);
3283
3284 keyname[0] = '\0';
3285 valuestring[0] = '\0';
3286
3287 if (ffgkyn(fptr, numkey, keyname, valuestring, comm, status) <= 0)
3288 {
3289 if (strcmp(keyname, name) )
3290 *status = BAD_ORDER; /* incorrect keyword name */
3291
3292 else
3293 {
3294 ffc2jj(valuestring, value, status); /* convert to integer */
3295
3296 if (*status > 0 || *value < 0 )
3297 *status = NOT_POS_INT;
3298 }
3299
3300 if (*status > 0)
3301 {
3302 snprintf(message, FLEN_ERRMSG,
3303 "ffgtknjj found unexpected keyword or value for keyword no. %d.",
3304 numkey);
3305 ffpmsg(message);
3306
3307 snprintf(message, FLEN_ERRMSG,
3308 " Expected positive integer keyword %s, but instead", name);
3309 ffpmsg(message);
3310
3311 snprintf(message, FLEN_ERRMSG,
3312 " found keyword %s with value %s", keyname, valuestring);
3313 ffpmsg(message);
3314 }
3315 }
3316
3317 return(*status);
3318 }
3319 /*--------------------------------------------------------------------------*/
fftkyn(fitsfile * fptr,int numkey,char * name,char * value,int * status)3320 int fftkyn(fitsfile *fptr, /* I - FITS file pointer */
3321 int numkey, /* I - number of the keyword to read */
3322 char *name, /* I - expected name of the keyword */
3323 char *value, /* I - expected value of the keyword */
3324 int *status) /* IO - error status */
3325 {
3326 /*
3327 test that keyword number NUMKEY has the expected name and the
3328 expected value string.
3329 */
3330 char keyname[FLEN_KEYWORD], valuestring[FLEN_VALUE];
3331 char comm[FLEN_COMMENT], message[FLEN_ERRMSG];
3332
3333 if (*status > 0)
3334 return(*status);
3335
3336 keyname[0] = '\0';
3337 valuestring[0] = '\0';
3338
3339 if (ffgkyn(fptr, numkey, keyname, valuestring, comm, status) <= 0)
3340 {
3341 if (strcmp(keyname, name) )
3342 *status = BAD_ORDER; /* incorrect keyword name */
3343
3344 if (strcmp(value, valuestring) )
3345 *status = NOT_POS_INT; /* incorrect keyword value */
3346 }
3347
3348 if (*status > 0)
3349 {
3350 snprintf(message, FLEN_ERRMSG,
3351 "fftkyn found unexpected keyword or value for keyword no. %d.",
3352 numkey);
3353 ffpmsg(message);
3354
3355 snprintf(message, FLEN_ERRMSG,
3356 " Expected keyword %s with value %s, but", name, value);
3357 ffpmsg(message);
3358
3359 snprintf(message, FLEN_ERRMSG,
3360 " found keyword %s with value %s", keyname, valuestring);
3361 ffpmsg(message);
3362 }
3363
3364 return(*status);
3365 }
3366 /*--------------------------------------------------------------------------*/
ffh2st(fitsfile * fptr,char ** header,int * status)3367 int ffh2st(fitsfile *fptr, /* I - FITS file pointer */
3368 char **header, /* O - returned header string */
3369 int *status) /* IO - error status */
3370
3371 /*
3372 read header keywords into a long string of chars. This routine allocates
3373 memory for the string, so the calling routine must eventually free the
3374 memory when it is not needed any more.
3375 */
3376 {
3377 int nkeys;
3378 long nrec;
3379 LONGLONG headstart;
3380
3381 if (*status > 0)
3382 return(*status);
3383
3384 /* get number of keywords in the header (doesn't include END) */
3385 if (ffghsp(fptr, &nkeys, NULL, status) > 0)
3386 return(*status);
3387
3388 nrec = (nkeys / 36 + 1);
3389
3390 /* allocate memory for all the keywords (multiple of 2880 bytes) */
3391 *header = (char *) calloc ( nrec * 2880 + 1, 1);
3392 if (!(*header))
3393 {
3394 *status = MEMORY_ALLOCATION;
3395 ffpmsg("failed to allocate memory to hold all the header keywords");
3396 return(*status);
3397 }
3398
3399 ffghadll(fptr, &headstart, NULL, NULL, status); /* get header address */
3400 ffmbyt(fptr, headstart, REPORT_EOF, status); /* move to header */
3401 ffgbyt(fptr, nrec * 2880, *header, status); /* copy header */
3402 *(*header + (nrec * 2880)) = '\0';
3403
3404 return(*status);
3405 }
3406 /*--------------------------------------------------------------------------*/
ffhdr2str(fitsfile * fptr,int exclude_comm,char ** exclist,int nexc,char ** header,int * nkeys,int * status)3407 int ffhdr2str( fitsfile *fptr, /* I - FITS file pointer */
3408 int exclude_comm, /* I - if TRUE, exclude commentary keywords */
3409 char **exclist, /* I - list of excluded keyword names */
3410 int nexc, /* I - number of names in exclist */
3411 char **header, /* O - returned header string */
3412 int *nkeys, /* O - returned number of 80-char keywords */
3413 int *status) /* IO - error status */
3414 /*
3415 read header keywords into a long string of chars. This routine allocates
3416 memory for the string, so the calling routine must eventually free the
3417 memory when it is not needed any more. If exclude_comm is TRUE, then all
3418 the COMMENT, HISTORY, and <blank> keywords will be excluded from the output
3419 string of keywords. Any other list of keywords to be excluded may be
3420 specified with the exclist parameter.
3421 */
3422 {
3423 int casesn, match, exact, totkeys;
3424 long ii, jj;
3425 char keybuf[162], keyname[FLEN_KEYWORD], *headptr;
3426
3427 *nkeys = 0;
3428
3429 if (*status > 0)
3430 return(*status);
3431
3432 /* get number of keywords in the header (doesn't include END) */
3433 if (ffghsp(fptr, &totkeys, NULL, status) > 0)
3434 return(*status);
3435
3436 /* allocate memory for all the keywords */
3437 /* (will reallocate it later to minimize the memory size) */
3438
3439 *header = (char *) calloc ( (totkeys + 1) * 80 + 1, 1);
3440 if (!(*header))
3441 {
3442 *status = MEMORY_ALLOCATION;
3443 ffpmsg("failed to allocate memory to hold all the header keywords");
3444 return(*status);
3445 }
3446
3447 headptr = *header;
3448 casesn = FALSE;
3449
3450 /* read every keyword */
3451 for (ii = 1; ii <= totkeys; ii++)
3452 {
3453 ffgrec(fptr, ii, keybuf, status);
3454 /* pad record with blanks so that it is at least 80 chars long */
3455 strcat(keybuf,
3456 " ");
3457
3458 keyname[0] = '\0';
3459 strncat(keyname, keybuf, 8); /* copy the keyword name */
3460
3461 if (exclude_comm)
3462 {
3463 if (!FSTRCMP("COMMENT ", keyname) ||
3464 !FSTRCMP("HISTORY ", keyname) ||
3465 !FSTRCMP(" ", keyname) )
3466 continue; /* skip this commentary keyword */
3467 }
3468
3469 /* does keyword match any names in the exclusion list? */
3470 for (jj = 0; jj < nexc; jj++ )
3471 {
3472 ffcmps(exclist[jj], keyname, casesn, &match, &exact);
3473 if (match)
3474 break;
3475 }
3476
3477 if (jj == nexc)
3478 {
3479 /* not in exclusion list, add this keyword to the string */
3480 strcpy(headptr, keybuf);
3481 headptr += 80;
3482 (*nkeys)++;
3483 }
3484 }
3485
3486 /* add the END keyword */
3487 strcpy(headptr,
3488 "END ");
3489 headptr += 80;
3490 (*nkeys)++;
3491
3492 *headptr = '\0'; /* terminate the header string */
3493 /* minimize the allocated memory */
3494 *header = (char *) realloc(*header, (*nkeys *80) + 1);
3495
3496 return(*status);
3497 }
3498 /*--------------------------------------------------------------------------*/
ffcnvthdr2str(fitsfile * fptr,int exclude_comm,char ** exclist,int nexc,char ** header,int * nkeys,int * status)3499 int ffcnvthdr2str( fitsfile *fptr, /* I - FITS file pointer */
3500 int exclude_comm, /* I - if TRUE, exclude commentary keywords */
3501 char **exclist, /* I - list of excluded keyword names */
3502 int nexc, /* I - number of names in exclist */
3503 char **header, /* O - returned header string */
3504 int *nkeys, /* O - returned number of 80-char keywords */
3505 int *status) /* IO - error status */
3506 /*
3507 Same as ffhdr2str, except that if the input HDU is a tile compressed image
3508 (stored in a binary table) then it will first convert that header back
3509 to that of a normal uncompressed FITS image before concatenating the header
3510 keyword records.
3511 */
3512 {
3513 fitsfile *tempfptr;
3514
3515 if (*status > 0)
3516 return(*status);
3517
3518 if (fits_is_compressed_image(fptr, status) )
3519 {
3520 /* this is a tile compressed image, so need to make an uncompressed */
3521 /* copy of the image header in memory before concatenating the keywords */
3522 if (fits_create_file(&tempfptr, "mem://", status) > 0) {
3523 return(*status);
3524 }
3525
3526 if (fits_img_decompress_header(fptr, tempfptr, status) > 0) {
3527 fits_delete_file(tempfptr, status);
3528 return(*status);
3529 }
3530
3531 ffhdr2str(tempfptr, exclude_comm, exclist, nexc, header, nkeys, status);
3532 fits_close_file(tempfptr, status);
3533
3534 } else {
3535 ffhdr2str(fptr, exclude_comm, exclist, nexc, header, nkeys, status);
3536 }
3537
3538 return(*status);
3539 }
3540