source: mainline/uspace/lib/c/generic/string.c@ c483fca

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c483fca was 9a5ae815, checked in by Jiří Zárevúcky <jiri.zarevucky@…>, 7 years ago

Fix strxfrm() return type

  • Property mode set to 100644
File size: 11.9 KB
Line 
1/*
2 * Copyright (c) 2018 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file
33 */
34
35/* Prevent an error from being generated */
36#undef _HELENOS_SOURCE
37#include <string.h>
38#define _HELENOS_SOURCE
39
40#include <stddef.h>
41#include <str_error.h>
42
43/** Copy string.
44 *
45 * Copy the string pointed to by @a s2 to the array pointed to by @a s1
46 * including the terminating null character. The source and destination
47 * must not overlap.
48 *
49 * @param s1 Destination array
50 * @param s2 Source string
51 * @return @a s1
52 */
53char *strcpy(char *s1, const char *s2)
54{
55 char *dp = s1;
56
57 /* Copy characters */
58 while (*s2 != '\0')
59 *dp++ = *s2++;
60
61 /* Copy the terminating null character */
62 *dp++ = *s2++;
63
64 return s1;
65}
66
67/** Copy not more than @a n characters.
68 *
69 * Copy not more than @a n characters from @a s2 to @a s1. Characters
70 * following a null character are not copied. If The string @a s2 is
71 * shorter than @a n characters, null characters are appended to the
72 * copy in @a s1, until @a n characters in all have been written.
73 *
74 * (I.e. @a s1 is padded with null characters up to size @a n).
75 * The source and destination must not overlap.
76 *
77 * @param s1 Destination array
78 * @param s2 Source string
79 * @param n Number of characters to copy
80 * @return @a s1
81 */
82char *strncpy(char *s1, const char *s2, size_t n)
83{
84 char *dp = s1;
85 size_t i;
86
87 for (i = 0; i < n; i++) {
88 *dp++ = *s2;
89 if (*s2 != '\0')
90 ++s2;
91 }
92
93 return s1;
94}
95
96/** Append string.
97 *
98 * Append a copy of string in @a s2 to the string pointed to by @a s1
99 * (including the terminating null character). @a s1 and @a s2 must not
100 * overlap.
101 *
102 * @param s1 Destination buffer holding a string to be appended to
103 * @param s2 String to be appended
104 * @return @a s1
105 */
106char *strcat(char *s1, const char *s2)
107{
108 char *dp = s1;
109
110 /* Find end of first string */
111 while (*dp != '\0')
112 ++dp;
113
114 /* Copy second string */
115 while (*s2 != '\0')
116 *dp++ = *s2++;
117
118 /* Copy null character */
119 *dp = '\0';
120
121 return s1;
122}
123
124/** Append not more than @a n characters.
125 *
126 * Append a copy of max. @a n characters from string in @a s2 to the string
127 * pointed to by @a s1. The resulting string is always null-terminated.
128 *
129 * @param s1 Destination buffer holding a string to be appended to
130 * @param s2 String to be appended
131 * @param n Maximum number of characters to copy
132 * @return @a s1
133 */
134char *strncat(char *s1, const char *s2, size_t n)
135{
136 char *dp = s1;
137
138 /* Find end of first string */
139 while (*dp != '\0')
140 ++dp;
141
142 /* Copy second string */
143 while (*s2 != '\0' && n > 0) {
144 *dp++ = *s2++;
145 --n;
146 }
147
148 /* Copy null character */
149 *dp = '\0';
150
151 return s1;
152}
153
154/** Compare two strings.
155 *
156 * @param s1 First string
157 * @param s2 Second string
158 * @return Greater than, equal to, less than zero if @a s1 > @a s2,
159 * @a s1 == @a s2, @a s1 < @a s2, resp.
160 */
161int strcmp(const char *s1, const char *s2)
162{
163 while (*s1 == *s2 && *s1 != '\0') {
164 ++s1;
165 ++s2;
166 }
167
168 return *s1 - *s2;
169}
170
171/** Compare two strings based on LC_COLLATE of current locale.
172 *
173 * @param s1 First string
174 * @param s2 Second string
175 * @return Greater than, equal to, less than zero if @a s1 > @a s2,
176 * @a s1 == @a s2, @a s1 < @a s2, resp.
177 */
178int strcoll(const char *s1, const char *s2)
179{
180 /* Note: we don't support locale other than "C" */
181 return strcmp(s1, s2);
182}
183
184/** Compare not more than @a n characters.
185 *
186 * @param s1 First string
187 * @param s2 Second string
188 * @param n Maximum number of characters to compare
189 * @return Greater than, equal to, less than zero if @a s1 > @a s2,
190 * @a s1 == @a s2, @a s1 < @a s2, resp. (within the first @a n chars.)
191 */
192int strncmp(const char *s1, const char *s2, size_t n)
193{
194 while (*s1 == *s2 && *s1 != '\0' && n > 0) {
195 ++s1;
196 ++s2;
197 --n;
198 }
199
200 if (n > 0)
201 return *s1 - *s2;
202
203 return 0;
204}
205
206/** Transform string for collation.
207 *
208 * Transform string in @a s2 to the buffer @a s1, writing no more than
209 * @a n characters (including the terminating null character). The transformed
210 * string is such that using strcmp on two transformed strings should be
211 * equivalent to using strcoll on the original strings.
212 *
213 * @param s1 Destination buffer
214 * @param s2 Source string
215 * @param n Max. number of characters to write (including terminating null)
216 * @return Length of the transformed string not including the null terminator.
217 * If the value returned is @a n or more, the contents of the buffer
218 * pointed to by @a s1 are undefined.
219 */
220size_t strxfrm(char *s1, const char *s2, size_t n)
221{
222 size_t i;
223 size_t len;
224
225 len = strlen(s2);
226
227 for (i = 0; i < n; i++) {
228 *s1++ = *s2;
229 if (*s2 == '\0')
230 break;
231 ++s2;
232 }
233
234 return len;
235}
236
237/** Find the first occurrence of a character in a string.
238 *
239 * The character @a c is converted to char. The null character is
240 * considered part of the string.
241 *
242 * @param s String
243 * @param c Character
244 * @return Pointer to the located character or @c NULL if the character
245 * does not occur in the string.
246 */
247char *strchr(const char *s, int c)
248{
249 do {
250 if (*s == (char) c)
251 return (char *) s;
252 } while (*s++ != '\0');
253
254 return NULL;
255}
256
257/** Compute the size of max. initial segment consisting of a complementary
258 * set of characters.
259 *
260 * Compute the size of the max. initial segment of @a s1 consisting only
261 * of characters *not* from @a s2.
262 *
263 * @param s1 String to search
264 * @param s2 String containing set of characters
265 * @return Size of initial segment of @a s1 consisting only of characters
266 * not from @a s2.
267 */
268size_t strcspn(const char *s1, const char *s2)
269{
270 char *p;
271 size_t n;
272
273 n = 0;
274 while (*s1 != '\0') {
275 /* Look for current character in s2 */
276 p = strchr(s2, *s1);
277
278 /* If found, return current character count. */
279 if (p != NULL)
280 break;
281
282 ++s1;
283 ++n;
284 }
285
286 return n;
287}
288
289/** Search string for occurrence of any of a set of characters.
290 *
291 * @param s1 String to search
292 * @param s2 String containing a set of characters
293 *
294 * @return Pointer to first character found or @c NULL if not found
295 */
296char *strpbrk(const char *s1, const char *s2)
297{
298 char *p;
299
300 while (*s1 != '\0') {
301 /* Look for current character in s2 */
302 p = strchr(s2, *s1);
303
304 /* If found, return pointer to current character. */
305 if (p != NULL)
306 return (char *) s1;
307
308 ++s1;
309 }
310
311 return NULL;
312}
313
314/** Find the last occurrence of a character in a string.
315 *
316 * The character @a c is converted to char. The null character is
317 * considered part of the string.
318 *
319 * @param s String
320 * @param c Character
321 * @return Pointer to the located character or @c NULL if the character
322 * does not occur in the string.
323 */
324char *strrchr(const char *s, int c)
325{
326 size_t i = strlen(s);
327
328 while (i > 0) {
329 if (s[i] == (char) c)
330 return (char *)s + i;
331 --i;
332 }
333
334 return NULL;
335}
336
337/** Compute the size of max. initial segment consisting of a set of characters.
338 *
339 * Compute tha size of the max. initial segment of @a s1 consisting only
340 * of characters from @a s2.
341 *
342 * @param s1 String to search
343 * @param s2 String containing set of characters
344 * @return Size of initial segment of @a s1 consisting only of characters
345 * from @a s2.
346 */
347size_t strspn(const char *s1, const char *s2)
348{
349 char *p;
350 size_t n;
351
352 n = 0;
353 while (*s1 != '\0') {
354 /* Look for current character in s2 */
355 p = strchr(s2, *s1);
356
357 /* If not found, return current character count. */
358 if (p == NULL)
359 break;
360
361 ++s1;
362 ++n;
363 }
364
365 return n;
366}
367
368/** Find occurrence of substring in a string.
369 *
370 * Find the first occurrence in @a s1 of the characters in @a s2, excluding
371 * the terminating null character. If s2 is an empty string, returns @a s1.
372 *
373 * @param s1 String to search
374 * @param s2 Sequence of characters to find
375 *
376 * @return Pointer inside @a s1 or @c NULL if not found.
377 */
378char *strstr(const char *s1, const char *s2)
379{
380 size_t len;
381
382 /*
383 * Naive search algorithm.
384 *
385 * Two-Way String-Matching might be a plausible alternative
386 * for larger haystack+needle combinations.
387 */
388
389 len = strlen(s2);
390 while (*s1 != '\0') {
391 if (strncmp(s1, s2, len) == 0)
392 return (char *) s1;
393 ++s1;
394 }
395
396 return NULL;
397}
398
399/** Tokenize a string (reentrant).
400 *
401 * The contents of @a s1 are modified (the separators get overwritten by null
402 * characters). The separators can be different each iteration, their identity\
403 * is, however, lost.
404 *
405 * @param s1 String buffer to get the first token, @c NULL to get the next
406 * token
407 * @param s2 String containing current separators
408 * @return Pointer to the next token
409 */
410char *__strtok_r(char *s1, const char *s2, char **saveptr)
411{
412 char *s;
413 char *tbegin;
414 char *tend;
415
416 if (s1 != NULL) {
417 /* Starting tokenization of a new string */
418 s = s1;
419 } else {
420 /* Use saved position of next token */
421 s = *saveptr;
422
423 /* Check if we ran out of tokens */
424 if (s == NULL)
425 return NULL;
426 }
427
428 /* Find position of first character that is not a separator */
429 tbegin = s;
430 while (*tbegin != '\0' && strchr(s2, *tbegin) != NULL)
431 ++tbegin;
432
433 /* If no such character is found, there are no tokens */
434 if (*tbegin == '\0')
435 return NULL;
436
437 /* Find first character that is a separator */
438 tend = strpbrk(tbegin, s2);
439 if (tend != NULL) {
440 /* Overwrite the separator, next token starts just after */
441 *tend = '\0';
442 *saveptr = tend + 1;
443 } else {
444 /* No more tokens will be returned next time */
445 *saveptr = NULL;
446 }
447
448 return tbegin;
449}
450
451/** Saved position of next token for function strtok */
452static char *strtok_saveptr = NULL;
453
454/** Tokenize a string.
455 *
456 * This function has internal state and thus is not reentrant.
457 * ISO C says the implementation should behave as if no (standard) library
458 * call calls strtok. The contents of @a s1 are modified (the separators
459 * get overwritten by null characters). The separators can be different
460 * each iteration, their identity is, however, lost.
461 *
462 * Never use this function since it's not reentrant.
463 *
464 * @param s1 String buffer to get the first token, @c NULL to get the next
465 * token
466 * @param s2 String containing current separators
467 * @return Pointer to the next token
468 */
469char *strtok(char *s1, const char *s2)
470{
471 return __strtok_r(s1, s2, &strtok_saveptr);
472}
473
474/** Map error number to a string.
475 *
476 * The string returned by the function may be overwritten by a subsequent
477 * call to strerror (ISO C). In our implementation the function is, in fact,
478 * reentrant, as the string returned is static and never modified.
479 *
480 * @param errnum Error number
481 * @return Pointer to error message
482 */
483char *strerror(int errnum)
484{
485 return (char *) str_error(errnum);
486}
487
488/** Return number of characters in string.
489 *
490 * @param s String
491 * @return Number of characters preceding the null character.
492 */
493size_t strlen(const char *s)
494{
495 size_t n;
496
497 n = 0;
498 while (*s != '\0') {
499 ++s;
500 ++n;
501 }
502
503 return n;
504}
505
506/** @}
507 */
Note: See TracBrowser for help on using the repository browser.