c1063516f3256e1714cac58e58a606712b29302d
[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(char *Str1, 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(char *Str, char Ch)
82  * \brief Search a string for an ascii character
83  */
84 int strpos(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  */
96 int ByteSum(void *Ptr, int Size)
97 {
98          int    sum = 0;
99         while(Size--)   sum += *(Uint8*)Ptr++;
100         return sum;
101 }
102
103 /**
104  * \fn Uint strlen(char *__str)
105  * \brief Get the length of string
106  */
107 Uint strlen(char *__str)
108 {
109         Uint    ret = 0;
110         while(*__str++) ret++;
111         return ret;
112 }
113
114 /**
115  * \fn char *strcpy(char *__str1, char *__str2)
116  * \brief Copy a string to a new location
117  */
118 char *strcpy(char *__str1, char *__str2)
119 {
120         while(*__str2)
121                 *__str1++ = *__str2++;
122         *__str1 = '\0'; // Terminate String
123         return __str1;
124 }
125
126 /**
127  * \fn int strcmp(char *str1, char *str2)
128  * \brief Compare two strings return the difference between
129  *        the first non-matching characters.
130  */
131 int strcmp(char *str1, char *str2)
132 {
133         while(*str1 && *str1 == *str2)
134                 str1++, str2++;
135         return *str1 - *str2;
136 }
137
138 /**
139  * \fn int strncmp(char *Str1, char *Str2, size_t num)
140  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
141  */
142 int strncmp(char *Str1, char *Str2, size_t num)
143 {
144         while(num-- && *Str1 && *Str1 == *Str2)
145                 Str1++, Str2++;
146         return *Str1-*Str2;
147 }
148
149 /**
150  * \fn char *strdup(char *str)
151  * \brief Duplicates a string
152  */
153 char *strdup(char *str)
154 {
155         char    *ret;
156         ret = malloc(strlen(str)+1);
157         strcpy(ret, str);
158         return ret;
159 }
160
161 /**
162  * \fn int strpos8(char *str, Uint32 search)
163  * \brief Search a string for a UTF-8 character
164  */
165 int strpos8(char *str, Uint32 Search)
166 {
167          int    pos;
168         Uint32  val = 0;
169         for(pos=0;str[pos];pos++)
170         {
171                 // ASCII Range
172                 if(Search < 128) {
173                         if(str[pos] == Search)  return pos;
174                         continue;
175                 }
176                 if(*(Uint8*)(str+pos) < 128)    continue;
177                 
178                 pos += ReadUTF8( (Uint8*)&str[pos], &val );
179                 if(val == Search)       return pos;
180         }
181         return -1;
182 }
183
184 /**
185  * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
186  * \brief Read a UTF-8 character from a string
187  */
188 int ReadUTF8(Uint8 *str, Uint32 *Val)
189 {
190         *Val = 0xFFFD;  // Assume invalid character
191         
192         // ASCII
193         if( !(*str & 0x80) ) {
194                 *Val = *str;
195                 return 1;
196         }
197         
198         // Middle of a sequence
199         if( (*str & 0xC0) == 0x80 ) {
200                 return 1;
201         }
202         
203         // Two Byte
204         if( (*str & 0xE0) == 0xC0 ) {
205                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
206                 str ++;
207                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
208                 *Val |= (*str & 0x3F);  // Lower 6 Bits
209                 return 2;
210         }
211         
212         // Three Byte
213         if( (*str & 0xF0) == 0xE0 ) {
214                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
215                 str ++;
216                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
217                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
218                 str ++;
219                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
220                 *Val |= (*str & 0x3F);  // Lower 6 Bits
221                 return 3;
222         }
223         
224         // Four Byte
225         if( (*str & 0xF1) == 0xF0 ) {
226                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
227                 str ++;
228                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
229                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
230                 str ++;
231                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
232                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
233                 str ++;
234                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
235                 *Val |= (*str & 0x3F);  // Lower 6 Bits
236                 return 4;
237         }
238         
239         // UTF-8 Doesn't support more than four bytes
240         return 4;
241 }
242
243 /**
244  * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
245  * \brief Write a UTF-8 character sequence to a string
246  */
247 int WriteUTF8(Uint8 *str, Uint32 Val)
248 {
249         // ASCII
250         if( Val < 128 ) {
251                 *str = Val;
252                 return 1;
253         }
254         
255         // Two Byte
256         if( Val < 0x8000 ) {
257                 *str = 0xC0 | (Val >> 6);
258                 str ++;
259                 *str = 0x80 | (Val & 0x3F);
260                 return 2;
261         }
262         
263         // Three Byte
264         if( Val < 0x10000 ) {
265                 *str = 0xE0 | (Val >> 12);
266                 str ++;
267                 *str = 0x80 | ((Val >> 6) & 0x3F);
268                 str ++;
269                 *str = 0x80 | (Val & 0x3F);
270                 return 3;
271         }
272         
273         // Four Byte
274         if( Val < 0x110000 ) {
275                 *str = 0xF0 | (Val >> 18);
276                 str ++;
277                 *str = 0x80 | ((Val >> 12) & 0x3F);
278                 str ++;
279                 *str = 0x80 | ((Val >> 6) & 0x3F);
280                 str ++;
281                 *str = 0x80 | (Val & 0x3F);
282                 return 4;
283         }
284         
285         // UTF-8 Doesn't support more than four bytes
286         return 0;
287 }
288
289 /**
290  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
291  * \brief Converts a date into an Acess Timestamp
292  */
293 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
294 {
295         Sint64  stamp;
296         stamp = sec;
297         stamp += mins*60;
298         stamp += hrs*3600;
299         
300         stamp += day*3600*24;
301         stamp += month*DAYS_BEFORE[month]*3600*24;
302         if(     (
303                 ((year&3) == 0 || year%100 != 0)
304                 || (year%100 == 0 && ((year/100)&3) == 0)
305                 ) && month > 1) // Leap year and after feb
306                 stamp += 3600*24;
307         
308         stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Foour Year Segments
309         stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
310         stamp += UNIX_TO_2K;
311         
312         return stamp * 1000;
313 }
314
315 /**
316  * \fn Uint rand()
317  * \brief Pseudo random number generator
318  * \note Unknown effectiveness (made up on the spot)
319  */
320 Uint rand()
321 {
322         Uint    old = giRandomState;
323         // Get the next state value
324         giRandomState = (RANDOM_A*giRandomState + RANDOM_C) & 0xFFFFFFFF;
325         // Check if it has changed, and if it hasn't, change it
326         if(giRandomState == old)        giRandomState += RANDOM_SPRUCE;
327         return giRandomState;
328 }
329
330 EXPORT(timestamp);
331 EXPORT(ReadUTF8);

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