source: mainline/uspace/lib/posix/string.c@ 557a747

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

Fix up string.h a bit.

  • Property mode set to 100644
File size: 9.4 KB
Line 
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
36#define LIBPOSIX_INTERNAL
37
38#include "string.h"
39
40#include "libc/assert.h"
41#include "libc/str_error.h"
42#include "errno.h"
43#include "limits.h"
44#include "stdlib.h"
45
46/**
47 * Returns true if s2 is a prefix of s1.
48 *
49 * @param s1
50 * @param s2
51 * @return
52 */
53static bool begins_with(const char *s1, const char *s2)
54{
55 while (*s1 == *s2 && *s2 != '\0') {
56 s1++;
57 s2++;
58 }
59
60 /* true if the end was reached */
61 return *s2 == '\0';
62}
63
64/**
65 * The same as strpbrk, except it returns pointer to the nul terminator
66 * if no occurence is found.
67 *
68 * @param s1
69 * @param s2
70 * @return
71 */
72static char *strpbrk_null(const char *s1, const char *s2)
73{
74 while (!posix_strchr(s2, *s1)) {
75 ++s1;
76 }
77
78 return (char *) s1;
79}
80
81/**
82 *
83 * @param dest
84 * @param src
85 * @return
86 */
87char *posix_strcpy(char *dest, const char *src)
88{
89 posix_stpcpy(dest, src);
90 return dest;
91}
92
93/**
94 *
95 * @param dest
96 * @param src
97 * @param n
98 * @return
99 */
100char *posix_strncpy(char *dest, const char *src, size_t n)
101{
102 posix_stpncpy(dest, src, n);
103 return dest;
104}
105
106/**
107 *
108 * @param dest
109 * @param src
110 * @return Pointer to the nul character in the dest string
111 */
112char *posix_stpcpy(char *restrict dest, const char *restrict src)
113{
114 assert(dest != NULL);
115 assert(src != NULL);
116
117 for (size_t i = 0; ; ++i) {
118 dest[i] = src[i];
119
120 if (src[i] == '\0') {
121 /* pointer to the terminating nul character */
122 return &dest[i];
123 }
124 }
125
126 /* unreachable */
127 return NULL;
128}
129
130/**
131 *
132 * @param dest
133 * @param src
134 * @param n
135 * @return Pointer to the first written nul character or &dest[n]
136 */
137char *posix_stpncpy(char *restrict dest, const char *restrict src, size_t n)
138{
139 assert(dest != NULL);
140 assert(src != NULL);
141
142 for (size_t i = 0; i < n; ++i) {
143 dest[i] = src[i];
144
145 /* the standard requires that nul characters
146 * are appended to the length of n, in case src is shorter
147 */
148 if (src[i] == '\0') {
149 char *result = &dest[i];
150 for (++i; i < n; ++i) {
151 dest[i] = '\0';
152 }
153 return result;
154 }
155 }
156
157 return &dest[n];
158}
159
160/**
161 *
162 * @param dest
163 * @param src
164 * @return
165 */
166char *posix_strcat(char *dest, const char *src)
167{
168 assert(dest != NULL);
169 assert(src != NULL);
170
171 posix_strcpy(posix_strchr(dest, '\0'), src);
172 return dest;
173}
174
175/**
176 *
177 * @param dest
178 * @param src
179 * @param n
180 * @return
181 */
182char *posix_strncat(char *dest, const char *src, size_t n)
183{
184 assert(dest != NULL);
185 assert(src != NULL);
186
187 char *zeroptr = posix_strncpy(posix_strchr(dest, '\0'), src, n);
188 /* strncpy doesn't append the nul terminator, so we do it here */
189 zeroptr[n] = '\0';
190 return dest;
191}
192
193/**
194 *
195 * @param dest
196 * @param src
197 * @param c
198 * @param n
199 * @return Pointer to the first byte after c in dest if found, NULL otherwise.
200 */
201void *posix_memccpy(void *dest, const void *src, int c, size_t n)
202{
203 assert(dest != NULL);
204 assert(src != NULL);
205
206 unsigned char* bdest = dest;
207 const unsigned char* bsrc = src;
208
209 for (size_t i = 0; i < n; ++i) {
210 bdest[i] = bsrc[i];
211
212 if (bsrc[i] == (unsigned char) c) {
213 /* pointer to the next byte */
214 return &bdest[i + 1];
215 }
216 }
217
218 return NULL;
219}
220
221/**
222 *
223 * @param s
224 * @return Newly allocated string
225 */
226char *posix_strdup(const char *s)
227{
228 return posix_strndup(s, SIZE_MAX);
229}
230
231/**
232 *
233 * @param s
234 * @param n
235 * @return Newly allocated string of length at most n
236 */
237char *posix_strndup(const char *s, size_t n)
238{
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;
251}
252
253/**
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
260 */
261int posix_memcmp(const void *mem1, const void *mem2, size_t n)
262{
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
275 return 0;
276}
277
278/**
279 *
280 * @param s1
281 * @param s2
282 * @return
283 */
284int posix_strcmp(const char *s1, const char *s2)
285{
286 assert(s1 != NULL);
287 assert(s2 != NULL);
288
289 return posix_strncmp(s1, s2, STR_NO_LIMIT);
290}
291
292/**
293 *
294 * @param s1
295 * @param s2
296 * @param n
297 * @return
298 */
299int posix_strncmp(const char *s1, const char *s2, size_t n)
300{
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
313 return 0;
314}
315
316/**
317 *
318 * @param mem
319 * @param c
320 * @param n
321 * @return
322 */
323void *posix_memchr(const void *mem, int c, size_t n)
324{
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;
335}
336
337/**
338 *
339 * @param s
340 * @param c
341 * @return
342 */
343char *posix_strchr(const char *s, int c)
344{
345 assert(s != NULL);
346
347 char *res = gnu_strchrnul(s, c);
348 return (*res == c) ? res : NULL;
349}
350
351/**
352 *
353 * @param s
354 * @param c
355 * @return
356 */
357char *posix_strrchr(const char *s, int c)
358{
359 assert(s != NULL);
360
361 const char *ptr = posix_strchr(s, '\0');
362
363 /* the same as in strchr, except it loops in reverse direction */
364 while (*ptr != (char) c) {
365 if (ptr == s) {
366 return NULL;
367 }
368
369 ptr++;
370 }
371
372 return (char *) ptr;
373}
374
375char *gnu_strchrnul(const char *s, int c)
376{
377 assert(s != NULL);
378
379 while (*s != c && *s != '\0') {
380 s++;
381 }
382
383 return (char *) s;
384}
385
386/**
387 *
388 * @param s1
389 * @param s2
390 * @return
391 */
392char *posix_strpbrk(const char *s1, const char *s2)
393{
394 assert(s1 != NULL);
395 assert(s2 != NULL);
396
397 char *ptr = strpbrk_null(s1, s2);
398 return (*ptr == '\0') ? NULL : ptr;
399}
400
401/**
402 *
403 * @param s1
404 * @param s2
405 * @return
406 */
407size_t posix_strcspn(const char *s1, const char *s2)
408{
409 assert(s1 != NULL);
410 assert(s2 != NULL);
411
412 char *ptr = strpbrk_null(s1, s2);
413 return (size_t) (ptr - s1);
414}
415
416/**
417 *
418 * @param s1
419 * @param s2
420 * @return
421 */
422size_t posix_strspn(const char *s1, const char *s2)
423{
424 assert(s1 != NULL);
425 assert(s2 != NULL);
426
427 const char *ptr;
428 for (ptr = s1; *ptr != '\0'; ++ptr) {
429 if (!posix_strchr(s2, *ptr)) {
430 break;
431 }
432 }
433 return ptr - s1;
434}
435
436/**
437 *
438 * @param s1
439 * @param s2
440 * @return
441 */
442char *posix_strstr(const char *s1, const char *s2)
443{
444 assert(s1 != NULL);
445 assert(s2 != NULL);
446
447 /* special case - needle is an empty string */
448 if (*s2 == '\0') {
449 return (char *) s1;
450 }
451
452 // TODO: use faster algorithm
453 /* check for prefix from every position - quadratic complexity */
454 while (*s1 != '\0') {
455 if (begins_with(s1, s2)) {
456 return (char *) s1;
457 }
458
459 s1++;
460 }
461
462 return NULL;
463}
464
465/**
466 * Currently ignores locale and just calls strcmp.
467 *
468 * @param s1
469 * @param s2
470 * @return
471 */
472int posix_strcoll(const char *s1, const char *s2)
473{
474 assert(s1 != NULL);
475 assert(s2 != NULL);
476
477 return posix_strcmp(s1, s2);
478}
479
480/**
481 * strcoll is equal to strcmp here, so this just makes a copy.
482 *
483 * @param s1
484 * @param s2
485 * @param n
486 * @return
487 */
488size_t posix_strxfrm(char *s1, const char *s2, size_t n)
489{
490 assert(s1 != NULL || n == 0);
491 assert(s2 != NULL);
492
493 size_t len = posix_strlen(s2);
494
495 if (n > len) {
496 posix_strcpy(s1, s2);
497 }
498
499 return len;
500}
501
502/**
503 *
504 * @param errnum
505 * @return
506 */
507char *posix_strerror(int errnum)
508{
509 /* uses function from libc, we just have to negate errno
510 * (POSIX uses positive errorcodes, HelenOS has negative)
511 */
512 return (char *) str_error(-errnum);
513}
514
515/**
516 *
517 * @param errnum Error code
518 * @param buf Buffer to store a human readable string to
519 * @param bufsz Size of buffer pointed to by buf
520 * @return
521 */
522int posix_strerror_r(int errnum, char *buf, size_t bufsz)
523{
524 assert(buf != NULL);
525
526 char *errstr = posix_strerror(errnum);
527 /* HelenOS str_error can't fail */
528
529 if (posix_strlen(errstr) + 1 > bufsz) {
530 return -ERANGE;
531 } else {
532 posix_strcpy(buf, errstr);
533 }
534
535 return 0;
536}
537
538/**
539 *
540 * @param s
541 * @return
542 */
543size_t posix_strlen(const char *s)
544{
545 assert(s != NULL);
546
547 return (size_t) (posix_strchr(s, '\0') - s);
548}
549
550/**
551 *
552 * @param s
553 * @param n
554 * @return
555 */
556size_t posix_strnlen(const char *s, size_t n)
557{
558 assert(s != NULL);
559
560 for (size_t sz = 0; sz < n; ++sz) {
561
562 if (s[sz] == '\0') {
563 return sz;
564 }
565 }
566
567 return n;
568}
569
570/** @}
571 */
Note: See TracBrowser for help on using the repository browser.