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

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