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

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