1 /* $Id: utility.c,v 1.18 2009-04-20 07:17:00 pkubanek Exp $
2 **
3 * Copyright (C) 1999, 2000 Juan Carlos Remis
4 * Copyright (C) 2002 Liam Girdwood
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22 /*------------------------------------------------------------------------*/
23 /* */
24 /* Module: */
25 /* */
26 /* Description: */
27 /* */
28 /* */
29 /* "CAVEAT UTILITOR". */
30 /* */
31 /* "Non sunt multiplicanda entia praeter necessitatem" */
32 /* Guillermo de Occam. */
33 /*------------------------------------------------------------------------*/
34 /* Revision History: */
35 /* */
36 /*------------------------------------------------------------------------*/
37
38 /**/
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <math.h>
44 #include <ctype.h>
45 #include <libnova/libnova.h>
46
47 /* Include unistd.h only if not on a Win32 platform */
48 /* Include Win32 Headers sys/types.h and sys/timeb.h if on Win32 */
49 #ifndef __WIN32__
50 #include <unistd.h>
51 #else
52 #include <sys/types.h>
53 #include <sys/timeb.h>
54 #endif
55
56 /* Conversion factors between degrees and radians */
57 #define D2R (1.7453292519943295769e-2) /* deg->radian */
58 #define R2D (5.7295779513082320877e1) /* radian->deg */
59 #define R2S (2.0626480624709635516e5) /* arc seconds per radian */
60 #define S2R (4.8481368110953599359e-6) /* radians per arc second */
61
62 #define DM_PI (2*M_PI)
63 #define RADIAN (180.0 / M_PI)
64
65 static const char ln_version[] = LIBNOVA_VERSION;
66
67 /*! \fn char * ln_get_version (void)
68 * \return Null terminated version string.
69 *
70 * Return the libnova library version number string
71 * e.g. "0.4.0"
72 */
ln_get_version(void)73 const char * ln_get_version (void)
74 {
75 return ln_version;
76 }
77
78
79 /* convert radians to degrees */
ln_rad_to_deg(double radians)80 double ln_rad_to_deg (double radians)
81 {
82 return (radians * R2D);
83 }
84
85 /* convert degrees to radians */
ln_deg_to_rad(double degrees)86 double ln_deg_to_rad (double degrees)
87 {
88 return (degrees * D2R);
89 }
90
91 /* convert hours:mins:secs to degrees */
ln_hms_to_deg(struct ln_hms * hms)92 double ln_hms_to_deg (struct ln_hms *hms)
93 {
94 double degrees;
95
96 degrees = ((double)hms->hours / 24) * 360;
97 degrees += ((double)hms->minutes / 60) * 15;
98 degrees += ((double)hms->seconds / 60) * 0.25;
99
100 return degrees;
101 }
102
103 /* convert hours:mins:secs to radians */
ln_hms_to_rad(struct ln_hms * hms)104 double ln_hms_to_rad (struct ln_hms *hms)
105 {
106 double radians;
107
108 radians = ((double)hms->hours / 24.0) * 2.0 * M_PI;
109 radians += ((double)hms->minutes / 60.0) * 2.0 * M_PI / 24.0;
110 radians += ((double)hms->seconds / 60.0) * 2.0 * M_PI / 1440.0;
111
112 return radians;
113 }
114
115
116 /* convert degrees to hh:mm:ss */
ln_deg_to_hms(double degrees,struct ln_hms * hms)117 void ln_deg_to_hms (double degrees, struct ln_hms * hms)
118 {
119 double dtemp;
120
121 degrees = ln_range_degrees (degrees);
122
123 /* divide degrees by 15 to get the hours */
124 dtemp = degrees / 15.0;
125 hms->hours = (unsigned short)dtemp;
126
127 /* multiply remainder by 60 to get minutes */
128 dtemp = 60*(dtemp - hms->hours);
129 hms->minutes = (unsigned short)dtemp;
130
131 /* multiply remainder by 60 to get seconds */
132 hms->seconds = 60*(dtemp - hms->minutes);
133
134 /* catch any overflows */
135 if (hms->seconds > 59) {
136 hms->seconds = 0;
137 hms->minutes ++;
138 }
139 if (hms->minutes > 59) {
140 hms->minutes = 0;
141 hms->hours ++;
142 }
143 }
144
145 /* convert radians to hh:mm:ss */
ln_rad_to_hms(double radians,struct ln_hms * hms)146 void ln_rad_to_hms (double radians, struct ln_hms * hms)
147 {
148 double degrees;
149
150 radians = ln_range_radians(radians);
151 degrees = ln_rad_to_deg(radians);
152
153 ln_deg_to_hms(degrees, hms);
154 }
155
156
157 /* convert dms to degrees */
ln_dms_to_deg(struct ln_dms * dms)158 double ln_dms_to_deg (struct ln_dms *dms)
159 {
160 double degrees;
161
162 degrees = fabs((double)dms->degrees);
163 degrees += fabs((double)dms->minutes / 60);
164 degrees += fabs((double)dms->seconds / 3600);
165
166 // negative ?
167 if (dms->neg)
168 degrees *= -1.0;
169
170 return degrees;
171 }
172
173 /* convert dms to radians */
ln_dms_to_rad(struct ln_dms * dms)174 double ln_dms_to_rad (struct ln_dms *dms)
175 {
176 double radians;
177
178 radians = fabs((double)dms->degrees / 360.0 * 2.0 * M_PI);
179 radians += fabs((double)dms->minutes / 21600.0 * 2.0 * M_PI);
180 radians += fabs((double)dms->seconds / 1296000.0 * 2.0 * M_PI);
181
182 // negative ?
183 if (dms->neg)
184 radians *= -1.0;
185
186 return radians;
187 }
188
189 /* convert degrees to dms */
ln_deg_to_dms(double degrees,struct ln_dms * dms)190 void ln_deg_to_dms (double degrees, struct ln_dms * dms)
191 {
192 double dtemp;
193
194 if (degrees >= 0)
195 dms->neg = 0;
196 else
197 dms->neg = 1;
198
199 degrees = fabs(degrees);
200 dms->degrees = (int)degrees;
201
202 /* multiply remainder by 60 to get minutes */
203 dtemp = 60*(degrees - dms->degrees);
204 dms->minutes = (unsigned short)dtemp;
205
206 /* multiply remainder by 60 to get seconds */
207 dms->seconds = 60*(dtemp - dms->minutes);
208
209 /* catch any overflows */
210 if (dms->seconds > 59) {
211 dms->seconds = 0;
212 dms->minutes ++;
213 }
214 if (dms->minutes > 59) {
215 dms->minutes = 0;
216 dms->degrees ++;
217 }
218 }
219
220 /* convert radians to dms */
ln_rad_to_dms(double radians,struct ln_dms * dms)221 void ln_rad_to_dms (double radians, struct ln_dms * dms)
222 {
223 double degrees = ln_rad_to_deg(radians);
224
225 ln_deg_to_dms(degrees, dms);
226 }
227
228
229 /* puts a large angle in the correct range 0 - 360 degrees */
ln_range_degrees(double angle)230 double ln_range_degrees (double angle)
231 {
232 double temp;
233
234 if (angle >= 0.0 && angle < 360.0)
235 return angle;
236
237 temp = (int)(angle / 360);
238 if (angle < 0.0)
239 temp --;
240 temp *= 360;
241 return angle - temp;
242 }
243
244 /* puts a large angle in the correct range 0 - 2PI radians */
ln_range_radians(double angle)245 double ln_range_radians (double angle)
246 {
247 double temp;
248
249 if (angle >= 0.0 && angle < (2.0 * M_PI))
250 return angle;
251
252 temp = (int)(angle / (M_PI * 2.0));
253
254 if (angle < 0.0)
255 temp --;
256 temp *= (M_PI * 2.0);
257 return angle - temp;
258 }
259
260 /* puts a large angle in the correct range -2PI - 2PI radians */
261 /* preserve sign */
ln_range_radians2(double angle)262 double ln_range_radians2 (double angle)
263 {
264 double temp;
265
266 if (angle > (-2.0 * M_PI) && angle < (2.0 * M_PI))
267 return angle;
268
269 temp = (int)(angle / (M_PI * 2.0));
270 temp *= (M_PI * 2.0);
271 return angle - temp;
272 }
273
274
275 /* add seconds to hms */
ln_add_secs_hms(struct ln_hms * hms,double seconds)276 void ln_add_secs_hms (struct ln_hms * hms, double seconds)
277 {
278 struct ln_hms source_hms;
279
280 /* breaks double seconds int hms */
281 source_hms.hours = (unsigned short)(seconds / 3600);
282 seconds -= source_hms.hours * 3600;
283 source_hms.minutes = (unsigned short)(seconds / 60);
284 seconds -= source_hms.minutes * 60;
285 source_hms.seconds = seconds;
286
287 /* add hms to hms */
288 ln_add_hms (&source_hms, hms);
289 }
290
291
292 /* add hms to hms */
ln_add_hms(struct ln_hms * source,struct ln_hms * dest)293 void ln_add_hms (struct ln_hms * source, struct ln_hms * dest)
294 {
295 dest->seconds += source->seconds;
296 if (dest->seconds >= 60) {
297 /* carry */
298 source->minutes ++;
299 dest->seconds -= 60;
300 } else {
301 if (dest->seconds < 0) {
302 /* carry */
303 source->minutes --;
304 dest->seconds += 60;
305 }
306 }
307
308 dest->minutes += source->minutes;
309 if (dest->minutes >= 60) {
310 /* carry */
311 source->hours ++;
312 dest->minutes -= 60;
313 } else {
314 if (dest->seconds < 0) {
315 /* carry */
316 source->hours --;
317 dest->minutes += 60;
318 }
319 }
320
321 dest->hours += source->hours;
322 }
323
324 /*! \fn void ln_hequ_to_equ (struct lnh_equ_posn * hpos, struct ln_equ_posn * pos)
325 * \brief human readable equatorial position to double equatorial position
326 * \ingroup conversion
327 */
ln_hequ_to_equ(struct lnh_equ_posn * hpos,struct ln_equ_posn * pos)328 void ln_hequ_to_equ (struct lnh_equ_posn * hpos, struct ln_equ_posn * pos)
329 {
330 pos->ra = ln_hms_to_deg (&hpos->ra);
331 pos->dec = ln_dms_to_deg (&hpos->dec);
332 }
333
334 /*! \fn void ln_equ_to_hequ (struct ln_equ_posn * pos, struct lnh_equ_posn * hpos)
335 * \brief human double equatorial position to human readable equatorial position
336 * \ingroup conversion
337 */
ln_equ_to_hequ(struct ln_equ_posn * pos,struct lnh_equ_posn * hpos)338 void ln_equ_to_hequ (struct ln_equ_posn * pos, struct lnh_equ_posn * hpos)
339 {
340 ln_deg_to_hms (pos->ra, &hpos->ra);
341 ln_deg_to_dms (pos->dec, &hpos->dec);
342 }
343
344 /*! \fn void ln_hhrz_to_hrz (struct lnh_hrz_posn * hpos, struct ln_hrz_posn * pos)
345 * \brief human readable horizontal position to double horizontal position
346 * \ingroup conversion
347 */
ln_hhrz_to_hrz(struct lnh_hrz_posn * hpos,struct ln_hrz_posn * pos)348 void ln_hhrz_to_hrz (struct lnh_hrz_posn * hpos, struct ln_hrz_posn * pos)
349 {
350 pos->alt = ln_dms_to_deg (&hpos->alt);
351 pos->az = ln_dms_to_deg (&hpos->az);
352 }
353
354 /*! \fn void ln_hrz_to_hhrz (struct ln_hrz_posn * pos, struct lnh_hrz_posn * hpos)
355 * \brief double horizontal position to human readable horizontal position
356 * \ingroup conversion
357 */
ln_hrz_to_hhrz(struct ln_hrz_posn * pos,struct lnh_hrz_posn * hpos)358 void ln_hrz_to_hhrz (struct ln_hrz_posn * pos, struct lnh_hrz_posn * hpos)
359 {
360 ln_deg_to_dms (pos->alt, &hpos->alt);
361 ln_deg_to_dms (pos->az, &hpos->az);
362 }
363
364 /*! \fn const char * ln_hrz_to_nswe (struct ln_hrz_posn * pos);
365 * \brief returns direction of given azimuth - like N,S,W,E,NSW,...
366 * \ingroup conversion
367 */
ln_hrz_to_nswe(struct ln_hrz_posn * pos)368 const char * ln_hrz_to_nswe (struct ln_hrz_posn * pos)
369 {
370 char * directions[] = {"S", "SSW", "SW", "SWW", "W", "NWW", "NW", "NNW", "N", "NNE", "NE", "NEE",
371 "E", "SEE", "SE", "SSE"};
372 return directions[(int)(pos->az / 22.5)];
373 }
374
375 /*! \fn void ln_hlnlat_to_lnlat (struct lnh_lnlat_posn * hpos, struct ln_lnlat_posn * pos)
376 * \brief human readable long/lat position to double long/lat position
377 * \ingroup conversion
378 */
ln_hlnlat_to_lnlat(struct lnh_lnlat_posn * hpos,struct ln_lnlat_posn * pos)379 void ln_hlnlat_to_lnlat (struct lnh_lnlat_posn * hpos, struct ln_lnlat_posn * pos)
380 {
381 pos->lng = ln_dms_to_deg (&hpos->lng);
382 pos->lat = ln_dms_to_deg (&hpos->lat);
383 }
384
385 /*! \fn void ln_lnlat_to_hlnlat (struct ln_lnlat_posn * pos, struct lnh_lnlat_posn * hpos)
386 * \brief double long/lat position to human readable long/lat position
387 * \ingroup conversion
388 */
ln_lnlat_to_hlnlat(struct ln_lnlat_posn * pos,struct lnh_lnlat_posn * hpos)389 void ln_lnlat_to_hlnlat (struct ln_lnlat_posn * pos, struct lnh_lnlat_posn * hpos)
390 {
391 ln_deg_to_dms (pos->lng, &hpos->lng);
392 ln_deg_to_dms (pos->lat, &hpos->lat);
393 }
394
395 /*
396 * \fn double ln_get_rect_distance (struct ln_rect_posn * a, struct ln_rect_posn * b)
397 * \param a First rectangular coordinate
398 * \param b Second rectangular coordinate
399 * \return Distance between a and b.
400 *
401 * Calculate the distance between rectangular points a and b.
402 */
ln_get_rect_distance(struct ln_rect_posn * a,struct ln_rect_posn * b)403 double ln_get_rect_distance (struct ln_rect_posn * a, struct ln_rect_posn * b)
404 {
405 double x,y,z;
406
407 x = a->X - b->X;
408 y = a->Y - b->Y;
409 z = a->Z - b->Z;
410
411 x *=x;
412 y *=y;
413 z *=z;
414
415 return sqrt (x + y + z);
416 }
417
418 /*
419 * \fn double ln_get_light_time (double dist)
420 * \param dist Distance in AU
421 * \return Distance in light days.
422 *
423 * Convert units of AU into light days.
424 */
ln_get_light_time(double dist)425 double ln_get_light_time (double dist)
426 {
427 return dist * 0.005775183;
428 }
429
430
431 /* local types and macros */
432 typedef int BOOL;
433 #define TRUE 1
434 #define FALSE 0
435 #define iswhite(c) ((c)== ' ' || (c)=='\t')
436
437 /*
438 []------------------------------------------------------------------------[]
439 | trim() & strip() |
440 | |
441 | strips trailing whitespaces from buf. |
442 | |
443 []------------------------------------------------------------------------[]
444 */
trim(char * x)445 static char *trim(char *x)
446 {
447 char *y;
448
449 if(!x)
450 return(x);
451 y = x + strlen(x)-1;
452 while (y >= x && isspace(*y))
453 *y-- = 0; /* skip white space */
454 return x;
455 }
456
457
458 /*
459 []------------------------------------------------------------------------[]
460 | |
461 | skipwhite() |
462 | salta espacios en blanco |
463 | |
464 []------------------------------------------------------------------------[]
465 */
skipwhite(char ** s)466 static void skipwhite(char **s)
467 {
468 while(iswhite(**s))
469 (*s)++;
470 }
471
472
473 /*! \fn double ln_get_dec_location(char * s)
474 * \param s Location string
475 * \return angle in degrees
476 *
477 * Obtains Latitude, Longitude, RA or Declination from a string.
478 *
479 * If the last char is N/S doesn't accept more than 90 degrees.
480 * If it is E/W doesn't accept more than 180 degrees.
481 * If they are hours don't accept more than 24:00
482 *
483 * Any position can be expressed as follows:
484 * (please use a 8 bits charset if you want
485 * to view the degrees separator char '0xba')
486 *
487 * 42.30.35,53
488 * 90º0'0,01 W
489 * 42º30'35.53 N
490 * 42º30'35.53S
491 * 42º30'N
492 * - 42.30.35.53
493 * 42:30:35.53 S
494 * + 42.30.35.53
495 * +42º30 35,53
496 * 23h36'45,0
497 *
498 *
499 * 42:30:35.53 S = -42º30'35.53"
500 * + 42 30.35.53 S the same previous position, the plus (+) sign is
501 * considered like an error, the last 'S' has precedence over the sign
502 *
503 * 90º0'0,01 N ERROR: +- 90º0'00.00" latitude limit
504 *
505 */
ln_get_dec_location(char * s)506 double ln_get_dec_location(char *s)
507 {
508 char *ptr, *dec, *hh, *ame, *tok_ptr;
509 BOOL negative = FALSE;
510 char delim1[] = " :.,;DdHhMm'\n\t";
511 char delim2[] = " NSEWnsew\"\n\t";
512 int dghh = 0, minutes = 0;
513 double seconds = 0.0, pos;
514 short count;
515 enum _type{
516 HOURS, DEGREES, LAT, LONG
517 }type;
518
519 if (s == NULL || !*s)
520 return(-0.0);
521
522 count = strlen(s) + 1;
523 if ((ptr = (char *) alloca(count)) == NULL)
524 return (-0.0);
525
526 memcpy(ptr, s, count);
527 trim(ptr);
528 skipwhite(&ptr);
529 if (*ptr == '+' || *ptr == '-')
530 negative = (char) (*ptr++ == '-' ? TRUE : negative);
531
532 /* the last letter has precedence over the sign */
533 if (strpbrk(ptr,"SsWw") != NULL)
534 negative = TRUE;
535
536 skipwhite(&ptr);
537 if ((hh = strpbrk(ptr,"Hh")) != NULL && hh < ptr + 3) {
538 type = HOURS;
539 if (negative) /* if RA no negative numbers */
540 negative = FALSE;
541 } else if ((ame = strpbrk(ptr,"SsNn")) != NULL) {
542 type = LAT;
543 if (ame == ptr) /* the North/South found before data */
544 ptr++;
545 } else
546 type = DEGREES; /* unspecified, the caller must control it */
547 if ((ptr = strtok_r(ptr,delim1, &tok_ptr)) != NULL)
548 dghh = atoi (ptr);
549 else
550 return (-0.0);
551 if ((ptr = strtok_r(NULL,delim1, &tok_ptr)) != NULL) {
552 minutes = atoi (ptr);
553 if (minutes > 59)
554 return (-0.0);
555 } else
556 return (-0.0);
557
558 if ((ptr = strtok_r(NULL,delim2,&tok_ptr)) != NULL) {
559 if ((dec = strchr(ptr,',')) != NULL)
560 *dec = '.';
561 seconds = strtod (ptr, NULL);
562 if (seconds >= 60)
563 return (-0.0);
564 }
565
566 if ((ptr = strtok(NULL," \n\t")) != NULL) {
567 skipwhite(&ptr);
568 if (*ptr == 'S' || *ptr == 'W' || *ptr == 's' || *ptr == 'W')
569 negative = TRUE;
570 }
571
572 pos = dghh + minutes /60.0 + seconds / 3600.0;
573 if (type == HOURS && pos > 24.0)
574 return (-0.0);
575 if (type == LAT && pos > 90.0)
576 return (-0.0);
577 if (negative == TRUE)
578 pos = 0.0 - pos;
579 return pos;
580 }
581
582
583 /*! \fn const char * ln_get_humanr_location(double location)
584 * \param location Location angle in degress
585 * \return Angle string
586 *
587 * Obtains a human readable location in the form: ddºmm'ss.ss"
588 */
ln_get_humanr_location(double location)589 const char * ln_get_humanr_location(double location)
590 {
591 static char buf[16];
592 double deg = 0.0;
593 double min = 0.0;
594 double sec = 0.0;
595 *buf = 0;
596 sec = 60.0 * (modf(location, °));
597 if (sec < 0.0)
598 sec *= -1;
599 sec = 60.0 * (modf(sec, &min));
600 sprintf(buf,"%+dº%d'%.2f\"",(int)deg, (int) min, sec);
601 return buf;
602 }
603
604 /*! \fn double ln_interpolate3 (double n, double y1, double y2, double y3)
605 * \return interpolation value
606 * \param n Interpolation factor
607 * \param y1 Argument 1
608 * \param y2 Argument 2
609 * \param y3 Argument 3
610 *
611 * Calculate an intermediate value of the 3 arguments for the given interpolation
612 * factor.
613 */
ln_interpolate3(double n,double y1,double y2,double y3)614 double ln_interpolate3 (double n, double y1, double y2, double y3)
615 {
616 double y,a,b,c;
617
618 /* equ 3.2 */
619 a = y2 - y1;
620 b = y3 - y2;
621 c = b - a;
622
623 /* equ 3.3 */
624 y = y2 + n / 2.0 * (a + b + n * c);
625
626 return y;
627 }
628
629
630 /*! \fn double ln_interpolate5 (double n, double y1, double y2, double y3, double y4, double y5)
631 * \return interpolation value
632 * \param n Interpolation factor
633 * \param y1 Argument 1
634 * \param y2 Argument 2
635 * \param y3 Argument 3
636 * \param y4 Argument 4
637 * \param y5 Argument 5
638 *
639 * Calculate an intermediate value of the 5 arguments for the given interpolation
640 * factor.
641 */
ln_interpolate5(double n,double y1,double y2,double y3,double y4,double y5)642 double ln_interpolate5 (double n, double y1, double y2, double y3, double y4, double y5)
643 {
644 double y,A,B,C,D,E,F,G,H,J,K;
645 double n2,n3,n4;
646
647 /* equ 3.8 */
648 A = y2 - y1;
649 B = y3 - y2;
650 C = y4 - y3;
651 D = y5 - y4;
652 E = B - A;
653 F = C - B;
654 G = D - C;
655 H = F - E;
656 J = G - F;
657 K = J - H;
658
659 y = 0.0;
660 n2 = n* n;
661 n3 = n2 * n;
662 n4 = n3 * n;
663
664 y += y3;
665 y += n * ((B + C ) / 2.0 - (H + J) / 12.0);
666 y += n2 * (F / 2.0 - K / 24.0);
667 y += n3 * ((H + J) / 12.0);
668 y += n4 * (K / 24.0);
669
670 return y;
671 }
672
673 /* This section is for Win32 substitutions. */
674 #ifdef __WIN32__
675
676 /* Catches calls to the POSIX gettimeofday and converts them to a related WIN32 version. */
gettimeofday(struct timeval * tv,struct timezone * tz)677 int gettimeofday(struct timeval *tv, struct timezone *tz)
678 {
679 struct _timeb timeptr;
680
681 _ftime_s (&timeptr);
682
683 tv->tv_sec = timeptr.time;
684 tv->tv_usec = timeptr.millitm * 1000;
685
686 tz->tz_dsttime = timeptr.dstflag;
687 tz->tz_dsttime = timeptr.timezone;
688
689 return 0;
690 }
691
692 /* Catches calls to the POSIX gmtime_r and converts them to a related WIN32 version. */
gmtime_r(time_t * t,struct tm * gmt)693 struct tm *gmtime_r (time_t *t, struct tm *gmt)
694 {
695 gmtime_s (gmt, t);
696
697 return gmt;
698 }
699
700 /* Catches calls to the POSIX strtok_r and converts them to a related WIN32 version. */
strtok_r(char * str,const char * sep,char ** last)701 char *strtok_r(char *str, const char *sep, char **last)
702 {
703 return strtok_s(str, sep, last);
704 }
705
706 #endif /* __WIN32__ */
707
708 /* C89 substitutions for C99 functions. */
709 #ifdef __C89_SUB__
710
711 /* Simple cube root */
cbrt(double x)712 double cbrt (double x)
713 {
714 return pow (x, 1.0/3.0);
715 }
716
717 #endif /* __C89_SUB__ */
718
719 #if defined(__WIN32__) || defined(sun) || defined(__C89_SUB__)
720
721 /* Not a Number function generator */
nan(const char * code)722 double nan (const char *code)
723 {
724 double zero = 0.0;
725
726 return zero/0.0;
727 }
728
729 #endif /* defined(__WIN32__) || defined(sun) || defined(__C89_SUB__) */
730