xref: /aosp_15_r20/external/coreboot/payloads/libpayload/libc/string.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2007 Uwe Hermann <[email protected]>
4  * Copyright (C) 2008 Advanced Micro Devices, Inc.
5  * Copyright (C) 2010 coresystems GmbH
6  *
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.
17  *
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.
29  */
30 
31 #include <libpayload.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <inttypes.h>
35 #include <limits.h>
36 #include <errno.h>
37 
38 /**
39  * Calculate the length of a fixed-size string.
40  *
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.
45  */
strnlen(const char * str,size_t maxlen)46 size_t strnlen(const char *str, size_t maxlen)
47 {
48 	size_t len = 0;
49 
50 	/* NULL and empty strings have length 0. */
51 	if (!str)
52 		return 0;
53 
54 	/* Loop until we find a NUL character, or maxlen is reached. */
55 	while ((*str++ != '\0') && (len < maxlen))
56 		len++;
57 
58 	return len;
59 }
60 
61 /**
62  * Calculate the length of a string.
63  *
64  * @param str The input string.
65  * @return The length of the string, not including the final NUL character.
66  */
strlen(const char * str)67 size_t strlen(const char *str)
68 {
69 	size_t len = 0;
70 
71 	/* NULL and empty strings have length 0. */
72 	if (!str)
73 		return 0;
74 
75 	/* Loop until we find a NUL character. */
76 	while (*str++ != '\0')
77 		len++;
78 
79 	return len;
80 }
81 
82 /**
83  * Compare two strings.
84  *
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.
90  */
strcasecmp(const char * s1,const char * s2)91 int strcasecmp(const char *s1, const char *s2)
92 {
93 	int res;
94 
95 	for (size_t i = 0; 1; i++) {
96 		res = tolower(s1[i]) - tolower(s2[i]);
97 		if (res || (s1[i] == '\0'))
98 			break;
99 	}
100 
101 	return res;
102 }
103 
104 /**
105  * Compare two strings with fixed length.
106  *
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.
111  */
strncasecmp(const char * s1,const char * s2,size_t maxlen)112 int strncasecmp(const char *s1, const char *s2, size_t maxlen)
113 {
114 	int res = 0;
115 
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;
120 	}
121 
122 	return res;
123 }
124 
125 /**
126  * Compare two strings.
127  *
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.
133  */
strcmp(const char * s1,const char * s2)134 int strcmp(const char *s1, const char *s2)
135 {
136 	int res;
137 
138 	for (size_t i = 0; 1; i++) {
139 		res = s1[i] - s2[i];
140 		if (res || (s1[i] == '\0'))
141 			break;
142 	}
143 
144 	return res;
145 }
146 
147 /**
148  * Compare two strings with fixed length.
149  *
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.
154  */
strncmp(const char * s1,const char * s2,size_t maxlen)155 int strncmp(const char *s1, const char *s2, size_t maxlen)
156 {
157 	int res = 0;
158 
159 	for (size_t i = 0; i < maxlen; i++) {
160 		res = s1[i] - s2[i];
161 		if (res || (s1[i] == '\0'))
162 			break;
163 	}
164 
165 	return res;
166 }
167 
168 /**
169  * Copy a string with a maximum length.
170  *
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.
175  */
strncpy(char * d,const char * s,size_t n)176 char *strncpy(char *d, const char *s, size_t n)
177 {
178 	/* Use +1 to get the NUL terminator. */
179 	size_t max = n > strlen(s) + 1 ? strlen(s) + 1 : n;
180 
181 	for (size_t i = 0; i < max; i++)
182 		d[i] = (char)s[i];
183 
184 	return d;
185 }
186 
187 /**
188  * Copy a string.
189  *
190  * @param d The destination memory.
191  * @param s The source string.
192  * @return A pointer to the destination memory.
193  */
strcpy(char * d,const char * s)194 char *strcpy(char *d, const char *s)
195 {
196 	return strncpy(d, s, strlen(s) + 1);
197 }
198 
199 /**
200  * Concatenates two strings
201  *
202  * @param d The destination string.
203  * @param s The source string.
204  * @return A pointer to the destination string.
205  */
strcat(char * d,const char * s)206 char *strcat(char *d, const char *s)
207 {
208 	char *p = d + strlen(d);
209 	size_t sl = strlen(s);
210 
211 	for (size_t i = 0; i < sl; i++)
212 		p[i] = s[i];
213 
214 	p[sl] = '\0';
215 	return d;
216 }
217 
218 /**
219  * Concatenates two strings with a maximum length.
220  *
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.
225  */
strncat(char * d,const char * s,size_t n)226 char *strncat(char *d, const char *s, size_t n)
227 {
228 	char *p = d + strlen(d);
229 	size_t sl = strlen(s);
230 	size_t max = n > sl ? sl : n;
231 
232 	for (size_t i = 0; i < max; i++)
233 		p[i] = s[i];
234 
235 	p[max] = '\0';
236 	return d;
237 }
238 
239 /**
240  * Concatenates two strings with a maximum length.
241  *
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.
246  */
strlcat(char * d,const char * s,size_t n)247 size_t strlcat(char *d, const char *s, size_t n)
248 {
249 	size_t sl = strlen(s);
250 	size_t dl = strlen(d);
251 
252 	if (n <= dl + 1)
253 		return sl + dl;
254 
255 	char *p = d + dl;
256 	size_t max = n > (sl + dl) ? sl : (n - dl - 1);
257 
258 	for (size_t i = 0; i < max; i++)
259 		p[i] = s[i];
260 
261 	p[max] = '\0';
262 	return sl + dl;
263 }
264 
265 /**
266  * Find a character in a string.
267  *
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.
272  */
strchr(const char * s,int c)273 char *strchr(const char *s, int c)
274 {
275 	char *p = (char *)s;
276 
277 	for (; *p != 0; p++) {
278 		if (*p == c)
279 			return p;
280 	}
281 
282 	return NULL;
283 }
284 
285 /**
286  * Find a character in a string.
287  *
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.
292  */
293 
strrchr(const char * s,int c)294 char *strrchr(const char *s, int c)
295 {
296 	char *p = (char *)s + strlen(s);
297 
298 	for (; p >= s; p--) {
299 		if (*p == c)
300 			return p;
301 	}
302 
303 	return NULL;
304 }
305 
306 /**
307  * Duplicate a string.
308  *
309  * @param s The string to duplicate.
310  * @return A pointer to the copy of the original string.
311  */
strdup(const char * s)312 char *strdup(const char *s)
313 {
314 	size_t n = strlen(s);
315 	char *p = malloc(n + 1);
316 
317 	if (p != NULL) {
318 		strncpy(p, s, n);
319 		p[n] = 0;
320 	}
321 	return p;
322 }
323 
324 /**
325  * Duplicate a string with a max length of size
326  *
327  * @param s The string to duplicate.
328  * @param size The max length of the string
329  * @return A pointer to the copy of the original string.
330  */
strndup(const char * s,size_t size)331 char *strndup(const char *s, size_t size)
332 {
333 	size_t n = strnlen(s, size);
334 	char *p = malloc(n + 1);
335 
336 	if (p != NULL) {
337 		strncpy(p, s, n);
338 		p[n] = 0;
339 	}
340 	return p;
341 }
342 
343 /**
344  * Find a substring within a string.
345  *
346  * @param h The haystack string.
347  * @param n The needle string (substring).
348  * @return A pointer to the first occurrence of the substring in
349  * the string, or NULL if the substring was not encountered within the string.
350  */
strstr(const char * h,const char * n)351 char *strstr(const char *h, const char *n)
352 {
353 	size_t hn = strlen(h);
354 	size_t nn = strlen(n);
355 
356 	if (hn < nn)
357 		return NULL;
358 
359 	for (size_t i = 0; i <= hn - nn; i++)
360 		if (!memcmp(&h[i], n, nn))
361 			return (char *)&h[i];
362 
363 	return NULL;
364 }
365 
366 /**
367  * Separate strings.
368  *
369  * @param stringp reference of the string to separate.
370  * @param delim string containing all delimiters.
371  * @return Token string.
372  */
strsep(char ** stringp,const char * delim)373 char *strsep(char **stringp, const char *delim)
374 {
375 	char *walk, *token;
376 
377 	if (!stringp || !*stringp || !**stringp)
378 		return NULL;
379 
380 	token = walk = *stringp;
381 
382 	/* Walk, search for delimiters */
383 	while (*walk && !strchr(delim, *walk))
384 		walk++;
385 
386 	if (*walk) {
387 		/* NUL terminate */
388 		*walk = '\0';
389 		walk++;
390 	}
391 
392 	*stringp = walk;
393 
394 	return token;
395 }
396 
397 /* Check that a character is in the valid range for the
398    given base
399 */
400 
_valid(char ch,int base)401 static int _valid(char ch, int base)
402 {
403 	char end = (base > 9) ? '9' : '0' + (base - 1);
404 
405 	/* all bases will be some subset of the 0-9 range */
406 
407 	if (ch >= '0' && ch <= end)
408 		return 1;
409 
410 	/* Bases > 11 will also have to match in the a-z range */
411 
412 	if (base > 11) {
413 		if (tolower(ch) >= 'a' &&
414 		    tolower(ch) <= 'a' + (base - 11))
415 			return 1;
416 	}
417 
418 	return 0;
419 }
420 
421 /* Return the "value" of the character in the given base */
422 
_offset(char ch,int base)423 static int _offset(char ch, int base)
424 {
425 	if (ch >= '0' && ch <= '9')
426 		return ch - '0';
427 	else
428 		return 10 + tolower(ch) - 'a';
429 }
430 
431 /**
432  * Convert the initial portion of a string into a signed int
433  * @param ptr A pointer to the string to convert
434  * @param endptr A pointer to the unconverted part of the string
435  * @param base The base of the number to convert, or 0 for auto
436  * @return A signed integer representation of the string
437  */
438 
strtoll(const char * orig_ptr,char ** endptr,int base)439 long long int strtoll(const char *orig_ptr, char **endptr, int base)
440 {
441 	const char *ptr = orig_ptr;
442 	int is_negative = 0;
443 
444 	/* Purge whitespace */
445 
446 	for ( ; *ptr && isspace(*ptr); ptr++);
447 
448 	if (ptr[0] == '-') {
449 		is_negative = 1;
450 		ptr++;
451 	}
452 
453 	unsigned long long uval = strtoull(ptr, endptr, base);
454 
455 	/* If the whole string is unparseable, endptr should point to start. */
456 	if (endptr && *endptr == ptr)
457 		*endptr = (char *)orig_ptr;
458 
459 	if (uval > (unsigned long long)LLONG_MAX + !!is_negative)
460 		uval = (unsigned long long)LLONG_MAX + !!is_negative;
461 
462 	if (is_negative)
463 		return -uval;
464 	else
465 		return uval;
466 }
467 
strtol(const char * ptr,char ** endptr,int base)468 long int strtol(const char *ptr, char **endptr, int base)
469 {
470 	long long int val = strtoll(ptr, endptr, base);
471 	if (val > LONG_MAX)
472 		return LONG_MAX;
473 	if (val < LONG_MIN)
474 		return LONG_MIN;
475 	return val;
476 }
477 
atol(const char * nptr)478 long atol(const char *nptr)
479 {
480 	return strtol(nptr, NULL, 10);
481 }
482 
483 /**
484  * Convert the initial portion of a string into an unsigned int
485  * @param ptr A pointer to the string to convert
486  * @param endptr A pointer to the unconverted part of the string
487  * @param base The base of the number to convert, or 0 for auto
488  * @return An unsigned integer representation of the string
489  */
490 
strtoull(const char * ptr,char ** endptr,int base)491 unsigned long long int strtoull(const char *ptr, char **endptr, int base)
492 {
493 	unsigned long long int ret = 0;
494 
495 	if (endptr != NULL)
496 		*endptr = (char *) ptr;
497 
498 	/* Purge whitespace */
499 
500 	for ( ; *ptr && isspace(*ptr); ptr++);
501 
502 	if (!*ptr)
503 		return 0;
504 
505 	/* Determine the base */
506 
507 	if (base == 0) {
508 		if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
509 			base = 16;
510 		else if (ptr[0] == '0') {
511 			base = 8;
512 			ptr++;
513 		} else {
514 			base = 10;
515 		}
516 	}
517 
518 	/* Base 16 allows the 0x on front - so skip over it */
519 
520 	if (base == 16) {
521 		if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X') &&
522 		    _valid(ptr[2], base))
523 			ptr += 2;
524 	}
525 
526 	for ( ; *ptr && _valid(*ptr, base); ptr++)
527 		ret = (ret * base) + _offset(*ptr, base);
528 
529 	if (endptr != NULL)
530 		*endptr = (char *) ptr;
531 
532 	return ret;
533 }
534 
strtoul(const char * ptr,char ** endptr,int base)535 unsigned long int strtoul(const char *ptr, char **endptr, int base)
536 {
537 	unsigned long long val = strtoull(ptr, endptr, base);
538 	if (val > ULONG_MAX)
539 		return ULONG_MAX;
540 	return val;
541 }
542 
543 /**
544  * Determine the number of leading characters in s that match characters in a
545  * @param s A pointer to the string to analyse
546  * @param a A pointer to an array of characters that match the prefix
547  * @return The number of matching characters
548  */
strspn(const char * s,const char * a)549 size_t strspn(const char *s, const char *a)
550 {
551 	size_t i;
552 	size_t al = strlen(a);
553 	for (i = 0; s[i] != 0; i++) {
554 		int found = 0;
555 		for (size_t j = 0; j < al; j++) {
556 			if (s[i] == a[j]) {
557 				found = 1;
558 				break;
559 			}
560 		}
561 		if (!found)
562 			break;
563 	}
564 	return i;
565 }
566 
567 /**
568  * Determine the number of leading characters in s that do not match characters in a
569  * @param s A pointer to the string to analyse
570  * @param a A pointer to an array of characters that do not match the prefix
571  * @return The number of not matching characters
572  */
strcspn(const char * s,const char * a)573 size_t strcspn(const char *s, const char *a)
574 {
575 	size_t i;
576 	size_t al = strlen(a);
577 	for (i = 0; s[i] != 0; i++) {
578 		int found = 0;
579 		for (size_t j = 0; j < al; j++) {
580 			if (s[i] == a[j]) {
581 				found = 1;
582 				break;
583 			}
584 		}
585 		if (found)
586 			break;
587 	}
588 	return i;
589 }
590 
591 /**
592  * Extract first token in string str that is delimited by a character in tokens.
593  * Destroys str and eliminates the token delimiter.
594  * @param str A pointer to the string to tokenize.
595  * @param delim A pointer to an array of characters that delimit the token
596  * @param ptr A pointer to a string pointer to keep state of the tokenizer
597  * @return Pointer to token
598  */
strtok_r(char * str,const char * delim,char ** ptr)599 char *strtok_r(char *str, const char *delim, char **ptr)
600 {
601 	/* start new tokenizing job or continue existing one? */
602 	if (str == NULL)
603 		str = *ptr;
604 
605 	/* skip over prefix delimiters */
606 	char *start = str + strspn(str, delim);
607 
608 	if (start[0] == '\0')
609 		return NULL;
610 
611 	/* find first delimiter character */
612 	char *end = start + strcspn(start, delim);
613 	*ptr = end;
614 	if (end[0] != '\0')
615 		*(*ptr)++ = '\0';
616 
617 	return start;
618 }
619 
620 /**
621  * Extract first token in string str that is delimited by a character in tokens.
622  * Destroys str, eliminates the token delimiter and uses global state.
623  * @param str A pointer to the string to tokenize.
624  * @param delim A pointer to an array of characters that delimit the token
625  * @return Pointer to token
626  */
strtok(char * str,const char * delim)627 char *strtok(char *str, const char *delim)
628 {
629 	static char *strtok_ptr;
630 
631 	return strtok_r(str, delim, &strtok_ptr);
632 }
633 
634 /**
635  * Print error message and error number
636  * @param s Error message to print
637  */
perror(const char * s)638 void perror(const char *s)
639 {
640 	printf("%s: %d\n", s?s:"(none)", errno);
641 }
642 
643 /**
644  * Get a message string describing the given error number.
645  *
646  * @param errnum The error number to be interpreted
647  * @return A pointer to a string describing the given error number
648  */
strerror(int errnum)649 char *strerror(int errnum)
650 {
651 	/* Reserve enough space for the string below + INT64_MIN in decimal + \0 */
652 	static char errstr[35];
653 	snprintf(errstr, sizeof(errstr), "Unknown error %d", errnum);
654 	return errstr;
655 }
656 
657 /*
658  * Simple routine to convert UTF-16 to ASCII, giving up with ? if too high.
659  * A single code point may convert to ?? if not in the BMP.
660  * @param utf16_string A string encoded in UTF-16LE
661  * @param maxlen Maximum possible length of the string in code points
662  * @return Newly allocated ASCII string
663  */
utf16le_to_ascii(const uint16_t * utf16_string,size_t maxlen)664 char *utf16le_to_ascii(const uint16_t *utf16_string, size_t maxlen)
665 {
666 	char *ascii_string = xmalloc(maxlen + 1);  /* +1 for trailing \0 */
667 	ascii_string[maxlen] = '\0';
668 	for (size_t i = 0; i < maxlen; i++) {
669 		uint16_t wchar = utf16_string[i];
670 		ascii_string[i] = wchar > 0x7f ? '?' : (char)wchar;
671 	}
672 	return ascii_string;
673 }
674