xref: /openbmc/linux/tools/include/nolibc/stdlib.h (revision 67d108e2)
106fdba53SWilly Tarreau /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
206fdba53SWilly Tarreau /*
306fdba53SWilly Tarreau  * stdlib function definitions for NOLIBC
406fdba53SWilly Tarreau  * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
506fdba53SWilly Tarreau  */
606fdba53SWilly Tarreau 
706fdba53SWilly Tarreau #ifndef _NOLIBC_STDLIB_H
806fdba53SWilly Tarreau #define _NOLIBC_STDLIB_H
906fdba53SWilly Tarreau 
1006fdba53SWilly Tarreau #include "std.h"
1106fdba53SWilly Tarreau #include "arch.h"
1206fdba53SWilly Tarreau #include "types.h"
1306fdba53SWilly Tarreau #include "sys.h"
140e0ff638SAmmar Faizi #include "string.h"
15c61a0780SAmmar Faizi #include <linux/auxvec.h>
1606fdba53SWilly Tarreau 
170e0ff638SAmmar Faizi struct nolibc_heap {
180e0ff638SAmmar Faizi 	size_t	len;
190e0ff638SAmmar Faizi 	char	user_p[] __attribute__((__aligned__));
200e0ff638SAmmar Faizi };
2166c397c4SWilly Tarreau 
2266c397c4SWilly Tarreau /* Buffer used to store int-to-ASCII conversions. Will only be implemented if
2366c397c4SWilly Tarreau  * any of the related functions is implemented. The area is large enough to
2466c397c4SWilly Tarreau  * store "18446744073709551615" or "-9223372036854775808" and the final zero.
2566c397c4SWilly Tarreau  */
2666c397c4SWilly Tarreau static __attribute__((unused)) char itoa_buffer[21];
2766c397c4SWilly Tarreau 
2806fdba53SWilly Tarreau /*
2906fdba53SWilly Tarreau  * As much as possible, please keep functions alphabetically sorted.
3006fdba53SWilly Tarreau  */
3106fdba53SWilly Tarreau 
32f0f04f28SWilly Tarreau /* must be exported, as it's used by libgcc for various divide functions */
33f0f04f28SWilly Tarreau __attribute__((weak,unused,noreturn,section(".text.nolibc_abort")))
abort(void)34f0f04f28SWilly Tarreau void abort(void)
35f0f04f28SWilly Tarreau {
36f0f04f28SWilly Tarreau 	sys_kill(sys_getpid(), SIGABRT);
37f0f04f28SWilly Tarreau 	for (;;);
38f0f04f28SWilly Tarreau }
39f0f04f28SWilly Tarreau 
4006fdba53SWilly Tarreau static __attribute__((unused))
atol(const char * s)4106fdba53SWilly Tarreau long atol(const char *s)
4206fdba53SWilly Tarreau {
4306fdba53SWilly Tarreau 	unsigned long ret = 0;
4406fdba53SWilly Tarreau 	unsigned long d;
4506fdba53SWilly Tarreau 	int neg = 0;
4606fdba53SWilly Tarreau 
4706fdba53SWilly Tarreau 	if (*s == '-') {
4806fdba53SWilly Tarreau 		neg = 1;
4906fdba53SWilly Tarreau 		s++;
5006fdba53SWilly Tarreau 	}
5106fdba53SWilly Tarreau 
5206fdba53SWilly Tarreau 	while (1) {
5306fdba53SWilly Tarreau 		d = (*s++) - '0';
5406fdba53SWilly Tarreau 		if (d > 9)
5506fdba53SWilly Tarreau 			break;
5606fdba53SWilly Tarreau 		ret *= 10;
5706fdba53SWilly Tarreau 		ret += d;
5806fdba53SWilly Tarreau 	}
5906fdba53SWilly Tarreau 
6006fdba53SWilly Tarreau 	return neg ? -ret : ret;
6106fdba53SWilly Tarreau }
6206fdba53SWilly Tarreau 
6306fdba53SWilly Tarreau static __attribute__((unused))
atoi(const char * s)6406fdba53SWilly Tarreau int atoi(const char *s)
6506fdba53SWilly Tarreau {
6606fdba53SWilly Tarreau 	return atol(s);
6706fdba53SWilly Tarreau }
6806fdba53SWilly Tarreau 
690e0ff638SAmmar Faizi static __attribute__((unused))
free(void * ptr)700e0ff638SAmmar Faizi void free(void *ptr)
710e0ff638SAmmar Faizi {
720e0ff638SAmmar Faizi 	struct nolibc_heap *heap;
730e0ff638SAmmar Faizi 
740e0ff638SAmmar Faizi 	if (!ptr)
750e0ff638SAmmar Faizi 		return;
760e0ff638SAmmar Faizi 
770e0ff638SAmmar Faizi 	heap = container_of(ptr, struct nolibc_heap, user_p);
780e0ff638SAmmar Faizi 	munmap(heap, heap->len);
790e0ff638SAmmar Faizi }
800e0ff638SAmmar Faizi 
812475d37aSWilly Tarreau /* getenv() tries to find the environment variable named <name> in the
822475d37aSWilly Tarreau  * environment array pointed to by global variable "environ" which must be
832475d37aSWilly Tarreau  * declared as a char **, and must be terminated by a NULL (it is recommended
842475d37aSWilly Tarreau  * to set this variable to the "envp" argument of main()). If the requested
852475d37aSWilly Tarreau  * environment variable exists its value is returned otherwise NULL is
86*67d108e2SThomas Weißschuh  * returned.
87077d0a39SWilly Tarreau  */
88077d0a39SWilly Tarreau static __attribute__((unused))
getenv(const char * name)89*67d108e2SThomas Weißschuh char *getenv(const char *name)
90077d0a39SWilly Tarreau {
91077d0a39SWilly Tarreau 	int idx, i;
92077d0a39SWilly Tarreau 
93077d0a39SWilly Tarreau 	if (environ) {
94077d0a39SWilly Tarreau 		for (idx = 0; environ[idx]; idx++) {
95077d0a39SWilly Tarreau 			for (i = 0; name[i] && name[i] == environ[idx][i];)
96077d0a39SWilly Tarreau 				i++;
97077d0a39SWilly Tarreau 			if (!name[i] && environ[idx][i] == '=')
98077d0a39SWilly Tarreau 				return &environ[idx][i+1];
99077d0a39SWilly Tarreau 		}
100077d0a39SWilly Tarreau 	}
101077d0a39SWilly Tarreau 	return NULL;
102077d0a39SWilly Tarreau }
103077d0a39SWilly Tarreau 
1040e0ff638SAmmar Faizi static __attribute__((unused))
getauxval(unsigned long type)105c61a0780SAmmar Faizi unsigned long getauxval(unsigned long type)
106c61a0780SAmmar Faizi {
107c61a0780SAmmar Faizi 	const unsigned long *auxv = _auxv;
108c61a0780SAmmar Faizi 	unsigned long ret;
109c61a0780SAmmar Faizi 
110c61a0780SAmmar Faizi 	if (!auxv)
111c61a0780SAmmar Faizi 		return 0;
112c61a0780SAmmar Faizi 
113c61a0780SAmmar Faizi 	while (1) {
114c61a0780SAmmar Faizi 		if (!auxv[0] && !auxv[1]) {
115c61a0780SAmmar Faizi 			ret = 0;
116c61a0780SAmmar Faizi 			break;
117c61a0780SAmmar Faizi 		}
118c61a0780SAmmar Faizi 
119c61a0780SAmmar Faizi 		if (auxv[0] == type) {
120c61a0780SAmmar Faizi 			ret = auxv[1];
121c61a0780SAmmar Faizi 			break;
122c61a0780SAmmar Faizi 		}
123c61a0780SAmmar Faizi 
124c61a0780SAmmar Faizi 		auxv += 2;
125c61a0780SAmmar Faizi 	}
126c61a0780SAmmar Faizi 
127c61a0780SAmmar Faizi 	return ret;
128c61a0780SAmmar Faizi }
129c61a0780SAmmar Faizi 
130c61a0780SAmmar Faizi static __attribute__((unused))
malloc(size_t len)1310e0ff638SAmmar Faizi void *malloc(size_t len)
1320e0ff638SAmmar Faizi {
1330e0ff638SAmmar Faizi 	struct nolibc_heap *heap;
1340e0ff638SAmmar Faizi 
1350e0ff638SAmmar Faizi 	/* Always allocate memory with size multiple of 4096. */
1360e0ff638SAmmar Faizi 	len  = sizeof(*heap) + len;
1370e0ff638SAmmar Faizi 	len  = (len + 4095UL) & -4096UL;
1380e0ff638SAmmar Faizi 	heap = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE,
1390e0ff638SAmmar Faizi 		    -1, 0);
1400e0ff638SAmmar Faizi 	if (__builtin_expect(heap == MAP_FAILED, 0))
1410e0ff638SAmmar Faizi 		return NULL;
1420e0ff638SAmmar Faizi 
1430e0ff638SAmmar Faizi 	heap->len = len;
1440e0ff638SAmmar Faizi 	return heap->user_p;
1450e0ff638SAmmar Faizi }
1460e0ff638SAmmar Faizi 
1470e0ff638SAmmar Faizi static __attribute__((unused))
calloc(size_t size,size_t nmemb)1480e0ff638SAmmar Faizi void *calloc(size_t size, size_t nmemb)
1490e0ff638SAmmar Faizi {
1501ef150cfSAmmar Faizi 	size_t x = size * nmemb;
1510e0ff638SAmmar Faizi 
1521ef150cfSAmmar Faizi 	if (__builtin_expect(size && ((x / size) != nmemb), 0)) {
1530e0ff638SAmmar Faizi 		SET_ERRNO(ENOMEM);
1540e0ff638SAmmar Faizi 		return NULL;
1550e0ff638SAmmar Faizi 	}
1560e0ff638SAmmar Faizi 
1570e0ff638SAmmar Faizi 	/*
1580e0ff638SAmmar Faizi 	 * No need to zero the heap, the MAP_ANONYMOUS in malloc()
1590e0ff638SAmmar Faizi 	 * already does it.
1600e0ff638SAmmar Faizi 	 */
1611ef150cfSAmmar Faizi 	return malloc(x);
1620e0ff638SAmmar Faizi }
1630e0ff638SAmmar Faizi 
1640e0ff638SAmmar Faizi static __attribute__((unused))
realloc(void * old_ptr,size_t new_size)1650e0ff638SAmmar Faizi void *realloc(void *old_ptr, size_t new_size)
1660e0ff638SAmmar Faizi {
1670e0ff638SAmmar Faizi 	struct nolibc_heap *heap;
1680e0ff638SAmmar Faizi 	size_t user_p_len;
1690e0ff638SAmmar Faizi 	void *ret;
1700e0ff638SAmmar Faizi 
1710e0ff638SAmmar Faizi 	if (!old_ptr)
1720e0ff638SAmmar Faizi 		return malloc(new_size);
1730e0ff638SAmmar Faizi 
1740e0ff638SAmmar Faizi 	heap = container_of(old_ptr, struct nolibc_heap, user_p);
1750e0ff638SAmmar Faizi 	user_p_len = heap->len - sizeof(*heap);
1760e0ff638SAmmar Faizi 	/*
1770e0ff638SAmmar Faizi 	 * Don't realloc() if @user_p_len >= @new_size, this block of
1780e0ff638SAmmar Faizi 	 * memory is still enough to handle the @new_size. Just return
1790e0ff638SAmmar Faizi 	 * the same pointer.
1800e0ff638SAmmar Faizi 	 */
1810e0ff638SAmmar Faizi 	if (user_p_len >= new_size)
1820e0ff638SAmmar Faizi 		return old_ptr;
1830e0ff638SAmmar Faizi 
1840e0ff638SAmmar Faizi 	ret = malloc(new_size);
1850e0ff638SAmmar Faizi 	if (__builtin_expect(!ret, 0))
1860e0ff638SAmmar Faizi 		return NULL;
1870e0ff638SAmmar Faizi 
1880e0ff638SAmmar Faizi 	memcpy(ret, heap->user_p, heap->len);
1890e0ff638SAmmar Faizi 	munmap(heap, heap->len);
1900e0ff638SAmmar Faizi 	return ret;
1910e0ff638SAmmar Faizi }
1920e0ff638SAmmar Faizi 
1935f493178SWilly Tarreau /* Converts the unsigned long integer <in> to its hex representation into
1945f493178SWilly Tarreau  * buffer <buffer>, which must be long enough to store the number and the
1955f493178SWilly Tarreau  * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The
1965f493178SWilly Tarreau  * buffer is filled from the first byte, and the number of characters emitted
1975f493178SWilly Tarreau  * (not counting the trailing zero) is returned. The function is constructed
1985f493178SWilly Tarreau  * in a way to optimize the code size and avoid any divide that could add a
1995f493178SWilly Tarreau  * dependency on large external functions.
2005f493178SWilly Tarreau  */
2015f493178SWilly Tarreau static __attribute__((unused))
utoh_r(unsigned long in,char * buffer)2025f493178SWilly Tarreau int utoh_r(unsigned long in, char *buffer)
2035f493178SWilly Tarreau {
2045f493178SWilly Tarreau 	signed char pos = (~0UL > 0xfffffffful) ? 60 : 28;
2055f493178SWilly Tarreau 	int digits = 0;
2065f493178SWilly Tarreau 	int dig;
2075f493178SWilly Tarreau 
2085f493178SWilly Tarreau 	do {
2095f493178SWilly Tarreau 		dig = in >> pos;
2105f493178SWilly Tarreau 		in -= (uint64_t)dig << pos;
2115f493178SWilly Tarreau 		pos -= 4;
2125f493178SWilly Tarreau 		if (dig || digits || pos < 0) {
2135f493178SWilly Tarreau 			if (dig > 9)
2145f493178SWilly Tarreau 				dig += 'a' - '0' - 10;
2155f493178SWilly Tarreau 			buffer[digits++] = '0' + dig;
2165f493178SWilly Tarreau 		}
2175f493178SWilly Tarreau 	} while (pos >= 0);
2185f493178SWilly Tarreau 
2195f493178SWilly Tarreau 	buffer[digits] = 0;
2205f493178SWilly Tarreau 	return digits;
2215f493178SWilly Tarreau }
2225f493178SWilly Tarreau 
2235f493178SWilly Tarreau /* converts unsigned long <in> to an hex string using the static itoa_buffer
2245f493178SWilly Tarreau  * and returns the pointer to that string.
2255f493178SWilly Tarreau  */
2260738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
utoh(unsigned long in)2275f493178SWilly Tarreau char *utoh(unsigned long in)
2285f493178SWilly Tarreau {
2295f493178SWilly Tarreau 	utoh_r(in, itoa_buffer);
2305f493178SWilly Tarreau 	return itoa_buffer;
2315f493178SWilly Tarreau }
2325f493178SWilly Tarreau 
23366c397c4SWilly Tarreau /* Converts the unsigned long integer <in> to its string representation into
23466c397c4SWilly Tarreau  * buffer <buffer>, which must be long enough to store the number and the
23566c397c4SWilly Tarreau  * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for
23666c397c4SWilly Tarreau  * 4294967295 in 32-bit). The buffer is filled from the first byte, and the
23766c397c4SWilly Tarreau  * number of characters emitted (not counting the trailing zero) is returned.
23866c397c4SWilly Tarreau  * The function is constructed in a way to optimize the code size and avoid
23966c397c4SWilly Tarreau  * any divide that could add a dependency on large external functions.
24056d68a3cSWilly Tarreau  */
24156d68a3cSWilly Tarreau static __attribute__((unused))
utoa_r(unsigned long in,char * buffer)24266c397c4SWilly Tarreau int utoa_r(unsigned long in, char *buffer)
24356d68a3cSWilly Tarreau {
24466c397c4SWilly Tarreau 	unsigned long lim;
24566c397c4SWilly Tarreau 	int digits = 0;
24666c397c4SWilly Tarreau 	int pos = (~0UL > 0xfffffffful) ? 19 : 9;
24766c397c4SWilly Tarreau 	int dig;
24856d68a3cSWilly Tarreau 
24956d68a3cSWilly Tarreau 	do {
25066c397c4SWilly Tarreau 		for (dig = 0, lim = 1; dig < pos; dig++)
25166c397c4SWilly Tarreau 			lim *= 10;
25256d68a3cSWilly Tarreau 
25366c397c4SWilly Tarreau 		if (digits || in >= lim || !pos) {
25466c397c4SWilly Tarreau 			for (dig = 0; in >= lim; dig++)
25566c397c4SWilly Tarreau 				in -= lim;
25666c397c4SWilly Tarreau 			buffer[digits++] = '0' + dig;
25766c397c4SWilly Tarreau 		}
25866c397c4SWilly Tarreau 	} while (pos--);
25966c397c4SWilly Tarreau 
26066c397c4SWilly Tarreau 	buffer[digits] = 0;
26166c397c4SWilly Tarreau 	return digits;
26256d68a3cSWilly Tarreau }
26356d68a3cSWilly Tarreau 
26466c397c4SWilly Tarreau /* Converts the signed long integer <in> to its string representation into
26566c397c4SWilly Tarreau  * buffer <buffer>, which must be long enough to store the number and the
26666c397c4SWilly Tarreau  * trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for
26766c397c4SWilly Tarreau  * -2147483648 in 32-bit). The buffer is filled from the first byte, and the
26866c397c4SWilly Tarreau  * number of characters emitted (not counting the trailing zero) is returned.
26966c397c4SWilly Tarreau  */
27056d68a3cSWilly Tarreau static __attribute__((unused))
itoa_r(long in,char * buffer)27166c397c4SWilly Tarreau int itoa_r(long in, char *buffer)
27256d68a3cSWilly Tarreau {
27366c397c4SWilly Tarreau 	char *ptr = buffer;
27466c397c4SWilly Tarreau 	int len = 0;
27566c397c4SWilly Tarreau 
27666c397c4SWilly Tarreau 	if (in < 0) {
27766c397c4SWilly Tarreau 		in = -in;
27866c397c4SWilly Tarreau 		*(ptr++) = '-';
27966c397c4SWilly Tarreau 		len++;
28066c397c4SWilly Tarreau 	}
28166c397c4SWilly Tarreau 	len += utoa_r(in, ptr);
28266c397c4SWilly Tarreau 	return len;
28366c397c4SWilly Tarreau }
28466c397c4SWilly Tarreau 
28566c397c4SWilly Tarreau /* for historical compatibility, same as above but returns the pointer to the
28666c397c4SWilly Tarreau  * buffer.
28766c397c4SWilly Tarreau  */
2880738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
ltoa_r(long in,char * buffer)28966c397c4SWilly Tarreau char *ltoa_r(long in, char *buffer)
29066c397c4SWilly Tarreau {
29166c397c4SWilly Tarreau 	itoa_r(in, buffer);
29266c397c4SWilly Tarreau 	return buffer;
29366c397c4SWilly Tarreau }
29466c397c4SWilly Tarreau 
29566c397c4SWilly Tarreau /* converts long integer <in> to a string using the static itoa_buffer and
29666c397c4SWilly Tarreau  * returns the pointer to that string.
29766c397c4SWilly Tarreau  */
2980738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
itoa(long in)29966c397c4SWilly Tarreau char *itoa(long in)
30066c397c4SWilly Tarreau {
30166c397c4SWilly Tarreau 	itoa_r(in, itoa_buffer);
30266c397c4SWilly Tarreau 	return itoa_buffer;
30366c397c4SWilly Tarreau }
30466c397c4SWilly Tarreau 
30566c397c4SWilly Tarreau /* converts long integer <in> to a string using the static itoa_buffer and
30666c397c4SWilly Tarreau  * returns the pointer to that string. Same as above, for compatibility.
30766c397c4SWilly Tarreau  */
3080738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
ltoa(long in)30966c397c4SWilly Tarreau char *ltoa(long in)
31066c397c4SWilly Tarreau {
31166c397c4SWilly Tarreau 	itoa_r(in, itoa_buffer);
31266c397c4SWilly Tarreau 	return itoa_buffer;
31366c397c4SWilly Tarreau }
31466c397c4SWilly Tarreau 
31566c397c4SWilly Tarreau /* converts unsigned long integer <in> to a string using the static itoa_buffer
31666c397c4SWilly Tarreau  * and returns the pointer to that string.
31766c397c4SWilly Tarreau  */
3180738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
utoa(unsigned long in)31966c397c4SWilly Tarreau char *utoa(unsigned long in)
32066c397c4SWilly Tarreau {
32166c397c4SWilly Tarreau 	utoa_r(in, itoa_buffer);
32266c397c4SWilly Tarreau 	return itoa_buffer;
32356d68a3cSWilly Tarreau }
32456d68a3cSWilly Tarreau 
3255f493178SWilly Tarreau /* Converts the unsigned 64-bit integer <in> to its hex representation into
3265f493178SWilly Tarreau  * buffer <buffer>, which must be long enough to store the number and the
3275f493178SWilly Tarreau  * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from
3285f493178SWilly Tarreau  * the first byte, and the number of characters emitted (not counting the
3295f493178SWilly Tarreau  * trailing zero) is returned. The function is constructed in a way to optimize
3305f493178SWilly Tarreau  * the code size and avoid any divide that could add a dependency on large
3315f493178SWilly Tarreau  * external functions.
3325f493178SWilly Tarreau  */
3335f493178SWilly Tarreau static __attribute__((unused))
u64toh_r(uint64_t in,char * buffer)3345f493178SWilly Tarreau int u64toh_r(uint64_t in, char *buffer)
3355f493178SWilly Tarreau {
3365f493178SWilly Tarreau 	signed char pos = 60;
3375f493178SWilly Tarreau 	int digits = 0;
3385f493178SWilly Tarreau 	int dig;
3395f493178SWilly Tarreau 
3405f493178SWilly Tarreau 	do {
341ac90226dSWilly Tarreau 		if (sizeof(long) >= 8) {
342ac90226dSWilly Tarreau 			dig = (in >> pos) & 0xF;
343ac90226dSWilly Tarreau 		} else {
344ac90226dSWilly Tarreau 			/* 32-bit platforms: avoid a 64-bit shift */
345ac90226dSWilly Tarreau 			uint32_t d = (pos >= 32) ? (in >> 32) : in;
346ac90226dSWilly Tarreau 			dig = (d >> (pos & 31)) & 0xF;
347ac90226dSWilly Tarreau 		}
3485f493178SWilly Tarreau 		if (dig > 9)
3495f493178SWilly Tarreau 			dig += 'a' - '0' - 10;
350ac90226dSWilly Tarreau 		pos -= 4;
351ac90226dSWilly Tarreau 		if (dig || digits || pos < 0)
3525f493178SWilly Tarreau 			buffer[digits++] = '0' + dig;
3535f493178SWilly Tarreau 	} while (pos >= 0);
3545f493178SWilly Tarreau 
3555f493178SWilly Tarreau 	buffer[digits] = 0;
3565f493178SWilly Tarreau 	return digits;
3575f493178SWilly Tarreau }
3585f493178SWilly Tarreau 
3595f493178SWilly Tarreau /* converts uint64_t <in> to an hex string using the static itoa_buffer and
3605f493178SWilly Tarreau  * returns the pointer to that string.
3615f493178SWilly Tarreau  */
3620738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
u64toh(uint64_t in)3635f493178SWilly Tarreau char *u64toh(uint64_t in)
3645f493178SWilly Tarreau {
3655f493178SWilly Tarreau 	u64toh_r(in, itoa_buffer);
3665f493178SWilly Tarreau 	return itoa_buffer;
3675f493178SWilly Tarreau }
3685f493178SWilly Tarreau 
369b1c21e7dSWilly Tarreau /* Converts the unsigned 64-bit integer <in> to its string representation into
370b1c21e7dSWilly Tarreau  * buffer <buffer>, which must be long enough to store the number and the
371b1c21e7dSWilly Tarreau  * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from
372b1c21e7dSWilly Tarreau  * the first byte, and the number of characters emitted (not counting the
373b1c21e7dSWilly Tarreau  * trailing zero) is returned. The function is constructed in a way to optimize
374b1c21e7dSWilly Tarreau  * the code size and avoid any divide that could add a dependency on large
375b1c21e7dSWilly Tarreau  * external functions.
376b1c21e7dSWilly Tarreau  */
377b1c21e7dSWilly Tarreau static __attribute__((unused))
u64toa_r(uint64_t in,char * buffer)378b1c21e7dSWilly Tarreau int u64toa_r(uint64_t in, char *buffer)
379b1c21e7dSWilly Tarreau {
380b1c21e7dSWilly Tarreau 	unsigned long long lim;
381b1c21e7dSWilly Tarreau 	int digits = 0;
382b1c21e7dSWilly Tarreau 	int pos = 19; /* start with the highest possible digit */
383b1c21e7dSWilly Tarreau 	int dig;
384b1c21e7dSWilly Tarreau 
385b1c21e7dSWilly Tarreau 	do {
386b1c21e7dSWilly Tarreau 		for (dig = 0, lim = 1; dig < pos; dig++)
387b1c21e7dSWilly Tarreau 			lim *= 10;
388b1c21e7dSWilly Tarreau 
389b1c21e7dSWilly Tarreau 		if (digits || in >= lim || !pos) {
390b1c21e7dSWilly Tarreau 			for (dig = 0; in >= lim; dig++)
391b1c21e7dSWilly Tarreau 				in -= lim;
392b1c21e7dSWilly Tarreau 			buffer[digits++] = '0' + dig;
393b1c21e7dSWilly Tarreau 		}
394b1c21e7dSWilly Tarreau 	} while (pos--);
395b1c21e7dSWilly Tarreau 
396b1c21e7dSWilly Tarreau 	buffer[digits] = 0;
397b1c21e7dSWilly Tarreau 	return digits;
398b1c21e7dSWilly Tarreau }
399b1c21e7dSWilly Tarreau 
400b1c21e7dSWilly Tarreau /* Converts the signed 64-bit integer <in> to its string representation into
401b1c21e7dSWilly Tarreau  * buffer <buffer>, which must be long enough to store the number and the
402b1c21e7dSWilly Tarreau  * trailing zero (21 bytes for -9223372036854775808). The buffer is filled from
403b1c21e7dSWilly Tarreau  * the first byte, and the number of characters emitted (not counting the
404b1c21e7dSWilly Tarreau  * trailing zero) is returned.
405b1c21e7dSWilly Tarreau  */
406b1c21e7dSWilly Tarreau static __attribute__((unused))
i64toa_r(int64_t in,char * buffer)407b1c21e7dSWilly Tarreau int i64toa_r(int64_t in, char *buffer)
408b1c21e7dSWilly Tarreau {
409b1c21e7dSWilly Tarreau 	char *ptr = buffer;
410b1c21e7dSWilly Tarreau 	int len = 0;
411b1c21e7dSWilly Tarreau 
412b1c21e7dSWilly Tarreau 	if (in < 0) {
413b1c21e7dSWilly Tarreau 		in = -in;
414b1c21e7dSWilly Tarreau 		*(ptr++) = '-';
415b1c21e7dSWilly Tarreau 		len++;
416b1c21e7dSWilly Tarreau 	}
417b1c21e7dSWilly Tarreau 	len += u64toa_r(in, ptr);
418b1c21e7dSWilly Tarreau 	return len;
419b1c21e7dSWilly Tarreau }
420b1c21e7dSWilly Tarreau 
421b1c21e7dSWilly Tarreau /* converts int64_t <in> to a string using the static itoa_buffer and returns
422b1c21e7dSWilly Tarreau  * the pointer to that string.
423b1c21e7dSWilly Tarreau  */
4240738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
i64toa(int64_t in)425b1c21e7dSWilly Tarreau char *i64toa(int64_t in)
426b1c21e7dSWilly Tarreau {
427b1c21e7dSWilly Tarreau 	i64toa_r(in, itoa_buffer);
428b1c21e7dSWilly Tarreau 	return itoa_buffer;
429b1c21e7dSWilly Tarreau }
430b1c21e7dSWilly Tarreau 
431b1c21e7dSWilly Tarreau /* converts uint64_t <in> to a string using the static itoa_buffer and returns
432b1c21e7dSWilly Tarreau  * the pointer to that string.
433b1c21e7dSWilly Tarreau  */
4340738c2d7SThomas Weißschuh static __inline__ __attribute__((unused))
u64toa(uint64_t in)435b1c21e7dSWilly Tarreau char *u64toa(uint64_t in)
436b1c21e7dSWilly Tarreau {
437b1c21e7dSWilly Tarreau 	u64toa_r(in, itoa_buffer);
438b1c21e7dSWilly Tarreau 	return itoa_buffer;
439b1c21e7dSWilly Tarreau }
440b1c21e7dSWilly Tarreau 
44155abdd1fSWilly Tarreau /* make sure to include all global symbols */
44255abdd1fSWilly Tarreau #include "nolibc.h"
44355abdd1fSWilly Tarreau 
44406fdba53SWilly Tarreau #endif /* _NOLIBC_STDLIB_H */
445