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, &deg));
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