source: mainline/uspace/lib/c/generic/string.c@ 28a5ebd

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

Fix strndup()

PCUT showed one failure which occured while testing
the string function strndup(). The last letter was not
a \0. This commit invokes in strndup() the function
strncpy() instead of strcpy() which corrects this
failure

  • Property mode set to 100644
File size: 13.1 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#include <errno.h>
36#include <stddef.h>
37#include <stdlib.h>
38#include <str_error.h>
39#include <string.h>
40
41/** Copy string.
42 *
43 * Copy the string pointed to by @a s2 to the array pointed to by @a s1
44 * including the terminating null character. The source and destination
45 * must not overlap.
46 *
47 * @param s1 Destination array
48 * @param s2 Source string
49 * @return @a s1
50 */
51char *strcpy(char *s1, const char *s2)
52{
53 char *dp = s1;
54
55 /* Copy characters */
56 while (*s2 != '\0')
57 *dp++ = *s2++;
58
59 /* Copy the terminating null character */
60 *dp++ = *s2++;
61
62 return s1;
63}
64
65/** Copy not more than @a n characters.
66 *
67 * Copy not more than @a n characters from @a s2 to @a s1. Characters
68 * following a null character are not copied. If The string @a s2 is
69 * shorter than @a n characters, null characters are appended to the
70 * copy in @a s1, until @a n characters in all have been written.
71 *
72 * (I.e. @a s1 is padded with null characters up to size @a n).
73 * The source and destination must not overlap.
74 *
75 * @param s1 Destination array
76 * @param s2 Source string
77 * @param n Number of characters to copy
78 * @return @a s1
79 */
80char *strncpy(char *s1, const char *s2, size_t n)
81{
82 char *dp = s1;
83 size_t i;
84
85 for (i = 0; i < n; i++) {
86 *dp++ = *s2;
87 if (*s2 != '\0')
88 ++s2;
89 }
90
91 return s1;
92}
93
94/** Append string.
95 *
96 * Append a copy of string in @a s2 to the string pointed to by @a s1
97 * (including the terminating null character). @a s1 and @a s2 must not
98 * overlap.
99 *
100 * @param s1 Destination buffer holding a string to be appended to
101 * @param s2 String to be appended
102 * @return @a s1
103 */
104char *strcat(char *s1, const char *s2)
105{
106 char *dp = s1;
107
108 /* Find end of first string */
109 while (*dp != '\0')
110 ++dp;
111
112 /* Copy second string */
113 while (*s2 != '\0')
114 *dp++ = *s2++;
115
116 /* Copy null character */
117 *dp = '\0';
118
119 return s1;
120}
121
122/** Append not more than @a n characters.
123 *
124 * Append a copy of max. @a n characters from string in @a s2 to the string
125 * pointed to by @a s1. The resulting string is always null-terminated.
126 *
127 * @param s1 Destination buffer holding a string to be appended to
128 * @param s2 String to be appended
129 * @param n Maximum number of characters to copy
130 * @return @a s1
131 */
132char *strncat(char *s1, const char *s2, size_t n)
133{
134 char *dp = s1;
135
136 /* Find end of first string */
137 while (*dp != '\0')
138 ++dp;
139
140 /* Copy second string */
141 while (*s2 != '\0' && n > 0) {
142 *dp++ = *s2++;
143 --n;
144 }
145
146 /* Copy null character */
147 *dp = '\0';
148
149 return s1;
150}
151
152/** Compare two strings.
153 *
154 * @param s1 First string
155 * @param s2 Second string
156 * @return Greater than, equal to, less than zero if @a s1 > @a s2,
157 * @a s1 == @a s2, @a s1 < @a s2, resp.
158 */
159int strcmp(const char *s1, const char *s2)
160{
161 while (*s1 == *s2 && *s1 != '\0') {
162 ++s1;
163 ++s2;
164 }
165
166 return *s1 - *s2;
167}
168
169/** Compare two strings based on LC_COLLATE of current locale.
170 *
171 * @param s1 First string
172 * @param s2 Second string
173 * @return Greater than, equal to, less than zero if @a s1 > @a s2,
174 * @a s1 == @a s2, @a s1 < @a s2, resp.
175 */
176int strcoll(const char *s1, const char *s2)
177{
178 /* Note: we don't support locale other than "C" */
179 return strcmp(s1, s2);
180}
181
182/** Compare not more than @a n characters.
183 *
184 * @param s1 First string
185 * @param s2 Second string
186 * @param n Maximum number of characters to compare
187 * @return Greater than, equal to, less than zero if @a s1 > @a s2,
188 * @a s1 == @a s2, @a s1 < @a s2, resp. (within the first @a n chars.)
189 */
190int strncmp(const char *s1, const char *s2, size_t n)
191{
192 while (*s1 == *s2 && *s1 != '\0' && n > 0) {
193 ++s1;
194 ++s2;
195 --n;
196 }
197
198 if (n > 0)
199 return *s1 - *s2;
200
201 return 0;
202}
203
204/** Transform string for collation.
205 *
206 * Transform string in @a s2 to the buffer @a s1, writing no more than
207 * @a n characters (including the terminating null character). The transformed
208 * string is such that using strcmp on two transformed strings should be
209 * equivalent to using strcoll on the original strings.
210 *
211 * @param s1 Destination buffer
212 * @param s2 Source string
213 * @param n Max. number of characters to write (including terminating null)
214 * @return Length of the transformed string not including the null terminator.
215 * If the value returned is @a n or more, the contents of the buffer
216 * pointed to by @a s1 are undefined.
217 */
218size_t strxfrm(char *s1, const char *s2, size_t n)
219{
220 size_t i;
221 size_t len;
222
223 len = strlen(s2);
224
225 for (i = 0; i < n; i++) {
226 *s1++ = *s2;
227 if (*s2 == '\0')
228 break;
229 ++s2;
230 }
231
232 return len;
233}
234
235/** Find the first occurrence of a character in a string.
236 *
237 * The character @a c is converted to char. The null character is
238 * considered part of the string.
239 *
240 * @param s String
241 * @param c Character
242 * @return Pointer to the located character or @c NULL if the character
243 * does not occur in the string.
244 */
245char *strchr(const char *s, int c)
246{
247 do {
248 if (*s == (char) c)
249 return (char *) s;
250 } while (*s++ != '\0');
251
252 return NULL;
253}
254
255/** Compute the size of max. initial segment consisting of a complementary
256 * set of characters.
257 *
258 * Compute the size of the max. initial segment of @a s1 consisting only
259 * of characters *not* from @a s2.
260 *
261 * @param s1 String to search
262 * @param s2 String containing set of characters
263 * @return Size of initial segment of @a s1 consisting only of characters
264 * not from @a s2.
265 */
266size_t strcspn(const char *s1, const char *s2)
267{
268 char *p;
269 size_t n;
270
271 n = 0;
272 while (*s1 != '\0') {
273 /* Look for current character in s2 */
274 p = strchr(s2, *s1);
275
276 /* If found, return current character count. */
277 if (p != NULL)
278 break;
279
280 ++s1;
281 ++n;
282 }
283
284 return n;
285}
286
287/** Search string for occurrence of any of a set of characters.
288 *
289 * @param s1 String to search
290 * @param s2 String containing a set of characters
291 *
292 * @return Pointer to first character found or @c NULL if not found
293 */
294char *strpbrk(const char *s1, const char *s2)
295{
296 char *p;
297
298 while (*s1 != '\0') {
299 /* Look for current character in s2 */
300 p = strchr(s2, *s1);
301
302 /* If found, return pointer to current character. */
303 if (p != NULL)
304 return (char *) s1;
305
306 ++s1;
307 }
308
309 return NULL;
310}
311
312/** Find the last occurrence of a character in a string.
313 *
314 * The character @a c is converted to char. The null character is
315 * considered part of the string.
316 *
317 * @param s String
318 * @param c Character
319 * @return Pointer to the located character or @c NULL if the character
320 * does not occur in the string.
321 */
322char *strrchr(const char *s, int c)
323{
324 size_t i = strlen(s);
325
326 while (i > 0) {
327 if (s[i] == (char) c)
328 return (char *)s + i;
329 --i;
330 }
331
332 return NULL;
333}
334
335/** Compute the size of max. initial segment consisting of a set of characters.
336 *
337 * Compute tha size of the max. initial segment of @a s1 consisting only
338 * of characters from @a s2.
339 *
340 * @param s1 String to search
341 * @param s2 String containing set of characters
342 * @return Size of initial segment of @a s1 consisting only of characters
343 * from @a s2.
344 */
345size_t strspn(const char *s1, const char *s2)
346{
347 char *p;
348 size_t n;
349
350 n = 0;
351 while (*s1 != '\0') {
352 /* Look for current character in s2 */
353 p = strchr(s2, *s1);
354
355 /* If not found, return current character count. */
356 if (p == NULL)
357 break;
358
359 ++s1;
360 ++n;
361 }
362
363 return n;
364}
365
366/** Find occurrence of substring in a string.
367 *
368 * Find the first occurrence in @a s1 of the characters in @a s2, excluding
369 * the terminating null character. If s2 is an empty string, returns @a s1.
370 *
371 * @param s1 String to search
372 * @param s2 Sequence of characters to find
373 *
374 * @return Pointer inside @a s1 or @c NULL if not found.
375 */
376char *strstr(const char *s1, const char *s2)
377{
378 size_t len;
379
380 /*
381 * Naive search algorithm.
382 *
383 * Two-Way String-Matching might be a plausible alternative
384 * for larger haystack+needle combinations.
385 */
386
387 len = strlen(s2);
388 while (*s1 != '\0') {
389 if (strncmp(s1, s2, len) == 0)
390 return (char *) s1;
391 ++s1;
392 }
393
394 return NULL;
395}
396
397/** Tokenize a string (reentrant).
398 *
399 * The contents of @a s1 are modified (the separators get overwritten by null
400 * characters). The separators can be different each iteration, their identity\
401 * is, however, lost.
402 *
403 * @param s1 String buffer to get the first token, @c NULL to get the next
404 * token
405 * @param s2 String containing current separators
406 * @return Pointer to the next token
407 */
408char *__strtok_r(char *s1, const char *s2, char **saveptr)
409{
410 char *s;
411 char *tbegin;
412 char *tend;
413
414 if (s1 != NULL) {
415 /* Starting tokenization of a new string */
416 s = s1;
417 } else {
418 /* Use saved position of next token */
419 s = *saveptr;
420
421 /* Check if we ran out of tokens */
422 if (s == NULL)
423 return NULL;
424 }
425
426 /* Find position of first character that is not a separator */
427 tbegin = s;
428 while (*tbegin != '\0' && strchr(s2, *tbegin) != NULL)
429 ++tbegin;
430
431 /* If no such character is found, there are no tokens */
432 if (*tbegin == '\0')
433 return NULL;
434
435 /* Find first character that is a separator */
436 tend = strpbrk(tbegin, s2);
437 if (tend != NULL) {
438 /* Overwrite the separator, next token starts just after */
439 *tend = '\0';
440 *saveptr = tend + 1;
441 } else {
442 /* No more tokens will be returned next time */
443 *saveptr = NULL;
444 }
445
446 return tbegin;
447}
448
449/** Saved position of next token for function strtok */
450static char *strtok_saveptr = NULL;
451
452/** Tokenize a string.
453 *
454 * This function has internal state and thus is not reentrant.
455 * ISO C says the implementation should behave as if no (standard) library
456 * call calls strtok. The contents of @a s1 are modified (the separators
457 * get overwritten by null characters). The separators can be different
458 * each iteration, their identity is, however, lost.
459 *
460 * Never use this function since it's not reentrant.
461 *
462 * @param s1 String buffer to get the first token, @c NULL to get the next
463 * token
464 * @param s2 String containing current separators
465 * @return Pointer to the next token
466 */
467char *strtok(char *s1, const char *s2)
468{
469 return __strtok_r(s1, s2, &strtok_saveptr);
470}
471
472/** Map error number to a string.
473 *
474 * The string returned by the function may be overwritten by a subsequent
475 * call to strerror (ISO C). In our implementation the function is, in fact,
476 * reentrant, as the string returned is static and never modified.
477 *
478 * @param errnum Error number
479 * @return Pointer to error message
480 */
481char *strerror(int errnum)
482{
483 return (char *) str_error(errnum);
484}
485
486/** Return number of characters in string.
487 *
488 * @param s String
489 * @return Number of characters preceding the null character.
490 */
491size_t strlen(const char *s)
492{
493 size_t n;
494
495 n = 0;
496 while (*s != '\0') {
497 ++s;
498 ++n;
499 }
500
501 return n;
502}
503
504/** Return number of characters in string with length limit.
505 *
506 * @param s String
507 * @param maxlen Maximum number of characters to read
508 * @return Number of characters preceding the null character, at most @a maxlen.
509 */
510size_t strnlen(const char *s, size_t maxlen)
511{
512 size_t n;
513
514 n = 0;
515 while (n < maxlen && *s != '\0') {
516 ++s;
517 ++n;
518 }
519
520 return n;
521}
522
523/** Allocate a new duplicate of string.
524 *
525 * @param s String to duplicate
526 * @return New string or @c NULL on failure (in which case @c errno is set
527 * to ENOMEM).
528 */
529char *strdup(const char *s)
530{
531 size_t sz;
532 char *dup;
533
534 sz = strlen(s);
535 dup = malloc(sz + 1);
536 if (dup == NULL) {
537 errno = ENOMEM;
538 return NULL;
539 }
540
541 strcpy(dup, s);
542 return dup;
543}
544
545/** Allocate a new duplicate of string with length limit.
546 *
547 * Creates a new duplicate of @a s. If @a s is longer than @a n characters,
548 * only @a n characters are copied and a null character is appended.
549 *
550 * @param s String to duplicate
551 * @param n Maximum number of characters to copy
552 * @return New string or @c NULL on failure (in which case @c errno is set
553 * to ENOMEM).
554 */
555char *strndup(const char *s, size_t n)
556{
557 size_t sz;
558 char *dup;
559
560 sz = strnlen(s, n);
561 dup = malloc(sz + 1);
562 if (dup == NULL) {
563 errno = ENOMEM;
564 return NULL;
565 }
566
567 strncpy(dup, s, sz);
568 return dup;
569}
570
571/** @}
572 */
Note: See TracBrowser for help on using the repository browser.