Made directories indeterminitely sized in FAT
[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        0x12231ADE
10 #define RANDOM_C        0x1BADBEEF
11 //                          Jan Feb Mar Apr May  Jun  Jul  Aug  Sept Oct  Nov  Dec
12 const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
13 #define UNIX_TO_2K      ((30*365*3600*24) + (7*3600*24))        //Normal years + leap years
14
15 // === PROTOTYPES ===
16  int    ReadUTF8(Uint8 *str, Uint32 *Val);
17
18 // === CODE ===
19 static const char cUCDIGITS[] = "0123456789ABCDEF";
20 /**
21  * \fn static void itoa(char *buf, Uint num, int base, int minLength, char pad)
22  * \brief Convert an integer into a character string
23  */
24 void itoa(char *buf, Uint num, int base, int minLength, char pad)
25 {
26         char    tmpBuf[BITS];
27          int    pos=0, i;
28
29         // Sanity check
30         if(!buf)        return;
31         
32         // Sanity Check
33         if(base > 16 || base < 2) {
34                 buf[0] = 0;
35                 return;
36         }
37         
38         // Convert 
39         while(num > base-1) {
40                 tmpBuf[pos] = cUCDIGITS[ num % base ];
41                 num /= (Uint)base;              // Shift `num` right 1 digit
42                 pos++;
43         }
44         tmpBuf[pos++] = cUCDIGITS[ num % base ];                // Last digit of `num`
45         
46         // Put in reverse
47         i = 0;
48         minLength -= pos;
49         while(minLength-- > 0)  buf[i++] = pad;
50         while(pos-- > 0)                buf[i++] = tmpBuf[pos]; // Reverse the order of characters
51         buf[i] = 0;
52 }
53
54 /**
55  * \fn int tolower(int __c)
56  * \brief Converts a character to lower case
57  */
58 int tolower(int c)
59 {
60         if('A' <= c && c <= 'Z')
61                 return c - 'A' + 'a';
62         return c;
63 }
64
65 /**
66  * \fn int strucmp(char *Str1, char *Str2)
67  * \brief Compare \a Str1 and \a Str2 case-insensitively
68  */
69 int strucmp(char *Str1, char *Str2)
70 {
71         while(*Str1 && tolower(*Str1) == tolower(*Str2))
72                 Str1++, Str2++;
73         return tolower(*Str1) - tolower(*Str2);
74 }
75
76 /**
77  * \fn int strpos(char *Str, char Ch)
78  * \brief Search a string for an ascii character
79  */
80 int strpos(char *Str, char Ch)
81 {
82          int    pos;
83         for(pos=0;Str[pos];pos++)
84         {
85                 if(Str[pos] == Ch)      return pos;
86         }
87         return -1;
88 }
89
90 /**
91  */
92 int ByteSum(void *Ptr, int Size)
93 {
94          int    sum = 0;
95         while(Size--)   sum += *(Uint8*)Ptr++;
96         return sum;
97 }
98
99 /**
100  * \fn Uint strlen(char *__str)
101  * \brief Get the length of string
102  */
103 Uint strlen(char *__str)
104 {
105         Uint    ret = 0;
106         while(*__str++) ret++;
107         return ret;
108 }
109
110 /**
111  * \fn char *strcpy(char *__str1, char *__str2)
112  * \brief Copy a string to a new location
113  */
114 char *strcpy(char *__str1, char *__str2)
115 {
116         while(*__str2)
117                 *__str1++ = *__str2++;
118         *__str1 = '\0'; // Terminate String
119         return __str1;
120 }
121
122 /**
123  * \fn int strcmp(char *str1, char *str2)
124  * \brief Compare two strings return the difference between
125  *        the first non-matching characters.
126  */
127 int strcmp(char *str1, char *str2)
128 {
129         while(*str1 && *str1 == *str2)
130                 str1++, str2++;
131         return *str1 - *str2;
132 }
133
134 /**
135  * \fn int strncmp(char *Str1, char *Str2, size_t num)
136  * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
137  */
138 int strncmp(char *Str1, char *Str2, size_t num)
139 {
140         while(num-- && *Str1 && *Str1 == *Str2)
141                 Str1++, Str2++;
142         return *Str1-*Str2;
143 }
144
145 /**
146  * \fn int strpos8(char *str, Uint32 search)
147  * \brief Search a string for a UTF-8 character
148  */
149 int strpos8(char *str, Uint32 Search)
150 {
151          int    pos;
152         Uint32  val = 0;
153         for(pos=0;str[pos];pos++)
154         {
155                 // ASCII Range
156                 if(Search < 128) {
157                         if(str[pos] == Search)  return pos;
158                         continue;
159                 }
160                 if(*(Uint8*)(str+pos) < 128)    continue;
161                 
162                 pos += ReadUTF8( (Uint8*)&str[pos], &val );
163                 if(val == Search)       return pos;
164         }
165         return -1;
166 }
167
168 /**
169  * \fn int ReadUTF8(Uint8 *str, Uint32 *Val)
170  * \brief Read a UTF-8 character from a string
171  */
172 int ReadUTF8(Uint8 *str, Uint32 *Val)
173 {
174         *Val = 0xFFFD;  // Assume invalid character
175         
176         // ASCII
177         if( !(*str & 0x80) ) {
178                 *Val = *str;
179                 return 1;
180         }
181         
182         // Middle of a sequence
183         if( (*str & 0xC0) == 0x80 ) {
184                 return 1;
185         }
186         
187         // Two Byte
188         if( (*str & 0xE0) == 0xC0 ) {
189                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
190                 str ++;
191                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
192                 *Val |= (*str & 0x3F);  // Lower 6 Bits
193                 return 2;
194         }
195         
196         // Three Byte
197         if( (*str & 0xF0) == 0xE0 ) {
198                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
199                 str ++;
200                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
201                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
202                 str ++;
203                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
204                 *Val |= (*str & 0x3F);  // Lower 6 Bits
205                 return 3;
206         }
207         
208         // Four Byte
209         if( (*str & 0xF1) == 0xF0 ) {
210                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
211                 str ++;
212                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
213                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
214                 str ++;
215                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
216                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
217                 str ++;
218                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
219                 *Val |= (*str & 0x3F);  // Lower 6 Bits
220                 return 4;
221         }
222         
223         // UTF-8 Doesn't support more than four bytes
224         return 4;
225 }
226
227 /**
228  * \fn int WriteUTF8(Uint8 *str, Uint32 Val)
229  * \brief Write a UTF-8 character sequence to a string
230  */
231 int WriteUTF8(Uint8 *str, Uint32 Val)
232 {
233         // ASCII
234         if( Val < 128 ) {
235                 *str = Val;
236                 return 1;
237         }
238         
239         // Two Byte
240         if( Val < 0x8000 ) {
241                 *str = 0xC0 | (Val >> 6);
242                 str ++;
243                 *str = 0x80 | (Val & 0x3F);
244                 return 2;
245         }
246         
247         // Three Byte
248         if( Val < 0x10000 ) {
249                 *str = 0xE0 | (Val >> 12);
250                 str ++;
251                 *str = 0x80 | ((Val >> 6) & 0x3F);
252                 str ++;
253                 *str = 0x80 | (Val & 0x3F);
254                 return 3;
255         }
256         
257         // Four Byte
258         if( Val < 0x110000 ) {
259                 *str = 0xF0 | (Val >> 18);
260                 str ++;
261                 *str = 0x80 | ((Val >> 12) & 0x3F);
262                 str ++;
263                 *str = 0x80 | ((Val >> 6) & 0x3F);
264                 str ++;
265                 *str = 0x80 | (Val & 0x3F);
266                 return 4;
267         }
268         
269         // UTF-8 Doesn't support more than four bytes
270         return 0;
271 }
272
273 /**
274  * \fn Uint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
275  * \brief Converts a date into an Acess Timestamp
276  */
277 Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year)
278 {
279         Sint64  stamp;
280         stamp = sec;
281         stamp += mins*60;
282         stamp += hrs*3600;
283         
284         stamp += day*3600*24;
285         stamp += month*DAYS_BEFORE[month]*3600*24;
286         if(     (
287                 ((year&3) == 0 || year%100 != 0)
288                 || (year%100 == 0 && ((year/100)&3) == 0)
289                 ) && month > 1) // Leap year and after feb
290                 stamp += 3600*24;
291         
292         stamp += ((365*4+1) * ((year-2000)&~3)) * 3600*24;      // Foour Year Segments
293         stamp += ((year-2000)&3) * 365*3600*24; // Inside four year segment
294         stamp += UNIX_TO_2K;
295         
296         return stamp * 1000;
297 }
298
299 /**
300  * \fn Uint rand()
301  * \brief Pseudo random number generator
302  * \note Unknown effectiveness (made up on the spot)
303  */
304 Uint rand()
305 {
306         #if 0
307         static Uint     randomState = RANDOM_SEED;
308         Uint    ret = randomState;
309          int    roll = randomState & 31;
310         randomState = (randomState << roll) | (randomState >> (32-roll));
311         randomState ^= 0x9A3C5E78;
312         return ret;
313         #else
314         static Uint     randomState = RANDOM_SEED;
315         return randomState = (RANDOM_A*randomState + RANDOM_C) & 0xFFFFFFFF;
316         #endif
317 }
318
319 EXPORT(timestamp);
320 EXPORT(ReadUTF8);

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