Kernel - Split libc-esque functions into another file (to aid AcessNative)
[tpg/acess2.git] / KernelLand / Kernel / libc.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * libc.c
6  * - Kernel-land C Library
7  */
8 #include <acess.h>
9 #include <hal_proc.h>   // For MM_*
10
11 // === CONSTANTS ===
12 #define RANDOM_SEED     0xACE55052
13 #define RANDOM_A        0x00731ADE
14 #define RANDOM_C        12345
15 #define RANDOM_SPRUCE   0xf12b039
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  int    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 size_t  strlen(const char *__s);
32 char    *strcpy(char *__str1, const char *__str2);
33 char    *strncpy(char *__str1, const char *__str2, size_t max);
34 char    *strcat(char *dest, const char *source);
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  int    rand(void);
39 void    *memmove(void *__dest, const void *__src, size_t len);
40
41  int    CheckString(char *String);
42  int    CheckMem(void *Mem, int NumBytes); 
43 #endif
44
45 // === EXPORTS ===
46 EXPORT(atoi);
47 EXPORT(itoa);
48 EXPORT(vsnprintf);
49 EXPORT(snprintf);
50 EXPORT(sprintf);
51 EXPORT(tolower);
52 EXPORT(strucmp);
53 EXPORT(strchr);
54 EXPORT(strpos);
55 EXPORT(strlen);
56 EXPORT(strcpy);
57 EXPORT(strncpy);
58 EXPORT(strcat);
59 EXPORT(strncat);
60 EXPORT(strcmp);
61 EXPORT(strncmp);
62 //EXPORT(strdup);
63 EXPORT(_strdup);        // Takes File/Line too
64 EXPORT(rand);
65 EXPORT(memmove);
66
67 EXPORT(CheckString);
68 EXPORT(CheckMem);
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         ParseInt(string, &ret);
78         return ret;
79 }
80 int ParseInt(const char *string, int *Val)
81 {
82          int    ret = 0;
83          int    bNeg = 0;
84         const char *orig_string = string;
85         
86         //Log("atoi: (string='%s')", string);
87         
88         // Clear non-numeric characters
89         while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
90         if( *string == '-' ) {
91                 bNeg = 1;
92                 while( !('0' <= *string && *string <= '9') )    string++;
93         }
94         
95         if(*string == '0')
96         {
97                 string ++;
98                 if(*string == 'x')
99                 {
100                         // Hex
101                         string ++;
102                         for( ;; string ++ )
103                         {
104                                 if('0' <= *string && *string <= '9') {
105                                         ret *= 16;
106                                         ret += *string - '0';
107                                 }
108                                 else if('A' <= *string && *string <= 'F') {
109                                         ret *= 16;
110                                         ret += *string - 'A' + 10;
111                                 }
112                                 else if('a' <= *string && *string <= 'f') {
113                                         ret *= 16;
114                                         ret += *string - 'a' + 10;
115                                 }
116                                 else
117                                         break;
118                         }
119                 }
120                 else    // Octal
121                 {
122                         for( ; '0' <= *string && *string <= '7'; string ++ )
123                         {
124                                 ret *= 8;
125                                 ret += *string - '0';
126                         }
127                 }
128         }
129         else    // Decimal
130         {
131                 for( ; '0' <= *string && *string <= '9'; string++)
132                 {
133                         ret *= 10;
134                         ret += *string - '0';
135                 }
136                 // Error check
137                 if( ret == 0 )  return 0;
138         }
139         
140         if(bNeg)        ret = -ret;
141         
142         //Log("atoi: RETURN %i", ret);
143         
144         if(Val) *Val = ret;
145         
146         return string - orig_string;
147 }
148
149 static const char cUCDIGITS[] = "0123456789ABCDEF";
150 /**
151  * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
152  * \brief Convert an integer into a character string
153  */
154 void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
155 {
156         char    tmpBuf[64+1];
157          int    pos=0, i;
158         Uint64  rem;
159
160         // Sanity check
161         if(!buf)        return;
162         
163         // Sanity Check
164         if(base > 16 || base < 2) {
165                 buf[0] = 0;
166                 return;
167         }
168         
169         // Convert 
170         while(num > base-1) {
171                 num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
172                 tmpBuf[pos] = cUCDIGITS[ rem ];
173                 pos++;
174         }
175         tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
176         
177         // Put in reverse
178         i = 0;
179         minLength -= pos;
180         while(minLength-- > 0)  buf[i++] = pad;
181         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
182         buf[i] = 0;
183 }
184
185 /**
186  * \brief Append a character the the vsnprintf output
187  */
188 #define PUTCH(c)        _putch(c)
189 #define GETVAL()        do {\
190         if(isLongLong)  val = va_arg(args, Uint64);\
191         else    val = va_arg(args, unsigned int);\
192         }while(0)
193 /**
194  * \brief VArg String Number Print Formatted
195  */
196 int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
197 {
198         char    c, pad = ' ';
199          int    minSize = 0, precision = -1, len;
200         char    tmpBuf[34];     // For Integers
201         const char      *p = NULL;
202          int    isLongLong = 0;
203         Uint64  val;
204         size_t  pos = 0;
205         // Flags
206          int    bPadLeft = 0;
207         
208         auto void _putch(char ch);
209
210         void _putch(char ch)
211         {
212                 if(pos < __maxlen)
213                 {
214                         if(__s) __s[pos] = ch;
215                         pos ++;
216                 }
217         }
218
219         while((c = *__format++) != 0)
220         {
221                 // Non control character
222                 if(c != '%') { PUTCH(c); continue; }
223
224                 c = *__format++;
225                 if(c == '\0')   break;
226                 
227                 // Literal %
228                 if(c == '%') { PUTCH('%'); continue; }
229                 
230                 // Pointer - Done first for debugging
231                 if(c == 'p') {
232                         Uint    ptr = va_arg(args, Uint);
233                         PUTCH('*');     PUTCH('0');     PUTCH('x');
234                         for( len = BITS/4; len --; )
235                                 PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
236                         continue ;
237                 }
238                 
239                 // - Padding Side Flag
240                 if(c == '-') {
241                         bPadLeft = 1;
242                         c = *__format++;
243                 }
244                 
245                 // - Padding
246                 if(c == '0') {
247                         pad = '0';
248                         c = *__format++;
249                 }
250                 else
251                         pad = ' ';
252                 
253                 // - Minimum length
254                 if(c == '*') {  // Dynamic length
255                         minSize = va_arg(args, unsigned int);
256                         c = *__format++;
257                 }
258                 else if('1' <= c && c <= '9')
259                 {
260                         minSize = 0;
261                         while('0' <= c && c <= '9')
262                         {
263                                 minSize *= 10;
264                                 minSize += c - '0';
265                                 c = *__format++;
266                         }
267                 }
268                 else
269                         minSize = 0;
270                 
271                 // - Precision
272                 precision = -1;
273                 if( c == '.' ) {
274                         c = *__format++;
275                         
276                         if(c == '*') {  // Dynamic length
277                                 precision = va_arg(args, unsigned int);
278                                 c = *__format++;
279                         }
280                         else if('1' <= c && c <= '9')
281                         {
282                                 precision = 0;
283                                 while('0' <= c && c <= '9')
284                                 {
285                                         precision *= 10;
286                                         precision += c - '0';
287                                         c = *__format++;
288                                 }
289                         }
290                 }
291                 
292                 // - Default, Long or LongLong?
293                 isLongLong = 0;
294                 if(c == 'l')    // Long is actually the default on x86
295                 {
296                         c = *__format++;
297                         if(c == 'l') {
298                                 c = *__format++;
299                                 isLongLong = 1;
300                         }
301                 }
302                 
303                 // - Now get the format code
304                 p = tmpBuf;
305                 switch(c)
306                 {
307                 case 'd':
308                 case 'i':
309                         GETVAL();
310                         if( isLongLong && val >> 63 ) {
311                                 PUTCH('-');
312                                 val = -val;
313                         }
314                         else if( !isLongLong && val >> 31 ) {
315                                 PUTCH('-');
316                                 val = -(Sint32)val;
317                         }
318                         itoa(tmpBuf, val, 10, minSize, pad);
319                         goto printString;
320                 case 'u':       // Unsigned
321                         GETVAL();
322                         itoa(tmpBuf, val, 10, minSize, pad);
323                         goto printString;
324                 case 'P':       // Physical Address
325                         PUTCH('0');
326                         PUTCH('x');
327                         if(sizeof(tPAddr) > 4)  isLongLong = 1;
328                         GETVAL();
329                         itoa(tmpBuf, val, 16, minSize, pad);
330                         goto printString;
331                 case 'X':       // Hex
332                         if(BITS == 64)
333                                 isLongLong = 1; // TODO: Handle non-x86 64-bit archs
334                         GETVAL();
335                         itoa(tmpBuf, val, 16, minSize, pad);
336                         goto printString;
337                         
338                 case 'x':       // Lower case hex
339                         GETVAL();
340                         itoa(tmpBuf, val, 16, minSize, pad);
341                         goto printString;
342                 case 'o':       // Octal
343                         GETVAL();
344                         itoa(tmpBuf, val, 8, minSize, pad);
345                         goto printString;
346                 case 'b':
347                         GETVAL();
348                         itoa(tmpBuf, val, 2, minSize, pad);
349                         goto printString;
350
351                 case 'B':       //Boolean
352                         val = va_arg(args, unsigned int);
353                         if(val) p = "True";
354                         else    p = "False";
355                         goto printString;
356                 
357                 // String - Null Terminated Array
358                 case 's':
359                         p = va_arg(args, char*);        // Get Argument
360                         if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
361                 printString:
362                         if(!p)          p = "(null)";
363                         len = strlen(p);
364                         if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
365                         while(*p && precision--)        PUTCH(*p++);
366                         if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
367                         break;
368                 
369                 case 'C':       // Non-Null Terminated Character Array
370                         p = va_arg(args, char*);
371                         if( !CheckMem(p, minSize) )     continue;       // No #PFs please
372                         if(!p)  goto printString;
373                         while(minSize--)        PUTCH(*p++);
374                         break;
375                 
376                 // Single Character
377                 case 'c':
378                 default:
379                         GETVAL();
380                         PUTCH( (Uint8)val );
381                         break;
382                 }
383         }
384         
385         if(__s && pos != __maxlen)
386                 __s[pos] = '\0';
387         
388         return pos;
389 }
390 #undef PUTCH
391
392 /**
393  */
394 int snprintf(char *__s, size_t __n, const char *__format, ...)
395 {
396         va_list args;
397          int    ret;
398         
399         va_start(args, __format);
400         ret = vsnprintf(__s, __n, __format, args);
401         va_end(args);
402         
403         return ret;
404 }
405
406 /**
407  */
408 int sprintf(char *__s, const char *__format, ...)
409 {
410         va_list args;
411          int    ret;
412         
413         va_start(args, __format);
414         ret = vsnprintf(__s, -1, __format, args);
415         va_end(args);
416         
417         return ret;
418 }
419
420 /**
421  * \fn int tolower(int c)
422  * \brief Converts a character to lower case
423  */
424 int tolower(int c)
425 {
426         if('A' <= c && c <= 'Z')
427                 return c - 'A' + 'a';
428         return c;
429 }
430
431 /**
432  * \fn int strucmp(const char *Str1, const char *Str2)
433  * \brief Compare \a Str1 and \a Str2 case-insensitively
434  */
435 int strucmp(const char *Str1, const char *Str2)
436 {
437         while(*Str1 && tolower(*Str1) == tolower(*Str2))
438                 Str1++, Str2++;
439         return tolower(*Str1) - tolower(*Str2);
440 }
441
442 /**
443  * \brief Locate a byte in a string
444  */
445 char *strchr(const char *__s, int __c)
446 {
447         for( ; *__s; __s ++ )
448         {
449                 if( *__s == __c )       return (char*)__s;
450         }
451         return NULL;
452 }
453
454 /**
455  * \fn int strpos(const char *Str, char Ch)
456  * \brief Search a string for an ascii character
457  */
458 int strpos(const char *Str, char Ch)
459 {
460          int    pos;
461         for(pos=0;Str[pos];pos++)
462         {
463                 if(Str[pos] == Ch)      return pos;
464         }
465         return -1;
466 }
467
468 /**
469  * \fn size_t strlen(const char *__str)
470  * \brief Get the length of string
471  */
472 size_t strlen(const char *__str)
473 {
474         size_t  ret = 0;
475         while(*__str++) ret++;
476         return ret;
477 }
478
479 /**
480  * \brief Copy a string to a new location
481  */
482 char *strcpy(char *__str1, const char *__str2)
483 {
484         while(*__str2)
485                 *__str1++ = *__str2++;
486         *__str1 = '\0'; // Terminate String
487         return __str1;
488 }
489
490 /**
491  * \brief Copy a string to a new location
492  * \note Copies at most `max` chars
493  */
494 char *strncpy(char *__str1, const char *__str2, size_t __max)
495 {
496         while(*__str2 && __max-- >= 1)
497                 *__str1++ = *__str2++;
498         if(__max)
499                 *__str1 = '\0'; // Terminate String
500         return __str1;
501 }
502
503 /**
504  * \brief Append a string to another
505  */
506 char *strcat(char *__dest, const char *__src)
507 {
508         while(*__dest++);
509         __dest--;
510         while(*__src)
511                 *__dest++ = *__src++;
512         *__dest = '\0';
513         return __dest;
514 }
515
516 /**
517  * \brief Append at most \a n chars to a string from another
518  * \note At most n+1 chars are written (the dest is always zero terminated)
519  */
520 char *strncat(char *__dest, const char *__src, size_t n)
521 {
522         while(*__dest++);
523         while(*__src && n-- >= 1)
524                 *__dest++ = *__src++;
525         *__dest = '\0';
526         return __dest;
527 }
528
529 /**
530  * \fn int strcmp(const char *str1, const char *str2)
531  * \brief Compare two strings return the difference between
532  *        the first non-matching characters.
533  */
534 int strcmp(const char *str1, const char *str2)
535 {
536         while(*str1 && *str1 == *str2)
537                 str1++, str2++;
538         return *str1 - *str2;
539 }
540
541 /**
542  * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
543  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
544  */
545 int strncmp(const char *Str1, const char *Str2, size_t num)
546 {
547         if(num == 0)    return 0;       // TODO: Check what should officially happen here
548         while(--num && *Str1 && *Str1 == *Str2)
549                 Str1++, Str2++;
550         return *Str1-*Str2;
551 }
552
553 #if 0
554 /**
555  * \fn char *strdup(const char *Str)
556  * \brief Duplicates a string
557  */
558 char *strdup(const char *Str)
559 {
560         char    *ret;
561         ret = malloc(strlen(Str)+1);
562         if( !ret )      return NULL;
563         strcpy(ret, Str);
564         return ret;
565 }
566 #else
567
568 /**
569  * \fn char *_strdup(const char *File, int Line, const char *Str)
570  * \brief Duplicates a string
571  */
572 char *_strdup(const char *File, int Line, const char *Str)
573 {
574         char    *ret;
575         ret = Heap_Allocate(File, Line, strlen(Str)+1);
576         if( !ret )      return NULL;
577         strcpy(ret, Str);
578         return ret;
579 }
580 #endif
581
582 /**
583  * \fn int rand()
584  * \brief Pseudo random number generator
585  */
586 int rand(void)
587 {
588         #if 0
589         static Uint     state = RANDOM_SEED;
590         Uint    old = state;
591         // Get the next state value
592         giRandomState = (RANDOM_A*state + RANDOM_C);
593         // Check if it has changed, and if it hasn't, change it
594         if(state == old)        state += RANDOM_SPRUCE;
595         return state;
596         #else
597         // http://en.wikipedia.org/wiki/Xorshift
598         // 2010-10-03
599         static Uint32   x = 123456789;
600         static Uint32   y = 362436069;
601         static Uint32   z = 521288629;
602         static Uint32   w = 88675123; 
603         Uint32  t;
604  
605         t = x ^ (x << 11);
606         x = y; y = z; z = w;
607         return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
608         #endif
609 }
610
611 void *memmove(void *__dest, const void *__src, size_t len)
612 {
613         size_t  block_size;
614         char    *dest = __dest;
615         const char      *src = __src;
616         void    *ret = __dest;
617
618         if( len == 0 || dest == src )
619                 return dest;
620         
621         if( (tVAddr)dest > (tVAddr)src + len )
622                 return memcpy(dest, src, len);
623         if( (tVAddr)dest + len < (tVAddr)src )
624                 return memcpy(dest, src, len);
625         
626         // NOTE: Assumes memcpy works forward
627         if( (tVAddr)dest < (tVAddr)src )
628                 return memcpy(dest, src, len);
629
630         if( (tVAddr)dest < (tVAddr)src )
631                 block_size = (tVAddr)src - (tVAddr)dest;
632         else
633                 block_size = (tVAddr)dest - (tVAddr)src;
634         
635         block_size &= ~0xF;
636         
637         while(len >= block_size)
638         {
639                 memcpy(dest, src, block_size);
640                 len -= block_size;
641                 dest += block_size;
642                 src += block_size;
643         }
644         memcpy(dest, src, len);
645         return ret;
646         
647 }
648
649 // NOTE: Strictly not libc, but lib.c is used by userland code too
650 /**
651  * \name Memory Validation
652  * \{
653  */
654 /**
655  * \brief Checks if a string resides fully in valid memory
656  */
657 int CheckString(const char *String)
658 {
659         tVAddr  addr;
660          int    bUser;
661
662         addr = (tVAddr)String;
663
664         if( !MM_GetPhysAddr( addr ) )
665                 return 0;
666         
667         // Check 1st page
668         bUser = MM_IsUser( addr );
669         
670         while( *(char*)addr )
671         {
672                 if( (addr & (PAGE_SIZE-1)) == 0 )
673                 {
674                         if(bUser && !MM_IsUser(addr) )
675                                 return 0;
676                         if(!bUser && !MM_GetPhysAddr(addr) )
677                                 return 0;
678                 }
679                 addr ++;
680         }
681         return 1;
682 }
683
684 /**
685  * \brief Check if a sized memory region is valid memory
686  * \return Boolean success
687  */
688 int CheckMem(const void *Mem, int NumBytes)
689 {
690         return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
691 }
692 /* *
693  * \}
694  */
695

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