mb/google/brya/var/omnigul: Modify NVMe and UFS Storage support
[coreboot.git] / payloads / libpayload / libc / string.c
blob46c3c019bdf7b7296dc3e2756b513c2654c3fb1b
1 /*
3 * Copyright (C) 2007 Uwe Hermann <uwe@hermann-uwe.de>
4 * Copyright (C) 2008 Advanced Micro Devices, Inc.
5 * Copyright (C) 2010 coresystems GmbH
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. 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 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
31 #include <libpayload.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <inttypes.h>
35 #include <limits.h>
36 #include <errno.h>
38 /**
39 * Calculate the length of a fixed-size string.
41 * @param str The input string.
42 * @param maxlen Return at most maxlen characters as length of the string.
43 * @return The length of the string, not including the final NUL character.
44 * The maximum length returned is maxlen.
46 size_t strnlen(const char *str, size_t maxlen)
48 size_t len = 0;
50 /* NULL and empty strings have length 0. */
51 if (!str)
52 return 0;
54 /* Loop until we find a NUL character, or maxlen is reached. */
55 while ((*str++ != '\0') && (len < maxlen))
56 len++;
58 return len;
61 /**
62 * Calculate the length of a string.
64 * @param str The input string.
65 * @return The length of the string, not including the final NUL character.
67 size_t strlen(const char *str)
69 size_t len = 0;
71 /* NULL and empty strings have length 0. */
72 if (!str)
73 return 0;
75 /* Loop until we find a NUL character. */
76 while (*str++ != '\0')
77 len++;
79 return len;
82 /**
83 * Compare two strings.
85 * @param s1 The first string.
86 * @param s2 The second string.
87 * @return Returns a value less than zero, if s1 is shorter than s2. Returns
88 * zero, if s1 equals s2. Returns a value greater than zero, if
89 * s1 is longer than s2.
91 int strcasecmp(const char *s1, const char *s2)
93 int res;
95 for (size_t i = 0; 1; i++) {
96 res = tolower(s1[i]) - tolower(s2[i]);
97 if (res || (s1[i] == '\0'))
98 break;
101 return res;
105 * Compare two strings with fixed length.
107 * @param s1 The first string.
108 * @param s2 The second string.
109 * @param maxlen Return at most maxlen characters as length of the string.
110 * @return A non-zero value if s1 and s2 differ, or zero if s1 equals s2.
112 int strncasecmp(const char *s1, const char *s2, size_t maxlen)
114 int res = 0;
116 for (size_t i = 0; i < maxlen; i++) {
117 res = tolower(s1[i]) - tolower(s2[i]);
118 if (res || (s1[i] == '\0'))
119 break;
122 return res;
126 * Compare two strings.
128 * @param s1 The first string.
129 * @param s2 The second string.
130 * @return Returns a value less than zero, if s1 is shorter than s2. Returns
131 * zero, if s1 equals s2. Returns a value greater than zero, if
132 * s1 is longer than s2.
134 int strcmp(const char *s1, const char *s2)
136 int res;
138 for (size_t i = 0; 1; i++) {
139 res = s1[i] - s2[i];
140 if (res || (s1[i] == '\0'))
141 break;
144 return res;
148 * Compare two strings with fixed length.
150 * @param s1 The first string.
151 * @param s2 The second string.
152 * @param maxlen Return at most maxlen characters as length of the string.
153 * @return A non-zero value if s1 and s2 differ, or zero if s1 equals s2.
155 int strncmp(const char *s1, const char *s2, size_t maxlen)
157 int res = 0;
159 for (size_t i = 0; i < maxlen; i++) {
160 res = s1[i] - s2[i];
161 if (res || (s1[i] == '\0'))
162 break;
165 return res;
169 * Copy a string with a maximum length.
171 * @param d The destination memory.
172 * @param s The source string.
173 * @param n Copy at most n characters as length of the string.
174 * @return A pointer to the destination memory.
176 char *strncpy(char *d, const char *s, size_t n)
178 /* Use +1 to get the NUL terminator. */
179 size_t max = n > strlen(s) + 1 ? strlen(s) + 1 : n;
181 for (size_t i = 0; i < max; i++)
182 d[i] = (char)s[i];
184 return d;
188 * Copy a string.
190 * @param d The destination memory.
191 * @param s The source string.
192 * @return A pointer to the destination memory.
194 char *strcpy(char *d, const char *s)
196 return strncpy(d, s, strlen(s) + 1);
200 * Concatenates two strings
202 * @param d The destination string.
203 * @param s The source string.
204 * @return A pointer to the destination string.
206 char *strcat(char *d, const char *s)
208 char *p = d + strlen(d);
209 size_t sl = strlen(s);
211 for (size_t i = 0; i < sl; i++)
212 p[i] = s[i];
214 p[sl] = '\0';
215 return d;
219 * Concatenates two strings with a maximum length.
221 * @param d The destination string.
222 * @param s The source string.
223 * @param n Not more than n characters from s will be appended to d.
224 * @return A pointer to the destination string.
226 char *strncat(char *d, const char *s, size_t n)
228 char *p = d + strlen(d);
229 size_t sl = strlen(s);
230 size_t max = n > sl ? sl : n;
232 for (size_t i = 0; i < max; i++)
233 p[i] = s[i];
235 p[max] = '\0';
236 return d;
240 * Concatenates two strings with a maximum length.
242 * @param d The destination string.
243 * @param s The source string.
244 * @param n d will have at most n-1 characters (plus NUL) after invocation.
245 * @return The total length of the concatenated string.
247 size_t strlcat(char *d, const char *s, size_t n)
249 size_t sl = strlen(s);
250 size_t dl = strlen(d);
252 if (n <= dl + 1)
253 return sl + dl;
255 char *p = d + dl;
256 size_t max = n > (sl + dl) ? sl : (n - dl - 1);
258 for (size_t i = 0; i < max; i++)
259 p[i] = s[i];
261 p[max] = '\0';
262 return sl + dl;
266 * Find a character in a string.
268 * @param s The string.
269 * @param c The character.
270 * @return A pointer to the first occurrence of the character in the
271 * string, or NULL if the character was not encountered within the string.
273 char *strchr(const char *s, int c)
275 char *p = (char *)s;
277 for (; *p != 0; p++) {
278 if (*p == c)
279 return p;
282 return NULL;
286 * Find a character in a string.
288 * @param s The string.
289 * @param c The character.
290 * @return A pointer to the last occurrence of the character in the
291 * string, or NULL if the character was not encountered within the string.
294 char *strrchr(const char *s, int c)
296 char *p = (char *)s + strlen(s);
298 for (; p >= s; p--) {
299 if (*p == c)
300 return p;
303 return NULL;
307 * Duplicate a string.
309 * @param s The string to duplicate.
310 * @return A pointer to the copy of the original string.
312 char *strdup(const char *s)
314 size_t n = strlen(s);
315 char *p = malloc(n + 1);
317 if (p != NULL) {
318 strncpy(p, s, n);
319 p[n] = 0;
321 return p;
325 * Find a substring within a string.
327 * @param h The haystack string.
328 * @param n The needle string (substring).
329 * @return A pointer to the first occurrence of the substring in
330 * the string, or NULL if the substring was not encountered within the string.
332 char *strstr(const char *h, const char *n)
334 size_t hn = strlen(h);
335 size_t nn = strlen(n);
337 if (hn < nn)
338 return NULL;
340 for (size_t i = 0; i <= hn - nn; i++)
341 if (!memcmp(&h[i], n, nn))
342 return (char *)&h[i];
344 return NULL;
348 * Separate strings.
350 * @param stringp reference of the string to separate.
351 * @param delim string containing all delimiters.
352 * @return Token string.
354 char *strsep(char **stringp, const char *delim)
356 char *walk, *token;
358 if (!stringp || !*stringp || !**stringp)
359 return NULL;
361 token = walk = *stringp;
363 /* Walk, search for delimiters */
364 while (*walk && !strchr(delim, *walk))
365 walk++;
367 if (*walk) {
368 /* NUL terminate */
369 *walk = '\0';
370 walk++;
373 *stringp = walk;
375 return token;
378 /* Check that a character is in the valid range for the
379 given base
382 static int _valid(char ch, int base)
384 char end = (base > 9) ? '9' : '0' + (base - 1);
386 /* all bases will be some subset of the 0-9 range */
388 if (ch >= '0' && ch <= end)
389 return 1;
391 /* Bases > 11 will also have to match in the a-z range */
393 if (base > 11) {
394 if (tolower(ch) >= 'a' &&
395 tolower(ch) <= 'a' + (base - 11))
396 return 1;
399 return 0;
402 /* Return the "value" of the character in the given base */
404 static int _offset(char ch, int base)
406 if (ch >= '0' && ch <= '9')
407 return ch - '0';
408 else
409 return 10 + tolower(ch) - 'a';
413 * Convert the initial portion of a string into a signed int
414 * @param ptr A pointer to the string to convert
415 * @param endptr A pointer to the unconverted part of the string
416 * @param base The base of the number to convert, or 0 for auto
417 * @return A signed integer representation of the string
420 long long int strtoll(const char *orig_ptr, char **endptr, int base)
422 const char *ptr = orig_ptr;
423 int is_negative = 0;
425 /* Purge whitespace */
427 for ( ; *ptr && isspace(*ptr); ptr++);
429 if (ptr[0] == '-') {
430 is_negative = 1;
431 ptr++;
434 unsigned long long uval = strtoull(ptr, endptr, base);
436 /* If the whole string is unparseable, endptr should point to start. */
437 if (endptr && *endptr == ptr)
438 *endptr = (char *)orig_ptr;
440 if (uval > (unsigned long long)LLONG_MAX + !!is_negative)
441 uval = (unsigned long long)LLONG_MAX + !!is_negative;
443 if (is_negative)
444 return -uval;
445 else
446 return uval;
449 long int strtol(const char *ptr, char **endptr, int base)
451 long long int val = strtoll(ptr, endptr, base);
452 if (val > LONG_MAX)
453 return LONG_MAX;
454 if (val < LONG_MIN)
455 return LONG_MIN;
456 return val;
459 long atol(const char *nptr)
461 return strtol(nptr, NULL, 10);
465 * Convert the initial portion of a string into an unsigned int
466 * @param ptr A pointer to the string to convert
467 * @param endptr A pointer to the unconverted part of the string
468 * @param base The base of the number to convert, or 0 for auto
469 * @return An unsigned integer representation of the string
472 unsigned long long int strtoull(const char *ptr, char **endptr, int base)
474 unsigned long long int ret = 0;
476 if (endptr != NULL)
477 *endptr = (char *) ptr;
479 /* Purge whitespace */
481 for ( ; *ptr && isspace(*ptr); ptr++);
483 if (!*ptr)
484 return 0;
486 /* Determine the base */
488 if (base == 0) {
489 if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
490 base = 16;
491 else if (ptr[0] == '0') {
492 base = 8;
493 ptr++;
494 } else {
495 base = 10;
499 /* Base 16 allows the 0x on front - so skip over it */
501 if (base == 16) {
502 if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X') &&
503 _valid(ptr[2], base))
504 ptr += 2;
507 for ( ; *ptr && _valid(*ptr, base); ptr++)
508 ret = (ret * base) + _offset(*ptr, base);
510 if (endptr != NULL)
511 *endptr = (char *) ptr;
513 return ret;
516 unsigned long int strtoul(const char *ptr, char **endptr, int base)
518 unsigned long long val = strtoull(ptr, endptr, base);
519 if (val > ULONG_MAX)
520 return ULONG_MAX;
521 return val;
525 * Determine the number of leading characters in s that match characters in a
526 * @param s A pointer to the string to analyse
527 * @param a A pointer to an array of characters that match the prefix
528 * @return The number of matching characters
530 size_t strspn(const char *s, const char *a)
532 size_t i;
533 size_t al = strlen(a);
534 for (i = 0; s[i] != 0; i++) {
535 int found = 0;
536 for (size_t j = 0; j < al; j++) {
537 if (s[i] == a[j]) {
538 found = 1;
539 break;
542 if (!found)
543 break;
545 return i;
549 * Determine the number of leading characters in s that do not match characters in a
550 * @param s A pointer to the string to analyse
551 * @param a A pointer to an array of characters that do not match the prefix
552 * @return The number of not matching characters
554 size_t strcspn(const char *s, const char *a)
556 size_t i;
557 size_t al = strlen(a);
558 for (i = 0; s[i] != 0; i++) {
559 int found = 0;
560 for (size_t j = 0; j < al; j++) {
561 if (s[i] == a[j]) {
562 found = 1;
563 break;
566 if (found)
567 break;
569 return i;
573 * Extract first token in string str that is delimited by a character in tokens.
574 * Destroys str and eliminates the token delimiter.
575 * @param str A pointer to the string to tokenize.
576 * @param delim A pointer to an array of characters that delimit the token
577 * @param ptr A pointer to a string pointer to keep state of the tokenizer
578 * @return Pointer to token
580 char *strtok_r(char *str, const char *delim, char **ptr)
582 /* start new tokenizing job or continue existing one? */
583 if (str == NULL)
584 str = *ptr;
586 /* skip over prefix delimiters */
587 char *start = str + strspn(str, delim);
589 if (start[0] == '\0')
590 return NULL;
592 /* find first delimiter character */
593 char *end = start + strcspn(start, delim);
594 *ptr = end;
595 if (end[0] != '\0')
596 *(*ptr)++ = '\0';
598 return start;
602 * Extract first token in string str that is delimited by a character in tokens.
603 * Destroys str, eliminates the token delimiter and uses global state.
604 * @param str A pointer to the string to tokenize.
605 * @param delim A pointer to an array of characters that delimit the token
606 * @return Pointer to token
608 char *strtok(char *str, const char *delim)
610 static char *strtok_ptr;
612 return strtok_r(str, delim, &strtok_ptr);
616 * Print error message and error number
617 * @param s Error message to print
619 void perror(const char *s)
621 printf("%s: %d\n", s?s:"(none)", errno);
625 * Get a message string describing the given error number.
627 * @param errnum The error number to be interpreted
628 * @return A pointer to a string describing the given error number
630 char *strerror(int errnum)
632 /* Reserve enough space for the string below + INT64_MIN in decimal + \0 */
633 static char errstr[35];
634 snprintf(errstr, sizeof(errstr), "Unknown error %d", errnum);
635 return errstr;
639 * Simple routine to convert UTF-16 to ASCII, giving up with ? if too high.
640 * A single code point may convert to ?? if not in the BMP.
641 * @param utf16_string A string encoded in UTF-16LE
642 * @param maxlen Maximum possible length of the string in code points
643 * @return Newly allocated ASCII string
645 char *utf16le_to_ascii(const uint16_t *utf16_string, size_t maxlen)
647 char *ascii_string = xmalloc(maxlen + 1); /* +1 for trailing \0 */
648 ascii_string[maxlen] = '\0';
649 for (size_t i = 0; i < maxlen; i++) {
650 uint16_t wchar = utf16_string[i];
651 ascii_string[i] = wchar > 0x7f ? '?' : (char)wchar;
653 return ascii_string;