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
8667d108e2SThomas Weißschuh * returned.
87077d0a39SWilly Tarreau */
88077d0a39SWilly Tarreau static __attribute__((unused))
getenv(const char * name)8967d108e2SThomas 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
188*f678c3c3SBrennan Xavier McManus memcpy(ret, heap->user_p, user_p_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