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

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