1 /*
2 fitsutil.c
3
4 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 *
6 * Part of: The LDAC Tools
7 *
8 * Author: E.BERTIN, DeNIS/LDAC
9 *
10 * Contents: functions for handling FITS keywords.
11 *
12 * Last modify: 17/11/2004
13 *
14 *%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "fitscat_defs.h"
26 #include "fitscat.h"
27
28 char histokeys[][12] = {"COMMENT ", "HISTORY ", " ", ""};
29
30 /****** fitsadd ***************************************************************
31 PROTO int fitsadd(char *fitsbuf, char *keyword, char *comment)
32 PURPOSE Write a FITS keyword in a fits header.
33 INPUT pointer to the FITS buffer,
34 name of the keyword to be created,
35 a comment to put beyond the slash, or next to a COMMENT or HISTORY.
36 OUTPUT line position or RETURN_ERROR if the keyword is invalid.
37 NOTES For all keywords except commentary ones (like COMMENT, HISTORY or
38 blank), it is checked that they do not exist already.
39 Enough memory should be provided for the FITS header to contain one
40 more line of 80 char.
41 AUTHOR E. Bertin (IAP & Leiden observatory)
42 VERSION 13/06/2004
43 ***/
fitsadd(char * fitsbuf,char * keyword,char * comment)44 int fitsadd(char *fitsbuf, char *keyword, char *comment)
45
46 {
47 char *key_ptr;
48 char str[82];
49 int headpos, headpos2, commentflag,
50 i, n;
51
52
53 if (strcspn(keyword, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 -_"))
54 return RETURN_ERROR;
55 commentflag = findkey(keyword, (char *)histokeys, 12)==RETURN_ERROR?0:1;
56 if (commentflag || (headpos = fitsfind(fitsbuf, keyword))==RETURN_ERROR)
57 {
58 headpos2 = headpos = fitsfind(fitsbuf, "END ");
59 /*-- Special case of NAXIS parameters */
60 if (!strncmp(keyword, "NAXIS", 5) && keyword[5] && keyword[5] != ' ')
61 {
62 sscanf(keyword, "NAXIS%d", &n);
63 /*---- Look for all previous NAXIS parameters */
64 for (i=n; i--;)
65 {
66 sprintf(str, "NAXIS%-3d", i);
67 headpos=fitsfind(fitsbuf, str);
68 if (headpos>0)
69 break;
70 }
71 if (headpos<0)
72 /*---- Most likely keyword is NAXIS1 */
73 headpos=fitsfind(fitsbuf, "NAXIS ");
74 if (headpos>0)
75 headpos++;
76 else
77 return RETURN_ERROR;
78 }
79 key_ptr = fitsbuf+80*headpos;
80 memmove(key_ptr+80, key_ptr, 80*(headpos2-headpos+1));
81
82 if (commentflag)
83 sprintf(str, "%-8.8s %-71.71s",
84 keyword, comment?comment:" ");
85 else if (comment && *comment)
86 sprintf(str, "%-8.8s= / %-47.47s",
87 keyword, comment);
88 else
89 sprintf(str, "%-8.8s= %-47.47s",
90 keyword, " ");
91
92 memcpy(key_ptr, str, 80);
93 }
94
95 return headpos;
96 }
97
98
99 /****** fitsfind **************************************************************
100 PROTO int fitsfind(char *fitsbuf, char *keyword)
101 PURPOSE Search for a FITS keyword in a FITS header.
102 INPUT pointer to the FITS buffer,
103 name of the keyword to search for.
104 OUTPUT position in lines of 80 char (0=first) of the keyword if it was
105 found, RETURN_ERROR otherwise.
106 NOTES The buffer MUST contain the ``END '' keyword.
107 AUTHOR E. Bertin (IAP & Leiden observatory)
108 VERSION 15/02/96
109 ***/
fitsfind(char * fitsbuf,char * keyword)110 int fitsfind(char *fitsbuf, char *keyword)
111
112 {
113 char *ptr;
114 int i, len;
115
116 len = strlen(keyword);
117 for (i=0; strncmp(ptr=&fitsbuf[80*i], "END ", 8); i++)
118 if (!wstrncmp(ptr, keyword, len))
119 return i;
120 if (strncmp(keyword, "END ", 8))
121 return RETURN_ERROR;
122 else
123 return i;
124 }
125
126
127 /****** fitsnfind *************************************************************
128 PROTO char *fitsnfind(char *fitsbuf, char *str, int nblock)
129 PURPOSE Search for a FITS keyword in a fits header of nblock blocks.
130 INPUT pointer to the FITS buffer,
131 name of the keyword to search for,
132 number of FITS blocks (2880 bytes each).
133 OUTPUT pointer at the keyword position if it was found, NULL otherwise.
134 NOTES No need for an ``END '' keyword.
135 AUTHOR E. Bertin (IAP & Leiden observatory)
136 VERSION 25/04/97
137 ***/
fitsnfind(char * fitsbuf,char * str,int nblock)138 char *fitsnfind(char *fitsbuf, char *str, int nblock)
139 {
140 int i;
141
142 for (i=36*nblock;i--; fitsbuf+=80)
143 if (!strncmp(fitsbuf, str, strlen(str)))
144 return fitsbuf;
145
146 return (char *)NULL;
147 }
148
149
150 /****** fitspick **************************************************************
151 PROTO int fitspick(char *fitsline, char *keyword, void *ptr, h_type *htype,
152 t_type *ttype, char *comment)
153
154 PURPOSE Pick up FITS keyword,content,type and comment in a fits header line.
155 INPUT pointer to the current line of FITS buffer,
156 pointer to a char * (where to put the keyword),
157 pointer to ``where to put the data'',
158 pointer to ``where to put the h_type'',
159 pointer to ``where to put the t_type'',
160 pointer to a char * (where to put the comment).
161 OUTPUT RETURN_OK if something was found, RETURN_ERROR otherwise.
162 NOTES -.
163 AUTHOR E. Bertin (IAP),
164 E.R. Deul - Handling of NaN
165 VERSION 04/08/2004
166 ***/
fitspick(char * fitsline,char * keyword,void * ptr,h_type * htype,t_type * ttype,char * comment)167 int fitspick(char *fitsline, char *keyword, void *ptr, h_type *htype,
168 t_type *ttype, char *comment)
169
170 {
171 char *fptr, *cptr, c, *lastspace;
172 int i,j, toggle;
173
174 *((char *)ptr) = 0;
175 /*First, get the keyword*/
176 memcpy(keyword, fitsline, 8);
177 keyword[8] = 0;
178
179 /*Handle comments*/
180 if ((int)fitsline[8] != '=')
181 {
182 if (strncmp(keyword, "COMMENT ", 8)
183 && strncmp(keyword, "HISTORY ", 8)
184 && strncmp(keyword, "HIERARCH", 8)
185 && strncmp(keyword, " ", 8))
186 return RETURN_ERROR;
187 memcpy(comment, fitsline+9, 71);
188 comment[71] = 0;
189 *htype = H_COMMENT;
190 *ttype = T_STRING;
191 return RETURN_OK;
192 }
193
194 for (j=10; j<80 && fitsline[j] == (char)' '; j++);
195 if (j==80 || fitsline[j] == '/')
196 {
197 *htype = H_COMMENT;
198 *ttype = T_STRING;
199 return RETURN_ERROR;
200 }
201 if ((int)fitsline[j] == '\'')
202 {
203 cptr = ptr;
204 for (fptr = fitsline + (i=j+1); i<80; i++)
205 {
206 if (*fptr==(char)'\'')
207 {
208 if (i++>=79 || *(fptr+1)!=(char)'\'')
209 break;
210 else
211 fptr++;
212 }
213 *cptr++ = *fptr++;
214 }
215 *cptr = 0;
216 /*-- Check if there is a trailing space */
217 *htype = (cptr != ptr && *(cptr-1)==' ') ? H_STRINGS: H_STRING;
218 *ttype = T_STRING;
219 }
220 else if (fitsline[j] == (char)'T' || fitsline[j] == (char)'F')
221 {
222 *((BYTE *)ptr) = fitsline[j]==(char)'T'?1:0;
223 *htype = H_BOOL;
224 *ttype = T_BYTE;
225 }
226 else if (!strncmp(fitsline+j, "NaN", 3))
227 {
228 *((double *)ptr) = BIG;
229 *htype = H_EXPO;
230 *ttype = T_DOUBLE;
231 }
232 else
233 {
234 for (i=j; i<80 && fitsline[i]!=(char)'/' && fitsline[i]!=(char)'.'; i++);
235 /*-- Handle floats*/
236 if (i==80)
237 {
238 *((int *)ptr) = 0;
239 *htype = H_INT;
240 *ttype = T_LONG;
241 }
242 else if (fitsline[i]==(char)'.')
243 {
244 fixexponent(fitsline+j);
245 *((double *)ptr) = atof(fitsline+j);
246 *htype = H_EXPO;
247 *ttype = T_DOUBLE;
248 }
249 else
250 /*---- Handle ints*/
251 {
252 *((int *)ptr) = atoi(fitsline+j);
253 *htype = H_INT;
254 *ttype = T_LONG;
255 }
256 }
257
258 /*Store comment if it is found*/
259 toggle = 0;
260 lastspace = NULL;
261 for (fptr = fitsline + (i=j); i<80; i++)
262 {
263 if (*fptr == (char)'\'')
264 toggle^=toggle;
265 if (*(fptr++) == (char)'/' && !toggle)
266 {
267 while (++i<80 && *fptr<=' ')
268 fptr++;
269 i--;
270 while (++i<80)
271 if ((c=*(fptr++))>= ' ')
272 {
273 *(comment++) = c;
274 if (c>' ')
275 lastspace = comment;
276 }
277 }
278 }
279 if (lastspace)
280 *lastspace = '\0';
281 else
282 *comment = '\0';
283
284 return RETURN_OK;
285 }
286
287
288 /****** fitsread **************************************************************
289 PROTO int fitsread(char *fitsbuf, char *keyword, void *ptr, h_type htype,
290 t_type ttype)
291 PURPOSE Read a FITS keyword in a fits header.
292 INPUT pointer to the FITS buffer,
293 name of the keyword to be read,
294 pointer where to put the read data,
295 h_type of the data to be read (see fitscat.h),
296 t_type of the data to be read (see fitscat.h).
297 OUTPUT RETURN_OK if the keyword was found, RETURN_ERROR otherwise.
298 NOTES The buffer MUST contain the ``END '' keyword.
299 AUTHOR E. Bertin (IAP & Leiden observatory)
300 VERSION 04/08/2004
301 ***/
fitsread(char * fitsbuf,char * keyword,void * ptr,h_type htype,t_type ttype)302 int fitsread(char *fitsbuf, char *keyword, void *ptr, h_type htype,
303 t_type ttype)
304
305 {
306 int i,pos;
307 char s[4], str[82];
308 char *st, *st2;
309
310 if ((pos = fitsfind(fitsbuf, keyword)) < 0)
311 return RETURN_ERROR;
312
313 strncpy(str,fitsbuf+80*pos,80);
314 str[80] = '\0';
315
316 switch(htype)
317 {
318 case H_INT: if (ttype == T_SHORT)
319 sscanf(str+10, " %hd", (short *)ptr);
320 else
321 sscanf(str+10, " %d", (LONG *)ptr);
322 break;
323
324 case H_FLOAT:
325 case H_EXPO: fixexponent(str);
326 if (ttype == T_DOUBLE)
327 sscanf(str+10, " %lf", (double *)ptr);
328 else
329 sscanf(str+10, " %f", (float *)ptr);
330 break;
331
332 case H_BOOL: sscanf(str+10, "%1s", s);
333 if (ttype == T_BYTE)
334 *(BYTE *)ptr = ((int)s[0] == 'T') ? 1 : 0;
335 else if (ttype == T_SHORT)
336 *(short *)ptr = ((int)s[0] == 'T') ? 1 : 0;
337 else
338 *(LONG *)ptr = ((int)s[0] == 'T') ? 1 : 0;
339 break;
340
341 case H_STRING: st = ptr;
342 st2= str+10;
343 for (i=70; i-- && *(st2++)!=(char)'\'';);
344 while (i-->0)
345 {
346 if (*st2 == '\'' && *(++st2) != '\'')
347 break;
348 *(st++) = *(st2++);
349 }
350 do
351 {
352 *(st--) = (char)'\0';
353 } while (st>(char *)ptr && (*st == (char)' '));
354 break;
355
356 case H_STRINGS: st = ptr;
357 st2= str+10;
358 for (i=70; i-- && *(st2++)!=(char)'\'';);
359 while (i-->0)
360 {
361 if (*st2 == '\'' && *(++st2) != '\'')
362 break;
363 *(st++) = *(st2++);
364 }
365 *st = (char)'\0';
366 break;
367
368 case H_COMMENT: strcpy(ptr,str+9);
369 break;
370
371 case H_HCOMMENT: strcpy(ptr,str+33);
372 break;
373
374 default: error(EXIT_FAILURE,
375 "*Internal Error*: Unknown FITS type in ",
376 "fitsread()");
377 break;
378 }
379
380 return RETURN_OK;
381 }
382
383
384 /****** fitsremove ************************************************************
385 PROTO int fitsremove(char *fitsbuf, char *keyword)
386 PURPOSE Remove one (or more) FITS keyword from a fits header.
387 INPUT pointer to the FITS buffer,
388 name of the keyword to be created.
389 OUTPUT RETURN_OK if the keyword was found, RETURN_ERROR otherwise.
390 NOTES '?' wildcard allowed;
391 Don't remove the ``END'' keyword with this!!!
392 AUTHOR E. Bertin (IAP & Leiden observatory)
393 VERSION 08/04/99
394 ***/
395
fitsremove(char * fitsbuf,char * keyword)396 int fitsremove(char *fitsbuf, char *keyword)
397
398 {
399 char *cp1,*cp2;
400 int endpos,pos, i,n;
401
402 endpos = fitsfind(fitsbuf, "END ");
403 for (n=0; (pos = fitsfind(fitsbuf, keyword))>=0; n++, endpos--)
404 for (cp1=fitsbuf+80*(pos+1), cp2=fitsbuf+80*pos, i=80*(endpos - pos); i--;)
405 *(cp2++) = *(cp1++);
406
407 if (!n)
408 return RETURN_ERROR;
409
410 memset(fitsbuf+80*(endpos+1), ' ', 80*n);
411
412 return RETURN_OK;
413 }
414
415
416 /****** fitswrite *************************************************************
417 PROTO int fitswrite(char *fitsbuf, char *keyword, void *ptr, h_type htype,
418 t_type ttype)
419 PURPOSE Write a FITS keyword in a fits header.
420 INPUT pointer to the FITS buffer,
421 name of the keyword to be written,
422 pointer where to retrieve the data,
423 h_type of the data to be written (see fitscat.h),
424 t_type of the data to be written (see fitscat.h).
425 OUTPUT RETURN_OK if the keyword was found, RETURN_ERROR otherwise.
426 NOTES The buffer MUST contain the ``END '' keyword.
427 The keyword must already exist in the buffer (use fitsadd()).
428 AUTHOR E. Bertin (IAP & Leiden observatory)
429 VERSION 17/11/2004
430 ***/
fitswrite(char * fitsbuf,char * keyword,void * ptr,h_type htype,t_type ttype)431 int fitswrite(char *fitsbuf, char *keyword, void *ptr, h_type htype,
432 t_type ttype)
433
434 {
435 int i, l, pos, posoff, flag;
436 char str[81],str2[81];
437 char *cstr, *cstr1,*cstr2,
438 c;
439
440 /* Ignore HISTORY and COMMENTS */
441 if (findkey(keyword, (char *)histokeys, 12)!=RETURN_ERROR
442 || (pos = fitsfind(fitsbuf, keyword)) < 0)
443 return RETURN_ERROR;
444 posoff = 10;
445 fitsbuf += 80*pos;
446 switch(htype)
447 {
448 case H_INT: sprintf(str, "%20d", (ttype==T_SHORT)?
449 *(short *)ptr: *(int *)ptr);
450 break;
451
452 case H_FLOAT: sprintf(str, " %12.4f", (ttype==T_DOUBLE)?
453 *(double *)ptr: *(float *)ptr);
454 break;
455
456 case H_EXPO: sprintf(str, " %16.9E", (ttype==T_DOUBLE)?
457 *(double *)ptr: *(float *)ptr);
458 break;
459
460 case H_BOOL: if (((ttype==T_SHORT)? *(short *)ptr : *(LONG *)ptr))
461 sprintf(str, " T");
462 else
463 sprintf(str, " F");
464 break;
465
466 case H_STRING: /* Handle the famous quote */
467 cstr1 = (char *)ptr;
468 cstr2 = str2;
469 for (i=0; i<80; i++)
470 if (!(c=*(cstr2++) = *(cstr1++)))
471 break;
472 else if (c == '\'')
473 {
474 *(cstr2++) = '\'';
475 i++;
476 }
477 if (strlen(str2)<=18)
478 {
479 sprintf(str, "'%-18.18s ", str2);
480 cstr = str+18;
481 i = 10;
482 }
483 else
484 {
485 sprintf(str, "'%-68.68s ", str2);
486 cstr = str+68;
487 i = 60;
488 }
489 for (; i-- && *cstr==(char)' '; cstr--);
490 *(++cstr) = (char)'\'';
491 if (i>9)
492 *(++cstr) = 0;
493 break;
494
495 case H_STRINGS: /* Handle the famous quote */
496 cstr1 = (char *)ptr;
497 cstr2 = str2;
498 for (i=0; i<80; i++)
499 if (!(c=*(cstr2++) = *(cstr1++)))
500 break;
501 else if (c == '\'')
502 {
503 *(cstr2++) = '\'';
504 i++;
505 }
506 sprintf(str, "'%s'", str2);
507 for (i+=2;i<20; i++)
508 str[i]=' ';
509 str[i] = '\0';
510 break;
511
512 case H_COMMENT: sprintf(str, "%-70s", (char *)ptr);
513 posoff = 9;
514 break;
515
516 /* Special case of ``half-comments'' */
517 case H_HCOMMENT: sprintf(str, " / %-47s", (char *)ptr);
518 posoff = 30;
519 break;
520
521 default: error(EXIT_FAILURE,
522 "*FATAL ERROR*: Unknown FITS type in ",
523 "fitswrite()");
524 break;
525 }
526
527
528 /* Now the tricky problem of (former) comments */
529 flag=1;
530 cstr = fitsbuf+10;
531 for (i=71; --i; cstr++)
532 {
533 if (*cstr=='\'')
534 flag ^= 1;
535 else if (flag && *cstr=='/')
536 break;
537 }
538 if (posoff==10 && i && (l=69-strlen(str))>0)
539 {
540 strncpy(str2, cstr, i);
541 str2[i+1] = 0;
542 strcat(str, " ");
543 strncat(str, str2, l);
544 }
545
546 memset(fitsbuf+9, ' ', 71);
547 fitsbuf += posoff;
548
549 /* Finally copy the result to the right place (except the trailing zero) */
550 for (cstr = str; *cstr; *(fitsbuf++) = *(cstr++));
551
552 return RETURN_OK;
553 }
554
555
556 /****** fixexponent ***********************************************************
557 PROTO void fixexponent(char *s)
558 PURPOSE Replaces the FORTRAN 'D' exponent sign to 'E' in a FITS line.
559 INPUT FITS line
560 OUTPUT -.
561 NOTES -.
562 AUTHOR E. Bertin (IAP & Leiden observatory)
563 VERSION 25/04/97
564 ***/
fixexponent(char * s)565 void fixexponent(char *s)
566
567 {
568 int i;
569
570 s += 9;
571 for (i=71; (int)*s != '/' && i--; s++)
572 if ((int)*s == 'D' || (int)*s == 'd')
573 *s = (char)'E';
574
575 return;
576 }
577
578
579