Altered debug print function to use vsnprintf and to use Debug_Puts instead of Debug_...
[tpg/acess2.git] / Kernel / lib.c
1 /*
2  * Acess2
3  * Common Library Functions
4  */
5 #include <acess.h>
6
7 // === CONSTANTS ===
8 #define RANDOM_SEED     0xACE55052
9 #define RANDOM_A        0x00731ADE
10 #define RANDOM_C        12345
11 #define RANDOM_SPRUCE   0xf12b02b
12 //                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
13 const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
14 #define UNIX_TO_2K      ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
15
16 // === PROTOTYPES ===
17  int    atoi(const char *string);
18 void    itoa(char *buf, Uint num, int base, int minLength, char pad);
19  int    vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
20  int    sprintf(char *__s, const char *__format, ...);
21  int    tolower(int c);
22  int    strucmp(const char *Str1, const char *Str2);
23  int    strpos(const char *Str, char Ch);
24  Uint8  ByteSum(void *Ptr, int Size);
25 size_t  strlen(const char *__s);
26 char    *strcpy(char *__str1, const char *__str2);
27 char    *strncpy(char *__str1, const char *__str2, size_t max);
28  int    strcmp(const char *str1, const char *str2);
29  int    strncmp(const char *str1, const char *str2, size_t num);
30 char    *strdup(const char *Str);
31  int    DivUp(int num, int dem);
32  int    strpos8(const char *str, Uint32 Search);
33  int    ReadUTF8(Uint8 *str, Uint32 *Val);
34  int    WriteUTF8(Uint8 *str, Uint32 Val);
35 Sint64  timestamp(int sec, int mins, int hrs, int day, int month, int year);
36 Uint    rand(void);
37  int    CheckString(char *String);
38  int    CheckMem(void *Mem, int NumBytes);
39  int    ModUtil_LookupString(char **Array, char *Needle);
40  int    ModUtil_SetIdent(char *Dest, char *Value);
41
42 // === EXPORTS ===
43 EXPORT(atoi);
44 EXPORT(itoa);
45 EXPORT(vsnprintf);
46 EXPORT(sprintf);
47 EXPORT(tolower);
48 EXPORT(strucmp);
49 EXPORT(strpos);
50 EXPORT(ByteSum);
51 EXPORT(strlen);
52 EXPORT(strcpy);
53 EXPORT(strncpy);
54 EXPORT(strcmp);
55 EXPORT(strncmp);
56 EXPORT(strdup);
57 EXPORT(DivUp);
58 EXPORT(strpos8);
59 EXPORT(ReadUTF8);
60 EXPORT(WriteUTF8);
61 EXPORT(timestamp);
62 EXPORT(CheckString);
63 EXPORT(CheckMem);
64 EXPORT(ModUtil_LookupString);
65 EXPORT(ModUtil_SetIdent);
66
67 // === GLOBALS ===
68 static Uint     giRandomState = RANDOM_SEED;
69
70 // === CODE ===
71 /**
72  * \brief Convert a string into an integer
73  */
74 int atoi(const char *string)
75 {
76          int    ret = 0;
77          int    bNeg = 0;
78         
79         //Log("atoi: (string='%s')", string);
80         
81         // Clear non-numeric characters
82         while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
83         if( *string == '-' ) {
84                 bNeg = 1;
85                 while( !('0' <= *string && *string <= '9') )    string++;
86         }
87         
88         if(*string == '0')
89         {
90                 string ++;
91                 if(*string == 'x')
92                 {
93                         // Hex
94                         string ++;
95                         for( ;; string ++ )
96                         {
97                                 if('0' <= *string && *string <= '9') {
98                                         ret *= 16;
99                                         ret += *string - '0';
100                                 }
101                                 else if('A' <= *string && *string <= 'F') {
102                                         ret *= 16;
103                                         ret += *string - 'A' + 10;
104                                 }
105                                 else if('a' <= *string && *string <= 'f') {
106                                         ret *= 16;
107                                         ret += *string - 'a' + 10;
108                                 }
109                                 else
110                                         break;
111                         }
112                 }
113                 else    // Octal
114                 {
115                         for( ; '0' <= *string && *string <= '7'; string ++ )
116                         {
117                                 ret *= 8;
118                                 ret += *string - '0';
119                         }
120                 }
121         }
122         else    // Decimal
123         {
124                 for( ; '0' <= *string && *string <= '9'; string++)
125                 {
126                         ret *= 10;
127                         ret += *string - '0';
128                 }
129         }
130         
131         if(bNeg)        ret = -ret;
132         
133         //Log("atoi: RETURN %i", ret);
134         
135         return ret;
136 }
137
138 static const char cUCDIGITS[] = "0123456789ABCDEF";
139 /**
140  * \fn void itoa(char *buf, Uint num, int base, int minLength, char pad)
141  * \brief Convert an integer into a character string
142  */
143 void itoa(char *buf, Uint num, int base, int minLength, char pad)
144 {
145         char    tmpBuf[BITS];
146          int    pos=0, i;
147
148         // Sanity check
149         if(!buf)        return;
150         
151         // Sanity Check
152         if(base > 16 || base < 2) {
153                 buf[0] = 0;
154                 return;
155         }
156         
157         // Convert 
158         while(num > base-1) {
159                 tmpBuf[pos] = cUCDIGITS[ num % base ];
160                 num /= (Uint)base;              // Shift `num` right 1 digit
161                 pos++;
162         }
163         tmpBuf[pos++] = cUCDIGITS[ num % base ];                // Last digit of `num`
164         
165         // Put in reverse
166         i = 0;
167         minLength -= pos;
168         while(minLength-- > 0)  buf[i++] = pad;
169         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
170         buf[i] = 0;
171 }
172
173 /**
174  * \brief Append a character the the vsnprintf output
175  */
176 #define PUTCH(c)        do{\
177         char ch=(c);\
178         if(pos==__maxlen){return pos;}\
179         if(__s){__s[pos++]=ch;}else{pos++;}\
180         }while(0)
181 int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
182 {
183         char    c, pad = ' ';
184          int    minSize = 0, len;
185         char    tmpBuf[34];     // For Integers
186         char    *p = NULL;
187          int    isLongLong = 0;
188         Uint64  val;
189         size_t  pos = 0;
190         // Flags
191          int    bPadLeft = 0;
192         
193         //Log("vsnprintf: (__s=%p, __maxlen=%i, __format='%s', ...)", __s, __maxlen, __format);
194         
195         while((c = *__format++) != 0)
196         {
197                 // Non control character
198                 if(c != '%') { PUTCH(c); continue; }
199                 
200                 c = *__format++;
201                 //Log("pos = %i", pos);
202                 
203                 // Literal %
204                 if(c == '%') { PUTCH('%'); continue; }
205                 
206                 // Pointer - Done first for debugging
207                 if(c == 'p') {
208                         Uint    ptr = va_arg(args, Uint);
209                         PUTCH('*');     PUTCH('0');     PUTCH('x');
210                         p = tmpBuf;
211                         itoa(p, ptr, 16, BITS/4, '0');
212                         goto printString;
213                 }
214                 
215                 // Get Argument
216                 val = va_arg(args, Uint);
217                 
218                 // - Padding Side Flag
219                 if(c == '+') {
220                         bPadLeft = 1;
221                         c = *__format++;
222                 }
223                 
224                 // - Padding
225                 if(c == '0') {
226                         pad = '0';
227                         c = *__format++;
228                 }
229                 else
230                         pad = ' ';
231                 
232                 // - Minimum length
233                 minSize = 1;
234                 if('1' <= c && c <= '9')
235                 {
236                         minSize = 0;
237                         while('0' <= c && c <= '9')
238                         {
239                                 minSize *= 10;
240                                 minSize += c - '0';
241                                 c = *__format++;
242                         }
243                 }
244                 
245                 // - Default, Long or LongLong?
246                 isLongLong = 0;
247                 if(c == 'l')    // Long is actually the default on x86
248                 {
249                         c = *__format++;
250                         if(c == 'l') {
251                                 #if BITS == 32
252                                 val |= (Uint64)va_arg(args, Uint) << 32;
253                                 #endif
254                                 c = *__format++;
255                                 isLongLong = 1;
256                         }
257                 }
258                 
259                 // - Now get the format code
260                 p = tmpBuf;
261                 switch(c)
262                 {
263                 case 'd':
264                 case 'i':
265                         if( (isLongLong && val >> 63) || (!isLongLong && val >> 31) ) {
266                                 PUTCH('-');
267                                 val = -val;
268                         }
269                         itoa(p, val, 10, minSize, pad);
270                         goto printString;
271                 case 'u':
272                         itoa(p, val, 10, minSize, pad);
273                         goto printString;
274                 case 'x':
275                         itoa(p, val, 16, minSize, pad);
276                         goto printString;
277                 case 'o':
278                         itoa(p, val, 8, minSize, pad);
279                         goto printString;
280                 case 'b':
281                         itoa(p, val, 2, minSize, pad);
282                         goto printString;
283
284                 case 'B':       //Boolean
285                         if(val) p = "True";
286                         else    p = "False";
287                         goto printString;
288                 
289                 // String - Null Terminated Array
290                 case 's':
291                         p = (char*)(Uint)val;
292                 printString:
293                         if(!p)          p = "(null)";
294                         len = strlen(p);
295                         if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
296                         while(*p)       PUTCH(*p++);
297                         if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
298                         break;
299                 
300                 case 'C':       // Non-Null Terminated Character Array
301                         p = (char*)(Uint)val;
302                         if(!p)  goto printString;
303                         while(minSize--)        PUTCH(*p++);
304                         break;
305                 
306                 // Single Character
307                 case 'c':
308                 default:
309                         PUTCH( (Uint8)val );
310                         break;
311                 }
312         }
313         
314         if(__s && pos != __maxlen)
315                 __s[pos] = '\0';
316         
317         return pos;
318 }
319 #undef PUTCH
320
321 /**
322  */
323 int sprintf(char *__s, const char *__format, ...)
324 {
325         va_list args;
326          int    ret;
327         
328         va_start(args, __format);
329         ret = vsnprintf(__s, -1, __format, args);
330         va_end(args);
331         
332         return ret;
333 }
334
335 /**
336  * \fn int tolower(int c)
337  * \brief Converts a character to lower case
338  */
339 int tolower(int c)
340 {
341         if('A' <= c && c <= 'Z')
342                 return c - 'A' + 'a';
343         return c;
344 }
345
346 /**
347  * \fn int strucmp(const char *Str1, const char *Str2)
348  * \brief Compare \a Str1 and \a Str2 case-insensitively
349  */
350 int strucmp(const char *Str1, const char *Str2)
351 {
352         while(*Str1 && tolower(*Str1) == tolower(*Str2))
353                 Str1++, Str2++;
354         return tolower(*Str1) - tolower(*Str2);
355 }
356
357 /**
358  * \fn int strpos(const char *Str, char Ch)
359  * \brief Search a string for an ascii character
360  */
361 int strpos(const char *Str, char Ch)
362 {
363          int    pos;
364         for(pos=0;Str[pos];pos++)
365         {
366                 if(Str[pos] == Ch)      return pos;
367         }
368         return -1;
369 }
370
371 /**
372  * \fn Uint8 ByteSum(void *Ptr, int Size)
373  * \brief Adds the bytes in a memory region and returns the sum
374  */
375 Uint8 ByteSum(void *Ptr, int Size)
376 {
377         Uint8   sum = 0;
378         while(Size--)   sum += *(Uint8*)Ptr++;
379         return sum;
380 }
381
382 /**
383  * \fn Uint strlen(const char *__str)
384  * \brief Get the length of string
385  */
386 Uint strlen(const char *__str)
387 {
388         Uint    ret = 0;
389         while(*__str++) ret++;
390         return ret;
391 }
392
393 /**
394  * \fn char *strcpy(char *__str1, const char *__str2)
395  * \brief Copy a string to a new location
396  */
397 char *strcpy(char *__str1, const char *__str2)
398 {
399         while(*__str2)
400                 *__str1++ = *__str2++;
401         *__str1 = '\0'; // Terminate String
402         return __str1;
403 }
404
405 /**
406  * \fn char *strncpy(char *__str1, const char *__str2, size_t max)
407  * \brief Copy a string to a new location
408  */
409 char *strncpy(char *__str1, const char *__str2, size_t max)
410 {
411         while(*__str2 && max-- >= 1)
412                 *__str1++ = *__str2++;
413         if(max)
414                 *__str1 = '\0'; // Terminate String
415         return __str1;
416 }
417
418 /**
419  * \fn int strcmp(const char *str1, const char *str2)
420  * \brief Compare two strings return the difference between
421  *        the first non-matching characters.
422  */
423 int strcmp(const char *str1, const char *str2)
424 {
425         while(*str1 && *str1 == *str2)
426                 str1++, str2++;
427         return *str1 - *str2;
428 }
429
430 /**
431  * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
432  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
433  */
434 int strncmp(const char *Str1, const char *Str2, size_t num)
435 {
436         if(num == 0)    return 0;       // TODO: Check what should officially happen here
437         while(--num && *Str1 && *Str1 == *Str2)
438                 Str1++, Str2++;
439         return *Str1-*Str2;
440 }
441
442 /**
443  * \fn char *strdup(const char *Str)
444  * \brief Duplicates a string
445  */
446 char *strdup(const char *Str)
447 {
448         char    *ret;
449         ret = malloc(strlen(Str)+1);
450         strcpy(ret, Str);
451         return ret;
452 }
453
454 /**
455  * \fn int DivUp(int num, int dem)
456  * \brief Divide two numbers, rounding up
457  * \param num   Numerator
458  * \param dem   Denominator
459  */
460 int DivUp(int num, int dem)
461 {
462         return (num+dem-1)/dem;
463 }
464
465 /**
466  * \fn int strpos8(const char *str, Uint32 search)
467  * \brief Search a string for a UTF-8 character
468  */
469 int strpos8(const char *str, Uint32 Search)
470 {
471          int    pos;
472         Uint32  val = 0;
473         for(pos=0;str[pos];pos++)
474         {
475                 // ASCII Range
476                 if(Search < 128) {
477                         if(str[pos] == Search)  return pos;
478                         continue;
479                 }
480                 if(*(Uint8*)(str+pos) < 128)    continue;
481                 
482                 pos += ReadUTF8( (Uint8*)&str[pos], &val );
483                 if(val == Search)       return pos;
484         }
485         return -1;
486 }
487
488 /**
489  * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
490  * \brief Read a UTF-8 character from a string
491  */
492 int ReadUTF8(Uint8 *str, Uint32 *Val)
493 {
494         *Val = 0xFFFD;  // Assume invalid character
495         
496         // ASCII
497         if( !(*str & 0x80) ) {
498                 *Val = *str;
499                 return 1;
500         }
501         
502         // Middle of a sequence
503         if( (*str & 0xC0) == 0x80 ) {
504                 return 1;
505         }
506         
507         // Two Byte
508         if( (*str & 0xE0) == 0xC0 ) {
509                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
510                 str ++;
511                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
512                 *Val |= (*str & 0x3F);  // Lower 6 Bits
513                 return 2;
514         }
515         
516         // Three Byte
517         if( (*str & 0xF0) == 0xE0 ) {
518                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
519                 str ++;
520                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
521                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
522                 str ++;
523                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
524                 *Val |= (*str & 0x3F);  // Lower 6 Bits
525                 return 3;
526         }
527         
528         // Four Byte
529         if( (*str & 0xF1) == 0xF0 ) {
530                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
531                 str ++;
532                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
533                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
534                 str ++;
535                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
536                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
537                 str ++;
538                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
539                 *Val |= (*str & 0x3F);  // Lower 6 Bits
540                 return 4;
541         }
542         
543         // UTF-8 Doesn't support more than four bytes
544         return 4;
545 }
546
547 /**
548  * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
549  * \brief Write a UTF-8 character sequence to a string
550  */
551 int WriteUTF8(Uint8 *str, Uint32 Val)
552 {
553         // ASCII
554         if( Val < 128 ) {
555                 *str = Val;
556                 return 1;
557         }
558         
559         // Two Byte
560         if( Val < 0x8000 ) {
561                 *str = 0xC0 | (Val >> 6);
562                 str ++;
563                 *str = 0x80 | (Val & 0x3F);
564                 return 2;
565         }
566         
567         // Three Byte
568         if( Val < 0x10000 ) {
569                 *str = 0xE0 | (Val >> 12);
570                 str ++;
571                 *str = 0x80 | ((Val >> 6) & 0x3F);
572                 str ++;
573                 *str = 0x80 | (Val & 0x3F);
574                 return 3;
575         }
576         
577         // Four Byte
578         if( Val < 0x110000 ) {
579                 *str = 0xF0 | (Val >> 18);
580                 str ++;
581                 *str = 0x80 | ((Val >> 12) & 0x3F);
582                 str ++;
583                 *str = 0x80 | ((Val >> 6) & 0x3F);
584                 str ++;
585                 *str = 0x80 | (Val & 0x3F);
586                 return 4;
587         }
588         
589         // UTF-8 Doesn't support more than four bytes
590         return 0;
591 }
592
593 /**
594  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
595  * \brief Converts a date into an Acess Timestamp
596  */
597 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
598 {
599         Sint64  stamp;
600         stamp = sec;
601         stamp += mins*60;
602         stamp += hrs*3600;
603         
604         stamp += day*3600*24;
605         stamp += month*DAYS_BEFORE[month]*3600*24;
606         if(     (
607                 ((year&3) == 0 || year%100 != 0)
608                 || (year%100 == 0 && ((year/100)&3) == 0)
609                 ) && month > 1) // Leap year and after feb
610                 stamp += 3600*24;
611         
612         stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Foour Year Segments
613         stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
614         stamp += UNIX_TO_2K;
615         
616         return stamp * 1000;
617 }
618
619 /**
620  * \fn Uint rand()
621  * \brief Pseudo random number generator
622  * \note Unknown effectiveness (made up on the spot)
623  */
624 Uint rand(void)
625 {
626         Uint    old = giRandomState;
627         // Get the next state value
628         giRandomState = (RANDOM_A*giRandomState + RANDOM_C) & 0xFFFFFFFF;
629         // Check if it has changed, and if it hasn't, change it
630         if(giRandomState == old)        giRandomState += RANDOM_SPRUCE;
631         return giRandomState;
632 }
633
634 /// \name Memory Validation
635 /// \{
636 /**
637  * \brief Checks if a string resides fully in valid memory
638  */
639 int CheckString(char *String)
640 {
641         // Check 1st page
642         if( MM_IsUser( (tVAddr)String ) )
643         {
644                 // Traverse String
645                 while( *String )
646                 {
647                         if( !MM_IsUser( (tVAddr)String ) )
648                                 return 0;
649                         // Increment string pointer
650                         String ++;
651                 }
652                 return 1;
653         }
654         else if( MM_GetPhysAddr( (tVAddr)String ) )
655         {
656                 // Traverse String
657                 while( *String )
658                 {
659                         if( !MM_GetPhysAddr( (tVAddr)String ) )
660                                 return 0;
661                         // Increment string pointer
662                         String ++;
663                 }
664                 return 1;
665         }
666         return 0;
667 }
668
669 /**
670  * \brief Check if a sized memory region is valid memory
671  */
672 int CheckMem(void *Mem, int NumBytes)
673 {
674         tVAddr  addr = (tVAddr)Mem;
675         
676         if( MM_IsUser( addr ) )
677         {
678                 while( NumBytes-- )
679                 {
680                         if( !MM_IsUser( addr ) )
681                                 return 0;
682                         addr ++;
683                 }
684                 return 1;
685         }
686         else if( MM_GetPhysAddr( addr ) )
687         {
688                 while( NumBytes-- )
689                 {
690                         if( !MM_GetPhysAddr( addr ) )
691                                 return 0;
692                         addr ++;
693                 }
694                 return 1;
695         }
696         return 0;
697 }
698 /// \}
699
700 /**
701  * \brief Search a string array for \a Needle
702  * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
703  */
704 int ModUtil_LookupString(char **Array, char *Needle)
705 {
706          int    i;
707         if( !CheckString(Needle) )      return -1;
708         for( i = 0; Array[i]; i++ )
709         {
710                 if(strcmp(Array[i], Needle) == 0)       return i;
711         }
712         return -1;
713 }
714
715 int ModUtil_SetIdent(char *Dest, char *Value)
716 {
717         if( !CheckMem(Dest, 32) )       return -1;
718         strncpy(Dest, Value, 32);
719         return 1;
720 }

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