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