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

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