f6149652eeafd2285effc5254a47374f3d66841b
[tpg/acess2.git] / Kernel / lib.c
1 /*
2  * Acess2
3  * Common Library Functions
4  */
5 #include <common.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 /**
59  * \fn int tolower(int c)
60  * \brief Converts a character to lower case
61  */
62 int tolower(int c)
63 {
64         if('A' <= c && c <= 'Z')
65                 return c - 'A' + 'a';
66         return c;
67 }
68
69 /**
70  * \fn int strucmp(char *Str1, char *Str2)
71  * \brief Compare \a Str1 and \a Str2 case-insensitively
72  */
73 int strucmp(const char *Str1, const char *Str2)
74 {
75         while(*Str1 && tolower(*Str1) == tolower(*Str2))
76                 Str1++, Str2++;
77         return tolower(*Str1) - tolower(*Str2);
78 }
79
80 /**
81  * \fn int strpos(const char *Str, char Ch)
82  * \brief Search a string for an ascii character
83  */
84 int strpos(const char *Str, char Ch)
85 {
86          int    pos;
87         for(pos=0;Str[pos];pos++)
88         {
89                 if(Str[pos] == Ch)      return pos;
90         }
91         return -1;
92 }
93
94 /**
95  * \fn int ByteSum(void *Ptr, int Size)
96  * \brief Adds the bytes in a memory region and returns the sum
97  */
98 int ByteSum(void *Ptr, int Size)
99 {
100          int    sum = 0;
101         while(Size--)   sum += *(Uint8*)Ptr++;
102         return sum;
103 }
104
105 /**
106  * \fn Uint strlen(const char *__str)
107  * \brief Get the length of string
108  */
109 Uint strlen(const char *__str)
110 {
111         Uint    ret = 0;
112         while(*__str++) ret++;
113         return ret;
114 }
115
116 /**
117  * \fn char *strcpy(const char *__str1, const char *__str2)
118  * \brief Copy a string to a new location
119  */
120 char *strcpy(char *__str1, const char *__str2)
121 {
122         while(*__str2)
123                 *__str1++ = *__str2++;
124         *__str1 = '\0'; // Terminate String
125         return __str1;
126 }
127
128 /**
129  * \fn int strcmp(const char *str1, const char *str2)
130  * \brief Compare two strings return the difference between
131  *        the first non-matching characters.
132  */
133 int strcmp(const char *str1, const char *str2)
134 {
135         while(*str1 && *str1 == *str2)
136                 str1++, str2++;
137         return *str1 - *str2;
138 }
139
140 /**
141  * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
142  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
143  */
144 int strncmp(const char *Str1, const char *Str2, size_t num)
145 {
146         if(num == 0)    return 0;       // TODO: Check what should officially happen here
147         while(--num && *Str1 && *Str1 == *Str2)
148                 Str1++, Str2++;
149         return *Str1-*Str2;
150 }
151
152 /**
153  * \fn char *strdup(const char *Str)
154  * \brief Duplicates a string
155  */
156 char *strdup(const char *Str)
157 {
158         char    *ret;
159         ret = malloc(strlen(Str)+1);
160         strcpy(ret, Str);
161         return ret;
162 }
163
164 /**
165  * \fn int DivUp(int num, int dem)
166  * \brief Divide two numbers, rounding up
167  * \param num   Numerator
168  * \param dem   Denominator
169  */
170 int DivUp(int num, int dem)
171 {
172         return (num+dem-1)/dem;
173 }
174
175 /**
176  * \fn int strpos8(const char *str, Uint32 search)
177  * \brief Search a string for a UTF-8 character
178  */
179 int strpos8(const char *str, Uint32 Search)
180 {
181          int    pos;
182         Uint32  val = 0;
183         for(pos=0;str[pos];pos++)
184         {
185                 // ASCII Range
186                 if(Search < 128) {
187                         if(str[pos] == Search)  return pos;
188                         continue;
189                 }
190                 if(*(Uint8*)(str+pos) < 128)    continue;
191                 
192                 pos += ReadUTF8( (Uint8*)&str[pos], &val );
193                 if(val == Search)       return pos;
194         }
195         return -1;
196 }
197
198 /**
199  * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
200  * \brief Read a UTF-8 character from a string
201  */
202 int ReadUTF8(Uint8 *str, Uint32 *Val)
203 {
204         *Val = 0xFFFD;  // Assume invalid character
205         
206         // ASCII
207         if( !(*str & 0x80) ) {
208                 *Val = *str;
209                 return 1;
210         }
211         
212         // Middle of a sequence
213         if( (*str & 0xC0) == 0x80 ) {
214                 return 1;
215         }
216         
217         // Two Byte
218         if( (*str & 0xE0) == 0xC0 ) {
219                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
220                 str ++;
221                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
222                 *Val |= (*str & 0x3F);  // Lower 6 Bits
223                 return 2;
224         }
225         
226         // Three Byte
227         if( (*str & 0xF0) == 0xE0 ) {
228                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
229                 str ++;
230                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
231                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
232                 str ++;
233                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
234                 *Val |= (*str & 0x3F);  // Lower 6 Bits
235                 return 3;
236         }
237         
238         // Four Byte
239         if( (*str & 0xF1) == 0xF0 ) {
240                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
241                 str ++;
242                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
243                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
244                 str ++;
245                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
246                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
247                 str ++;
248                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
249                 *Val |= (*str & 0x3F);  // Lower 6 Bits
250                 return 4;
251         }
252         
253         // UTF-8 Doesn't support more than four bytes
254         return 4;
255 }
256
257 /**
258  * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
259  * \brief Write a UTF-8 character sequence to a string
260  */
261 int WriteUTF8(Uint8 *str, Uint32 Val)
262 {
263         // ASCII
264         if( Val < 128 ) {
265                 *str = Val;
266                 return 1;
267         }
268         
269         // Two Byte
270         if( Val < 0x8000 ) {
271                 *str = 0xC0 | (Val >> 6);
272                 str ++;
273                 *str = 0x80 | (Val & 0x3F);
274                 return 2;
275         }
276         
277         // Three Byte
278         if( Val < 0x10000 ) {
279                 *str = 0xE0 | (Val >> 12);
280                 str ++;
281                 *str = 0x80 | ((Val >> 6) & 0x3F);
282                 str ++;
283                 *str = 0x80 | (Val & 0x3F);
284                 return 3;
285         }
286         
287         // Four Byte
288         if( Val < 0x110000 ) {
289                 *str = 0xF0 | (Val >> 18);
290                 str ++;
291                 *str = 0x80 | ((Val >> 12) & 0x3F);
292                 str ++;
293                 *str = 0x80 | ((Val >> 6) & 0x3F);
294                 str ++;
295                 *str = 0x80 | (Val & 0x3F);
296                 return 4;
297         }
298         
299         // UTF-8 Doesn't support more than four bytes
300         return 0;
301 }
302
303 /**
304  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
305  * \brief Converts a date into an Acess Timestamp
306  */
307 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
308 {
309         Sint64  stamp;
310         stamp = sec;
311         stamp += mins*60;
312         stamp += hrs*3600;
313         
314         stamp += day*3600*24;
315         stamp += month*DAYS_BEFORE[month]*3600*24;
316         if(     (
317                 ((year&3) == 0 || year%100 != 0)
318                 || (year%100 == 0 && ((year/100)&3) == 0)
319                 ) && month > 1) // Leap year and after feb
320                 stamp += 3600*24;
321         
322         stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Foour Year Segments
323         stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
324         stamp += UNIX_TO_2K;
325         
326         return stamp * 1000;
327 }
328
329 /**
330  * \fn Uint rand()
331  * \brief Pseudo random number generator
332  * \note Unknown effectiveness (made up on the spot)
333  */
334 Uint rand()
335 {
336         Uint    old = giRandomState;
337         // Get the next state value
338         giRandomState = (RANDOM_A*giRandomState + RANDOM_C) & 0xFFFFFFFF;
339         // Check if it has changed, and if it hasn't, change it
340         if(giRandomState == old)        giRandomState += RANDOM_SPRUCE;
341         return giRandomState;
342 }
343
344 /// \name Memory Validation
345 /// \{
346 /**
347  * \brief Checks if a string resides fully in valid memory
348  */
349 int CheckString(char *String)
350 {
351         // Check 1st page
352         if( MM_IsUser( (tVAddr)String ) )
353         {
354                 // Traverse String
355                 while( *String )
356                 {
357                         if( !MM_IsUser( (tVAddr)String ) )
358                                 return 0;
359                         // Increment string pointer
360                         String ++;
361                 }
362                 return 1;
363         }
364         else if( MM_GetPhysAddr( (tVAddr)String ) )
365         {
366                 // Traverse String
367                 while( *String )
368                 {
369                         if( !MM_GetPhysAddr( (tVAddr)String ) )
370                                 return 0;
371                         // Increment string pointer
372                         String ++;
373                 }
374                 return 1;
375         }
376         return 0;
377 }
378
379 /**
380  * \brief Check if a sized memory region is valid memory
381  */
382 int CheckMem(void *Mem, int NumBytes)
383 {
384         tVAddr  addr = (tVAddr)Mem;
385         
386         if( MM_IsUser( addr ) )
387         {
388                 while( NumBytes-- )
389                 {
390                         if( !MM_IsUser( addr ) )
391                                 return 0;
392                         addr ++;
393                 }
394                 return 1;
395         }
396         else if( MM_GetPhysAddr( addr ) )
397         {
398                 while( NumBytes-- )
399                 {
400                         if( !MM_GetPhysAddr( addr ) )
401                                 return 0;
402                         addr ++;
403                 }
404                 return 1;
405         }
406         return 0;
407 }
408 /// \}
409
410 /**
411  * \brief Search a string array for \a Needle
412  * \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
413  */
414 int LookupString(char **Array, char *Needle)
415 {
416          int    i;
417         for( i = 0; Array[i]; i++ )
418         {
419                 if(strcmp(Array[i], Needle) == 0)       return i;
420         }
421         return -1;
422 }
423
424 EXPORT(strlen);
425 EXPORT(strdup);
426 EXPORT(strcmp);
427 EXPORT(strncmp);
428 EXPORT(strcpy);
429 //EXPORT(strncpy);
430
431 EXPORT(timestamp);
432 EXPORT(ReadUTF8);
433 EXPORT(CheckMem);
434 EXPORT(CheckString);
435 EXPORT(LookupString);

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