Kernel - Added strtoul and friends to acess.h
[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 unsigned long long      strtoull(const char *str, char **end, int base);
20 unsigned long   strtoul(const char *str, char **end, int base);
21 signed long long        strtoll(const char *str, char **end, int base);
22 signed long     strtol(const char *str, char **end, int base);
23  int    atoi(const char *string);
24  int    ParseInt(const char *string, int *Val);
25 void    itoa(char *buf, Uint64 num, int base, int minLength, char pad);
26  int    vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
27  int    snprintf(char *__s, size_t __n, const char *__format, ...);
28  int    sprintf(char *__s, const char *__format, ...);
29  int    strucmp(const char *Str1, const char *Str2);
30 char    *strchr(const char *__s, int __c);
31  int    strpos(const char *Str, char Ch);
32 size_t  strlen(const char *__s);
33 char    *strcpy(char *__str1, const char *__str2);
34 char    *strncpy(char *__str1, const char *__str2, size_t max);
35 char    *strcat(char *dest, const char *source);
36  int    strcmp(const char *str1, const char *str2);
37  int    strncmp(const char *str1, const char *str2, size_t num);
38 char    *_strdup(const char *File, int Line, const char *Str);
39  int    rand(void);
40 void    *memmove(void *__dest, const void *__src, size_t len);
41
42  int    CheckString(char *String);
43  int    CheckMem(void *Mem, int NumBytes); 
44 #endif
45
46 // === EXPORTS ===
47 EXPORT(atoi);
48 EXPORT(itoa);
49 EXPORT(vsnprintf);
50 EXPORT(snprintf);
51 EXPORT(sprintf);
52 EXPORT(tolower);
53
54 EXPORT(strucmp);
55 EXPORT(strchr);
56 EXPORT(strrchr);
57 EXPORT(strpos);
58 EXPORT(strlen);
59 EXPORT(strcpy);
60 EXPORT(strncpy);
61 EXPORT(strcat);
62 EXPORT(strncat);
63 EXPORT(strcmp);
64 EXPORT(strncmp);
65 //EXPORT(strdup);
66 EXPORT(_strdup);        // Takes File/Line too
67 EXPORT(rand);
68 EXPORT(memmove);
69
70 EXPORT(CheckString);
71 EXPORT(CheckMem);
72
73 // === CODE ===
74 // - Import userland stroi.c file
75 #define _LIB_H_
76 #include "../../Usermode/Libraries/libc.so_src/strtoi.c"
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(ch)       do { \
187                 if(pos < __maxlen) { \
188                         if(__s) __s[pos] = ch; \
189                 } else { \
190                         (void)ch;\
191                 } \
192                 pos ++; \
193         } while(0)
194 #define GETVAL()        do {\
195         if(isLongLong)  val = va_arg(args, Uint64);\
196         else    val = va_arg(args, unsigned int);\
197         }while(0)
198 /**
199  * \brief VArg String Number Print Formatted
200  */
201 int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
202 {
203         char    c, pad = ' ';
204          int    minSize = 0, precision = -1, len;
205         char    tmpBuf[34];     // For Integers
206         const char      *p = NULL;
207          int    isLongLong = 0;
208         Uint64  val;
209         size_t  pos = 0;
210         // Flags
211          int    bPadLeft = 0;
212
213         while((c = *__format++) != 0)
214         {
215                 // Non control character
216                 if(c != '%') { PUTCH(c); continue; }
217
218                 c = *__format++;
219                 if(c == '\0')   break;
220                 
221                 // Literal %
222                 if(c == '%') { PUTCH('%'); continue; }
223                 
224                 // Pointer - Done first for debugging
225                 if(c == 'p') {
226                         Uint    ptr = va_arg(args, Uint);
227                         PUTCH('*');     PUTCH('0');     PUTCH('x');
228                         for( len = BITS/4; len -- && ((ptr>>(len*4))&15) == 0; )
229                                 ;
230                         len ++;
231                         if( len == 0 )
232                                 PUTCH( '0' );
233                         else
234                                 while( 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); 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--) {
374                                 PUTCH(*p);
375                                 p ++;
376                         }
377                         break;
378                 
379                 // Single Character
380                 case 'c':
381                 default:
382                         GETVAL();
383                         PUTCH( (Uint8)val );
384                         break;
385                 }
386         }
387         
388         if(__s && pos != __maxlen)
389                 __s[pos] = '\0';
390         
391         return pos;
392 }
393 #undef PUTCH
394
395 /**
396  */
397 int snprintf(char *__s, size_t __n, const char *__format, ...)
398 {
399         va_list args;
400          int    ret;
401         
402         va_start(args, __format);
403         ret = vsnprintf(__s, __n, __format, args);
404         va_end(args);
405         
406         return ret;
407 }
408
409 /**
410  */
411 int sprintf(char *__s, const char *__format, ...)
412 {
413         va_list args;
414          int    ret;
415         
416         va_start(args, __format);
417         ret = vsnprintf(__s, -1, __format, args);
418         va_end(args);
419         
420         return ret;
421 }
422
423 /*
424  * ==================
425  * ctype.h
426  * ==================
427  */
428 int isalnum(int c)
429 {
430         return isalpha(c) || isdigit(c);
431 }
432 int isalpha(int c)
433 {
434         return isupper(c) || islower(c);
435 }
436 int isascii(int c)
437 {
438         return (0 <= c && c < 128);
439 }
440 int isblank(int c)
441 {
442         if(c == '\t')   return 1;
443         if(c == ' ')    return 1;
444         return 0;
445 }
446 int iscntrl(int c)
447 {
448         // TODO: Check iscntrl
449         if(c < ' ')     return 1;
450         return 0;
451 }
452 int isdigit(int c)
453 {
454         return ('0' <= c && c <= '9');
455 }
456 int isgraph(int c)
457 {
458         // TODO: Check isgraph
459         return 0;
460 }
461 int islower(int c)
462 {
463         return ('a' <= c && c <= 'z');
464 }
465 int isprint(int c)
466 {
467         if( ' ' <= c && c <= 0x7F )     return 1;
468         return 0;
469 }
470 int ispunct(int c)
471 {
472         switch(c)
473         {
474         case '.':       case ',':
475         case '?':       case '!':
476                 return 1;
477         default:
478                 return 0;
479         }
480 }
481 int isspace(int c)
482 {
483         if(c == ' ')    return 1;
484         if(c == '\t')   return 1;
485         if(c == '\v')   return 1;
486         if(c == '\n')   return 1;
487         if(c == '\r')   return 1;
488         return 0;
489 }
490 int isupper(int c)
491 {
492         return ('a' <= c && c <= 'z');
493 }
494 int isxdigit(int c)
495 {
496         return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
497 }
498
499 int toupper(int c)
500 {
501         if( islower(c) )
502                 return c - 0x20;
503         else
504                 return c;
505 }
506 int tolower(int c)
507 {
508         if( isupper(c) )
509                 return c + 0x20;
510         else
511                 return c;
512 }
513
514 /**
515  * \fn int strucmp(const char *Str1, const char *Str2)
516  * \brief Compare \a Str1 and \a Str2 case-insensitively
517  */
518 int strucmp(const char *Str1, const char *Str2)
519 {
520         while(*Str1 && tolower(*Str1) == tolower(*Str2))
521                 Str1++, Str2++;
522         return tolower(*Str1) - tolower(*Str2);
523 }
524
525 /**
526  * \brief Locate a byte in a string
527  */
528 char *strchr(const char *__s, int __c)
529 {
530         for( ; *__s; __s ++ )
531         {
532                 if( *__s == __c )       return (char*)__s;
533         }
534         return NULL;
535 }
536
537 char *strrchr(const char *__s, int __c)
538 {
539         size_t ofs = strlen(__s);
540         while(--ofs && __s[ofs] != __c);
541         if( __s[ofs] == __c )
542                 return (char*)__s + ofs;
543         return NULL;
544 }
545
546 /**
547  * \fn int strpos(const char *Str, char Ch)
548  * \brief Search a string for an ascii character
549  */
550 int strpos(const char *Str, char Ch)
551 {
552          int    pos;
553         for(pos=0;Str[pos];pos++)
554         {
555                 if(Str[pos] == Ch)      return pos;
556         }
557         return -1;
558 }
559
560 /**
561  * \fn size_t strlen(const char *__str)
562  * \brief Get the length of string
563  */
564 size_t strlen(const char *__str)
565 {
566         size_t  ret = 0;
567         while(*__str++) ret++;
568         return ret;
569 }
570
571 /**
572  * \brief Copy a string to a new location
573  */
574 char *strcpy(char *__str1, const char *__str2)
575 {
576         while(*__str2)
577                 *__str1++ = *__str2++;
578         *__str1 = '\0'; // Terminate String
579         return __str1;
580 }
581
582 /**
583  * \brief Copy a string to a new location
584  * \note Copies at most `max` chars
585  */
586 char *strncpy(char *__str1, const char *__str2, size_t __max)
587 {
588         while(*__str2 && __max-- >= 1)
589                 *__str1++ = *__str2++;
590         if(__max)
591                 *__str1 = '\0'; // Terminate String
592         return __str1;
593 }
594
595 /**
596  * \brief Append a string to another
597  */
598 char *strcat(char *__dest, const char *__src)
599 {
600         while(*__dest++);
601         __dest--;
602         while(*__src)
603                 *__dest++ = *__src++;
604         *__dest = '\0';
605         return __dest;
606 }
607
608 /**
609  * \brief Append at most \a n chars to a string from another
610  * \note At most n+1 chars are written (the dest is always zero terminated)
611  */
612 char *strncat(char *__dest, const char *__src, size_t n)
613 {
614         while(*__dest++);
615         while(*__src && n-- >= 1)
616                 *__dest++ = *__src++;
617         *__dest = '\0';
618         return __dest;
619 }
620
621 /**
622  * \fn int strcmp(const char *str1, const char *str2)
623  * \brief Compare two strings return the difference between
624  *        the first non-matching characters.
625  */
626 int strcmp(const char *str1, const char *str2)
627 {
628         while(*str1 && *str1 == *str2)
629                 str1++, str2++;
630         return *str1 - *str2;
631 }
632
633 /**
634  * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
635  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
636  */
637 int strncmp(const char *Str1, const char *Str2, size_t num)
638 {
639         if(num == 0)    return 0;       // TODO: Check what should officially happen here
640         while(--num && *Str1 && *Str1 == *Str2)
641                 Str1++, Str2++;
642         return *Str1-*Str2;
643 }
644
645 #if 0
646 /**
647  * \fn char *strdup(const char *Str)
648  * \brief Duplicates a string
649  */
650 char *strdup(const char *Str)
651 {
652         char    *ret;
653         ret = malloc(strlen(Str)+1);
654         if( !ret )      return NULL;
655         strcpy(ret, Str);
656         return ret;
657 }
658 #else
659
660 /**
661  * \fn char *_strdup(const char *File, int Line, const char *Str)
662  * \brief Duplicates a string
663  */
664 char *_strdup(const char *File, int Line, const char *Str)
665 {
666         char    *ret;
667         ret = Heap_Allocate(File, Line, strlen(Str)+1);
668         if( !ret )      return NULL;
669         strcpy(ret, Str);
670         return ret;
671 }
672 #endif
673
674 /**
675  * \fn int rand()
676  * \brief Pseudo random number generator
677  */
678 int rand(void)
679 {
680         #if 0
681         static Uint     state = RANDOM_SEED;
682         Uint    old = state;
683         // Get the next state value
684         giRandomState = (RANDOM_A*state + RANDOM_C);
685         // Check if it has changed, and if it hasn't, change it
686         if(state == old)        state += RANDOM_SPRUCE;
687         return state;
688         #else
689         // http://en.wikipedia.org/wiki/Xorshift
690         // 2010-10-03
691         static Uint32   x = 123456789;
692         static Uint32   y = 362436069;
693         static Uint32   z = 521288629;
694         static Uint32   w = 88675123; 
695         Uint32  t;
696  
697         t = x ^ (x << 11);
698         x = y; y = z; z = w;
699         return w = w ^ (w >> 19) ^ t ^ (t >> 8); 
700         #endif
701 }
702
703 void *memmove(void *__dest, const void *__src, size_t len)
704 {
705         char    *dest = __dest;
706         const char      *src = __src;
707         void    *ret = __dest;
708
709         if( len == 0 || dest == src )
710                 return dest;
711         
712         if( (tVAddr)dest > (tVAddr)src + len )
713                 return memcpy(dest, src, len);
714         if( (tVAddr)dest + len < (tVAddr)src )
715                 return memcpy(dest, src, len);
716         
717         // NOTE: Assumes memcpy works forward
718         if( (tVAddr)dest < (tVAddr)src )
719                 return memcpy(dest, src, len);
720
721         #if 0
722         size_t  block_size;
723         if( (tVAddr)dest < (tVAddr)src )
724                 block_size = (tVAddr)src - (tVAddr)dest;
725         else
726                 block_size = (tVAddr)dest - (tVAddr)src;
727         
728         block_size &= ~0xF;
729         
730         while(len >= block_size)
731         {
732                 memcpy(dest, src, block_size);
733                 len -= block_size;
734                 dest += block_size;
735                 src += block_size;
736         }
737         memcpy(dest, src, len);
738         return ret;
739         #else
740         for( int i = len; i--; )
741         {
742                 dest[i] = src[i];
743         }
744         return ret;
745         #endif
746         
747 }
748
749 // NOTE: Strictly not libc, but lib.c is used by userland code too and hence these two
750 // can't be in it.
751 /**
752  * \name Memory Validation
753  * \{
754  */
755 /**
756  * \brief Checks if a string resides fully in valid memory
757  */
758 int CheckString(const char *String)
759 {
760         tVAddr  addr;
761          int    bUser;
762
763         addr = (tVAddr)String;
764
765         if( !MM_GetPhysAddr( (void*)addr ) )
766                 return 0;
767         
768         // Check 1st page
769         bUser = MM_IsUser( addr );
770         
771         while( *(char*)addr )
772         {
773                 if( (addr & (PAGE_SIZE-1)) == 0 )
774                 {
775                         if(bUser && !MM_IsUser(addr) )
776                                 return 0;
777                         if(!bUser && !MM_GetPhysAddr((void*)addr) )
778                                 return 0;
779                 }
780                 addr ++;
781         }
782         return 1;
783 }
784
785 /**
786  * \brief Check if a sized memory region is valid memory
787  * \return Boolean success
788  */
789 int CheckMem(const void *Mem, int NumBytes)
790 {
791         return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
792 }
793 /* *
794  * \}
795  */
796

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