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