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

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