source: mainline/uspace/lib/posix/src/string.c@ f1380b7

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 16.5 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 String manipulation.
34 */
35
36#include "internal/common.h"
37#include "posix/string.h"
38
39#include <assert.h>
40
41#include <errno.h>
42
43#include "posix/limits.h"
44#include "posix/stdlib.h"
45#include "posix/signal.h"
46
47#include "libc/str.h"
48#include "libc/str_error.h"
49
50/**
51 * The same as strpbrk, except it returns pointer to the nul terminator
52 * if no occurence is found.
53 *
54 * @param s1 String in which to look for the bytes.
55 * @param s2 String of bytes to look for.
56 * @return Pointer to the found byte on success, pointer to the
57 * string terminator otherwise.
58 */
59static char *strpbrk_null(const char *s1, const char *s2)
60{
61 while (!strchr(s2, *s1)) {
62 ++s1;
63 }
64
65 return (char *) s1;
66}
67
68/**
69 * Copy a string.
70 *
71 * @param dest Destination pre-allocated buffer.
72 * @param src Source string to be copied.
73 * @return Pointer to the destination buffer.
74 */
75char *strcpy(char *restrict dest, const char *restrict src)
76{
77 stpcpy(dest, src);
78 return dest;
79}
80
81/**
82 * Copy fixed length string.
83 *
84 * @param dest Destination pre-allocated buffer.
85 * @param src Source string to be copied.
86 * @param n Number of bytes to be stored into destination buffer.
87 * @return Pointer to the destination buffer.
88 */
89char *strncpy(char *restrict dest, const char *restrict src, size_t n)
90{
91 stpncpy(dest, src, n);
92 return dest;
93}
94
95/**
96 * Copy a string.
97 *
98 * @param dest Destination pre-allocated buffer.
99 * @param src Source string to be copied.
100 * @return Pointer to the nul character in the destination string.
101 */
102char *stpcpy(char *restrict dest, const char *restrict src)
103{
104 assert(dest != NULL);
105 assert(src != NULL);
106
107 for (size_t i = 0; ; ++i) {
108 dest[i] = src[i];
109
110 if (src[i] == '\0') {
111 /* pointer to the terminating nul character */
112 return &dest[i];
113 }
114 }
115
116 /* unreachable */
117 return NULL;
118}
119
120/**
121 * Copy fixed length string.
122 *
123 * @param dest Destination pre-allocated buffer.
124 * @param src Source string to be copied.
125 * @param n Number of bytes to be stored into destination buffer.
126 * @return Pointer to the first written nul character or &dest[n].
127 */
128char *stpncpy(char *restrict dest, const char *restrict src, size_t n)
129{
130 assert(dest != NULL);
131 assert(src != NULL);
132
133 for (size_t i = 0; i < n; ++i) {
134 dest[i] = src[i];
135
136 /* the standard requires that nul characters
137 * are appended to the length of n, in case src is shorter
138 */
139 if (src[i] == '\0') {
140 char *result = &dest[i];
141 for (++i; i < n; ++i) {
142 dest[i] = '\0';
143 }
144 return result;
145 }
146 }
147
148 return &dest[n];
149}
150
151/**
152 * Concatenate two strings.
153 *
154 * @param dest String to which src shall be appended.
155 * @param src String to be appended after dest.
156 * @return Pointer to destination buffer.
157 */
158char *strcat(char *restrict dest, const char *restrict src)
159{
160 assert(dest != NULL);
161 assert(src != NULL);
162
163 strcpy(strchr(dest, '\0'), src);
164 return dest;
165}
166
167/**
168 * Concatenate a string with part of another.
169 *
170 * @param dest String to which part of src shall be appended.
171 * @param src String whose part shall be appended after dest.
172 * @param n Number of bytes to append after dest.
173 * @return Pointer to destination buffer.
174 */
175char *strncat(char *restrict dest, const char *restrict src, size_t n)
176{
177 assert(dest != NULL);
178 assert(src != NULL);
179
180 char *zeroptr = strncpy(strchr(dest, '\0'), src, n);
181 /* strncpy doesn't append the nul terminator, so we do it here */
182 zeroptr[n] = '\0';
183 return dest;
184}
185
186/**
187 * Copy limited number of bytes in memory.
188 *
189 * @param dest Destination buffer.
190 * @param src Source buffer.
191 * @param c Character after which the copying shall stop.
192 * @param n Number of bytes that shall be copied if not stopped earlier by c.
193 * @return Pointer to the first byte after c in dest if found, NULL otherwise.
194 */
195void *memccpy(void *restrict dest, const void *restrict src, int c, size_t n)
196{
197 assert(dest != NULL);
198 assert(src != NULL);
199
200 unsigned char* bdest = dest;
201 const unsigned char* bsrc = src;
202
203 for (size_t i = 0; i < n; ++i) {
204 bdest[i] = bsrc[i];
205
206 if (bsrc[i] == (unsigned char) c) {
207 /* pointer to the next byte */
208 return &bdest[i + 1];
209 }
210 }
211
212 return NULL;
213}
214
215/**
216 * Duplicate a string.
217 *
218 * @param s String to be duplicated.
219 * @return Newly allocated copy of the string.
220 */
221char *strdup(const char *s)
222{
223 return strndup(s, SIZE_MAX);
224}
225
226/**
227 * Duplicate a specific number of bytes from a string.
228 *
229 * @param s String to be duplicated.
230 * @param n Maximum length of the resulting string..
231 * @return Newly allocated string copy of length at most n.
232 */
233char *strndup(const char *s, size_t n)
234{
235 assert(s != NULL);
236
237 size_t len = strnlen(s, n);
238 char *dup = malloc(len + 1);
239 if (dup == NULL) {
240 return NULL;
241 }
242
243 memcpy(dup, s, len);
244 dup[len] = '\0';
245
246 return dup;
247}
248
249/**
250 * Compare two strings.
251 *
252 * @param s1 First string to be compared.
253 * @param s2 Second string to be compared.
254 * @return Difference of the first pair of inequal characters,
255 * or 0 if strings have the same content.
256 */
257int strcmp(const char *s1, const char *s2)
258{
259 assert(s1 != NULL);
260 assert(s2 != NULL);
261
262 return strncmp(s1, s2, STR_NO_LIMIT);
263}
264
265/**
266 * Compare part of two strings.
267 *
268 * @param s1 First string to be compared.
269 * @param s2 Second string to be compared.
270 * @param n Maximum number of characters to be compared.
271 * @return Difference of the first pair of inequal characters,
272 * or 0 if strings have the same content.
273 */
274int strncmp(const char *s1, const char *s2, size_t n)
275{
276 assert(s1 != NULL);
277 assert(s2 != NULL);
278
279 for (size_t i = 0; i < n; ++i) {
280 if (s1[i] != s2[i]) {
281 return s1[i] - s2[i];
282 }
283 if (s1[i] == '\0') {
284 break;
285 }
286 }
287
288 return 0;
289}
290
291/**
292 * Find byte in memory.
293 *
294 * @param mem Memory area in which to look for the byte.
295 * @param c Byte to look for.
296 * @param n Maximum number of bytes to be inspected.
297 * @return Pointer to the specified byte on success,
298 * NULL pointer otherwise.
299 */
300void *memchr(const void *mem, int c, size_t n)
301{
302 assert(mem != NULL);
303
304 const unsigned char *s = mem;
305
306 for (size_t i = 0; i < n; ++i) {
307 if (s[i] == (unsigned char) c) {
308 return (void *) &s[i];
309 }
310 }
311 return NULL;
312}
313
314/**
315 * Scan string for a first occurence of a character.
316 *
317 * @param s String in which to look for the character.
318 * @param c Character to look for.
319 * @return Pointer to the specified character on success,
320 * NULL pointer otherwise.
321 */
322char *strchr(const char *s, int c)
323{
324 assert(s != NULL);
325
326 char *res = gnu_strchrnul(s, c);
327 return (*res == c) ? res : NULL;
328}
329
330/**
331 * Scan string for a last occurence of a character.
332 *
333 * @param s String in which to look for the character.
334 * @param c Character to look for.
335 * @return Pointer to the specified character on success,
336 * NULL pointer otherwise.
337 */
338char *strrchr(const char *s, int c)
339{
340 assert(s != NULL);
341
342 const char *ptr = strchr(s, '\0');
343
344 /* the same as in strchr, except it loops in reverse direction */
345 while (*ptr != (char) c) {
346 if (ptr == s) {
347 return NULL;
348 }
349
350 ptr--;
351 }
352
353 return (char *) ptr;
354}
355
356/**
357 * Scan string for a first occurence of a character.
358 *
359 * @param s String in which to look for the character.
360 * @param c Character to look for.
361 * @return Pointer to the specified character on success, pointer to the
362 * string terminator otherwise.
363 */
364char *gnu_strchrnul(const char *s, int c)
365{
366 assert(s != NULL);
367
368 while (*s != c && *s != '\0') {
369 s++;
370 }
371
372 return (char *) s;
373}
374
375/**
376 * Scan a string for a first occurence of one of provided bytes.
377 *
378 * @param s1 String in which to look for the bytes.
379 * @param s2 String of bytes to look for.
380 * @return Pointer to the found byte on success,
381 * NULL pointer otherwise.
382 */
383char *strpbrk(const char *s1, const char *s2)
384{
385 assert(s1 != NULL);
386 assert(s2 != NULL);
387
388 char *ptr = strpbrk_null(s1, s2);
389 return (*ptr == '\0') ? NULL : ptr;
390}
391
392/**
393 * Get the length of a complementary substring.
394 *
395 * @param s1 String that shall be searched for complementary prefix.
396 * @param s2 String of bytes that shall not occur in the prefix.
397 * @return Length of the prefix.
398 */
399size_t strcspn(const char *s1, const char *s2)
400{
401 assert(s1 != NULL);
402 assert(s2 != NULL);
403
404 char *ptr = strpbrk_null(s1, s2);
405 return (size_t) (ptr - s1);
406}
407
408/**
409 * Get length of a substring.
410 *
411 * @param s1 String that shall be searched for prefix.
412 * @param s2 String of bytes that the prefix must consist of.
413 * @return Length of the prefix.
414 */
415size_t strspn(const char *s1, const char *s2)
416{
417 assert(s1 != NULL);
418 assert(s2 != NULL);
419
420 const char *ptr;
421 for (ptr = s1; *ptr != '\0'; ++ptr) {
422 if (!strchr(s2, *ptr)) {
423 break;
424 }
425 }
426 return ptr - s1;
427}
428
429/**
430 * Find a substring. Uses Knuth-Morris-Pratt algorithm.
431 *
432 * @param s1 String in which to look for a substring.
433 * @param s2 Substring to look for.
434 * @return Pointer to the first character of the substring in s1, or NULL if
435 * not found.
436 */
437char *strstr(const char *haystack, const char *needle)
438{
439 assert(haystack != NULL);
440 assert(needle != NULL);
441
442 /* Special case - needle is an empty string. */
443 if (needle[0] == '\0') {
444 return (char *) haystack;
445 }
446
447 /* Preprocess needle. */
448 size_t nlen = strlen(needle);
449 size_t prefix_table[nlen + 1];
450
451 {
452 size_t i = 0;
453 ssize_t j = -1;
454
455 prefix_table[i] = j;
456
457 while (i < nlen) {
458 while (j >= 0 && needle[i] != needle[j]) {
459 j = prefix_table[j];
460 }
461 i++; j++;
462 prefix_table[i] = j;
463 }
464 }
465
466 /* Search needle using the precomputed table. */
467 size_t npos = 0;
468
469 for (size_t hpos = 0; haystack[hpos] != '\0'; ++hpos) {
470 while (npos != 0 && haystack[hpos] != needle[npos]) {
471 npos = prefix_table[npos];
472 }
473
474 if (haystack[hpos] == needle[npos]) {
475 npos++;
476
477 if (npos == nlen) {
478 return (char *) (haystack + hpos - nlen + 1);
479 }
480 }
481 }
482
483 return NULL;
484}
485
486/** Split string by delimiters.
487 *
488 * @param s String to be tokenized. May not be NULL.
489 * @param delim String with the delimiters.
490 * @return Pointer to the prefix of @a s before the first
491 * delimiter character. NULL if no such prefix
492 * exists.
493 */
494char *strtok(char *s, const char *delim)
495{
496 static char *next;
497
498 return strtok_r(s, delim, &next);
499}
500
501
502/** Split string by delimiters.
503 *
504 * @param s String to be tokenized. May not be NULL.
505 * @param delim String with the delimiters.
506 * @param next Variable which will receive the pointer to the
507 * continuation of the string following the first
508 * occurrence of any of the delimiter characters.
509 * May be NULL.
510 * @return Pointer to the prefix of @a s before the first
511 * delimiter character. NULL if no such prefix
512 * exists.
513 */
514char *strtok_r(char *s, const char *delim, char **next)
515{
516 char *start, *end;
517
518 if (s == NULL)
519 s = *next;
520
521 /* Skip over leading delimiters. */
522 while (*s && (strchr(delim, *s) != NULL)) ++s;
523 start = s;
524
525 /* Skip over token characters. */
526 while (*s && (strchr(delim, *s) == NULL)) ++s;
527 end = s;
528 *next = (*s ? s + 1 : s);
529
530 if (start == end) {
531 return NULL; /* No more tokens. */
532 }
533
534 /* Overwrite delimiter with NULL terminator. */
535 *end = '\0';
536 return start;
537}
538
539/**
540 * String comparison using collating information.
541 *
542 * Currently ignores locale and just calls strcmp.
543 *
544 * @param s1 First string to be compared.
545 * @param s2 Second string to be compared.
546 * @return Difference of the first pair of inequal characters,
547 * or 0 if strings have the same content.
548 */
549int strcoll(const char *s1, const char *s2)
550{
551 assert(s1 != NULL);
552 assert(s2 != NULL);
553
554 return strcmp(s1, s2);
555}
556
557/**
558 * Transform a string in such a way that the resulting string yields the same
559 * results when passed to the strcmp as if the original string is passed to
560 * the strcoll.
561 *
562 * Since strcoll is equal to strcmp here, this just makes a copy.
563 *
564 * @param s1 Transformed string.
565 * @param s2 Original string.
566 * @param n Maximum length of the transformed string.
567 * @return Length of the transformed string.
568 */
569size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n)
570{
571 assert(s1 != NULL || n == 0);
572 assert(s2 != NULL);
573
574 size_t len = strlen(s2);
575
576 if (n > len) {
577 strcpy(s1, s2);
578 }
579
580 return len;
581}
582
583/**
584 * Get error message string.
585 *
586 * @param errnum Error code for which to obtain human readable string.
587 * @return Error message.
588 */
589char *strerror(int errnum)
590{
591 // FIXME: move strerror() and strerror_r() to libc.
592 return (char *) str_error(errnum);
593}
594
595/**
596 * Get error message string.
597 *
598 * @param errnum Error code for which to obtain human readable string.
599 * @param buf Buffer to store a human readable string to.
600 * @param bufsz Size of buffer pointed to by buf.
601 * @return Zero on success, errno otherwise.
602 */
603int strerror_r(int errnum, char *buf, size_t bufsz)
604{
605 assert(buf != NULL);
606
607 char *errstr = strerror(errnum);
608
609 if (strlen(errstr) + 1 > bufsz) {
610 return ERANGE;
611 } else {
612 strcpy(buf, errstr);
613 }
614
615 return EOK;
616}
617
618/**
619 * Get length of the string.
620 *
621 * @param s String which length shall be determined.
622 * @return Length of the string.
623 */
624size_t strlen(const char *s)
625{
626 assert(s != NULL);
627
628 return (size_t) (strchr(s, '\0') - s);
629}
630
631/**
632 * Get limited length of the string.
633 *
634 * @param s String which length shall be determined.
635 * @param n Maximum number of bytes that can be examined to determine length.
636 * @return The lower of either string length or n limit.
637 */
638size_t strnlen(const char *s, size_t n)
639{
640 assert(s != NULL);
641
642 for (size_t sz = 0; sz < n; ++sz) {
643
644 if (s[sz] == '\0') {
645 return sz;
646 }
647 }
648
649 return n;
650}
651
652/**
653 * Get description of a signal.
654 *
655 * @param signum Signal number.
656 * @return Human readable signal description.
657 */
658char *strsignal(int signum)
659{
660 static const char *const sigstrings[] = {
661 [SIGABRT] = "SIGABRT (Process abort signal)",
662 [SIGALRM] = "SIGALRM (Alarm clock)",
663 [SIGBUS] = "SIGBUS (Access to an undefined portion of a memory object)",
664 [SIGCHLD] = "SIGCHLD (Child process terminated, stopped, or continued)",
665 [SIGCONT] = "SIGCONT (Continue executing, if stopped)",
666 [SIGFPE] = "SIGFPE (Erroneous arithmetic operation)",
667 [SIGHUP] = "SIGHUP (Hangup)",
668 [SIGILL] = "SIGILL (Illegal instruction)",
669 [SIGINT] = "SIGINT (Terminal interrupt signal)",
670 [SIGKILL] = "SIGKILL (Kill process)",
671 [SIGPIPE] = "SIGPIPE (Write on a pipe with no one to read it)",
672 [SIGQUIT] = "SIGQUIT (Terminal quit signal)",
673 [SIGSEGV] = "SIGSEGV (Invalid memory reference)",
674 [SIGSTOP] = "SIGSTOP (Stop executing)",
675 [SIGTERM] = "SIGTERM (Termination signal)",
676 [SIGTSTP] = "SIGTSTP (Terminal stop signal)",
677 [SIGTTIN] = "SIGTTIN (Background process attempting read)",
678 [SIGTTOU] = "SIGTTOU (Background process attempting write)",
679 [SIGUSR1] = "SIGUSR1 (User-defined signal 1)",
680 [SIGUSR2] = "SIGUSR2 (User-defined signal 2)",
681 [SIGPOLL] = "SIGPOLL (Pollable event)",
682 [SIGPROF] = "SIGPROF (Profiling timer expired)",
683 [SIGSYS] = "SIGSYS (Bad system call)",
684 [SIGTRAP] = "SIGTRAP (Trace/breakpoint trap)",
685 [SIGURG] = "SIGURG (High bandwidth data is available at a socket)",
686 [SIGVTALRM] = "SIGVTALRM (Virtual timer expired)",
687 [SIGXCPU] = "SIGXCPU (CPU time limit exceeded)",
688 [SIGXFSZ] = "SIGXFSZ (File size limit exceeded)"
689 };
690
691 if (signum <= _TOP_SIGNAL) {
692 return (char *) sigstrings[signum];
693 }
694
695 return (char *) "ERROR, Invalid signal number";
696}
697
698/** @}
699 */
Note: See TracBrowser for help on using the repository browser.