1 /*============================================================================
2   WCSLIB 7.7 - an implementation of the FITS WCS standard.
3   Copyright (C) 1995-2021, Mark Calabretta
4 
5   This file is part of WCSLIB.
6 
7   WCSLIB is free software: you can redistribute it and/or modify it under the
8   terms of the GNU Lesser General Public License as published by the Free
9   Software Foundation, either version 3 of the License, or (at your option)
10   any later version.
11 
12   WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15   more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with WCSLIB.  If not, see http://www.gnu.org/licenses.
19 
20   Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
21   http://www.atnf.csiro.au/people/Mark.Calabretta
22   $Id: wcsutil.c,v 7.7 2021/07/12 06:36:49 mcalabre Exp $
23 *===========================================================================*/
24 
25 #include <ctype.h>
26 #include <locale.h>
27 #include <math.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include "wcsutil.h"
33 #include "wcsmath.h"
34 
35 //----------------------------------------------------------------------------
36 
wcsdealloc(void * ptr)37 void wcsdealloc(void *ptr)
38 
39 {
40   free(ptr);
41 
42   return;
43 }
44 
45 //----------------------------------------------------------------------------
46 
wcsutil_strcvt(int n,char c,int nt,const char src[],char dst[])47 void wcsutil_strcvt(int n, char c, int nt, const char src[], char dst[])
48 
49 {
50   if (n <= 0) return;
51 
52   if (c != '\0') c = ' ';
53 
54   if (src == 0x0) {
55     if (dst) {
56       memset(dst, c, n);
57     }
58 
59   } else {
60     // Copy to the first NULL character.
61     int j;
62     for (j = 0; j < n; j++) {
63       if ((dst[j] = src[j]) == '\0') {
64         break;
65       }
66     }
67 
68     if (j < n) {
69       // The given string is null-terminated.
70       memset(dst+j, c, n-j);
71 
72     } else {
73       // The given string is not null-terminated.
74       if (c == '\0') {
75         // Work backwards, looking for the first non-blank.
76         for (j = n - 1; j >= 0; j--) {
77           if (dst[j] != ' ') {
78             break;
79           }
80         }
81 
82         j++;
83 	if (j == n && !nt) {
84 	  dst[n-1] = '\0';
85 	} else {
86           memset(dst+j, '\0', n-j);
87 	}
88       }
89     }
90   }
91 
92   if (nt) dst[n] = '\0';
93 
94   return;
95 }
96 
97 //----------------------------------------------------------------------------
98 
wcsutil_blank_fill(int n,char c[])99 void wcsutil_blank_fill(int n, char c[])
100 
101 {
102   if (n <= 0) return;
103 
104   if (c == 0x0) {
105     return;
106   }
107 
108   // Replace the terminating null and all successive characters.
109   for (int j = 0; j < n; j++) {
110     if (c[j] == '\0') {
111       memset(c+j, ' ', n-j);
112       break;
113     }
114   }
115 
116   return;
117 }
118 
119 //----------------------------------------------------------------------------
120 
wcsutil_null_fill(int n,char c[])121 void wcsutil_null_fill(int n, char c[])
122 
123 {
124   if (n <= 0) return;
125 
126   if (c == 0x0) {
127     return;
128   }
129 
130   // Find the first NULL character.
131   int j;
132   for (j = 0; j < n; j++) {
133     if (c[j] == '\0') {
134       break;
135     }
136   }
137 
138   // Ensure null-termination.
139   if (j == n) {
140     j = n - 1;
141     c[j] = '\0';
142   }
143 
144   // Work backwards, looking for the first non-blank.
145   j--;
146   for (; j > 0; j--) {
147     if (c[j] != ' ') {
148       break;
149     }
150   }
151 
152   if (++j < n) {
153     memset(c+j, '\0', n-j);
154   }
155 
156   return;
157 }
158 
159 //----------------------------------------------------------------------------
160 
wcsutil_all_ival(int nelem,int ival,const int iarr[])161 int wcsutil_all_ival(int nelem, int ival, const int iarr[])
162 
163 {
164   for (int i = 0; i < nelem; i++) {
165     if (iarr[i] != ival) return 0;
166   }
167 
168   return 1;
169 }
170 
171 //----------------------------------------------------------------------------
172 
wcsutil_all_dval(int nelem,double dval,const double darr[])173 int wcsutil_all_dval(int nelem, double dval, const double darr[])
174 
175 {
176   for (int i = 0; i < nelem; i++) {
177     if (darr[i] != dval) return 0;
178   }
179 
180   return 1;
181 }
182 
183 //----------------------------------------------------------------------------
184 
wcsutil_all_sval(int nelem,const char * sval,const char (* sarr)[72])185 int wcsutil_all_sval(int nelem, const char *sval, const char (*sarr)[72])
186 
187 {
188   for (int i = 0; i < nelem; i++) {
189     if (strncmp(sarr[i], sval, 72)) return 0;
190   }
191 
192   return 1;
193 }
194 
195 //----------------------------------------------------------------------------
196 
wcsutil_allEq(int nvec,int nelem,const double * first)197 int wcsutil_allEq(int nvec, int nelem, const double *first)
198 
199 {
200   if (nvec <= 0 || nelem <= 0) return 0;
201 
202   double v0 = *first;
203   for (const double *vp = first+nelem; vp < first + nvec*nelem; vp += nelem) {
204     if (*vp != v0) return 0;
205   }
206 
207   return 1;
208 }
209 
210 //----------------------------------------------------------------------------
211 
wcsutil_dblEq(int nelem,double tol,const double * darr1,const double * darr2)212 int wcsutil_dblEq(
213   int nelem,
214   double tol,
215   const double *darr1,
216   const double *darr2)
217 
218 {
219   if (nelem == 0) return 1;
220   if (nelem  < 0) return 0;
221 
222   if (darr1 == 0x0 && darr2 == 0x0) return 1;
223 
224   if (tol == 0.0) {
225     // Handled separately for speed of execution.
226     for (int i = 0; i < nelem; i++) {
227       double dval1 = (darr1 ? darr1[i] : UNDEFINED);
228       double dval2 = (darr2 ? darr2[i] : UNDEFINED);
229 
230       // Undefined values must match exactly.
231       if (dval1 == UNDEFINED && dval2 != UNDEFINED) return 0;
232       if (dval1 != UNDEFINED && dval2 == UNDEFINED) return 0;
233 
234       if (dval1 != dval2) return 0;
235     }
236 
237   } else {
238     for (int i = 0; i < nelem; i++) {
239       double dval1 = (darr1 ? darr1[i] : UNDEFINED);
240       double dval2 = (darr2 ? darr2[i] : UNDEFINED);
241 
242       // Undefined values must match exactly.
243       if (dval1 == UNDEFINED && dval2 != UNDEFINED) return 0;
244       if (dval1 != UNDEFINED && dval2 == UNDEFINED) return 0;
245 
246       // Otherwise, compare within the specified tolerance.
247       if (fabs(dval1 - dval2) > 0.5*tol) return 0;
248     }
249   }
250 
251   return 1;
252 }
253 
254 //----------------------------------------------------------------------------
255 
wcsutil_intEq(int nelem,const int * iarr1,const int * iarr2)256 int wcsutil_intEq(int nelem, const int *iarr1, const int *iarr2)
257 
258 {
259   if (nelem == 0) return 1;
260   if (nelem  < 0) return 0;
261 
262   if (iarr1 == 0x0 && iarr2 == 0x0) return 1;
263 
264   for (int i = 0; i < nelem; i++) {
265     int ival1 = (iarr1 ?  iarr1[i] : 0);
266     int ival2 = (iarr2 ?  iarr2[i] : 0);
267 
268     if (ival1 != ival2) return 0;
269   }
270 
271   return 1;
272 }
273 
274 //----------------------------------------------------------------------------
275 
wcsutil_strEq(int nelem,char (* sarr1)[72],char (* sarr2)[72])276 int wcsutil_strEq(int nelem, char (*sarr1)[72], char (*sarr2)[72])
277 
278 {
279   if (nelem == 0) return 1;
280   if (nelem  < 0) return 0;
281 
282   if (sarr1 == 0x0 && sarr2 == 0x0) return 1;
283 
284   for (int i = 0; i < nelem; i++) {
285     char *sval1 = (sarr1 ?  sarr1[i] : "");
286     char *sval2 = (sarr2 ?  sarr2[i] : "");
287 
288     if (strncmp(sval1, sval2, 72)) return 0;
289   }
290 
291   return 1;
292 }
293 
294 //----------------------------------------------------------------------------
295 
wcsutil_setAll(int nvec,int nelem,double * first)296 void wcsutil_setAll(int nvec, int nelem, double *first)
297 
298 {
299   if (nvec <= 0 || nelem <= 0) return;
300 
301   double v0 = *first;
302   for (double *vp = first+nelem; vp < first + nvec*nelem; vp += nelem) {
303     *vp = v0;
304   }
305 }
306 
307 //----------------------------------------------------------------------------
308 
wcsutil_setAli(int nvec,int nelem,int * first)309 void wcsutil_setAli(int nvec, int nelem, int *first)
310 
311 {
312   if (nvec <= 0 || nelem <= 0) return;
313 
314   int v0 = *first;
315   for (int *vp = first+nelem; vp < first + nvec*nelem; vp += nelem) {
316     *vp = v0;
317   }
318 }
319 
320 //----------------------------------------------------------------------------
321 
wcsutil_setBit(int nelem,const int * sel,int bits,int * array)322 void wcsutil_setBit(int nelem, const int *sel, int bits, int *array)
323 
324 {
325   if (bits == 0 || nelem <= 0) return;
326 
327   if (sel == 0x0) {
328     // All elements selected.
329     for (int *arrp = array; arrp < array + nelem; arrp++) {
330       *arrp |= bits;
331     }
332 
333   } else {
334     // Some elements selected.
335     for (int *arrp = array; arrp < array + nelem; arrp++) {
336       if (*(sel++)) *arrp |= bits;
337     }
338   }
339 }
340 
341 //----------------------------------------------------------------------------
342 
wcsutil_fptr2str(void (* fptr)(void),char hext[19])343 char *wcsutil_fptr2str(void (*fptr)(void), char hext[19])
344 
345 {
346   // Test for little-endian addresses.
347   int *(ip[2]), j[2], le = 1;
348   ip[0] = j;
349   ip[1] = j + 1;
350   unsigned char *p = (unsigned char *)(&fptr);
351   if ((unsigned char *)ip[0] < (unsigned char *)ip[1]) {
352     // Little-endian, reverse it.
353     p += sizeof(fptr) - 1;
354     le = -1;
355   }
356 
357   char *t = hext;
358   sprintf(t, "0x0");
359   t += 2;
360 
361   int gotone = 0;
362   for (size_t i = 0; i < sizeof(fptr); i++) {
363     // Skip leading zeroes.
364     if (*p) gotone = 1;
365 
366     if (gotone) {
367       sprintf(t, "%02x", *p);
368       t += 2;
369     }
370 
371     p += le;
372   }
373 
374   return hext;
375 }
376 
377 //----------------------------------------------------------------------------
378 
wcsutil_locale_to_dot(char * buf)379 static void wcsutil_locale_to_dot(char *buf)
380 
381 {
382   struct lconv *locale_data = localeconv();
383   const char *decimal_point = locale_data->decimal_point;
384 
385   if (decimal_point[0] != '.' || decimal_point[1] != 0) {
386     size_t decimal_point_len = strlen(decimal_point);
387     char *inbuf = buf;
388     char *outbuf = buf;
389 
390     for ( ; *inbuf; inbuf++) {
391       if (strncmp(inbuf, decimal_point, decimal_point_len) == 0) {
392         *outbuf++ = '.';
393         inbuf += decimal_point_len - 1;
394       } else {
395         *outbuf++ = *inbuf;
396       }
397     }
398 
399     *outbuf = '\0';
400   }
401 }
402 
403 
wcsutil_double2str(char * buf,const char * format,double value)404 void wcsutil_double2str(char *buf, const char *format, double value)
405 
406 {
407   sprintf(buf, format, value);
408   wcsutil_locale_to_dot(buf);
409 
410   // Look for a decimal point or exponent.
411   char *bp = buf;
412   while (*bp) {
413     if (*bp != ' ') {
414       if (*bp == '.') return;
415       if (*bp == 'e') return;
416       if (*bp == 'E') return;
417     }
418     bp++;
419   }
420 
421   // Not found, add a fractional part.
422   bp = buf;
423   if (*bp == ' ') {
424     char *cp = buf + 1;
425     if (*cp == ' ') cp++;
426 
427     while (*cp) {
428       *bp = *cp;
429       bp++;
430       cp++;
431     }
432 
433     *bp = '.';
434     bp++;
435     if (bp < cp) *bp = '0';
436   }
437 }
438 
439 //----------------------------------------------------------------------------
440 
wcsutil_dot_to_locale(const char * inbuf,char * outbuf)441 static const char *wcsutil_dot_to_locale(const char *inbuf, char *outbuf)
442 
443 {
444   struct lconv *locale_data = localeconv();
445   const char *decimal_point = locale_data->decimal_point;
446 
447   if (decimal_point[0] != '.' || decimal_point[1] != 0) {
448     char *out = outbuf;
449     size_t decimal_point_len = strlen(decimal_point);
450 
451     for ( ; *inbuf; inbuf++) {
452       if (*inbuf == '.') {
453         memcpy(out, decimal_point, decimal_point_len);
454         out += decimal_point_len;
455       } else {
456         *out++ = *inbuf;
457       }
458     }
459 
460     *out = '\0';
461 
462     return outbuf;
463   } else {
464     return inbuf;
465   }
466 }
467 
468 
wcsutil_str2double(const char * buf,double * value)469 int wcsutil_str2double(const char *buf, double *value)
470 
471 {
472   char ctmp[72];
473   return sscanf(wcsutil_dot_to_locale(buf, ctmp), "%lf", value) < 1;
474 }
475 
476 
wcsutil_str2double2(const char * buf,double * value)477 int wcsutil_str2double2(const char *buf, double *value)
478 
479 {
480   value[0] = 0.0;
481   value[1] = 0.0;
482 
483   // Get the integer part.
484   char ltmp[72];
485   if (sscanf(wcsutil_dot_to_locale(buf, ltmp), "%lf", value) < 1) {
486     return 1;
487   }
488   value[0] = floor(value[0]);
489 
490   char ctmp[72];
491   strcpy(ctmp, buf);
492 
493   // Look for a decimal point.
494   char *dptr = strchr(ctmp, '.');
495 
496   // Look for an exponent.
497   char *eptr;
498   if ((eptr = strchr(ctmp, 'E')) == NULL) {
499     if ((eptr = strchr(ctmp, 'D')) == NULL) {
500       if ((eptr = strchr(ctmp, 'e')) == NULL) {
501         eptr = strchr(ctmp, 'd');
502       }
503     }
504   }
505 
506   int exp = 0;
507   if (eptr) {
508     // Get the exponent.
509     if (sscanf(eptr+1, "%d", &exp) < 1) {
510       return 1;
511     }
512 
513     if (!dptr) {
514       dptr = eptr;
515       eptr++;
516     }
517 
518     if (dptr+exp <= ctmp) {
519       // There is only a fractional part.
520       return sscanf(wcsutil_dot_to_locale(buf, ctmp), "%lf", value+1) < 1;
521     } else if (eptr <= dptr+exp+1) {
522       // There is no fractional part.
523       return 0;
524     }
525   }
526 
527   // Get the fractional part.
528   if (dptr) {
529     char *cptr = ctmp;
530     while (cptr <= dptr+exp) {
531       if ('0' < *cptr && *cptr <= '9') *cptr = '0';
532       cptr++;
533     }
534 
535     if (sscanf(wcsutil_dot_to_locale(ctmp, ltmp), "%lf", value+1) < 1) {
536       return 1;
537     }
538   }
539 
540   return 0;
541 }
542