Usermode/libc #6 Fix string.h functions, add some more unit tests
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / string.c
1 /*
2  * AcessOS Basic C Library
3  * string.c
4  */
5 //#include <acess/sys.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <ctype.h>
9 #include "lib.h"
10 #include <string.h>
11
12 /**
13  * \fn EXPORT int strcmp(const char *s1, const char *s2)
14  * \brief Compare two strings
15  */
16 EXPORT int strcmp(const char *_s1, const char *_s2)
17 {
18         return strncmp(_s1, _s2, SIZE_MAX);
19 }
20
21 /**
22  * \fn EXPORT int strncmp(const char *s1, const char *s2, size_t n)
23  * \brief Compare two strings, stopping after n characters
24  */
25 EXPORT int strncmp(const char *_s1, const char *_s2, size_t n)
26 {
27         const unsigned char*    s1 = (const unsigned char*)_s1;
28         const unsigned char*    s2 = (const unsigned char*)_s2;
29         while(n && *s1 && *s1 == *s2)
30         {
31                 s1++; s2++;
32                 n --;
33         }
34         if( n == 0 )
35                 return 0;
36         else
37                 return (int)*s1 - (int)*s2;
38 }
39
40 EXPORT int strcasecmp(const char *_s1, const char *_s2)
41 {
42         return strncasecmp(_s1, _s2, SIZE_MAX);
43 }
44
45 EXPORT int strncasecmp(const char *_s1, const char *_s2, size_t n)
46 {
47         const unsigned char*    s1 = (const unsigned char*)_s1;
48         const unsigned char*    s2 = (const unsigned char*)_s2;
49         while( n-- && *s1 && *s2 )
50         {
51                 if( *s1 != *s2 )
52                 {
53                         int rv;
54                         rv = toupper(*s1) - toupper(*s2);
55                         if(rv != 0)
56                                 return rv;
57                         rv = tolower(*s1) - tolower(*s2);
58                         if(rv != 0)
59                                 return rv;
60                 }
61                 s1 ++;
62                 s2 ++;
63         }
64         return 0;
65 }
66
67 /**
68  * \fn EXPORT char *strcpy(char *dst, const char *src)
69  * \brief Copy a string to another
70  */
71 EXPORT char *strcpy(char *dst, const char *src)
72 {
73         char *_dst = dst;
74         while(*src) {
75                 *dst = *src;
76                 src++; dst++;
77         }
78         *dst = '\0';
79         return _dst;
80 }
81
82 /**
83  * \fn EXPORT char *strncpy(char *dst, const char *src)
84  * \brief Copy at most \a num characters from \a src to \a dst
85  * \return \a dst
86  */
87 EXPORT char *strncpy(char *dst, const char *src, size_t num)
88 {
89         char *to = dst;
90         while(*src && num--)    *to++ = *src++;
91         *to = '\0';
92         return dst;
93 }
94
95 /**
96  * \fn EXPORT char *strcat(char *dst, const char *src)
97  * \brief Append a string onto another
98  */
99 EXPORT char *strcat(char *dst, const char *src)
100 {
101         char    *to = dst;
102         // Find the end
103         while(*to)      to++;
104         // Copy
105         while(*src)     *to++ = *src++;
106         // End string
107         *to = '\0';
108         return dst;
109 }
110
111 EXPORT char *strncat(char *dst, const char *src, size_t n)
112 {
113         char    *to = dst;
114         // Find the end
115         while(*to)      to++;
116         // Copy
117         while(*src && n--)      *to++ = *src++;
118         // End string
119         *to = '\0';
120         return dst;
121 }
122
123 /**
124  * \brief Get the length of a string
125  */
126 EXPORT size_t strlen(const char *str)
127 {
128         size_t  retval;
129         for(retval = 0; *str != '\0'; str++, retval++);
130         return retval;
131 }
132
133 /**
134  * \brief Get the length of a string, with a maximum of \a maxlen
135  * 
136  * Gets the length of a string (excluding the terminating \0 byte)
137  */
138 EXPORT size_t strnlen(const char *str, size_t maxlen)
139 {
140         size_t  len;
141         for( len = 0; maxlen -- && *str; str ++, len ++ )
142                 ;
143         return len;
144 }
145
146 /**
147  * \fn EXPORT char *strdup(const char *str)
148  * \brief Duplicate a string using heap memory
149  * \note Defined in POSIX Spec, not C spec
150  */
151 EXPORT char *strdup(const char *str)
152 {
153         size_t  len = strlen(str);
154         char    *ret = malloc(len+1);
155         if(ret == NULL) return NULL;
156         strcpy(ret, str);
157         return ret;
158 }
159
160 /**
161  * \fn EXPORT char *strndup(const char *str, size_t maxlen)
162  * \brief Duplicate a string into the heap with a maximum length
163  * \param str   Input string buffer
164  * \param maxlen        Maximum valid size of the \a str buffer
165  * \return Heap string with the same value of \a str
166  */
167 EXPORT char *strndup(const char *str, size_t maxlen)
168 {
169         size_t  len;
170         char    *ret;
171         for( len = 0; len < maxlen && str[len]; len ++) ;
172         ret = malloc( len + 1);
173         memcpy( ret, str, len );
174         ret[len] = '\0';
175         return ret;
176 }
177
178 /**
179  * \fn EXPORT char *strchr(char *str, int character)
180  * \brief Locate a character in a string
181  */
182 EXPORT char *strchr(const char *_str, int character)
183 {
184         const unsigned char* str = (const unsigned char*)_str;
185         for(;*str;str++)
186         {
187                 if( *str == character )
188                         return (char*)str;
189         }
190         return NULL;
191 }
192
193 /**
194  * \fn EXPORT char *strrchr(char *str, int character)
195  * \brief Locate the last occurance of a character in a string
196  */
197 EXPORT char *strrchr(const char *_str, int character)
198 {
199         const unsigned char* str = (const unsigned char*)_str;
200         for( int i = strlen(_str); i--; )
201         {
202                 if(str[i] == character)
203                         return (void*)&str[i];
204         }
205         return NULL;
206 }
207
208 /**
209  * \fn EXPORT char *strstr(char *str1, const char *str2)
210  * \brief Search a \a str1 for the first occurance of \a str2
211  */
212 EXPORT char *strstr(const char *str1, const char *str2)
213 {
214         const char      *test = str2;
215         
216         for(;*str1;str1++)
217         {
218                 if(*test == '\0')       return (char*)str1;
219                 if(*str1 == *test)      test++;
220                 else    test = str2;
221         }
222         return NULL;
223 }
224
225 // --- Memory ---
226 /**
227  * \fn EXPORT void *memset(void *dest, int val, size_t num)
228  * \brief Clear memory with the specified value
229  */
230 EXPORT void *memset(void *dest, int val, size_t num)
231 {
232         unsigned char *p = dest;
233         while(num--)    *p++ = val;
234         return dest;
235 }
236
237 /**
238  * \fn EXPORT void *memcpy(void *dest, const void *src, size_t count)
239  * \brief Copy one memory area to another
240  */
241 EXPORT void *memcpy(void *__dest, const void *__src, size_t count)
242 {
243         const int       wordmask = sizeof(void*)-1;
244         uintptr_t       src = (uintptr_t)__src;
245         uintptr_t       dst = (uintptr_t)__dest;
246
247         if( count < sizeof(void*)*2 || (dst & wordmask) != (src & wordmask) )
248         {
249                 char    *dp = __dest;
250                 const char      *sp = __src;
251                 while(count--) *dp++ = *sp ++;
252         }
253         // TODO: Bulk aligned copies
254         #if 0
255         else if(count > 128 && (dst & 15) == (src & 15) )
256         {
257                 // SSE/bulk copy
258                 for( ; dst & 15; count -- )
259                         *(char*)dst++ = *(char*)src++;
260                 memcpy_16byte(dst, src, count / 16);
261                 dst += count & ~15;
262                 src += count & ~15;
263                 count &= 15;
264                 while(count --)
265                         *(char*)dst++ = *(char*)src++;
266         }
267         #endif
268         else
269         {
270                 void    **dp, **sp;
271                 for( ; count && (dst & wordmask) != 0; count -- )
272                         *(char*)dst++ = *(char*)src++;
273
274                 dp = (void*)dst; sp = (void*)src;
275                 while( count >= sizeof(void*) )
276                 {
277                         *dp++ = *sp++;
278                         count -= sizeof(void*);
279                 }
280                 dst = (uintptr_t)dp; src = (uintptr_t)sp;
281                 for( ; count; count -- )
282                         *(char*)dst++ = *(char*)src++;
283         }
284
285         return __dest;
286 }
287
288 // TODO: memccpy (POSIX defined)
289
290 /**
291  * \fn EXPORT void *memmove(void *dest, const void *src, size_t count)
292  * \brief Copy data in memory, avoiding overlap problems
293  */
294 EXPORT void *memmove(void *dest, const void *src, size_t count)
295 {
296         const char *sp = (const char *)src;
297         char *dp = (char *)dest;
298         // Check if the areas overlap
299         if( sp >= dp+count )
300                 memcpy(dest, src, count);
301         else if( dp >= sp+count )
302                 memcpy(dest, src, count);
303         else {
304                 if( sp < dp ) {
305                         while(count--)
306                                 dp[count] = sp[count];
307                 }
308                 else {
309                         while(count--)
310                                 *dp++ = *sp++;
311                 }
312         }
313         return dest;
314 }
315
316 /**
317  * \fn EXPORT int memcmp(const void *mem1, const void *mem2, size_t count)
318  * \brief Compare two regions of memory
319  * \param mem1  Region 1
320  * \param mem2  Region 2
321  * \param count Number of bytes to check
322  */
323 EXPORT int memcmp(const void *mem1, const void *mem2, size_t count)
324 {
325         const unsigned char     *p1 = mem1, *p2 = mem2;
326         while(count--)
327         {
328                 if( *p1 != *p2 )
329                         return (int)*p1 - (int)*p2;
330                 p1 ++;
331                 p2 ++;
332         }
333         return 0;
334 }
335
336 /**
337  * \fn EXPORT void *memchr(void *ptr, int value, size_t num)
338  * \brief Locates the first occurence of \a value starting at \a ptr
339  * \param ptr   Starting memory location
340  * \param value Value to find
341  * \param num   Size of memory area to check
342  */
343 EXPORT void *memchr(const void *ptr, int value, size_t num)
344 {
345         const unsigned char* buf = ptr;
346         while(num--)
347         {
348                 if( *buf == (unsigned char)value )
349                         return (void*)buf;
350                 buf ++;
351         }
352         return NULL;
353 }
354
355 EXPORT size_t strcspn(const char *haystack, const char *reject)
356 {
357         size_t  ret = 0;
358         while( *haystack )
359         {
360                 for( int i = 0; reject[i]; i ++ )
361                 {
362                         if( reject[i] == *haystack )
363                                 return ret;
364                 }
365                 ret ++;
366         }
367         return ret;
368 }
369
370 EXPORT size_t strspn(const char *haystack, const char *accept)
371 {
372         size_t  ret = 0;
373         while( *haystack )
374         {
375                 for( int i = 0; accept[i]; i ++ )
376                 {
377                         if( accept[i] != *haystack )
378                                 return ret;
379                 }
380                 ret ++;
381         }
382         return ret;
383 }
384
385 EXPORT char *strpbrk(const char *haystack, const char *accept)
386 {
387         while( *haystack )
388         {
389                 for( int i = 0; accept[i]; i ++ )
390                 {
391                         if( accept[i] == *haystack )
392                                 return (char*)haystack;
393                 }
394                 haystack ++;
395         }
396         return NULL;
397 }
398
399 char *strtok(char *str, const char *delim)
400 {
401         static char *__saveptr;
402         return strtok_r(str, delim, &__saveptr);
403 }
404 char *strtok_r(char *str, const char *delim, char **saveptr)
405 {
406         char *pos = (str ? str : *saveptr);
407         
408         while( strchr(delim, *pos) )
409                 pos ++;
410
411         if( *pos == '\0' )
412                 return NULL;
413
414         char *ret = pos;
415         while( !strchr(delim, *pos) )
416                 pos ++;
417         
418         // Cap the returned string
419         // - If we're at the end of the original string, don't shift pos
420         if( *pos != '\0' ) {
421                 *pos = '\0';
422                 pos ++;
423         }
424         
425         *saveptr = pos;
426         
427         return ret;
428 }
429

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