Altered & Renamed LookupString, Added DrvUtil_SetIdent
[tpg/acess2.git] / Kernel / lib.c
1 /*
2  * Acess2
3  * Common Library Functions
4  */
5 #include <acess.h>
6
7 // === CONSTANTS ===
8 #define RANDOM_SEED     0xACE55052
9 #define RANDOM_A        0x00731ADE
10 #define RANDOM_C        12345
11 #define RANDOM_SPRUCE   0xf12b02b
12 //                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
13 const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
14 #define UNIX_TO_2K      ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
15
16 // === PROTOTYPES ===
17  int    ReadUTF8(Uint8 *str, Uint32 *Val);
18
19 // === GLOBALS ===
20 static Uint     giRandomState = RANDOM_SEED;
21
22 // === CODE ===
23 static const char cUCDIGITS[] = "0123456789ABCDEF";
24 /**
25  * \fn static void itoa(char *buf, Uint num, int base, int minLength, char pad)
26  * \brief Convert an integer into a character string
27  */
28 void itoa(char *buf, Uint num, int base, int minLength, char pad)
29 {
30         char    tmpBuf[BITS];
31          int    pos=0, i;
32
33         // Sanity check
34         if(!buf)        return;
35         
36         // Sanity Check
37         if(base > 16 || base < 2) {
38                 buf[0] = 0;
39                 return;
40         }
41         
42         // Convert 
43         while(num > base-1) {
44                 tmpBuf[pos] = cUCDIGITS[ num % base ];
45                 num /= (Uint)base;              // Shift `num` right 1 digit
46                 pos++;
47         }
48         tmpBuf[pos++] = cUCDIGITS[ num % base ];                // Last digit of `num`
49         
50         // Put in reverse
51         i = 0;
52         minLength -= pos;
53         while(minLength-- > 0)  buf[i++] = pad;
54         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
55         buf[i] = 0;
56 }
57
58 #define PUTCH(c)        do{if(pos==__maxlen)break;if(__s){__s[pos++]=(c);}else{pos++;}}while(0)
59 int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
60 {
61         char    c, pad = ' ';
62          int    minSize = 0;
63         char    tmpBuf[34];     // For Integers
64         char    *p = NULL;
65          int    isLongLong = 0;
66         Uint64  val;
67         size_t  pos = 0;
68         
69         while((c = *__format++) != 0)
70         {
71                 // Non control character
72                 if(c != '%') { PUTCH(c); continue; }
73                 
74                 c = *__format++;
75                 
76                 // Literal %
77                 if(c == '%') { PUTCH('%'); continue; }
78                 
79                 // Pointer - Done first for debugging
80                 if(c == 'p') {
81                         Uint    ptr = va_arg(args, Uint);
82                         PUTCH('*');     PUTCH('0');     PUTCH('x');
83                         p = tmpBuf;
84                         itoa(p, ptr, 16, BITS/4, '0');
85                         goto printString;
86                 }
87                 
88                 // Get Argument
89                 val = va_arg(args, Uint);
90                 
91                 // - Padding
92                 if(c == '0') {
93                         pad = '0';
94                         c = *__format++;
95                 }
96                 else
97                         pad = ' ';
98                 
99                 // - Minimum length
100                 minSize = 1;
101                 if('1' <= c && c <= '9')
102                 {
103                         minSize = 0;
104                         while('0' <= c && c <= '9')
105                         {
106                                 minSize *= 10;
107                                 minSize += c - '0';
108                                 c = *__format++;
109                         }
110                 }
111                 
112                 // - Default, Long or LongLong?
113                 isLongLong = 0;
114                 if(c == 'l')    // Long is actually the default on x86
115                 {
116                         c = *__format++;
117                         if(c == 'l') {
118                                 #if BITS == 32
119                                 val |= (Uint64)va_arg(args, Uint) << 32;
120                                 #endif
121                                 c = *__format++;
122                                 isLongLong = 1;
123                         }
124                 }
125                 
126                 // - Now get the format code
127                 p = tmpBuf;
128                 switch(c)
129                 {
130                 case 'd':
131                 case 'i':
132                         if( (isLongLong && val >> 63) || (!isLongLong && val >> 31) ) {
133                                 PUTCH('-');
134                                 val = -val;
135                         }
136                         itoa(p, val, 10, minSize, pad);
137                         goto printString;
138                 case 'u':
139                         itoa(p, val, 10, minSize, pad);
140                         goto printString;
141                 case 'x':
142                         itoa(p, val, 16, minSize, pad);
143                         goto printString;
144                 case 'o':
145                         itoa(p, val, 8, minSize, pad);
146                         goto printString;
147                 case 'b':
148                         itoa(p, val, 2, minSize, pad);
149                         goto printString;
150
151                 case 'B':       //Boolean
152                         if(val) p = "True";
153                         else    p = "False";
154                         goto printString;
155                 
156                 // String - Null Terminated Array
157                 case 's':
158                         p = (char*)(Uint)val;
159                 printString:
160                         if(!p)          p = "(null)";
161                         while(*p)       PUTCH(*p++);
162                         break;
163                 
164                 case 'C':       // Non-Null Terminated Character Array
165                         p = (char*)(Uint)val;
166                         if(!p)  goto printString;
167                         while(minSize--)        PUTCH(*p++);
168                         break;
169                 
170                 // Single Character
171                 case 'c':
172                 default:
173                         PUTCH( (Uint8)val );
174                         break;
175                 }
176         }
177         
178         if(__s && pos != __maxlen)
179                 __s[pos] = '\0';
180                 
181         
182         return pos;
183 }
184 #undef PUTCH
185
186 /**
187  */
188 int sprintf(char *__s, const char *__format, ...)
189 {
190         va_list args;
191          int    ret;
192         
193         va_start(args, __format);
194         ret = vsnprintf(__s, -1, __format, args);
195         va_end(args);
196         
197         return ret;
198 }
199
200 /**
201  * \fn int tolower(int c)
202  * \brief Converts a character to lower case
203  */
204 int tolower(int c)
205 {
206         if('A' <= c && c <= 'Z')
207                 return c - 'A' + 'a';
208         return c;
209 }
210
211 /**
212  * \fn int strucmp(char *Str1, char *Str2)
213  * \brief Compare \a Str1 and \a Str2 case-insensitively
214  */
215 int strucmp(const char *Str1, const char *Str2)
216 {
217         while(*Str1 && tolower(*Str1) == tolower(*Str2))
218                 Str1++, Str2++;
219         return tolower(*Str1) - tolower(*Str2);
220 }
221
222 /**
223  * \fn int strpos(const char *Str, char Ch)
224  * \brief Search a string for an ascii character
225  */
226 int strpos(const char *Str, char Ch)
227 {
228          int    pos;
229         for(pos=0;Str[pos];pos++)
230         {
231                 if(Str[pos] == Ch)      return pos;
232         }
233         return -1;
234 }
235
236 /**
237  * \fn Uint8 ByteSum(void *Ptr, int Size)
238  * \brief Adds the bytes in a memory region and returns the sum
239  */
240 Uint8 ByteSum(void *Ptr, int Size)
241 {
242         Uint8   sum = 0;
243         while(Size--)   sum += *(Uint8*)Ptr++;
244         return sum;
245 }
246
247 /**
248  * \fn Uint strlen(const char *__str)
249  * \brief Get the length of string
250  */
251 Uint strlen(const char *__str)
252 {
253         Uint    ret = 0;
254         while(*__str++) ret++;
255         return ret;
256 }
257
258 /**
259  * \fn char *strcpy(const char *__str1, const char *__str2)
260  * \brief Copy a string to a new location
261  */
262 char *strcpy(char *__str1, const char *__str2)
263 {
264         while(*__str2)
265                 *__str1++ = *__str2++;
266         *__str1 = '\0'; // Terminate String
267         return __str1;
268 }
269
270 /**
271  * \fn char *strcpy(const char *__str1, const char *__str2)
272  * \brief Copy a string to a new location
273  */
274 char *strncpy(char *__str1, const char *__str2, size_t max)
275 {
276         while(*__str2 && max-- >= 1)
277                 *__str1++ = *__str2++;
278         if(max)
279                 *__str1 = '\0'; // Terminate String
280         return __str1;
281 }
282
283 /**
284  * \fn int strcmp(const char *str1, const char *str2)
285  * \brief Compare two strings return the difference between
286  *        the first non-matching characters.
287  */
288 int strcmp(const char *str1, const char *str2)
289 {
290         while(*str1 && *str1 == *str2)
291                 str1++, str2++;
292         return *str1 - *str2;
293 }
294
295 /**
296  * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
297  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
298  */
299 int strncmp(const char *Str1, const char *Str2, size_t num)
300 {
301         if(num == 0)    return 0;       // TODO: Check what should officially happen here
302         while(--num && *Str1 && *Str1 == *Str2)
303                 Str1++, Str2++;
304         return *Str1-*Str2;
305 }
306
307 /**
308  * \fn char *strdup(const char *Str)
309  * \brief Duplicates a string
310  */
311 char *strdup(const char *Str)
312 {
313         char    *ret;
314         ret = malloc(strlen(Str)+1);
315         strcpy(ret, Str);
316         return ret;
317 }
318
319 /**
320  * \fn int DivUp(int num, int dem)
321  * \brief Divide two numbers, rounding up
322  * \param num   Numerator
323  * \param dem   Denominator
324  */
325 int DivUp(int num, int dem)
326 {
327         return (num+dem-1)/dem;
328 }
329
330 /**
331  * \fn int strpos8(const char *str, Uint32 search)
332  * \brief Search a string for a UTF-8 character
333  */
334 int strpos8(const char *str, Uint32 Search)
335 {
336          int    pos;
337         Uint32  val = 0;
338         for(pos=0;str[pos];pos++)
339         {
340                 // ASCII Range
341                 if(Search < 128) {
342                         if(str[pos] == Search)  return pos;
343                         continue;
344                 }
345                 if(*(Uint8*)(str+pos) < 128)    continue;
346                 
347                 pos += ReadUTF8( (Uint8*)&str[pos], &val );
348                 if(val == Search)       return pos;
349         }
350         return -1;
351 }
352
353 /**
354  * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
355  * \brief Read a UTF-8 character from a string
356  */
357 int ReadUTF8(Uint8 *str, Uint32 *Val)
358 {
359         *Val = 0xFFFD;  // Assume invalid character
360         
361         // ASCII
362         if( !(*str & 0x80) ) {
363                 *Val = *str;
364                 return 1;
365         }
366         
367         // Middle of a sequence
368         if( (*str & 0xC0) == 0x80 ) {
369                 return 1;
370         }
371         
372         // Two Byte
373         if( (*str & 0xE0) == 0xC0 ) {
374                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
375                 str ++;
376                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
377                 *Val |= (*str & 0x3F);  // Lower 6 Bits
378                 return 2;
379         }
380         
381         // Three Byte
382         if( (*str & 0xF0) == 0xE0 ) {
383                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
384                 str ++;
385                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
386                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
387                 str ++;
388                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
389                 *Val |= (*str & 0x3F);  // Lower 6 Bits
390                 return 3;
391         }
392         
393         // Four Byte
394         if( (*str & 0xF1) == 0xF0 ) {
395                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
396                 str ++;
397                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
398                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
399                 str ++;
400                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
401                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
402                 str ++;
403                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
404                 *Val |= (*str & 0x3F);  // Lower 6 Bits
405                 return 4;
406         }
407         
408         // UTF-8 Doesn't support more than four bytes
409         return 4;
410 }
411
412 /**
413  * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
414  * \brief Write a UTF-8 character sequence to a string
415  */
416 int WriteUTF8(Uint8 *str, Uint32 Val)
417 {
418         // ASCII
419         if( Val < 128 ) {
420                 *str = Val;
421                 return 1;
422         }
423         
424         // Two Byte
425         if( Val < 0x8000 ) {
426                 *str = 0xC0 | (Val >> 6);
427                 str ++;
428                 *str = 0x80 | (Val & 0x3F);
429                 return 2;
430         }
431         
432         // Three Byte
433         if( Val < 0x10000 ) {
434                 *str = 0xE0 | (Val >> 12);
435                 str ++;
436                 *str = 0x80 | ((Val >> 6) & 0x3F);
437                 str ++;
438                 *str = 0x80 | (Val & 0x3F);
439                 return 3;
440         }
441         
442         // Four Byte
443         if( Val < 0x110000 ) {
444                 *str = 0xF0 | (Val >> 18);
445                 str ++;
446                 *str = 0x80 | ((Val >> 12) & 0x3F);
447                 str ++;
448                 *str = 0x80 | ((Val >> 6) & 0x3F);
449                 str ++;
450                 *str = 0x80 | (Val & 0x3F);
451                 return 4;
452         }
453         
454         // UTF-8 Doesn't support more than four bytes
455         return 0;
456 }
457
458 /**
459  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
460  * \brief Converts a date into an Acess Timestamp
461  */
462 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
463 {
464         Sint64  stamp;
465         stamp = sec;
466         stamp += mins*60;
467         stamp += hrs*3600;
468         
469         stamp += day*3600*24;
470         stamp += month*DAYS_BEFORE[month]*3600*24;
471         if(     (
472                 ((year&3) == 0 || year%100 != 0)
473                 || (year%100 == 0 && ((year/100)&3) == 0)
474                 ) && month > 1) // Leap year and after feb
475                 stamp += 3600*24;
476         
477         stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Foour Year Segments
478         stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
479         stamp += UNIX_TO_2K;
480         
481         return stamp * 1000;
482 }
483
484 /**
485  * \fn Uint rand()
486  * \brief Pseudo random number generator
487  * \note Unknown effectiveness (made up on the spot)
488  */
489 Uint rand()
490 {
491         Uint    old = giRandomState;
492         // Get the next state value
493         giRandomState = (RANDOM_A*giRandomState + RANDOM_C) & 0xFFFFFFFF;
494         // Check if it has changed, and if it hasn't, change it
495         if(giRandomState == old)        giRandomState += RANDOM_SPRUCE;
496         return giRandomState;
497 }
498
499 /// \name Memory Validation
500 /// \{
501 /**
502  * \brief Checks if a string resides fully in valid memory
503  */
504 int CheckString(char *String)
505 {
506         // Check 1st page
507         if( MM_IsUser( (tVAddr)String ) )
508         {
509                 // Traverse String
510                 while( *String )
511                 {
512                         if( !MM_IsUser( (tVAddr)String ) )
513                                 return 0;
514                         // Increment string pointer
515                         String ++;
516                 }
517                 return 1;
518         }
519         else if( MM_GetPhysAddr( (tVAddr)String ) )
520         {
521                 // Traverse String
522                 while( *String )
523                 {
524                         if( !MM_GetPhysAddr( (tVAddr)String ) )
525                                 return 0;
526                         // Increment string pointer
527                         String ++;
528                 }
529                 return 1;
530         }
531         return 0;
532 }
533
534 /**
535  * \brief Check if a sized memory region is valid memory
536  */
537 int CheckMem(void *Mem, int NumBytes)
538 {
539         tVAddr  addr = (tVAddr)Mem;
540         
541         if( MM_IsUser( addr ) )
542         {
543                 while( NumBytes-- )
544                 {
545                         if( !MM_IsUser( addr ) )
546                                 return 0;
547                         addr ++;
548                 }
549                 return 1;
550         }
551         else if( MM_GetPhysAddr( addr ) )
552         {
553                 while( NumBytes-- )
554                 {
555                         if( !MM_GetPhysAddr( addr ) )
556                                 return 0;
557                         addr ++;
558                 }
559                 return 1;
560         }
561         return 0;
562 }
563 /// \}
564
565 /**
566  * \brief Search a string array for \a Needle
567  * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
568  */
569 int ModUtil_LookupString(char **Array, char *Needle)
570 {
571          int    i;
572         if( !CheckString(Needle) )      return -1;
573         for( i = 0; Array[i]; i++ )
574         {
575                 if(strcmp(Array[i], Needle) == 0)       return i;
576         }
577         return -1;
578 }
579
580 int ModUtil_SetIdent(char *Dest, char *Value)
581 {
582         if( !CheckMem(Dest, 32) )       return -1;
583         strncpy(Dest, Value, 32);
584         return 1;
585 }
586
587 EXPORT(strlen);
588 EXPORT(strdup);
589 EXPORT(strcmp);
590 EXPORT(strncmp);
591 EXPORT(strcpy);
592 EXPORT(strncpy);
593
594 EXPORT(timestamp);
595 EXPORT(ReadUTF8);
596 EXPORT(CheckMem);
597 EXPORT(CheckString);
598 EXPORT(ModUtil_LookupString);
599 EXPORT(ModUtil_SetIdent);

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