1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <time.h>
5 #include <math.h>
6 #include <sys/types.h>
7 #ifdef __MSW__
8 # include <windows.h>
9 #else
10 # include <sys/time.h>
11 #endif
12 
13 #include "../include/strexp.h"
14 #include "../include/string.h"
15 
16 #include "sartime.h"
17 
18 time_t SARGetCurMilliTime(void);
19 unsigned int SARRandom(unsigned int seed_offset);
20 float SARRandomCoeff(unsigned int seed_offset);
21 
22 int SARParseTimeOfDay(
23 	const char *string,
24 	int *h, int *m, int *s
25 );
26 int SARParseLatitudeDMS(const char *string, float *dms);
27 int SARParseLongitudeDMS(const char *string, float *dms);
28 
29 
30 #define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
31 #define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
32 #define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
33 #define STRDUP(s)       (((s) != NULL) ? strdup(s) : NULL)
34 
35 #define MAX(a,b)        (((a) > (b)) ? (a) : (b))
36 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
37 #define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
38 #define IS_STRING_EMPTY(s)      (((s) != NULL) ? (*(s) == '\0') : TRUE)
39 
40 #define RADTODEG(r)     ((r) * 180 / PI)
41 #define DEGTORAD(d)     ((d) * PI / 180)
42 
43 
44 /*
45  *      Returns the current time since midnight in milliseconds from the
46  *      system.
47  */
SARGetCurMilliTime(void)48 time_t SARGetCurMilliTime(void)
49 {
50 #ifdef __MSW__
51 	SYSTEMTIME t;   /* Current time of day structure. */
52 
53 	GetSystemTime(&t);
54 	return(
55 	    (time_t)(
56 		(((((t.wHour * 60.0) + t.wMinute) * 60) + t.wSecond) * 1000) +
57 		t.wMilliseconds
58 	    )
59 	);
60 #else
61 	struct timeval tv[1];
62 
63 	if(gettimeofday(tv, NULL) < 0)
64 	    return(-1);
65 
66 	return(((tv->tv_sec % 86400) * 1000) + (tv->tv_usec / 1000));
67 #endif
68 }
69 
70 /*
71  *      Returns a random number in the range of 0 to 0xffffffff.
72  *
73  *      If you call this function more than once per cycle then you
74  *      should pass seed_offset as a unique value each time to better
75  *      obtain a more random number.
76  */
SARRandom(unsigned int seed_offset)77 unsigned int SARRandom(unsigned int seed_offset)
78 {
79 #if defined(RAND_MAX)
80 /*	srand((unsigned int)cur_millitime + seed_offset); */
81 	return(rand());
82 #else
83 	static u_int32_t gSeed = 1234145;
84 #ifdef __MSW__
85 	long result = gSeed * (long)1103515245 + 12345;
86 #else
87 	int64_t result = gSeed * (int64_t)1103515245 + 12345;
88 #endif
89 	gSeed = (u_int32_t)result;
90 
91 	return((u_int32_t)(result >> 16));
92 #endif
93 }
94 
95 /*
96  *      Returns a random coefficient from 0.0 to 1.0, setting the seed
97  *      as the current time in milliseconds plus the given seed_offset.
98  *
99  *      If you call this function more than once per cycle then you
100  *      should pass seed_offset as a unique value each time to better
101  *      obtain a more random number.
102  */
SARRandomCoeff(unsigned int seed_offset)103 float SARRandomCoeff(unsigned int seed_offset)
104 {
105 #if defined(RAND_MAX)
106 /*	srand((unsigned int)cur_millitime + seed_offset); */
107 	return((float)rand() / (float)RAND_MAX);
108 #else
109 	return((float)SARRandom(seed_offset) / (float)0xffffffff);
110 #endif
111 }
112 
113 
114 /*
115  *      Parses the given string which should be in the format
116  *      "h:m:s". Two available formats 24 and 12 hour are supported,
117  *      where the 12 hour is checked for by searching for an in
118  *      string 'p' character (case insensitive).
119  *
120  *      String is terminated by a null or blank character.
121  *
122  *      Returns non-zero if parsing failed.
123  */
SARParseTimeOfDay(const char * string,int * h,int * m,int * s)124 int SARParseTimeOfDay(
125 	const char *string,
126 	int *h, int *m, int *s
127 )
128 {
129 	const char *sp;
130 	int in_len, is_12hourpm = 0;
131 
132 	int lstring_len = 80;
133 	char *sp2, *sp3;
134 	char lstring[80];
135 
136 	/* Reset inputs. */
137 	if(h != NULL)
138 	    (*h) = 0;
139 	if(m != NULL)
140 	    (*m) = 0;
141 	if(s != NULL)
142 	    (*s) = 0;
143 
144 	if((string == NULL) ? 1 : ((*string) == '\0'))
145 	    return(-1);
146 
147 	/* Check if this is 12 or 24 hour format. */
148 	sp = string;
149 	in_len = 0;
150 	while(((*sp) != '\0') && !ISBLANK(*sp))
151 	{
152 	    if(toupper(*sp) == 'P')
153 		is_12hourpm = 1;
154 
155 	    sp++;
156 	    in_len++;
157 	}
158 
159 	/* Copy input string to local string. */
160 	if(in_len > 0)
161 	    strncpy(
162 		lstring, string, MIN(in_len, lstring_len)
163 	    );
164 	else
165 	    (*lstring) = '\0';
166 	lstring[MIN(in_len, lstring_len - 1)] = '\0';
167 
168 	/* Fetch hour. */
169 	sp2 = lstring;
170 	sp3 = strchr(sp2, ':');
171 	if(sp3 != NULL)
172 	{
173 	    (*sp3) = '\0';
174 	    if(h != NULL)
175 		*h = (ATOI(sp2) + ((is_12hourpm) ? + 12 : 0)) % 24;
176 	    sp2 = sp3 + 1;
177 	}
178 	else
179 	{
180 	    if(h != NULL)
181 		*h = (ATOI(sp2) + ((is_12hourpm) ? + 12 : 0)) % 24;
182 	    sp2 = NULL;
183 	}
184 	if(sp2 == NULL)
185 	    return(0);
186 
187 	/* Fetch minute. */
188 	sp3 = strchr(sp2, ':');
189 	if(sp3 != NULL)
190 	{
191 	    *sp3 = '\0';
192 	    if(m != NULL)
193 		*m = ATOI(sp2) % 60;
194 	    sp2 = sp3 + 1;
195 	}
196 	else
197 	{
198 	    if(m != NULL)
199 		*m = ATOI(sp2) % 60;
200 	    sp2 = NULL;
201 	}
202 	if(sp2 == NULL)
203 	    return(0);
204 
205 	/* Fetch seconds. */
206 	sp3 = strchr(sp2, ':');
207 	if(sp3 != NULL)
208 	{
209 	    *sp3 = '\0';
210 	    if(s != NULL)
211 		*s = ATOI(sp2) % 60;
212 	}
213 	else
214 	{
215 	    if(s != NULL)
216 		*s = ATOI(sp2) % 60;
217 	}
218 
219 	return(0);
220 }
221 
222 /*
223  *      Parses the given string which should be in the format
224  *      "d'm"s" or "d". Examples (respective) "34'10"59" or "34.1833".
225  *
226  *      For format "d" a decimal value from .000 to .999 can be used
227  *      to represent decimal degrees.
228  *
229  *      Degrees is bounded by -90.0 and 90.0.
230  *
231  *      String is terminated by a null or blank character.
232  *
233  *      Returns non-zero if parsing failed.
234  */
SARParseLatitudeDMS(const char * string,float * dms)235 int SARParseLatitudeDMS(const char *string, float *dms)
236 {
237 	const char *sp;
238 	int in_len, is_traditional = 0, is_south = 0;
239 
240 	int lstring_len = 80;
241 	char *sp2, *sp3;
242 	char lstring[80];
243 
244 	/* Reset inputs. */
245 	if(dms != NULL)
246 	    *dms = 0.0f;
247 
248 	if((string != NULL) ? (*string == '\0') : 1)
249 	    return(-1);
250 
251 	/* Check if this is in decimal or traditional notation. */
252 	sp = string;
253 	in_len = 0;
254 	while((*sp != '\0') && !ISBLANK(*sp))
255 	{
256 	    if(toupper(*sp) == '\'')
257 		is_traditional = 1;
258 
259 	    if(toupper(*sp) == 'S')
260 		is_south = 1;
261 
262 	    sp++;
263 	    in_len++;
264 	}
265 
266 	/* Copy input string to local string. */
267 	if(in_len > 0)
268 	    strncpy(
269 		lstring, string, MIN(in_len, lstring_len)
270 	    );
271 	else
272 	    *lstring = '\0';
273 	lstring[MIN(in_len, lstring_len - 1)] = '\0';
274 
275 	/* Handle by type. */
276 	if(is_traditional)
277 	{
278 	    /* Traditional notation. */
279 	    int d = 0, m = 0, s = 0;
280 
281 	    /* Fetch degrees. */
282 	    sp2 = lstring;
283 	    if(sp2 != NULL)
284 	    {
285 		sp3 = strchr(sp2, '\'');
286 		if(sp3 != NULL)
287 		{
288 		    *sp3 = '\0';
289 		    d = ATOI(sp2);
290 		    sp2 = sp3 + 1;
291 		}
292 		else
293 		{
294 		    d = ATOI(sp2);
295 		    sp2 = NULL;
296 		}
297 	    }
298 
299 	    /* Fetch minutes. */
300 	    if(sp2 != NULL)
301 	    {
302 		sp3 = strchr(sp2, '"');
303 		if(sp3 != NULL)
304 		{
305 		    *sp3 = '\0';
306 		    m = ATOI(sp2);
307 		    sp2 = sp3 + 1;
308 		}
309 		else
310 		{
311 		    m = ATOI(sp2);
312 		    sp2 = NULL;
313 		}
314 	    }
315 
316 	    /* Fetch seconds. */
317 	    if(sp2 != NULL)
318 	    {
319 		sp3 = strchr(sp2, '"');
320 		if(sp3 != NULL)
321 		{
322 		    *sp3 = '\0';
323 		    s = ATOI(sp2);
324 		    sp2 = sp3 + 1;
325 		}
326 		else
327 		{
328 		    s = ATOI(sp2);
329 		    sp2 = NULL;
330 		}
331 	    }
332 
333 	    /* Convert and add to dms return. */
334 	    if(dms != NULL)
335 	    {
336 		/* Negative? */
337 		if(is_south && (d > 0.0f))
338 		    *dms = (float)-d -
339 			((float)m / 60.0f) - ((float)s / 60.0f / 100.0f);
340 		else if(d < 0)
341 		    *dms = (float)d -
342 			((float)m / 60.0f) - ((float)s / 60.0f / 100.0f);
343 		else
344 		    *dms = (float)d +
345 			((float)m / 60.0f) + ((float)s / 60.0f / 100.0f);
346 	    }
347 	}
348 	else
349 	{
350 	    /* Decimal notation (this is easy). */
351 	    sp2 = lstring;
352 	    if(dms != NULL)
353 	    {
354 		float d = (float)ATOF(sp2);
355 		if(is_south && (d > 0.0f))
356 		    *dms = -d;
357 		else
358 		    *dms = d;
359 	    }
360 	}
361 
362 	return(0);
363 }
364 
365 /*
366  *      Parses the given string which should be in the format
367  *      "d'm"s" or "d". Examples (respective) "34'10"59" or "34.1833".
368  *
369  *      For format "d" a decimal value from .000 to .999 can be used
370  *      to represent decimal degrees.
371  *
372  *      Degrees is bounded by -140.0 and 140.0.
373  *
374  *      String is terminated by a null or blank character.
375  *
376  *      Returns non-zero if parsing failed.
377  */
SARParseLongitudeDMS(const char * string,float * dms)378 int SARParseLongitudeDMS(const char *string, float *dms)
379 {
380 	const char *sp;
381 	int in_len, is_traditional = 0, is_west = 0;
382 
383 	int lstring_len = 80;
384 	char *sp2, *sp3;
385 	char lstring[80];
386 
387 	/* Reset inputs. */
388 	if(dms != NULL)
389 	    *dms = 0.0f;
390 
391 	if((string != NULL) ? (*string == '\0') : 1)
392 	    return(-1);
393 
394 	/* Check if this is in decimal or traditional notation. */
395 	sp = string;
396 	in_len = 0;
397 	while((*sp != '\0') && !ISBLANK(*sp))
398 	{
399 	    if(toupper(*sp) == '\'')
400 		is_traditional = 1;
401 
402 	    if(toupper(*sp) == 'W')
403 		is_west = 1;
404 
405 	    sp++;
406 	    in_len++;
407 	}
408 
409 	/* Copy input string to local string. */
410 	if(in_len > 0)
411 	    strncpy(
412 		lstring, string, MIN(in_len, lstring_len)
413 	    );
414 	else
415 	    *lstring = '\0';
416 	lstring[MIN(in_len, lstring_len - 1)] = '\0';
417 
418 	/* Handle by type. */
419 	if(is_traditional)
420 	{
421 	    /* Traditional notation. */
422 	    int d = 0, m = 0, s = 0;
423 
424 	    /* Fetch degrees. */
425 	    sp2 = lstring;
426 	    if(sp2 != NULL)
427 	    {
428 		sp3 = strchr(sp2, '\'');
429 		if(sp3 != NULL)
430 		{
431 		    *sp3 = '\0';
432 		    d = ATOI(sp2);
433 		    sp2 = sp3 + 1;
434 		}
435 		else
436 		{
437 		    d = ATOI(sp2);
438 		    sp2 = NULL;
439 		}
440 	    }
441 
442 	    /* Fetch minutes. */
443 	    if(sp2 != NULL)
444 	    {
445 		sp3 = strchr(sp2, '"');
446 		if(sp3 != NULL)
447 		{
448 		    *sp3 = '\0';
449 		    m = ATOI(sp2);
450 		    sp2 = sp3 + 1;
451 		}
452 		else
453 		{
454 		    m = ATOI(sp2);
455 		    sp2 = NULL;
456 		}
457 	    }
458 
459 	    /* Fetch seconds. */
460 	    if(sp2 != NULL)
461 	    {
462 		sp3 = strchr(sp2, '"');
463 		if(sp3 != NULL)
464 		{
465 		    *sp3 = '\0';
466 		    s = ATOI(sp2);
467 		    sp2 = sp3 + 1;
468 		}
469 		else
470 		{
471 		    s = ATOI(sp2);
472 		    sp2 = NULL;
473 		}
474 	    }
475 
476 	    /* Convert and add to dms return. */
477 	    if(dms != NULL)
478 	    {
479 		/* Negative? */
480 		if(is_west && (d > 0))
481 		    *dms = (float)-d -
482 			((float)m / 60.0f) - ((float)s / 60.0f / 100.0f);
483 		else if(d < 0)
484 		    *dms = (float)d -
485 			((float)m / 60.0f) - ((float)s / 60.0f / 100.0f);
486 		else
487 		    *dms = (float)d +
488 			((float)m / 60.0f) + ((float)s / 60.0f / 100.0f);
489 	    }
490 	}
491 	else
492 	{
493 	    /* Decimal notation (this is easy). */
494 	    sp2 = lstring;
495 	    if(dms != NULL)
496 	    {
497 		float d = (float)ATOF(sp2);
498 		if(is_west && (d > 0.0f))
499 		    *dms = -d;
500 		else
501 		    *dms = d;
502 	    }
503 	}
504 
505 	return(0);
506 }
507 
508