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