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

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