Kernel - Imported userland strtoi file (and other minor changes)
[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 // - Import userland stroi.c file
71 #define _LIB_H_
72 #include "../../Usermode/Libraries/libc.so_src/strtoi.c"
73
74 int ParseInt(const char *string, int *Val)
75 {
76          int    ret = 0;
77          int    bNeg = 0;
78         const char *orig_string = string;
79         
80         //Log("atoi: (string='%s')", string);
81         
82         // Clear non-numeric characters
83         while( !('0' <= *string && *string <= '9') && *string != '-' )  string++;
84         if( *string == '-' ) {
85                 bNeg = 1;
86                 while( !('0' <= *string && *string <= '9') )    string++;
87         }
88         
89         if(*string == '0')
90         {
91                 string ++;
92                 if(*string == 'x')
93                 {
94                         // Hex
95                         string ++;
96                         for( ;; string ++ )
97                         {
98                                 if('0' <= *string && *string <= '9') {
99                                         ret *= 16;
100                                         ret += *string - '0';
101                                 }
102                                 else if('A' <= *string && *string <= 'F') {
103                                         ret *= 16;
104                                         ret += *string - 'A' + 10;
105                                 }
106                                 else if('a' <= *string && *string <= 'f') {
107                                         ret *= 16;
108                                         ret += *string - 'a' + 10;
109                                 }
110                                 else
111                                         break;
112                         }
113                 }
114                 else    // Octal
115                 {
116                         for( ; '0' <= *string && *string <= '7'; string ++ )
117                         {
118                                 ret *= 8;
119                                 ret += *string - '0';
120                         }
121                 }
122         }
123         else    // Decimal
124         {
125                 for( ; '0' <= *string && *string <= '9'; string++)
126                 {
127                         ret *= 10;
128                         ret += *string - '0';
129                 }
130                 // Error check
131                 if( ret == 0 )  return 0;
132         }
133         
134         if(bNeg)        ret = -ret;
135         
136         //Log("atoi: RETURN %i", ret);
137         
138         if(Val) *Val = ret;
139         
140         return string - orig_string;
141 }
142
143 static const char cUCDIGITS[] = "0123456789ABCDEF";
144 /**
145  * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
146  * \brief Convert an integer into a character string
147  */
148 void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
149 {
150         char    tmpBuf[64+1];
151          int    pos=0, i;
152         Uint64  rem;
153
154         // Sanity check
155         if(!buf)        return;
156         
157         // Sanity Check
158         if(base > 16 || base < 2) {
159                 buf[0] = 0;
160                 return;
161         }
162         
163         // Convert 
164         while(num > base-1) {
165                 num = DivMod64U(num, base, &rem);       // Shift `num` and get remainder
166                 tmpBuf[pos] = cUCDIGITS[ rem ];
167                 pos++;
168         }
169         tmpBuf[pos++] = cUCDIGITS[ num ];               // Last digit of `num`
170         
171         // Put in reverse
172         i = 0;
173         minLength -= pos;
174         while(minLength-- > 0)  buf[i++] = pad;
175         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
176         buf[i] = 0;
177 }
178
179 /**
180  * \brief Append a character the the vsnprintf output
181  */
182 #define PUTCH(ch)       do { \
183                 if(pos < __maxlen) { \
184                         if(__s) __s[pos] = ch; \
185                 } else { \
186                         (void)ch;\
187                 } \
188                 pos ++; \
189         } while(0)
190 #define GETVAL()        do {\
191         if(isLongLong)  val = va_arg(args, Uint64);\
192         else    val = va_arg(args, unsigned int);\
193         }while(0)
194 /**
195  * \brief VArg String Number Print Formatted
196  */
197 int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
198 {
199         char    c, pad = ' ';
200          int    minSize = 0, precision = -1, len;
201         char    tmpBuf[34];     // For Integers
202         const char      *p = NULL;
203          int    isLongLong = 0;
204         Uint64  val;
205         size_t  pos = 0;
206         // Flags
207          int    bPadLeft = 0;
208
209         while((c = *__format++) != 0)
210         {
211                 // Non control character
212                 if(c != '%') { PUTCH(c); continue; }
213
214                 c = *__format++;
215                 if(c == '\0')   break;
216                 
217                 // Literal %
218                 if(c == '%') { PUTCH('%'); continue; }
219                 
220                 // Pointer - Done first for debugging
221                 if(c == 'p') {
222                         Uint    ptr = va_arg(args, Uint);
223                         PUTCH('*');     PUTCH('0');     PUTCH('x');
224                         for( len = BITS/4; len -- && ((ptr>>(len*4))&15) == 0; )
225                                 ;
226                         len ++;
227                         if( len == 0 )
228                                 PUTCH( '0' );
229                         else
230                                 while( len -- )
231                                         PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
232                         continue ;
233                 }
234                 
235                 // - Padding Side Flag
236                 if(c == '-') {
237                         bPadLeft = 1;
238                         c = *__format++;
239                 }
240                 
241                 // - Padding
242                 if(c == '0') {
243                         pad = '0';
244                         c = *__format++;
245                 }
246                 else
247                         pad = ' ';
248                 
249                 // - Minimum length
250                 if(c == '*') {  // Dynamic length
251                         minSize = va_arg(args, unsigned int);
252                         c = *__format++;
253                 }
254                 else if('1' <= c && c <= '9')
255                 {
256                         minSize = 0;
257                         while('0' <= c && c <= '9')
258                         {
259                                 minSize *= 10;
260                                 minSize += c - '0';
261                                 c = *__format++;
262                         }
263                 }
264                 else
265                         minSize = 0;
266                 
267                 // - Precision
268                 precision = -1;
269                 if( c == '.' ) {
270                         c = *__format++;
271                         
272                         if(c == '*') {  // Dynamic length
273                                 precision = va_arg(args, unsigned int);
274                                 c = *__format++;
275                         }
276                         else if('1' <= c && c <= '9')
277                         {
278                                 precision = 0;
279                                 while('0' <= c && c <= '9')
280                                 {
281                                         precision *= 10;
282                                         precision += c - '0';
283                                         c = *__format++;
284                                 }
285                         }
286                 }
287                 
288                 // - Default, Long or LongLong?
289                 isLongLong = 0;
290                 if(c == 'l')    // Long is actually the default on x86
291                 {
292                         c = *__format++;
293                         if(c == 'l') {
294                                 c = *__format++;
295                                 isLongLong = 1;
296                         }
297                 }
298                 
299                 // - Now get the format code
300                 p = tmpBuf;
301                 switch(c)
302                 {
303                 case 'd':
304                 case 'i':
305                         GETVAL();
306                         if( isLongLong && val >> 63 ) {
307                                 PUTCH('-');
308                                 val = -val;
309                         }
310                         else if( !isLongLong && val >> 31 ) {
311                                 PUTCH('-');
312                                 val = -(Sint32)val;
313                         }
314                         itoa(tmpBuf, val, 10, minSize, pad);
315                         goto printString;
316                 case 'u':       // Unsigned
317                         GETVAL();
318                         itoa(tmpBuf, val, 10, minSize, pad);
319                         goto printString;
320                 case 'P':       // Physical Address
321                         PUTCH('0');
322                         PUTCH('x');
323                         if(sizeof(tPAddr) > 4)  isLongLong = 1;
324                         GETVAL();
325                         itoa(tmpBuf, val, 16, minSize, pad);
326                         goto printString;
327                 case 'X':       // Hex
328                         if(BITS == 64)
329                                 isLongLong = 1; // TODO: Handle non-x86 64-bit archs
330                         GETVAL();
331                         itoa(tmpBuf, val, 16, minSize, pad);
332                         goto printString;
333                         
334                 case 'x':       // Lower case hex
335                         GETVAL();
336                         itoa(tmpBuf, val, 16, minSize, pad);
337                         goto printString;
338                 case 'o':       // Octal
339                         GETVAL();
340                         itoa(tmpBuf, val, 8, minSize, pad);
341                         goto printString;
342                 case 'b':
343                         GETVAL();
344                         itoa(tmpBuf, val, 2, minSize, pad);
345                         goto printString;
346
347                 case 'B':       //Boolean
348                         val = va_arg(args, unsigned int);
349                         if(val) p = "True";
350                         else    p = "False";
351                         goto printString;
352                 
353                 // String - Null Terminated Array
354                 case 's':
355                         p = va_arg(args, char*);        // Get Argument
356                         if( !p || !CheckString(p) )     p = "(inval)";  // Avoid #PFs  
357                 printString:
358                         if(!p)          p = "(null)";
359                         len = strlen(p);
360                         if( !bPadLeft ) while(len++ < minSize)  PUTCH(pad);
361                         while(*p && precision--) { PUTCH(*p); p++;} 
362                         if( bPadLeft )  while(len++ < minSize)  PUTCH(pad);
363                         break;
364                 
365                 case 'C':       // Non-Null Terminated Character Array
366                         p = va_arg(args, char*);
367                         if( !CheckMem(p, minSize) )     continue;       // No #PFs please
368                         if(!p)  goto printString;
369                         while(minSize--) {
370                                 PUTCH(*p);
371                                 p ++;
372                         }
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 and hence these two
746 // can't be in it.
747 /**
748  * \name Memory Validation
749  * \{
750  */
751 /**
752  * \brief Checks if a string resides fully in valid memory
753  */
754 int CheckString(const char *String)
755 {
756         tVAddr  addr;
757          int    bUser;
758
759         addr = (tVAddr)String;
760
761         if( !MM_GetPhysAddr( (void*)addr ) )
762                 return 0;
763         
764         // Check 1st page
765         bUser = MM_IsUser( addr );
766         
767         while( *(char*)addr )
768         {
769                 if( (addr & (PAGE_SIZE-1)) == 0 )
770                 {
771                         if(bUser && !MM_IsUser(addr) )
772                                 return 0;
773                         if(!bUser && !MM_GetPhysAddr((void*)addr) )
774                                 return 0;
775                 }
776                 addr ++;
777         }
778         return 1;
779 }
780
781 /**
782  * \brief Check if a sized memory region is valid memory
783  * \return Boolean success
784  */
785 int CheckMem(const void *Mem, int NumBytes)
786 {
787         return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
788 }
789 /* *
790  * \}
791  */
792

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