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

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