3399d3d85ca7af8fb496117c03f09d7eb4c8e170
[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         if(num == 0)    return 0;       // TODO: Check what should officially happen here
145         while(--num && *Str1 && *Str1 == *Str2)
146                 Str1++, Str2++;
147         return *Str1-*Str2;
148 }
149
150 /**
151  * \fn char *strdup(char *str)
152  * \brief Duplicates a string
153  */
154 char *strdup(char *str)
155 {
156         char    *ret;
157         ret = malloc(strlen(str)+1);
158         strcpy(ret, str);
159         return ret;
160 }
161
162 /**
163  * \fn int strpos8(char *str, Uint32 search)
164  * \brief Search a string for a UTF-8 character
165  */
166 int strpos8(char *str, Uint32 Search)
167 {
168          int    pos;
169         Uint32  val = 0;
170         for(pos=0;str[pos];pos++)
171         {
172                 // ASCII Range
173                 if(Search < 128) {
174                         if(str[pos] == Search)  return pos;
175                         continue;
176                 }
177                 if(*(Uint8*)(str+pos) < 128)    continue;
178                 
179                 pos += ReadUTF8( (Uint8*)&str[pos], &val );
180                 if(val == Search)       return pos;
181         }
182         return -1;
183 }
184
185 /**
186  * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
187  * \brief Read a UTF-8 character from a string
188  */
189 int ReadUTF8(Uint8 *str, Uint32 *Val)
190 {
191         *Val = 0xFFFD;  // Assume invalid character
192         
193         // ASCII
194         if( !(*str & 0x80) ) {
195                 *Val = *str;
196                 return 1;
197         }
198         
199         // Middle of a sequence
200         if( (*str & 0xC0) == 0x80 ) {
201                 return 1;
202         }
203         
204         // Two Byte
205         if( (*str & 0xE0) == 0xC0 ) {
206                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
207                 str ++;
208                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
209                 *Val |= (*str & 0x3F);  // Lower 6 Bits
210                 return 2;
211         }
212         
213         // Three Byte
214         if( (*str & 0xF0) == 0xE0 ) {
215                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
216                 str ++;
217                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
218                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
219                 str ++;
220                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
221                 *Val |= (*str & 0x3F);  // Lower 6 Bits
222                 return 3;
223         }
224         
225         // Four Byte
226         if( (*str & 0xF1) == 0xF0 ) {
227                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
228                 str ++;
229                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
230                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
231                 str ++;
232                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
233                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
234                 str ++;
235                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
236                 *Val |= (*str & 0x3F);  // Lower 6 Bits
237                 return 4;
238         }
239         
240         // UTF-8 Doesn't support more than four bytes
241         return 4;
242 }
243
244 /**
245  * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
246  * \brief Write a UTF-8 character sequence to a string
247  */
248 int WriteUTF8(Uint8 *str, Uint32 Val)
249 {
250         // ASCII
251         if( Val < 128 ) {
252                 *str = Val;
253                 return 1;
254         }
255         
256         // Two Byte
257         if( Val < 0x8000 ) {
258                 *str = 0xC0 | (Val >> 6);
259                 str ++;
260                 *str = 0x80 | (Val & 0x3F);
261                 return 2;
262         }
263         
264         // Three Byte
265         if( Val < 0x10000 ) {
266                 *str = 0xE0 | (Val >> 12);
267                 str ++;
268                 *str = 0x80 | ((Val >> 6) & 0x3F);
269                 str ++;
270                 *str = 0x80 | (Val & 0x3F);
271                 return 3;
272         }
273         
274         // Four Byte
275         if( Val < 0x110000 ) {
276                 *str = 0xF0 | (Val >> 18);
277                 str ++;
278                 *str = 0x80 | ((Val >> 12) & 0x3F);
279                 str ++;
280                 *str = 0x80 | ((Val >> 6) & 0x3F);
281                 str ++;
282                 *str = 0x80 | (Val & 0x3F);
283                 return 4;
284         }
285         
286         // UTF-8 Doesn't support more than four bytes
287         return 0;
288 }
289
290 /**
291  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
292  * \brief Converts a date into an Acess Timestamp
293  */
294 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
295 {
296         Sint64  stamp;
297         stamp = sec;
298         stamp += mins*60;
299         stamp += hrs*3600;
300         
301         stamp += day*3600*24;
302         stamp += month*DAYS_BEFORE[month]*3600*24;
303         if(     (
304                 ((year&3) == 0 || year%100 != 0)
305                 || (year%100 == 0 && ((year/100)&3) == 0)
306                 ) && month > 1) // Leap year and after feb
307                 stamp += 3600*24;
308         
309         stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Foour Year Segments
310         stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
311         stamp += UNIX_TO_2K;
312         
313         return stamp * 1000;
314 }
315
316 /**
317  * \fn Uint rand()
318  * \brief Pseudo random number generator
319  * \note Unknown effectiveness (made up on the spot)
320  */
321 Uint rand()
322 {
323         Uint    old = giRandomState;
324         // Get the next state value
325         giRandomState = (RANDOM_A*giRandomState + RANDOM_C) & 0xFFFFFFFF;
326         // Check if it has changed, and if it hasn't, change it
327         if(giRandomState == old)        giRandomState += RANDOM_SPRUCE;
328         return giRandomState;
329 }
330
331 EXPORT(timestamp);
332 EXPORT(ReadUTF8);

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