1 /*** File libwcs/hput.c
2 *** September 9, 2011
3 *** By Jessica Mink, jmink@cfa.harvard.edu
4 *** Harvard-Smithsonian Center for Astrophysics
5 *** Copyright (C) 1995-2011
6 *** Smithsonian Astrophysical Observatory, Cambridge, MA, USA
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22 Correspondence concerning WCSTools should be addressed as follows:
23 Internet email: jmink@cfa.harvard.edu
24 Postal address: Jessica Mink
25 Smithsonian Astrophysical Observatory
26 60 Garden St.
27 Cambridge, MA 02138 USA
28
29 * Module: hput.c (Put FITS Header parameter values)
30 * Purpose: Implant values for parameters into FITS header string
31 * Subroutine: hputi4 (hstring,keyword,ival) sets int ival
32 * Subroutine: hputr4 (hstring,keyword,rval) sets real*4 rval
33 * Subroutine: hputr8 (hstring,keyword,dval) sets real*8 dval
34 * Subroutine: hputnr8 (hstring,keyword,ndec,dval) sets real*8 dval
35 * Subroutine: hputra (hstring,keyword,lval) sets right ascension as string
36 * Subroutine: hputdec (hstring,keyword,lval) sets declination as string
37 * Subroutine: hputl (hstring,keyword,lval) sets logical lval
38 * Subroutine: hputs (hstring,keyword,cval) sets character string adding ''
39 * Subroutine: hputm (hstring,keyword,cval) sets multi-line character string
40 * Subroutine: hputc (hstring,keyword,cval) sets character string cval
41 * Subroutine: hdel (hstring,keyword) deletes entry for keyword keyword
42 * Subroutine: hadd (hplace,keyword) adds entry for keyword at hplace
43 * Subroutine: hchange (hstring,keyword1,keyword2) changes keyword for entry
44 * Subroutine: hputcom (hstring,keyword,comment) sets comment for parameter keyword
45 * Subroutine: ra2str (out, lstr, ra, ndec) converts RA from degrees to string
46 * Subroutine: dec2str (out, lstr, dec, ndec) converts Dec from degrees to string
47 * Subroutine: deg2str (out, lstr, deg, ndec) converts degrees to string
48 * Subroutine: num2str (out, num, field, ndec) converts number to string
49 * Subroutine: getltime () returns current local time as ISO-style string
50 * Subroutine: getutime () returns current UT as ISO-style string
51 */
52 #include <sys/time.h>
53 #include <string.h> /* NULL, strlen, strstr, strcpy */
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <math.h>
57 #include "fitshead.h"
58
59 static int verbose=0; /* Set to 1 to print error messages and other info */
60
61 static void fixnegzero();
62
63
64 /* HPUTI4 - Set int keyword = ival in FITS header string */
65
66 int
hputi4(hstring,keyword,ival)67 hputi4 (hstring,keyword,ival)
68
69 char *hstring; /* FITS-style header information in the format
70 <keyword>= <value> {/ <comment>}
71 each entry is padded with spaces to 80 characters */
72
73 const char *keyword; /* Name of the variable in header to be returned.
74 If no line begins with this string, one is created.
75 The first 8 characters of keyword must be unique. */
76 int ival; /* int number */
77 {
78 char value[30];
79
80 /* Translate value from binary to ASCII */
81 sprintf (value,"%d",ival);
82
83 /* Put value into header string */
84 return (hputc (hstring,keyword,value));
85 }
86
87
88 /* HPUTR4 - Set float keyword = rval in FITS header string */
89
90 int
hputr4(hstring,keyword,rval)91 hputr4 (hstring, keyword, rval)
92
93 char *hstring; /* FITS header string */
94 const char *keyword; /* Keyword name */
95 const float *rval; /* float number */
96
97 {
98 char value[30];
99
100 /* Translate value from binary to ASCII */
101 sprintf (value, "%f", *rval);
102
103 /* Remove sign if string is -0 or extension thereof */
104 fixnegzero (value);
105
106 /* Put value into header string */
107 return (hputc (hstring, keyword, value));
108 }
109
110
111 /* HPUTR8 - Set double keyword = dval in FITS header string */
112
113 int
hputr8(hstring,keyword,dval)114 hputr8 (hstring, keyword, dval)
115
116 char *hstring; /* FITS header string */
117 const char *keyword; /* Keyword name */
118 const double dval; /* double number */
119 {
120 char value[30];
121
122 /* Translate value from binary to ASCII */
123 sprintf (value, "%g", dval);
124
125 /* Remove sign if string is -0 or extension thereof */
126 fixnegzero (value);
127
128 /* Put value into header string */
129 return (hputc (hstring, keyword, value));
130 }
131
132
133 /* HPUTNR8 - Set double keyword = dval in FITS header string */
134
135 int
hputnr8(hstring,keyword,ndec,dval)136 hputnr8 (hstring, keyword, ndec, dval)
137
138 char *hstring; /* FITS header string */
139 const char *keyword; /* Keyword name */
140 const int ndec; /* Number of decimal places to print */
141 const double dval; /* double number */
142 {
143 char value[30];
144 char format[8];
145 int i, lval;
146
147 /* Translate value from binary to ASCII */
148 if (ndec < 0) {
149 sprintf (format, "%%.%dg", -ndec);
150 sprintf (value, format, dval);
151 lval = (int) strlen (value);
152 for (i = 0; i < lval; i++)
153 if (value[i] == 'e') value[i] = 'E';
154 }
155 else {
156 sprintf (format, "%%.%df", ndec);
157 sprintf (value, format, dval);
158 }
159
160 /* Remove sign if string is -0 or extension thereof */
161 fixnegzero (value);
162
163 /* Put value into header string */
164 return (hputc (hstring, keyword, value));
165 }
166
167
168 /* HPUTRA - Set double keyword = hh:mm:ss.sss in FITS header string */
169
170 int
hputra(hstring,keyword,ra)171 hputra (hstring, keyword, ra)
172
173 char *hstring; /* FITS header string */
174 const char *keyword; /* Keyword name */
175 const double ra; /* Right ascension in degrees */
176 {
177 char value[30];
178
179 /* Translate value from binary to ASCII */
180 ra2str (value, 30, ra, 3);
181
182 /* Remove sign if string is -0 or extension thereof */
183 fixnegzero (value);
184
185 /* Put value into header string */
186 return (hputs (hstring, keyword, value));
187 }
188
189
190 /* HPUTDEC - Set double keyword = dd:mm:ss.sss in FITS header string */
191
192 int
hputdec(hstring,keyword,dec)193 hputdec (hstring, keyword, dec)
194
195 char *hstring; /* FITS header string */
196 const char *keyword; /* Keyword name */
197 const double dec; /* Declination in degrees */
198 {
199 char value[30];
200
201 /* Translate value from binary to ASCII */
202 dec2str (value, 30, dec, 2);
203
204 /* Remove sign if string is -0 or extension thereof */
205 fixnegzero (value);
206
207 /* Put value into header string */
208 return (hputs (hstring, keyword, value));
209 }
210
211
212 /* FIXNEGZERO -- Drop - sign from beginning of any string which is all zeros */
213
214 static void
fixnegzero(string)215 fixnegzero (string)
216
217 char *string;
218 {
219 int i, lstr;
220
221 if (string[0] != '-')
222 return;
223
224 /* Drop out if any non-zero digits in this string */
225 lstr = (int) strlen (string);
226 for (i = 1; i < lstr; i++) {
227 if (string[i] > '0' && string[i] <= '9')
228 return;
229 if (string[i] == 'd' || string[i] == 'e' || string[i] == ' ')
230 break;
231 }
232
233 /* Drop - from start of string; overwrite string in place */
234 for (i = 1; i < lstr; i++)
235 string[i-1] = string[i];
236 string[lstr-1] = (char) 0;
237
238 return;
239 }
240
241
242
243 /* HPUTL - Set keyword = F if lval=0, else T, in FITS header string */
244
245 int
hputl(hstring,keyword,lval)246 hputl (hstring, keyword,lval)
247
248 char *hstring; /* FITS header */
249 const char *keyword; /* Keyword name */
250 const int lval; /* logical variable (0=false, else true) */
251 {
252 char value[8];
253
254 /* Translate value from binary to ASCII */
255 if (lval)
256 strcpy (value, "T");
257 else
258 strcpy (value, "F");
259
260 /* Put value into header string */
261 return (hputc (hstring,keyword,value));
262 }
263
264
265 /* HPUTM - Set multi-line character string in FITS header string */
266 /* return number of keywords written */
267
268 int
hputm(hstring,keyword,cval)269 hputm (hstring,keyword,cval)
270
271 char *hstring; /* FITS header */
272 const char *keyword; /* Keyword name root (6 characters or less) */
273 const char *cval; /* character string containing the value for variable
274 keyword. trailing and leading blanks are removed. */
275 {
276 int lroot, lcv, i, ii, nkw, lkw, lval;
277 int comment = 0;
278 const char *v;
279 char keyroot[8], newkey[12], value[80];
280 char squot = 39;
281
282 /* If COMMENT or HISTORY, use the same keyword on every line */
283 lkw = (int) strlen (keyword);
284 if (lkw == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
285 strncmp (keyword,"HISTORY",7) == 0)) {
286 comment = 1;
287 lroot = 0;
288 }
289
290 /* Set up keyword root, shortening it to 6 characters, if necessary */
291 else {
292 comment = 0;
293 strcpy (keyroot, keyword);
294 lroot = (int) strlen (keyroot);
295 if (lroot > 6) {
296 keyroot[6] = (char) 0;
297 lroot = 6;
298 }
299 }
300
301 /* Write keyword value one line of up to 67 characters at a time */
302 ii = '1';
303 nkw = 0;
304 lcv = (int) strlen (cval);
305 if (!comment) {
306 strcpy (newkey, keyroot);
307 strcat (newkey, "_");
308 newkey[lroot+2] = (char) 0;
309 }
310 v = cval;
311 while (lcv > 0) {
312 if (lcv > 67)
313 lval = 67;
314 else
315 lval = lcv;
316 value[0] = squot;
317 for (i = 1; i <= lval; i++)
318 value[i] = *v++;
319
320 /* Pad short strings to 8 characters */
321 if (lval < 8) {
322 for (i = lval+1; i < 9; i++)
323 value[i] = ' ';
324 lval = 8;
325 }
326 value[lval+1] = squot;
327 value[lval+2] = (char) 0;
328
329 /* Add this line to the header */
330 if (comment)
331 i = hputc (hstring, keyroot, value);
332 else {
333 newkey[lroot+1] = ii;
334 ii++;
335 i = hputc (hstring, newkey, value);
336 }
337 if (i != 0) return (i);
338 nkw++;
339 if (lcv > 67)
340 lcv = lcv - 67;
341 else
342 break;
343 }
344 return (nkw);
345 }
346
347
348 /* HPUTS - Set character string keyword = 'cval' in FITS header string */
349
350 int
hputs(hstring,keyword,cval)351 hputs (hstring,keyword,cval)
352
353 char *hstring; /* FITS header */
354 const char *keyword; /* Keyword name */
355 const char *cval; /* character string containing the value for variable
356 keyword. trailing and leading blanks are removed. */
357 {
358 char squot = 39;
359 char value[80];
360 int lcval, i, lkeyword;
361
362 /* If COMMENT or HISTORY, just add it as is */
363 lkeyword = (int) strlen (keyword);
364 if (lkeyword == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
365 strncmp (keyword,"HISTORY",7) == 0))
366 return (hputc (hstring,keyword,cval));
367
368 /* find length of variable string */
369 lcval = (int) strlen (cval);
370 if (lcval > 67)
371 lcval = 67;
372
373 /* Put single quote at start of string */
374 value[0] = squot;
375 strncpy (&value[1],cval,lcval);
376
377 /* If string is less than eight characters, pad it with spaces */
378 if (lcval < 8) {
379 for (i = lcval; i < 8; i++) {
380 value[i+1] = ' ';
381 }
382 lcval = 8;
383 }
384
385 /* Add single quote and null to end of string */
386 value[lcval+1] = squot;
387 value[lcval+2] = (char) 0;
388
389 /* Put value into header string */
390 return (hputc (hstring,keyword,value));
391 }
392
393
394 /* HPUTC - Set character string keyword = value in FITS header string */
395 /* Return -1 if error, 0 if OK */
396
397 int
hputc(hstring,keyword,value)398 hputc (hstring,keyword,value)
399
400 char *hstring;
401 const char *keyword;
402 const char *value; /* character string containing the value for variable
403 keyword. trailing and leading blanks are removed. */
404 {
405 char squot = 39;
406 char line[100];
407 char newcom[50];
408 char *vp, *v1, *v2, *q1, *q2, *c1, *ve;
409 int lkeyword, lcom, lval, lc, lv1, lhead, lblank, ln, nc, i;
410
411 /* Find length of keyword, value, and header */
412 lkeyword = (int) strlen (keyword);
413 lval = (int) strlen (value);
414 lhead = gethlength (hstring);
415
416 /* If COMMENT or HISTORY, always add it just before the END */
417 if (lkeyword == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
418 strncmp (keyword,"HISTORY",7) == 0)) {
419
420 /* First look for blank lines before END */
421 v1 = blsearch (hstring, "END");
422
423 /* Otherwise, create a space for it at the end of the header */
424 if (v1 == NULL) {
425
426 /* Find end of header */
427 v1 = ksearch (hstring,"END");
428
429 /* Align pointer at start of 80-character line */
430 lc = v1 - hstring;
431 ln = lc / 80;
432 nc = ln * 80;
433 v1 = hstring + nc;
434 v2 = v1 + 80;
435
436 /* If header length is exceeded, return error code */
437 if (v2 - hstring > lhead) {
438 return (-1);
439 }
440
441 /* Move END down 80 characters */
442 strncpy (v2, v1, 80);
443 }
444 else
445 v2 = v1 + 80;
446
447 /* Insert keyword */
448 strncpy (v1,keyword,7);
449
450 /* Pad with spaces */
451 for (vp = v1+lkeyword; vp < v2; vp++)
452 *vp = ' ';
453
454 if (lval > 71)
455 lv1 = 71;
456 else
457 lv1 = lval;
458
459 /* Insert comment */
460 strncpy (v1+9,value,lv1);
461 return (0);
462 }
463
464 /* Otherwise search for keyword */
465 else
466 v1 = ksearch (hstring,keyword);
467
468 /* If parameter is not found, find a place to put it */
469 if (v1 == NULL) {
470
471 /* First look for blank lines before END */
472 v1 = blsearch (hstring, "END");
473
474 /* Otherwise, create a space for it at the end of the header */
475 if (v1 == NULL) {
476 ve = ksearch (hstring,"END");
477 v1 = ve;
478
479 /* Align pointer at start of 80-character line */
480 lc = v1 - hstring;
481 ln = lc / 80;
482 nc = ln * 80;
483 v1 = hstring + nc;
484 v2 = v1 + 80;
485
486 /* If header length is exceeded, return error code */
487 if (v2 - hstring > lhead) {
488 return (-1);
489 }
490
491 strncpy (v2, ve, 80);
492 }
493 else
494 v2 = v1 + 80;
495 lcom = 0;
496 newcom[0] = 0;
497 }
498
499 /* Otherwise, extract the entry for this keyword from the header */
500 else {
501
502 /* Align pointer at start of 80-character line */
503 lc = v1 - hstring;
504 ln = lc / 80;
505 nc = ln * 80;
506 v1 = hstring + nc;
507 v2 = v1 + 80;
508
509 strncpy (line, v1, 80);
510 line[80] = 0;
511 v2 = v1 + 80;
512
513 /* check for quoted value */
514 q1 = strchr (line, squot);
515 if (q1 != NULL) {
516 q2 = strchr (q1+1,squot);
517 if (q2 != NULL)
518 c1 = strchr (q2,'/');
519 else
520 c1 = strrchr (line+79,'/');
521 }
522 else
523 c1 = strchr (line,'/');
524
525 /* extract comment and discount trailing spaces */
526 if (c1 != NULL) {
527 lcom = 80 - (c1 + 2 - line);
528 strncpy (newcom, c1+2, lcom);
529 vp = newcom + lcom - 1;
530 while (vp-- > newcom && *vp == ' ')
531 lcom--;
532 }
533 else {
534 newcom[0] = 0;
535 lcom = 0;
536 }
537 }
538
539 /* Fill new entry with spaces */
540 for (vp = v1; vp < v2; vp++)
541 *vp = ' ';
542
543 /* Copy keyword to new entry */
544 strncpy (v1, keyword, lkeyword);
545
546 /* Add parameter value in the appropriate place */
547 vp = v1 + 8;
548 *vp = '=';
549 vp = v1 + 9;
550 *vp = ' ';
551 vp = vp + 1;
552 if (*value == squot) {
553 strncpy (vp, value, lval);
554 if (lval+12 > 31)
555 lc = lval + 12;
556 else
557 lc = 30;
558 }
559 else {
560 vp = v1 + 30 - lval;
561 strncpy (vp, value, lval);
562 lc = 30;
563 }
564
565 /* Add comment in the appropriate place */
566 if (lcom > 0) {
567 if (lc+2+lcom > 80)
568 lcom = 77 - lc;
569 vp = v1 + lc; /* Jul 16 1997: was vp = v1 + lc * 2 */
570 *vp++ = ' ';
571 *vp++ = '/';
572 *vp++ = ' ';
573 lblank = v2 - vp;
574 for (i = 0; i < lblank; i++)
575 vp[i] = ' ';
576 if (lcom > lblank)
577 lcom = lblank;
578 strncpy (vp, newcom, lcom);
579 }
580
581 if (verbose) {
582 if (lcom > 0)
583 fprintf (stderr,"HPUT: %s = %s / %s\n",keyword, value, newcom);
584 else
585 fprintf (stderr,"HPUT: %s = %s\n",keyword, value);
586 }
587
588 return (0);
589 }
590
591
592 /* HPUTCOM - Set comment for keyword or on line in FITS header string */
593
594 int
hputcom(hstring,keyword,comment)595 hputcom (hstring,keyword,comment)
596
597 char *hstring;
598 const char *keyword;
599 const char *comment;
600 {
601 char squot, slash, space;
602 char line[100];
603 int lkeyword, lcom, lhead, i, lblank, ln, nc, lc;
604 char *vp, *v1, *v2, *c0, *c1, *q1, *q2;
605
606 squot = (char) 39;
607 slash = (char) 47;
608 space = (char) 32;
609
610 /* Find length of variable name */
611 lkeyword = (int) strlen (keyword);
612 lhead = gethlength (hstring);
613 lcom = (int) strlen (comment);
614
615 /* If COMMENT or HISTORY, always add it just before the END */
616 if (lkeyword == 7 && (strncmp (keyword,"COMMENT",7) == 0 ||
617 strncmp (keyword,"HISTORY",7) == 0)) {
618
619 /* Find end of header */
620 v1 = ksearch (hstring,"END");
621
622 /* Align pointer at start of 80-character line */
623 lc = v1 - hstring;
624 ln = lc / 80;
625 nc = ln * 80;
626 v1 = hstring + nc;
627 v2 = v1 + 80;
628
629 /* If header length is exceeded, return error code */
630 if (v2 - hstring > lhead) {
631 return (-1);
632 }
633
634 /* Move END down 80 characters */
635 strncpy (v2, v1, 80);
636
637 /* blank out new line and insert keyword */
638 for (vp = v1; vp < v2; vp++)
639 *vp = ' ';
640 strncpy (v1, keyword, lkeyword);
641 c0 = v1 + lkeyword;
642 }
643
644 /* Search header string for variable name */
645 else {
646 v1 = ksearch (hstring,keyword);
647
648 /* If parameter is not found, return without doing anything */
649 if (v1 == NULL) {
650 if (verbose)
651 fprintf (stderr,"HPUTCOM: %s not found\n",keyword);
652 return (-1);
653 }
654
655 /* Align pointer at start of 80-character line */
656 lc = v1 - hstring;
657 ln = lc / 80;
658 nc = ln * 80;
659 v1 = hstring + nc;
660 v2 = v1 + 80;
661
662 /* Extract entry for this variable from the header */
663 strncpy (line, v1, 80);
664 line[80] = '\0'; /* Null-terminate line before strchr call */
665
666 /* check for quoted value */
667 q1 = strchr (line,squot);
668 c1 = strchr (line,slash);
669 if (q1 != NULL) {
670 if (c1 != NULL && q1 < c1) {
671 q2 = strchr (q1+1, squot);
672 if (q2 == NULL) {
673 q2 = c1 - 1;
674 while (*q2 == space)
675 q2--;
676 q2++;
677 }
678 else if (c1 < q2)
679 c1 = strchr (q2, slash);
680 }
681 else if (c1 == NULL) {
682 q2 = strchr (q1+1, squot);
683 if (q2 == NULL) {
684 q2 = line + 79;
685 while (*q2 == space)
686 q2--;
687 q2++;
688 }
689 }
690 else
691 q1 = NULL;
692 q2 = NULL;
693 }
694
695 else
696 q2 = NULL;
697
698 if (c1 != NULL)
699 c0 = v1 + (c1 - line) - 1;
700 else if (q2 == NULL || q2-line < 30)
701 c0 = v1 + 30;
702 else
703 c0 = v1 + (q2 - line) + 1; /* allan: 1997-09-30, was c0=q2+2 */
704
705 /* If comment will not fit at all, return */
706 if (c0 - v1 > 77)
707 return (-1);
708 strncpy (c0, " / ",3);
709 }
710
711 /* Create new entry */
712 if (lcom > 0) {
713 c1 = c0 + 3;
714 lblank = v1 + 79 - c1;
715 if (lcom > lblank)
716 lcom = lblank;
717 for (i = 0; i < lblank; i++)
718 c1[i] = ' ';
719 strncpy (c1, comment, lcom);
720 }
721
722 if (verbose) {
723 fprintf (stderr,"HPUTCOM: %s / %s\n",keyword,comment);
724 }
725 return (0);
726 }
727
728
729 static int leaveblank = 0; /* If 1, leave blank line when deleting */
730 void
setleaveblank(lb)731 setleaveblank (lb)
732 int lb; { leaveblank = lb; return; }
733
734 static int headshrink=1; /* Set to 1 to drop line after deleting keyword */
735 void
setheadshrink(hsh)736 setheadshrink (hsh)
737 int hsh;
738 {headshrink = hsh; return;}
739
740 /* HDEL - Set character string keyword = value in FITS header string
741 * returns 1 if entry deleted, else 0
742 */
743
744 int
hdel(hstring,keyword)745 hdel (hstring,keyword)
746
747 char *hstring; /* FITS header */
748 const char *keyword; /* Keyword of entry to be deleted */
749 {
750 char *v, *v1, *v2, *ve;
751
752 /* Search for keyword */
753 v1 = ksearch (hstring,keyword);
754
755 /* If keyword is not found, return header unchanged */
756 if (v1 == NULL) {
757 return (0);
758 }
759
760 /* Find end of header */
761 ve = ksearch (hstring,"END");
762
763 /* If headshrink is 0, leave END where it is */
764 if (!leaveblank && !headshrink)
765 ve = ve - 80;
766
767 /* Cover deleted keyword line with spaces */
768 if (leaveblank) {
769 v2 = v1 + 80;
770 for (v = ve; v < v2; v++)
771 *v = ' ';
772 }
773
774 /* Shift rest of header up one line */
775 else {
776 for (v = v1; v < ve; v = v + 80) {
777 v2 = v + 80;
778 strncpy (v, v2, 80);
779 }
780
781 /* Cover former last line with spaces */
782 v2 = ve + 80;
783 for (v = ve; v < v2; v++)
784 *v = ' ';
785 }
786
787 return (1);
788 }
789
790
791 /* HADD - Add character string keyword = value to FITS header string
792 * returns 1 if entry added, else 0
793 * Call hputx() to put value into entry
794 */
795
796 int
hadd(hplace,keyword)797 hadd (hplace, keyword)
798
799 char *hplace; /* FITS header position for new keyword */
800 const char *keyword; /* Keyword of entry to be deleted */
801 {
802 char *v, *v1, *v2, *ve;
803 int i, lkey;
804
805 /* Find end of header */
806 ve = ksearch (hplace,"END");
807
808 /* If END is not found, return header unchanged */
809 if (ve == NULL) {
810 return (0);
811 }
812
813 v1 = hplace;
814
815 /* Shift rest of header down one line */
816 /* limit bug found by Paolo Montegriffo fixed 2000-04-19 */
817 for (v = ve; v >= v1; v = v - 80) {
818 v2 = v + 80;
819 strncpy (v2, v, 80);
820 }
821
822 /* Cover former first line with new keyword */
823 lkey = (int) strlen (keyword);
824 strncpy (hplace, keyword, lkey);
825 if (lkey < 8) {
826 for (i = lkey; i < 8; i++)
827 hplace[i] = ' ';
828 hplace[8] = '=';
829 }
830 for (i = 9; i < 80; i++)
831 hplace[i] = ' ';
832
833 return (1);
834 }
835
836
837 /* HCHANGE - Changes keyword for entry from keyword1 to keyword2 in FITS
838 header string
839 * returns 1 if entry changed, else 0
840 */
841
842 int
hchange(hstring,keyword1,keyword2)843 hchange (hstring, keyword1, keyword2)
844
845 char *hstring; /* FITS header */
846 const char *keyword1; /* Keyword to be changed */
847 const char *keyword2; /* New keyword name */
848 {
849 char *v, *v1;
850 const char *v2;
851 int lv2, i;
852
853 /* Search for keyword */
854 v1 = ksearch (hstring,keyword1);
855
856 /* If keyword is not found, return header unchanged */
857 if (!v1)
858 return (0);
859
860 else {
861 lv2 = (int) strlen (keyword2);
862 v = v1;
863 v2 = keyword2;
864 for (i = 0; i < 8; i++) {
865 if (i < lv2)
866 v[i] = v2[i];
867 else
868 v[i] = ' ';
869 }
870 }
871
872 return (1);
873 }
874
875
876 /* Write the right ascension ra in sexagesimal format into string*/
877
878 void
ra2str(string,lstr,ra,ndec)879 ra2str (string, lstr, ra, ndec)
880
881 char *string; /* Character string (returned) */
882 int lstr; /* Maximum number of characters in string */
883 double ra; /* Right ascension in degrees */
884 int ndec; /* Number of decimal places in seconds */
885
886 {
887 double a,b;
888 double seconds;
889 char tstring[64];
890 int hours;
891 int minutes;
892 int isec, ltstr;
893 double dsgn;
894
895 /* Keep RA between 0 and 360 */
896 if (ra < 0.0 ) {
897 ra = -ra;
898 dsgn = -1.0;
899 }
900 else
901 dsgn = 1.0;
902 ra = fmod(ra, 360.0);
903 ra *= dsgn;
904 if (ra < 0.0)
905 ra = ra + 360.0;
906
907 a = ra / 15.0;
908
909 /* Convert to hours */
910 hours = (int) a;
911
912 /* Compute minutes */
913 b = (a - (double)hours) * 60.0;
914 minutes = (int) b;
915
916 /* Compute seconds */
917 seconds = (b - (double)minutes) * 60.0;
918
919 if (ndec > 5) {
920 if (seconds > 59.999999) {
921 seconds = 0.0;
922 minutes = minutes + 1;
923 }
924 if (minutes > 59) {
925 minutes = 0;
926 hours = hours + 1;
927 }
928 hours = hours % 24;
929 (void) sprintf (tstring,"%02d:%02d:%09.6f",hours,minutes,seconds);
930 }
931 else if (ndec > 4) {
932 if (seconds > 59.99999) {
933 seconds = 0.0;
934 minutes = minutes + 1;
935 }
936 if (minutes > 59) {
937 minutes = 0;
938 hours = hours + 1;
939 }
940 hours = hours % 24;
941 (void) sprintf (tstring,"%02d:%02d:%08.5f",hours,minutes,seconds);
942 }
943 else if (ndec > 3) {
944 if (seconds > 59.9999) {
945 seconds = 0.0;
946 minutes = minutes + 1;
947 }
948 if (minutes > 59) {
949 minutes = 0;
950 hours = hours + 1;
951 }
952 hours = hours % 24;
953 (void) sprintf (tstring,"%02d:%02d:%07.4f",hours,minutes,seconds);
954 }
955 else if (ndec > 2) {
956 if (seconds > 59.999) {
957 seconds = 0.0;
958 minutes = minutes + 1;
959 }
960 if (minutes > 59) {
961 minutes = 0;
962 hours = hours + 1;
963 }
964 hours = hours % 24;
965 (void) sprintf (tstring,"%02d:%02d:%06.3f",hours,minutes,seconds);
966 }
967 else if (ndec > 1) {
968 if (seconds > 59.99) {
969 seconds = 0.0;
970 minutes = minutes + 1;
971 }
972 if (minutes > 59) {
973 minutes = 0;
974 hours = hours + 1;
975 }
976 hours = hours % 24;
977 (void) sprintf (tstring,"%02d:%02d:%05.2f",hours,minutes,seconds);
978 }
979 else if (ndec > 0) {
980 if (seconds > 59.9) {
981 seconds = 0.0;
982 minutes = minutes + 1;
983 }
984 if (minutes > 59) {
985 minutes = 0;
986 hours = hours + 1;
987 }
988 hours = hours % 24;
989 (void) sprintf (tstring,"%02d:%02d:%04.1f",hours,minutes,seconds);
990 }
991 else {
992 isec = (int)(seconds + 0.5);
993 if (isec > 59) {
994 isec = 0;
995 minutes = minutes + 1;
996 }
997 if (minutes > 59) {
998 minutes = 0;
999 hours = hours + 1;
1000 }
1001 hours = hours % 24;
1002 (void) sprintf (tstring,"%02d:%02d:%02d",hours,minutes,isec);
1003 }
1004
1005 /* Move formatted string to returned string */
1006 ltstr = (int) strlen (tstring);
1007 if (ltstr < lstr-1)
1008 strcpy (string, tstring);
1009 else {
1010 strncpy (string, tstring, lstr-1);
1011 string[lstr-1] = 0;
1012 }
1013 return;
1014 }
1015
1016
1017 /* Write the variable a in sexagesimal format into string */
1018
1019 void
dec2str(string,lstr,dec,ndec)1020 dec2str (string, lstr, dec, ndec)
1021
1022 char *string; /* Character string (returned) */
1023 int lstr; /* Maximum number of characters in string */
1024 double dec; /* Declination in degrees */
1025 int ndec; /* Number of decimal places in arcseconds */
1026
1027 {
1028 double a, b, dsgn, deg1;
1029 double seconds;
1030 char sign;
1031 int degrees;
1032 int minutes;
1033 int isec, ltstr;
1034 char tstring[64];
1035
1036 /* Keep angle between -180 and 360 degrees */
1037 deg1 = dec;
1038 if (deg1 < 0.0 ) {
1039 deg1 = -deg1;
1040 dsgn = -1.0;
1041 }
1042 else
1043 dsgn = 1.0;
1044 deg1 = fmod(deg1, 360.0);
1045 deg1 *= dsgn;
1046 if (deg1 <= -180.0)
1047 deg1 = deg1 + 360.0;
1048
1049 a = deg1;
1050
1051 /* Set sign and do all the rest with a positive */
1052 if (a < 0) {
1053 sign = '-';
1054 a = -a;
1055 }
1056 else
1057 sign = '+';
1058
1059 /* Convert to degrees */
1060 degrees = (int) a;
1061
1062 /* Compute minutes */
1063 b = (a - (double)degrees) * 60.0;
1064 minutes = (int) b;
1065
1066 /* Compute seconds */
1067 seconds = (b - (double)minutes) * 60.0;
1068
1069 if (ndec > 5) {
1070 if (seconds > 59.999999) {
1071 seconds = 0.0;
1072 minutes = minutes + 1;
1073 }
1074 if (minutes > 59) {
1075 minutes = 0;
1076 degrees = degrees + 1;
1077 }
1078 (void) sprintf (tstring,"%c%02d:%02d:%09.6f",sign,degrees,minutes,seconds);
1079 }
1080 else if (ndec > 4) {
1081 if (seconds > 59.99999) {
1082 seconds = 0.0;
1083 minutes = minutes + 1;
1084 }
1085 if (minutes > 59) {
1086 minutes = 0;
1087 degrees = degrees + 1;
1088 }
1089 (void) sprintf (tstring,"%c%02d:%02d:%08.5f",sign,degrees,minutes,seconds);
1090 }
1091 else if (ndec > 3) {
1092 if (seconds > 59.9999) {
1093 seconds = 0.0;
1094 minutes = minutes + 1;
1095 }
1096 if (minutes > 59) {
1097 minutes = 0;
1098 degrees = degrees + 1;
1099 }
1100 (void) sprintf (tstring,"%c%02d:%02d:%07.4f",sign,degrees,minutes,seconds);
1101 }
1102 else if (ndec > 2) {
1103 if (seconds > 59.999) {
1104 seconds = 0.0;
1105 minutes = minutes + 1;
1106 }
1107 if (minutes > 59) {
1108 minutes = 0;
1109 degrees = degrees + 1;
1110 }
1111 (void) sprintf (tstring,"%c%02d:%02d:%06.3f",sign,degrees,minutes,seconds);
1112 }
1113 else if (ndec > 1) {
1114 if (seconds > 59.99) {
1115 seconds = 0.0;
1116 minutes = minutes + 1;
1117 }
1118 if (minutes > 59) {
1119 minutes = 0;
1120 degrees = degrees + 1;
1121 }
1122 (void) sprintf (tstring,"%c%02d:%02d:%05.2f",sign,degrees,minutes,seconds);
1123 }
1124 else if (ndec > 0) {
1125 if (seconds > 59.9) {
1126 seconds = 0.0;
1127 minutes = minutes + 1;
1128 }
1129 if (minutes > 59) {
1130 minutes = 0;
1131 degrees = degrees + 1;
1132 }
1133 (void) sprintf (tstring,"%c%02d:%02d:%04.1f",sign,degrees,minutes,seconds);
1134 }
1135 else {
1136 isec = (int)(seconds + 0.5);
1137 if (isec > 59) {
1138 isec = 0;
1139 minutes = minutes + 1;
1140 }
1141 if (minutes > 59) {
1142 minutes = 0;
1143 degrees = degrees + 1;
1144 }
1145 (void) sprintf (tstring,"%c%02d:%02d:%02d",sign,degrees,minutes,isec);
1146 }
1147
1148 /* Move formatted string to returned string */
1149 ltstr = (int) strlen (tstring);
1150 if (ltstr < lstr-1)
1151 strcpy (string, tstring);
1152 else {
1153 strncpy (string, tstring, lstr-1);
1154 string[lstr-1] = 0;
1155 }
1156 return;
1157 }
1158
1159
1160 /* Write the angle a in decimal format into string */
1161
1162 void
deg2str(string,lstr,deg,ndec)1163 deg2str (string, lstr, deg, ndec)
1164
1165 char *string; /* Character string (returned) */
1166 int lstr; /* Maximum number of characters in string */
1167 double deg; /* Angle in degrees */
1168 int ndec; /* Number of decimal places in degree string */
1169
1170 {
1171 char degform[8];
1172 int field, ltstr;
1173 char tstring[64];
1174 double deg1;
1175 double dsgn;
1176
1177 /* Keep angle between -180 and 360 degrees */
1178 deg1 = deg;
1179 if (deg1 < 0.0 ) {
1180 deg1 = -deg1;
1181 dsgn = -1.0;
1182 }
1183 else
1184 dsgn = 1.0;
1185 deg1 = fmod(deg1, 360.0);
1186 deg1 *= dsgn;
1187 if (deg1 <= -180.0)
1188 deg1 = deg1 + 360.0;
1189
1190 /* Write angle to string, adding 4 digits to number of decimal places */
1191 field = ndec + 4;
1192 if (ndec > 0) {
1193 sprintf (degform, "%%%d.%df", field, ndec);
1194 sprintf (tstring, degform, deg1);
1195 }
1196 else {
1197 sprintf (degform, "%%%4d", field);
1198 sprintf (tstring, degform, (int)deg1);
1199 }
1200
1201 /* Move formatted string to returned string */
1202 ltstr = (int) strlen (tstring);
1203 if (ltstr < lstr-1)
1204 strcpy (string, tstring);
1205 else {
1206 strncpy (string, tstring, lstr-1);
1207 string[lstr-1] = 0;
1208 }
1209 return;
1210 }
1211
1212
1213 /* Write the variable a in decimal format into field-character string */
1214
1215 void
num2str(string,num,field,ndec)1216 num2str (string, num, field, ndec)
1217
1218 char *string; /* Character string (returned) */
1219 double num; /* Number */
1220 int field; /* Number of characters in output field (0=any) */
1221 int ndec; /* Number of decimal places in degree string */
1222
1223 {
1224 char numform[8];
1225
1226 if (field > 0) {
1227 if (ndec > 0) {
1228 sprintf (numform, "%%%d.%df", field, ndec);
1229 sprintf (string, numform, num);
1230 }
1231 else {
1232 sprintf (numform, "%%%dd", field);
1233 sprintf (string, numform, (int)num);
1234 }
1235 }
1236 else {
1237 if (ndec > 0) {
1238 sprintf (numform, "%%.%df", ndec);
1239 sprintf (string, numform, num);
1240 }
1241 else {
1242 sprintf (string, "%d", (int)num);
1243 }
1244 }
1245 return;
1246 }
1247
1248 /* Dec 14 1995 Original subroutines
1249
1250 * Feb 5 1996 Added HDEL to delete keyword entry from FITS header
1251 * Feb 7 1996 Add EOS to LINE in HPUTC
1252 * Feb 21 1996 Add RA2STR and DEC2STR string routines
1253 * Jul 19 1996 Add HPUTRA and HPUTDEC
1254 * Jul 22 1996 Add HCHANGE to change keywords
1255 * Aug 5 1996 Add HPUTNR8 to save specific number of decimal places
1256 * Oct 15 1996 Fix spelling
1257 * Nov 1 1996 Add DEG2STR to set specific number of decimal places
1258 * Nov 1 1996 Allow DEC2STR to handle upt to 6 decimal places
1259 *
1260 * Mar 20 1997 Fix format error in DEG2STR
1261 * Jul 7 1997 Fix 2 errors in HPUTCOM found by Allan Brighton
1262 * Jul 16 1997 Fix error in HPUTC found by Allan Brighton
1263 * Jul 17 1997 Fix error in HPUTC found by Allan Brighton
1264 * Sep 30 1997 Fix error in HPUTCOM found by Allan Brighton
1265 * Dec 15 1997 Fix minor bugs after lint
1266 * Dec 31 1997 Always put two hour digits in RA2STR
1267 *
1268 * Feb 25 1998 Add HADD to insert keywords at specific locations
1269 * Mar 27 1998 If n is negative, write g format in HPUTNR8()
1270 * Apr 24 1998 Add NUM2STR() for easy output formatting
1271 * Apr 30 1998 Use BLSEARCH() to overwrite blank lines before END
1272 * May 27 1998 Keep Dec between -90 and +90 in DEC2STR()
1273 * May 28 1998 Keep RA between 0 and 360 in RA2STR()
1274 * Jun 2 1998 Fix bug when filling in blank lines before END
1275 * Jun 24 1998 Add string length to ra2str(), dec2str(), and deg2str()
1276 * Jun 25 1998 Make string converstion subroutines more robust
1277 * Aug 31 1998 Add getltime() and getutime()
1278 * Sep 28 1998 Null-terminate comment in HPUTCOM (Allan Brighton)
1279 * Oct 1 1998 Change clock declaration in getltime() from int (Allan Brighton)
1280 *
1281 * Jan 28 1999 Fix bug to avoid writing HISTORY or COMMENT past 80 characters
1282 * Jul 14 1999 Pad string in hputs() to minimum of 8 characters
1283 * Aug 16 1999 Keep angle between -180 and +360 in dec2str()
1284 * Oct 6 1999 Reallocate header buffer if it is too small in hputc()
1285 * Oct 14 1999 Do not reallocate header; return error if not successful
1286 *
1287 * Mar 2 2000 Do not add quotes if adding HISTORY or COMMENT with hputs()
1288 * Mar 22 2000 Move getutime() and getltime() to dateutil.c
1289 * Mar 27 2000 Add hputm() for muti-line keywords
1290 * Mar 27 2000 Fix bug testing for space to fit comment in hputcom()
1291 * Apr 19 2000 Fix bug in hadd() which overwrote line
1292 * Jun 2 2000 Dropped unused variable lv in hputm() after lint
1293 * Jul 20 2000 Drop unused variables blank and i in hputc()
1294 *
1295 * Jan 11 2001 Print all messages to stderr
1296 * Jan 18 2001 Drop declaration of blsearch(); it is in fitshead.h
1297 *
1298 * Jan 4 2002 Fix placement of comments
1299 *
1300 * Jul 1 2004 Add headshrink to optionally keep blank lines in header
1301 * Sep 3 2004 Fix bug so comments are not pushed onto next line if long value
1302 * Sep 16 2004 Add fixnegzero() to avoid putting signed zero values in header
1303 *
1304 * May 22 2006 Add option to leave blank line when deleting a keyword
1305 * Jun 15 2006 Fix comment alignment in hputc() and hputcom()
1306 * Jun 20 2006 Initialized uninitialized variables in hputm() and hputcom()
1307 *
1308 * Jan 4 2007 Declare keyword to be const
1309 * Jan 4 2007 Drop unused subroutine hputi2()
1310 * Jan 5 2007 Drop ksearch() declarations; it is now in fitshead.h
1311 * Jan 16 2007 Fix bugs in ra2str() and dec2str() so ndec=0 works
1312 * Aug 20 2007 Fix bug so comments after quoted keywords work
1313 * Aug 22 2007 If closing quote not found, make one up
1314 *
1315 * Sep 9 2011 Always initialize q2 and lroot
1316 */
1317