Usermode/libc - Fix strchr and strrchr behavior
[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(num --)
91         {
92                 if(*src)
93                         *to++ = *src++;
94                 else
95                         *to++ = '\0';
96         }
97         return dst;
98 }
99
100 /**
101  * \fn EXPORT char *strcat(char *dst, const char *src)
102  * \brief Append a string onto another
103  */
104 EXPORT char *strcat(char *dst, const char *src)
105 {
106         char    *to = dst;
107         // Find the end
108         while(*to)      to++;
109         // Copy
110         while(*src)     *to++ = *src++;
111         // End string
112         *to = '\0';
113         return dst;
114 }
115
116 EXPORT char *strncat(char *dst, const char *src, size_t n)
117 {
118         char    *to = dst;
119         // Find the end
120         while(*to)      to++;
121         // Copy
122         while(*src && n--)      *to++ = *src++;
123         // End string
124         *to = '\0';
125         return dst;
126 }
127
128 /**
129  * \brief Get the length of a string
130  */
131 EXPORT size_t strlen(const char *str)
132 {
133         size_t  len = 0;
134         while(str[len] != '\0')
135                 len ++;
136         return len;
137 }
138
139 /**
140  * \brief Get the length of a string, with a maximum of \a maxlen
141  * 
142  * Gets the length of a string (excluding the terminating \0 byte)
143  */
144 EXPORT size_t strnlen(const char *str, size_t maxlen)
145 {
146         size_t  len = 0;
147         while( len < maxlen && str[len] != '\0' )
148                 len ++;
149         return len;
150 }
151
152 /**
153  * \fn EXPORT char *strdup(const char *str)
154  * \brief Duplicate a string using heap memory
155  * \note Defined in POSIX Spec, not C spec
156  */
157 EXPORT char *strdup(const char *str)
158 {
159         size_t  len = strlen(str);
160         char    *ret = malloc(len+1);
161         if(ret == NULL) return NULL;
162         strcpy(ret, str);
163         return ret;
164 }
165
166 /**
167  * \fn EXPORT char *strndup(const char *str, size_t maxlen)
168  * \brief Duplicate a string into the heap with a maximum length
169  * \param str   Input string buffer
170  * \param maxlen        Maximum valid size of the \a str buffer
171  * \return Heap string with the same value of \a str
172  */
173 EXPORT char *strndup(const char *str, size_t maxlen)
174 {
175         size_t  len;
176         char    *ret;
177         for( len = 0; len < maxlen && str[len]; len ++) ;
178         ret = malloc( len + 1);
179         memcpy( ret, str, len );
180         ret[len] = '\0';
181         return ret;
182 }
183
184 /**
185  * \fn EXPORT char *strchr(char *str, int character)
186  * \brief Locate a character in a string
187  * \note The terminating NUL is part of the string
188  */
189 EXPORT char *strchr(const char *_str, int character)
190 {
191         const unsigned char* str = (const unsigned char*)_str;
192         do
193         {
194                 if( *str == character )
195                         return (char*)str;
196         } while( *str++ );
197         return NULL;
198 }
199
200 /**
201  * \fn EXPORT char *strrchr(char *str, int character)
202  * \brief Locate the last occurance of a character in a string
203  */
204 EXPORT char *strrchr(const char *_str, int character)
205 {
206         const unsigned char* str = (const unsigned char*)_str;
207         size_t  i = strlen(_str);
208         do
209         {
210                 if(str[i] == character)
211                         return (void*)&str[i];
212         } while( i -- );
213         return NULL;
214 }
215
216 /**
217  * \fn EXPORT char *strstr(char *str1, const char *str2)
218  * \brief Search a \a str1 for the first occurance of \a str2
219  */
220 EXPORT char *strstr(const char *str1, const char *str2)
221 {
222         const char      *test = str2;
223         
224         for(;*str1;str1++)
225         {
226                 if(*test == '\0')       return (char*)str1;
227                 if(*str1 == *test)      test++;
228                 else    test = str2;
229         }
230         return NULL;
231 }
232
233 // --- Memory ---
234 /**
235  * \fn EXPORT void *memset(void *dest, int val, size_t num)
236  * \brief Clear memory with the specified value
237  */
238 EXPORT void *memset(void *dest, int val, size_t num)
239 {
240         unsigned char *p = dest;
241         while(num--)    *p++ = val;
242         return dest;
243 }
244
245 /**
246  * \fn EXPORT void *memcpy(void *dest, const void *src, size_t count)
247  * \brief Copy one memory area to another
248  */
249 EXPORT void *memcpy(void *__dest, const void *__src, size_t count)
250 {
251         const int       wordmask = sizeof(void*)-1;
252         uintptr_t       src = (uintptr_t)__src;
253         uintptr_t       dst = (uintptr_t)__dest;
254
255         if( count < sizeof(void*)*2 || (dst & wordmask) != (src & wordmask) )
256         {
257                 char    *dp = __dest;
258                 const char      *sp = __src;
259                 while(count--) *dp++ = *sp ++;
260         }
261         // TODO: Bulk aligned copies
262         #if 0
263         else if(count > 128 && (dst & 15) == (src & 15) )
264         {
265                 // SSE/bulk copy
266                 for( ; dst & 15; count -- )
267                         *(char*)dst++ = *(char*)src++;
268                 memcpy_16byte(dst, src, count / 16);
269                 dst += count & ~15;
270                 src += count & ~15;
271                 count &= 15;
272                 while(count --)
273                         *(char*)dst++ = *(char*)src++;
274         }
275         #endif
276         else
277         {
278                 void    **dp, **sp;
279                 for( ; count && (dst & wordmask) != 0; count -- )
280                         *(char*)dst++ = *(char*)src++;
281
282                 dp = (void*)dst; sp = (void*)src;
283                 while( count >= sizeof(void*) )
284                 {
285                         *dp++ = *sp++;
286                         count -= sizeof(void*);
287                 }
288                 dst = (uintptr_t)dp; src = (uintptr_t)sp;
289                 for( ; count; count -- )
290                         *(char*)dst++ = *(char*)src++;
291         }
292
293         return __dest;
294 }
295
296 // TODO: memccpy (POSIX defined)
297
298 /**
299  * \fn EXPORT void *memmove(void *dest, const void *src, size_t count)
300  * \brief Copy data in memory, avoiding overlap problems
301  */
302 EXPORT void *memmove(void *dest, const void *src, size_t count)
303 {
304         const char *sp = (const char *)src;
305         char *dp = (char *)dest;
306         // Check if the areas overlap
307         if( sp >= dp+count )
308                 memcpy(dest, src, count);
309         else if( dp >= sp+count )
310                 memcpy(dest, src, count);
311         else {
312                 if( sp < dp ) {
313                         while(count--)
314                                 dp[count] = sp[count];
315                 }
316                 else {
317                         while(count--)
318                                 *dp++ = *sp++;
319                 }
320         }
321         return dest;
322 }
323
324 /**
325  * \fn EXPORT int memcmp(const void *mem1, const void *mem2, size_t count)
326  * \brief Compare two regions of memory
327  * \param mem1  Region 1
328  * \param mem2  Region 2
329  * \param count Number of bytes to check
330  */
331 EXPORT int memcmp(const void *mem1, const void *mem2, size_t count)
332 {
333         const unsigned char     *p1 = mem1, *p2 = mem2;
334         while(count--)
335         {
336                 if( *p1 != *p2 )
337                         return (int)*p1 - (int)*p2;
338                 p1 ++;
339                 p2 ++;
340         }
341         return 0;
342 }
343
344 /**
345  * \fn EXPORT void *memchr(void *ptr, int value, size_t num)
346  * \brief Locates the first occurence of \a value starting at \a ptr
347  * \param ptr   Starting memory location
348  * \param value Value to find
349  * \param num   Size of memory area to check
350  */
351 EXPORT void *memchr(const void *ptr, int value, size_t num)
352 {
353         const unsigned char* buf = ptr;
354         while(num--)
355         {
356                 if( *buf == (unsigned char)value )
357                         return (void*)buf;
358                 buf ++;
359         }
360         return NULL;
361 }
362
363 EXPORT size_t strcspn(const char *haystack, const char *reject)
364 {
365         size_t  ret = 0;
366         while( *haystack )
367         {
368                 for( int i = 0; reject[i]; i ++ )
369                 {
370                         if( reject[i] == *haystack )
371                                 return ret;
372                 }
373                 ret ++;
374         }
375         return ret;
376 }
377
378 EXPORT size_t strspn(const char *haystack, const char *accept)
379 {
380         size_t  ret = 0;
381         while( *haystack )
382         {
383                 for( int i = 0; accept[i]; i ++ )
384                 {
385                         if( accept[i] != *haystack )
386                                 return ret;
387                 }
388                 ret ++;
389         }
390         return ret;
391 }
392
393 EXPORT char *strpbrk(const char *haystack, const char *accept)
394 {
395         while( *haystack )
396         {
397                 for( int i = 0; accept[i]; i ++ )
398                 {
399                         if( accept[i] == *haystack )
400                                 return (char*)haystack;
401                 }
402                 haystack ++;
403         }
404         return NULL;
405 }
406
407 char *strtok(char *str, const char *delim)
408 {
409         static char *__saveptr;
410         return strtok_r(str, delim, &__saveptr);
411 }
412 char *strtok_r(char *str, const char *delim, char **saveptr)
413 {
414         char *pos = (str ? str : *saveptr);
415         
416         while( strchr(delim, *pos) )
417                 pos ++;
418
419         if( *pos == '\0' )
420                 return NULL;
421
422         char *ret = pos;
423         while( !strchr(delim, *pos) )
424                 pos ++;
425         
426         // Cap the returned string
427         // - If we're at the end of the original string, don't shift pos
428         if( *pos != '\0' ) {
429                 *pos = '\0';
430                 pos ++;
431         }
432         
433         *saveptr = pos;
434         
435         return ret;
436 }
437

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