source: mainline/uspace/lib/posix/string.c@ 1eee1283

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

Almost complete implementation of string.h

  • Property mode set to 100644
File size: 9.6 KB
RevLine 
[7bb9b53]1/*
2 * Copyright (c) 2011 Petr Koupy
3 * Copyright (c) 2011 Jiri Zarevucky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libposix
31 * @{
32 */
33/** @file
34 */
35
[4d10fc8]36#define LIBPOSIX_INTERNAL
37
[7bb9b53]38#include "string.h"
39
[ef6dd3f]40#include <assert.h>
[7bb9b53]41#include <str_error.h>
[ef6dd3f]42#include <stdlib.h>
43#include <errno.h>
44
45/* Defined for convenience. Returns pointer to the terminating nul character.
46 */
47static char *strzero(const char *s)
48{
49 while (*s != '\0')
50 s ++;
51
52 return (char*) s;
53}
54
55/* Returns true if s2 is a prefix of s1.
56 */
57static bool begins_with(const char *s1, const char *s2)
58{
59 while (*s1 == *s2 && *s2 != '\0') {
60 s1 ++;
61 s2 ++;
62 }
63
64 /* true if the end was reached */
65 return *s2 == '\0';
66}
67
68/* The same as strpbrk, except it returns pointer to the nul terminator
69 * if no occurence is found.
70 */
71static char *strpbrk_null(const char *s1, const char *s2)
72{
73 while (!posix_strchr(s2, *s1)) {
74 ++ s1;
75 }
76
77 return (char *) s1;
78}
[7bb9b53]79
80/**
81 *
82 * @param dest
83 * @param src
[ef6dd3f]84 * @return dest
[7bb9b53]85 */
86char *posix_strcpy(char *dest, const char *src)
87{
[ef6dd3f]88 posix_stpcpy(dest, src);
89 return dest;
[7bb9b53]90}
91
92/**
93 *
94 * @param dest
95 * @param src
96 * @param n
[ef6dd3f]97 * @return dest
[7bb9b53]98 */
99char *posix_strncpy(char *dest, const char *src, size_t n)
100{
[ef6dd3f]101 posix_stpncpy(dest, src, n);
102 return dest;
[7bb9b53]103}
104
105/**
106 *
107 * @param dest
108 * @param src
[ef6dd3f]109 * @return Pointer to the nul character in the dest string
[7bb9b53]110 */
[ef6dd3f]111char *posix_stpcpy(char *restrict dest, const char *restrict src)
[7bb9b53]112{
[ef6dd3f]113 assert(dest != NULL);
114 assert(src != NULL);
115
116 for (size_t i = 0; ; ++ i) {
117 dest[i] = src[i];
118
119 if (src[i] == '\0') {
120 /* pointer to the terminating nul character */
121 return &dest[i];
122 }
123 }
124
125 /* unreachable */
126 return NULL;
[7bb9b53]127}
128
129/**
130 *
131 * @param dest
132 * @param src
133 * @param n
[ef6dd3f]134 * @return Pointer to the first written nul character or &dest[n]
[7bb9b53]135 */
[ef6dd3f]136char *posix_stpncpy(char *restrict dest, const char *restrict src, size_t n)
[7bb9b53]137{
[ef6dd3f]138 assert(dest != NULL);
139 assert(src != NULL);
140
141 for (size_t i = 0; i < n; ++ i) {
142 dest[i] = src[i];
143
144 /* the standard requires that nul characters
145 * are appended to the length of n, in case src is shorter
146 */
147 if (src[i] == '\0') {
148 char *result = &dest[i];
149 for (++ i; i < n; ++ i) {
150 dest[i] = '\0';
151 }
152 return result;
153 }
154 }
155
156 return &dest[n];
[7bb9b53]157}
158
159/**
[ef6dd3f]160 *
[7bb9b53]161 * @param dest
162 * @param src
[ef6dd3f]163 * @return dest
[7bb9b53]164 */
[ef6dd3f]165char *posix_strcat(char *dest, const char *src)
[7bb9b53]166{
[ef6dd3f]167 assert(dest != NULL);
168 assert(src != NULL);
169
170 posix_strcpy(strzero(dest), src);
171 return dest;
[7bb9b53]172}
173
174/**
[ef6dd3f]175 *
176 * @param dest
177 * @param src
178 * @param n
179 * @return dest
[7bb9b53]180 */
[ef6dd3f]181char *posix_strncat(char *dest, const char *src, size_t n)
[7bb9b53]182{
[ef6dd3f]183 assert(dest != NULL);
184 assert(src != NULL);
185
186 char *zeroptr = posix_strncpy(strzero(dest), src, n);
187 /* strncpy doesn't append the nul terminator, so we do it here */
188 zeroptr[n] = '\0';
189 return dest;
[7bb9b53]190}
191
192/**
193 *
[ef6dd3f]194 * @param dest
195 * @param src
196 * @param c
[7bb9b53]197 * @param n
[ef6dd3f]198 * @return Pointer to the first byte after c in dest if found, NULL otherwise.
[7bb9b53]199 */
[ef6dd3f]200void *posix_memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
[7bb9b53]201{
[ef6dd3f]202 assert(dest != NULL);
203 assert(src != NULL);
204
205 unsigned char* bdest = dest;
206 const unsigned char* bsrc = src;
207
208 for (size_t i = 0; i < n; ++ i) {
209 bdest[i] = bsrc[i];
210
211 if (bsrc[i] == (unsigned char) c) {
212 /* pointer to the next byte */
213 return &bdest[i + 1];
214 }
215 }
216
217 return NULL;
[7bb9b53]218}
219
220/**
221 *
[ef6dd3f]222 * @param s
223 * @return Newly allocated string
[7bb9b53]224 */
[ef6dd3f]225char *posix_strdup(const char *s)
[7bb9b53]226{
[ef6dd3f]227 // FIXME: SIZE_MAX doesn't work
228 return posix_strndup(s, STR_NO_LIMIT);
[7bb9b53]229}
230
231/**
232 *
[ef6dd3f]233 * @param s
[7bb9b53]234 * @param n
[ef6dd3f]235 * @return Newly allocated string of length at most n
[7bb9b53]236 */
[ef6dd3f]237char *posix_strndup(const char *s, size_t n)
[7bb9b53]238{
[ef6dd3f]239 assert(s != NULL);
240
241 size_t len = posix_strnlen(s, n);
242 char *dup = malloc(len + 1);
243 if (dup == NULL) {
244 return NULL;
245 }
246
247 memcpy(dup, s, len);
248 dup[len] = '\0';
249
250 return dup;
[7bb9b53]251}
252
253/**
[ef6dd3f]254 *
255 * @param mem1
256 * @param mem2
257 * @param n
258 * @return Difference of the first pair of inequal bytes,
259 * or 0 if areas have the same content
[7bb9b53]260 */
[ef6dd3f]261int posix_memcmp(const void *mem1, const void *mem2, size_t n)
[7bb9b53]262{
[ef6dd3f]263 assert(mem1 != NULL);
264 assert(mem2 != NULL);
265
266 const unsigned char *s1 = mem1;
267 const unsigned char *s2 = mem2;
268
269 for (size_t i = 0; i < n; ++ i) {
270 if (s1[i] != s2[i]) {
271 return s2[i] - s1[i];
272 }
273 }
274
[7bb9b53]275 return 0;
276}
277
278/**
[ef6dd3f]279 *
[7bb9b53]280 * @param s1
281 * @param s2
282 * @return
283 */
[ef6dd3f]284int posix_strcmp(const char *s1, const char *s2)
[7bb9b53]285{
[ef6dd3f]286 assert(s1 != NULL);
287 assert(s2 != NULL);
288
289 return posix_strncmp(s1, s2, STR_NO_LIMIT);
[7bb9b53]290}
291
292/**
293 *
[ef6dd3f]294 * @param s1
295 * @param s2
[7bb9b53]296 * @param n
297 * @return
298 */
[ef6dd3f]299int posix_strncmp(const char *s1, const char *s2, size_t n)
[7bb9b53]300{
[ef6dd3f]301 assert(s1 != NULL);
302 assert(s2 != NULL);
303
304 for (size_t i = 0; i < n; ++ i) {
305 if (s1[i] != s2[i]) {
306 return s2[i] - s1[i];
307 }
308 if (s1[i] == '\0') {
309 break;
310 }
311 }
312
[7bb9b53]313 return 0;
314}
315
316/**
[ef6dd3f]317 *
[7bb9b53]318 * @param mem
319 * @param c
[ef6dd3f]320 * @param n
[7bb9b53]321 * @return
322 */
[ef6dd3f]323void *posix_memchr(const void *mem, int c, size_t n)
[7bb9b53]324{
[ef6dd3f]325 assert(mem != NULL);
326
327 const unsigned char *s = mem;
328
329 for (size_t i = 0; i < n; ++ i) {
330 if (s[i] == (unsigned char) c) {
331 return (void *) &s[i];
332 }
333 }
334 return NULL;
[7bb9b53]335}
336
337/**
338 *
339 * @param s
340 * @param c
341 * @return
342 */
343char *posix_strchr(const char *s, int c)
344{
[ef6dd3f]345 assert(s != NULL);
346
347 /* special handling for the case that zero is searched for */
348 if (c == '\0')
349 return strzero(s);
350
351 /* otherwise just loop through the string until found */
352 while (*s != (char) c) {
353 if (*s == '\0')
354 return NULL;
355
356 s ++;
357 }
358
359 return (char *) s;
[7bb9b53]360}
361
362/**
363 *
364 * @param s
365 * @param c
366 * @return
367 */
368char *posix_strrchr(const char *s, int c)
369{
[ef6dd3f]370 assert(s != NULL);
371
372 const char *ptr = strzero(s);
373
374 /* the same as in strchr, except it loops in reverse direction */
375 while (*ptr != (char) c) {
376 if (ptr == s)
377 return NULL;
378
379 ptr ++;
380 }
381
382 return (char *) ptr;
[7bb9b53]383}
384
385/**
386 *
387 * @param s1
388 * @param s2
389 * @return
390 */
391char *posix_strpbrk(const char *s1, const char *s2)
392{
[ef6dd3f]393 assert(s1 != NULL);
394 assert(s2 != NULL);
395
396 char *ptr = strpbrk_null(s1, s2);
397 return (*ptr == '\0') ? NULL : ptr;
[7bb9b53]398}
399
400/**
401 *
402 * @param s1
403 * @param s2
404 * @return
405 */
406size_t posix_strcspn(const char *s1, const char *s2)
407{
[ef6dd3f]408 assert(s1 != NULL);
409 assert(s2 != NULL);
410
411 char *ptr = strpbrk_null(s1, s2);
412 return (size_t) (ptr - s1);
[7bb9b53]413}
414
415/**
416 *
417 * @param s1
418 * @param s2
419 * @return
420 */
421size_t posix_strspn(const char *s1, const char *s2)
422{
[ef6dd3f]423 assert(s1 != NULL);
424 assert(s2 != NULL);
425
426 const char *ptr;
427 for (ptr = s1; *ptr != '\0'; ++ ptr) {
428 if (!posix_strchr(s2, *ptr))
429 break;
430 }
431 return ptr - s1;
[7bb9b53]432}
433
434/**
435 *
436 * @param s1
437 * @param s2
438 * @return
439 */
440char *posix_strstr(const char *s1, const char *s2)
441{
[ef6dd3f]442 assert(s1 != NULL);
443 assert(s2 != NULL);
444
445 /* special case - needle is an empty string */
446 if (*s2 == '\0')
447 return (char *) s1;
448
449 // TODO: use faster algorithm
450 /* check for prefix from every position - quadratic complexity */
451 while (*s1 != '\0') {
452 if (begins_with(s1, s2))
453 return (char *) s1;
454
455 s1 ++;
456 }
457
458 return NULL;
[7bb9b53]459}
460
461/**
[ef6dd3f]462 * Currently ignores locale and just calls strcmp.
[7bb9b53]463 *
464 * @param s1
465 * @param s2
466 * @return
467 */
468int posix_strcoll(const char *s1, const char *s2)
469{
[ef6dd3f]470 assert(s1 != NULL);
471 assert(s2 != NULL);
472
473 return posix_strcmp(s1, s2);
[7bb9b53]474}
475
476/**
[ef6dd3f]477 * strcoll is equal to strcmp here, so this just makes a copy.
[7bb9b53]478 *
479 * @param s1
480 * @param s2
481 * @param n
482 * @return
483 */
484size_t posix_strxfrm(char *s1, const char *s2, size_t n)
485{
[ef6dd3f]486 assert(s1 != NULL || n == 0);
487 assert(s2 != NULL);
488
489 size_t len = posix_strlen(s2);
490
491 if (n > len)
492 posix_strcpy(s1, s2);
493
494 return len;
[7bb9b53]495}
496
497/**
498 *
499 * @param errnum
500 * @return
501 */
502char *posix_strerror(int errnum)
503{
[ef6dd3f]504 /* uses function from libc, we just have to negate errno
505 (POSIX uses positive errorcodes, HelenOS has negative) */
506 return (char *) str_error (-errnum);
507}
508
509/**
510 *
511 * @param errnum Error code
512 * @param buf Buffer to store a human readable string to
513 * @param bufsz Size of buffer pointed to by buf
514 * @return
515 */
516int posix_strerror_r(int errnum, char *buf, size_t bufsz)
517{
518 assert(buf != NULL);
519
520 char *errstr = posix_strerror(errnum);
521 /* HelenOS str_error can't fail */
522
523 if (posix_strlen(errstr) + 1 > bufsz) {
524 return -ERANGE;
525 } else {
526 posix_strcpy(buf, errstr);
527 }
528
[7bb9b53]529 return 0;
530}
531
532/**
533 *
534 * @param s
535 * @return
536 */
537size_t posix_strlen(const char *s)
538{
[ef6dd3f]539 assert(s != NULL);
540
541 return (size_t) (strzero(s) - s);
542}
543
544/**
545 *
546 * @param s
547 * @param n
548 * @return
549 */
550size_t posix_strnlen(const char *s, size_t n)
551{
552 assert(s != NULL);
553
554 for (size_t sz = 0; sz < n; ++ sz) {
555
556 if (s[sz] == '\0') {
557 return sz;
558 }
559 }
560
561 return n;
[7bb9b53]562}
563
564/** @}
565 */
Note: See TracBrowser for help on using the repository browser.