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

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