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

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