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

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