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

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