Kernel - Slight reworks to timer code
[tpg/acess2.git] / Kernel / lib.c
1 /*
2  * Acess2
3  * Common Library Functions
4  */
5 #include <acess.h>
6 #include <hal_proc.h>
7
8 // === CONSTANTS ===
9 #define RANDOM_SEED     0xACE55052
10 #define RANDOM_A        0x00731ADE
11 #define RANDOM_C        12345
12 #define RANDOM_SPRUCE   0xf12b039
13 //                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
14 const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
15 #define UNIX_TO_2K      ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
16
17 // === PROTOTYPES ===
18 #if 0
19  int    atoi(const char *string);
20 void    itoa(char *buf, Uint64 num, int base, int minLength, char pad);
21  int    vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
22  int    sprintf(char *__s, const char *__format, ...);
23 #endif
24  int    tolower(int c);
25 #if 0
26  int    strucmp(const char *Str1, const char *Str2);
27 char    *strchr(const char *__s, int __c);
28  int    strpos(const char *Str, char Ch);
29  Uint8  ByteSum(void *Ptr, int Size);
30 size_t  strlen(const char *__s);
31 char    *strcpy(char *__str1, const char *__str2);
32 char    *strncpy(char *__str1, const char *__str2, size_t max);
33  int    strcmp(const char *str1, const char *str2);
34  int    strncmp(const char *str1, const char *str2, size_t num);
35 char    *_strdup(const char *File, int Line, const char *Str);
36 char    **str_split(const char *__str, char __ch);
37  int    strpos8(const char *str, Uint32 Search);
38  int    ReadUTF8(Uint8 *str, Uint32 *Val);
39  int    WriteUTF8(Uint8 *str, Uint32 Val);
40  int    DivUp(int num, int dem);
41 Sint64  timestamp(int sec, int mins, int hrs, int day, int month, int year);
42 void    format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
43  int    rand(void);
44  
45  int    CheckString(char *String);
46  int    CheckMem(void *Mem, int NumBytes);
47  
48  int    ModUtil_LookupString(char **Array, char *Needle);
49  int    ModUtil_SetIdent(char *Dest, char *Value);
50  
51  int    Hex(char *Dest, size_t Size, const Uint8 *SourceData);
52  int    UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
53 #endif
54
55 // === EXPORTS ===
56 EXPORT(atoi);
57 EXPORT(itoa);
58 EXPORT(vsnprintf);
59 EXPORT(sprintf);
60 EXPORT(tolower);
61 EXPORT(strucmp);
62 EXPORT(strchr);
63 EXPORT(strpos);
64 EXPORT(ByteSum);
65 EXPORT(strlen);
66 EXPORT(strcpy);
67 EXPORT(strncpy);
68 EXPORT(strcat);
69 EXPORT(strncat);
70 EXPORT(strcmp);
71 EXPORT(strncmp);
72 //EXPORT(strdup);
73 EXPORT(_strdup);        // Takes File/Line too
74 EXPORT(str_split);
75 EXPORT(strpos8);
76 EXPORT(DivUp);
77 EXPORT(ReadUTF8);
78 EXPORT(WriteUTF8);
79 EXPORT(timestamp);
80 EXPORT(CheckString);
81 EXPORT(CheckMem);
82 EXPORT(ModUtil_LookupString);
83 EXPORT(ModUtil_SetIdent);
84 EXPORT(UnHex);
85 EXPORT(SwapEndian16);
86 EXPORT(SwapEndian32);
87 EXPORT(memmove);
88
89 // === CODE ===
90 /**
91  * \brief Convert a string into an integer
92  */
93 int atoi(const char *string)
94 {
95         int ret = 0;
96         ParseInt(string, &ret);
97         return ret;
98 }
99 int ParseInt(const char *string, int *Val)
100 {
101          int    ret = 0;
102          int    bNeg = 0;
103         const char *orig_string = string;
104         
105         //Log("atoi: (string='%s')", string);
106         
107         // Clear non-numeric characters
108         while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
109         if( *string == '-' ) {
110                 bNeg = 1;
111                 while( !('0' <= *string && *string <= '9') )    string++;
112         }
113         
114         if(*string == '0')
115         {
116                 string ++;
117                 if(*string == 'x')
118                 {
119                         // Hex
120                         string ++;
121                         for( ;; string ++ )
122                         {
123                                 if('0' <= *string && *string <= '9') {
124                                         ret *= 16;
125                                         ret += *string - '0';
126                                 }
127                                 else if('A' <= *string && *string <= 'F') {
128                                         ret *= 16;
129                                         ret += *string - 'A' + 10;
130                                 }
131                                 else if('a' <= *string && *string <= 'f') {
132                                         ret *= 16;
133                                         ret += *string - 'a' + 10;
134                                 }
135                                 else
136                                         break;
137                         }
138                 }
139                 else    // Octal
140                 {
141                         for( ; '0' <= *string && *string <= '7'; string ++ )
142                         {
143                                 ret *= 8;
144                                 ret += *string - '0';
145                         }
146                 }
147         }
148         else    // Decimal
149         {
150                 for( ; '0' <= *string && *string <= '9'; string++)
151                 {
152                         ret *= 10;
153                         ret += *string - '0';
154                 }
155                 // Error check
156                 if( ret == 0 )  return 0;
157         }
158         
159         if(bNeg)        ret = -ret;
160         
161         //Log("atoi: RETURN %i", ret);
162         
163         if(Val) *Val = ret;
164         
165         return string - orig_string;
166 }
167
168 static const char cUCDIGITS[] = "0123456789ABCDEF";
169 /**
170  * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
171  * \brief Convert an integer into a character string
172  */
173 void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
174 {
175         char    tmpBuf[64+1];
176          int    pos=0, i;
177         Uint64  rem;
178
179         // Sanity check
180         if(!buf)        return;
181         
182         // Sanity Check
183         if(base > 16 || base < 2) {
184                 buf[0] = 0;
185                 return;
186         }
187         
188         // Convert 
189         while(num > base-1) {
190                 num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
191                 tmpBuf[pos] = cUCDIGITS[ rem ];
192                 pos++;
193         }
194         tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
195         
196         // Put in reverse
197         i = 0;
198         minLength -= pos;
199         while(minLength-- > 0)  buf[i++] = pad;
200         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
201         buf[i] = 0;
202 }
203
204 /**
205  * \brief Append a character the the vsnprintf output
206  */
207 #define PUTCH(c)        _putch(c)
208 #define GETVAL()        do {\
209         if(isLongLong)  val = va_arg(args, Uint64);\
210         else    val = va_arg(args, unsigned int);\
211         }while(0)
212 /**
213  * \brief VArg String Number Print Formatted
214  */
215 int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
216 {
217         char    c, pad = ' ';
218          int    minSize = 0, precision = -1, len;
219         char    tmpBuf[34];     // For Integers
220         const char      *p = NULL;
221          int    isLongLong = 0;
222         Uint64  val;
223         size_t  pos = 0;
224         // Flags
225          int    bPadLeft = 0;
226         
227         auto void _putch(char ch);
228
229         void _putch(char ch)
230         {
231                 if(pos < __maxlen)
232                 {
233                         if(__s) __s[pos] = ch;
234                         pos ++;
235                 }
236         }
237
238         while((c = *__format++) != 0)
239         {
240                 // Non control character
241                 if(c != '%') { PUTCH(c); continue; }
242
243                 c = *__format++;
244                 if(c == '\0')   break;
245                 
246                 // Literal %
247                 if(c == '%') { PUTCH('%'); continue; }
248                 
249                 // Pointer - Done first for debugging
250                 if(c == 'p') {
251                         Uint    ptr = va_arg(args, Uint);
252                         PUTCH('*');     PUTCH('0');     PUTCH('x');
253                         for( len = BITS/4; len --; )
254                                 PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
255                         continue ;
256                 }
257                 
258                 // - Padding Side Flag
259                 if(c == '-') {
260                         bPadLeft = 1;
261                         c = *__format++;
262                 }
263                 
264                 // - Padding
265                 if(c == '0') {
266                         pad = '0';
267                         c = *__format++;
268                 }
269                 else
270                         pad = ' ';
271                 
272                 // - Minimum length
273                 if(c == '*') {  // Dynamic length
274                         minSize = va_arg(args, unsigned int);
275                         c = *__format++;
276                 }
277                 else if('1' <= c && c <= '9')
278                 {
279                         minSize = 0;
280                         while('0' <= c && c <= '9')
281                         {
282                                 minSize *= 10;
283                                 minSize += c - '0';
284                                 c = *__format++;
285                         }
286                 }
287                 else
288                         minSize = 0;
289                 
290                 // - Precision
291                 precision = -1;
292                 if( c == '.' ) {
293                         c = *__format++;
294                         
295                         if(c == '*') {  // Dynamic length
296                                 precision = va_arg(args, unsigned int);
297                                 c = *__format++;
298                         }
299                         else if('1' <= c && c <= '9')
300                         {
301                                 precision = 0;
302                                 while('0' <= c && c <= '9')
303                                 {
304                                         precision *= 10;
305                                         precision += c - '0';
306                                         c = *__format++;
307                                 }
308                         }
309                 }
310                 
311                 // - Default, Long or LongLong?
312                 isLongLong = 0;
313                 if(c == 'l')    // Long is actually the default on x86
314                 {
315                         c = *__format++;
316                         if(c == 'l') {
317                                 c = *__format++;
318                                 isLongLong = 1;
319                         }
320                 }
321                 
322                 // - Now get the format code
323                 p = tmpBuf;
324                 switch(c)
325                 {
326                 case 'd':
327                 case 'i':
328                         GETVAL();
329                         if( isLongLong && val >> 63 ) {
330                                 PUTCH('-');
331                                 val = -val;
332                         }
333                         else if( !isLongLong && val >> 31 ) {
334                                 PUTCH('-');
335                                 val = -(Sint32)val;
336                         }
337                         itoa(tmpBuf, val, 10, minSize, pad);
338                         goto printString;
339                 case 'u':       // Unsigned
340                         GETVAL();
341                         itoa(tmpBuf, val, 10, minSize, pad);
342                         goto printString;
343                 case 'P':       // Physical Address
344                         PUTCH('0');
345                         PUTCH('x');
346                         if(sizeof(tPAddr) > 4)  isLongLong = 1;
347                         GETVAL();
348                         itoa(tmpBuf, val, 16, minSize, pad);
349                         goto printString;
350                 case 'X':       // Hex
351                         if(BITS == 64)
352                                 isLongLong = 1; // TODO: Handle non-x86 64-bit archs
353                         GETVAL();
354                         itoa(tmpBuf, val, 16, minSize, pad);
355                         goto printString;
356                         
357                 case 'x':       // Lower case hex
358                         GETVAL();
359                         itoa(tmpBuf, val, 16, minSize, pad);
360                         goto printString;
361                 case 'o':       // Octal
362                         GETVAL();
363                         itoa(tmpBuf, val, 8, minSize, pad);
364                         goto printString;
365                 case 'b':
366                         GETVAL();
367                         itoa(tmpBuf, val, 2, minSize, pad);
368                         goto printString;
369
370                 case 'B':       //Boolean
371                         val = va_arg(args, unsigned int);
372                         if(val) p = "True";
373                         else    p = "False";
374                         goto printString;
375                 
376                 // String - Null Terminated Array
377                 case 's':
378                         p = va_arg(args, char*);        // Get Argument
379                         if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
380                 printString:
381                         if(!p)          p = "(null)";
382                         len = strlen(p);
383                         if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
384                         while(*p && precision--)        PUTCH(*p++);
385                         if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
386                         break;
387                 
388                 case 'C':       // Non-Null Terminated Character Array
389                         p = va_arg(args, char*);
390                         if( !CheckMem(p, minSize) )     continue;       // No #PFs please
391                         if(!p)  goto printString;
392                         while(minSize--)        PUTCH(*p++);
393                         break;
394                 
395                 // Single Character
396                 case 'c':
397                 default:
398                         GETVAL();
399                         PUTCH( (Uint8)val );
400                         break;
401                 }
402         }
403         
404         if(__s && pos != __maxlen)
405                 __s[pos] = '\0';
406         
407         return pos;
408 }
409 #undef PUTCH
410
411 /**
412  */
413 int sprintf(char *__s, const char *__format, ...)
414 {
415         va_list args;
416          int    ret;
417         
418         va_start(args, __format);
419         ret = vsnprintf(__s, -1, __format, args);
420         va_end(args);
421         
422         return ret;
423 }
424
425 /**
426  * \fn int tolower(int c)
427  * \brief Converts a character to lower case
428  */
429 int tolower(int c)
430 {
431         if('A' <= c && c <= 'Z')
432                 return c - 'A' + 'a';
433         return c;
434 }
435
436 /**
437  * \fn int strucmp(const char *Str1, const char *Str2)
438  * \brief Compare \a Str1 and \a Str2 case-insensitively
439  */
440 int strucmp(const char *Str1, const char *Str2)
441 {
442         while(*Str1 && tolower(*Str1) == tolower(*Str2))
443                 Str1++, Str2++;
444         return tolower(*Str1) - tolower(*Str2);
445 }
446
447 /**
448  * \brief Locate a byte in a string
449  */
450 char *strchr(const char *__s, int __c)
451 {
452         for( ; *__s; __s ++ )
453         {
454                 if( *__s == __c )       return (char*)__s;
455         }
456         return NULL;
457 }
458
459 /**
460  * \fn int strpos(const char *Str, char Ch)
461  * \brief Search a string for an ascii character
462  */
463 int strpos(const char *Str, char Ch)
464 {
465          int    pos;
466         for(pos=0;Str[pos];pos++)
467         {
468                 if(Str[pos] == Ch)      return pos;
469         }
470         return -1;
471 }
472
473 /**
474  * \fn Uint8 ByteSum(void *Ptr, int Size)
475  * \brief Adds the bytes in a memory region and returns the sum
476  */
477 Uint8 ByteSum(const void *Ptr, int Size)
478 {
479         Uint8   sum = 0;
480         const Uint8     *data = Ptr;
481         while(Size--)   sum += *(data++);
482         return sum;
483 }
484
485 /**
486  * \fn size_t strlen(const char *__str)
487  * \brief Get the length of string
488  */
489 size_t strlen(const char *__str)
490 {
491         size_t  ret = 0;
492         while(*__str++) ret++;
493         return ret;
494 }
495
496 /**
497  * \brief Copy a string to a new location
498  */
499 char *strcpy(char *__str1, const char *__str2)
500 {
501         while(*__str2)
502                 *__str1++ = *__str2++;
503         *__str1 = '\0'; // Terminate String
504         return __str1;
505 }
506
507 /**
508  * \brief Copy a string to a new location
509  * \note Copies at most `max` chars
510  */
511 char *strncpy(char *__str1, const char *__str2, size_t __max)
512 {
513         while(*__str2 && __max-- >= 1)
514                 *__str1++ = *__str2++;
515         if(__max)
516                 *__str1 = '\0'; // Terminate String
517         return __str1;
518 }
519
520 /**
521  * \brief Append a string to another
522  */
523 char *strcat(char *__dest, const char *__src)
524 {
525         while(*__dest++);
526         __dest--;
527         while(*__src)
528                 *__dest++ = *__src++;
529         *__dest = '\0';
530         return __dest;
531 }
532
533 /**
534  * \brief Append at most \a n chars to a string from another
535  * \note At most n+1 chars are written (the dest is always zero terminated)
536  */
537 char *strncat(char *__dest, const char *__src, size_t n)
538 {
539         while(*__dest++);
540         while(*__src && n-- >= 1)
541                 *__dest++ = *__src++;
542         *__dest = '\0';
543         return __dest;
544 }
545
546 /**
547  * \fn int strcmp(const char *str1, const char *str2)
548  * \brief Compare two strings return the difference between
549  *        the first non-matching characters.
550  */
551 int strcmp(const char *str1, const char *str2)
552 {
553         while(*str1 && *str1 == *str2)
554                 str1++, str2++;
555         return *str1 - *str2;
556 }
557
558 /**
559  * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
560  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
561  */
562 int strncmp(const char *Str1, const char *Str2, size_t num)
563 {
564         if(num == 0)    return 0;       // TODO: Check what should officially happen here
565         while(--num && *Str1 && *Str1 == *Str2)
566                 Str1++, Str2++;
567         return *Str1-*Str2;
568 }
569
570 #if 0
571 /**
572  * \fn char *strdup(const char *Str)
573  * \brief Duplicates a string
574  */
575 char *strdup(const char *Str)
576 {
577         char    *ret;
578         ret = malloc(strlen(Str)+1);
579         if( !ret )      return NULL;
580         strcpy(ret, Str);
581         return ret;
582 }
583 #else
584
585 /**
586  * \fn char *_strdup(const char *File, int Line, const char *Str)
587  * \brief Duplicates a string
588  */
589 char *_strdup(const char *File, int Line, const char *Str)
590 {
591         char    *ret;
592         ret = Heap_Allocate(File, Line, strlen(Str)+1);
593         if( !ret )      return NULL;
594         strcpy(ret, Str);
595         return ret;
596 }
597 #endif
598
599 /**
600  * \brief Split a string using the passed character
601  * \return NULL terminated array of strings on the heap
602  * \param __str String to split
603  * \param __ch  Character to split by
604  */
605 char **str_split(const char *__str, char __ch)
606 {
607          int    i, j;
608          int    len = 1;
609         char    **ret;
610         char    *start;
611         
612         for( i = 0; __str[i]; i++ )
613         {
614                 if(__str[i] == __ch)
615                         len ++;
616         }
617         
618         ret = malloc( sizeof(char*)*(len+1) + (i + 1) );
619         if( !ret )      return NULL;
620         
621         j = 1;
622         start = (char *)&ret[len+1];
623         ret[0] = start;
624         for( i = 0; __str[i]; i++ )
625         {
626                 if(__str[i] == __ch) {
627                         *start++ = '\0';
628                         ret[j++] = start;
629                 }
630                 else {
631                         *start++ = __str[i]; 
632                 }
633         }
634         *start = '\0';
635         ret[j] = NULL;
636         
637         return ret;
638 }
639
640 /**
641  * \fn int DivUp(int num, int dem)
642  * \brief Divide two numbers, rounding up
643  * \param num   Numerator
644  * \param dem   Denominator
645  */
646 int DivUp(int num, int dem)
647 {
648         return (num+dem-1)/dem;
649 }
650
651 /**
652  * \fn int strpos8(const char *str, Uint32 search)
653  * \brief Search a string for a UTF-8 character
654  */
655 int strpos8(const char *str, Uint32 Search)
656 {
657          int    pos;
658         Uint32  val = 0;
659         for(pos=0;str[pos];pos++)
660         {
661                 // ASCII Range
662                 if(Search < 128) {
663                         if(str[pos] == Search)  return pos;
664                         continue;
665                 }
666                 if(*(Uint8*)(str+pos) < 128)    continue;
667                 
668                 pos += ReadUTF8( (Uint8*)&str[pos], &val );
669                 if(val == Search)       return pos;
670         }
671         return -1;
672 }
673
674 /**
675  * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
676  * \brief Read a UTF-8 character from a string
677  */
678 int ReadUTF8(const Uint8 *str, Uint32 *Val)
679 {
680         *Val = 0xFFFD;  // Assume invalid character
681         
682         // ASCII
683         if( !(*str & 0x80) ) {
684                 *Val = *str;
685                 return 1;
686         }
687         
688         // Middle of a sequence
689         if( (*str & 0xC0) == 0x80 ) {
690                 return 1;
691         }
692         
693         // Two Byte
694         if( (*str & 0xE0) == 0xC0 ) {
695                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
696                 str ++;
697                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
698                 *Val |= (*str & 0x3F);  // Lower 6 Bits
699                 return 2;
700         }
701         
702         // Three Byte
703         if( (*str & 0xF0) == 0xE0 ) {
704                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
705                 str ++;
706                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
707                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
708                 str ++;
709                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
710                 *Val |= (*str & 0x3F);  // Lower 6 Bits
711                 return 3;
712         }
713         
714         // Four Byte
715         if( (*str & 0xF1) == 0xF0 ) {
716                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
717                 str ++;
718                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
719                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
720                 str ++;
721                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
722                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
723                 str ++;
724                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
725                 *Val |= (*str & 0x3F);  // Lower 6 Bits
726                 return 4;
727         }
728         
729         // UTF-8 Doesn't support more than four bytes
730         return 4;
731 }
732
733 /**
734  * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
735  * \brief Write a UTF-8 character sequence to a string
736  */
737 int WriteUTF8(Uint8 *str, Uint32 Val)
738 {
739         // ASCII
740         if( Val < 128 ) {
741                 if( str ) {
742                         *str = Val;
743                 }
744                 return 1;
745         }
746         
747         // Two Byte
748         if( Val < 0x8000 ) {
749                 if( str ) {
750                         *str++ = 0xC0 | (Val >> 6);
751                         *str++ = 0x80 | (Val & 0x3F);
752                 }
753                 return 2;
754         }
755         
756         // Three Byte
757         if( Val < 0x10000 ) {
758                 if( str ) {
759                         *str++ = 0xE0 | (Val >> 12);
760                         *str++ = 0x80 | ((Val >> 6) & 0x3F);
761                         *str++ = 0x80 | (Val & 0x3F);
762                 }
763                 return 3;
764         }
765         
766         // Four Byte
767         if( Val < 0x110000 ) {
768                 if( str ) {
769                         *str++ = 0xF0 | (Val >> 18);
770                         *str++ = 0x80 | ((Val >> 12) & 0x3F);
771                         *str++ = 0x80 | ((Val >> 6) & 0x3F);
772                         *str++ = 0x80 | (Val & 0x3F);
773                 }
774                 return 4;
775         }
776         
777         // UTF-8 Doesn't support more than four bytes
778         return 0;
779 }
780
781 /**
782  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
783  * \brief Converts a date into an Acess Timestamp
784  */
785 Sint64 timestamp(int sec, int min, int hrs, int day, int month, int year)
786 {
787          int    is_leap;
788         Sint64  stamp;
789
790         if( !(0 <= sec && sec < 60) )   return 0;
791         if( !(0 <= min && min < 60) )   return 0;
792         if( !(0 <= hrs && hrs < 24) )   return 0;
793         if( !(0 <= day && day < 31) )   return 0;
794         if( !(0 <= month && month < 12) )       return 0;
795
796         stamp = DAYS_BEFORE[month] + day;
797
798         // Every 4 years
799         // - every 100 years
800         // + every 400 years
801         is_leap = (year % 4 == 0) - (year % 100 == 0) + (year % 400 == 0);
802         ASSERT(is_leap == 0 || is_leap == 1);
803
804         if( is_leap && month > 1 )      // Leap year and after feb
805                 stamp += 1;
806
807         // Get seconds before the first of specified year
808         year -= 2000;   // Base off Y2K
809         // base year days + total leap year days
810         stamp += year*365 + (year/400) - (year/100) + (year/4);
811         
812         stamp *= 3600*24;
813         stamp += UNIX_TO_2K;
814         stamp += sec;
815         stamp += min*60;
816         stamp += hrs*3600;
817         
818         return stamp * 1000;
819 }
820
821 void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms)
822 {
823          int    is_leap = 0, i;
824
825         auto Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R);
826         
827         Sint64 DivMod64(Sint64 N, Sint64 D, Sint64 *R)
828         {
829                 int sign = (N < 0) != (D < 0);
830                 if(N < 0)       N = -N;
831                 if(D < 0)       D = -D;
832                 if(sign)
833                         return -DivMod64U(N, D, (Uint64*)R);
834                 else
835                         return DivMod64U(N, D, (Uint64*)R);
836         }
837
838         // Get time
839         // TODO: Leap-seconds?
840         {
841                 Sint64  rem;
842                 TS = DivMod64( TS, 1000, &rem );
843                 *ms = rem;
844                 TS = DivMod64( TS, 60, &rem );
845                 *sec = rem;
846                 TS = DivMod64( TS, 60, &rem );
847                 *mins = rem;
848                 TS = DivMod64( TS, 24, &rem );
849                 *hrs = rem;
850         }
851
852         // Adjust to Y2K
853         TS -= UNIX_TO_2K/(3600*24);
854
855         // Year (400 yr blocks) - (400/4-3) leap years
856         *year = 400 * DivMod64( TS, 365*400 + (400/4-3), &TS );
857         if( TS < 366 )  // First year in 400 is a leap
858                 is_leap = 1;
859         else
860         {
861                 // 100 yr blocks - 100/4-1 leap years
862                 *year += 100 * DivMod64( TS, 365*100 + (100/4-1), &TS );
863                 if( TS < 366 )  // First year in 100 isn't a leap
864                         is_leap = 0;
865                 else
866                 {
867                         *year += 4 * DivMod64( TS, 365*4 + 1, &TS );
868                         if( TS < 366 )  // First year in 4 is a leap
869                                 is_leap = 1;
870                         else
871                         {
872                                 *year += DivMod64( TS, 356, &TS );
873                         }
874                 }
875         }
876         *year += 2000;
877
878         ASSERT(TS >= 0);
879         
880         *day = 0;
881         // Month (if after the first of march, which is 29 Feb in a leap year)
882         if( is_leap && TS > DAYS_BEFORE[2] ) {
883                 TS -= 1;        // Shifts 29 Feb to 28 Feb
884                 *day = 1;
885         }
886         // Get what month it is
887         for( i = 0; i < 12; i ++ ) {
888                 if( TS < DAYS_BEFORE[i] )
889                         break;
890         }
891         *month = i - 1;
892         // Get day
893         TS -= DAYS_BEFORE[i-1];
894         *day += TS;     // Plus offset from leap handling above
895 }
896
897 /**
898  * \fn int rand()
899  * \brief Pseudo random number generator
900  */
901 int rand(void)
902 {
903         #if 0
904         static Uint     state = RANDOM_SEED;
905         Uint    old = state;
906         // Get the next state value
907         giRandomState = (RANDOM_A*state + RANDOM_C);
908         // Check if it has changed, and if it hasn't, change it
909         if(state == old)        state += RANDOM_SPRUCE;
910         return state;
911         #else
912         // http://en.wikipedia.org/wiki/Xorshift
913         // 2010-10-03
914         static Uint32   x = 123456789;
915         static Uint32   y = 362436069;
916         static Uint32   z = 521288629;
917         static Uint32   w = 88675123; 
918         Uint32  t;
919  
920         t = x ^ (x << 11);
921         x = y; y = z; z = w;
922         return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
923         #endif
924 }
925
926 /* *
927  * \name Memory Validation
928  * \{
929  */
930 /**
931  * \brief Checks if a string resides fully in valid memory
932  */
933 int CheckString(const char *String)
934 {
935         tVAddr  addr;
936          int    bUser;
937
938         addr = (tVAddr)String;
939
940         if( !MM_GetPhysAddr( addr ) )
941                 return 0;
942         
943         // Check 1st page
944         bUser = MM_IsUser( addr );
945         
946         while( *(char*)addr )
947         {
948                 if( (addr & (PAGE_SIZE-1)) == 0 )
949                 {
950                         if(bUser && !MM_IsUser(addr) )
951                                 return 0;
952                         if(!bUser && !MM_GetPhysAddr(addr) )
953                                 return 0;
954                 }
955                 addr ++;
956         }
957         return 1;
958 }
959
960 /**
961  * \brief Check if a sized memory region is valid memory
962  * \return Boolean success
963  */
964 int CheckMem(const void *Mem, int NumBytes)
965 {
966         return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
967 }
968 /* *
969  * \}
970  */
971
972 /**
973  * \brief Search a string array for \a Needle
974  * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
975  */
976 int ModUtil_LookupString(const char **Array, const char *Needle)
977 {
978          int    i;
979         if( !CheckString(Needle) )      return -1;
980         for( i = 0; Array[i]; i++ )
981         {
982                 if(strcmp(Array[i], Needle) == 0)       return i;
983         }
984         return -1;
985 }
986
987 int ModUtil_SetIdent(char *Dest, const char *Value)
988 {
989         if( !CheckMem(Dest, 32) )       return -1;
990         strncpy(Dest, Value, 32);
991         return 1;
992 }
993
994 int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
995 {
996          int    i;
997         for( i = 0; i < Size; i ++ )
998         {
999                 sprintf(Dest + i*2, "%02x", SourceData[i]);
1000         }
1001         return i*2;
1002 }
1003
1004 /**
1005  * \brief Convert a string of hexadecimal digits into a byte stream
1006  */
1007 int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString)
1008 {
1009          int    i;
1010         
1011         for( i = 0; i < DestSize*2; i += 2 )
1012         {
1013                 Uint8   val = 0;
1014                 
1015                 if(SourceString[i] == '\0')     break;
1016                 
1017                 if('0' <= SourceString[i] && SourceString[i] <= '9')
1018                         val |= (SourceString[i]-'0') << 4;
1019                 else if('A' <= SourceString[i] && SourceString[i] <= 'F')
1020                         val |= (SourceString[i]-'A'+10) << 4;
1021                 else if('a' <= SourceString[i] && SourceString[i] <= 'f')
1022                         val |= (SourceString[i]-'a'+10) << 4;
1023                         
1024                 if(SourceString[i+1] == '\0')   break;
1025                 
1026                 if('0' <= SourceString[i+1] && SourceString[i+1] <= '9')
1027                         val |= (SourceString[i+1] - '0');
1028                 else if('A' <= SourceString[i+1] && SourceString[i+1] <= 'F')
1029                         val |= (SourceString[i+1] - 'A' + 10);
1030                 else if('a' <= SourceString[i+1] && SourceString[i+1] <= 'f')
1031                         val |= (SourceString[i+1] - 'a' + 10);
1032                 
1033                 Dest[i/2] = val;
1034         }
1035         return i/2;
1036 }
1037
1038 Uint16 SwapEndian16(Uint16 Val)
1039 {
1040         return ((Val&0xFF)<<8) | ((Val>>8)&0xFF);
1041 }
1042 Uint32 SwapEndian32(Uint32 Val)
1043 {
1044         return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
1045 }
1046
1047 void *memmove(void *__dest, const void *__src, size_t len)
1048 {
1049         size_t  block_size;
1050         char    *dest = __dest;
1051         const char      *src = __src;
1052         void    *ret = __dest;
1053
1054         if( len == 0 || dest == src )
1055                 return dest;
1056         
1057         if( (tVAddr)dest > (tVAddr)src + len )
1058                 return memcpy(dest, src, len);
1059         if( (tVAddr)dest + len < (tVAddr)src )
1060                 return memcpy(dest, src, len);
1061         
1062         // NOTE: Assumes memcpy works forward
1063         if( (tVAddr)dest < (tVAddr)src )
1064                 return memcpy(dest, src, len);
1065
1066         if( (tVAddr)dest < (tVAddr)src )
1067                 block_size = (tVAddr)src - (tVAddr)dest;
1068         else
1069                 block_size = (tVAddr)dest - (tVAddr)src;
1070         
1071         block_size &= ~0xF;
1072         
1073         while(len >= block_size)
1074         {
1075                 memcpy(dest, src, block_size);
1076                 len -= block_size;
1077                 dest += block_size;
1078                 src += block_size;
1079         }
1080         memcpy(dest, src, len);
1081         return ret;
1082         
1083 }
1084

UCC git Repository :: git.ucc.asn.au