162306a36Sopenharmony_ci/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * stdlib function definitions for NOLIBC 462306a36Sopenharmony_ci * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef _NOLIBC_STDLIB_H 862306a36Sopenharmony_ci#define _NOLIBC_STDLIB_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "std.h" 1162306a36Sopenharmony_ci#include "arch.h" 1262306a36Sopenharmony_ci#include "types.h" 1362306a36Sopenharmony_ci#include "sys.h" 1462306a36Sopenharmony_ci#include "string.h" 1562306a36Sopenharmony_ci#include <linux/auxvec.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct nolibc_heap { 1862306a36Sopenharmony_ci size_t len; 1962306a36Sopenharmony_ci char user_p[] __attribute__((__aligned__)); 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Buffer used to store int-to-ASCII conversions. Will only be implemented if 2362306a36Sopenharmony_ci * any of the related functions is implemented. The area is large enough to 2462306a36Sopenharmony_ci * store "18446744073709551615" or "-9223372036854775808" and the final zero. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistatic __attribute__((unused)) char itoa_buffer[21]; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * As much as possible, please keep functions alphabetically sorted. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* must be exported, as it's used by libgcc for various divide functions */ 3362306a36Sopenharmony_ci__attribute__((weak,unused,noreturn,section(".text.nolibc_abort"))) 3462306a36Sopenharmony_civoid abort(void) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci sys_kill(sys_getpid(), SIGABRT); 3762306a36Sopenharmony_ci for (;;); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic __attribute__((unused)) 4162306a36Sopenharmony_cilong atol(const char *s) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci unsigned long ret = 0; 4462306a36Sopenharmony_ci unsigned long d; 4562306a36Sopenharmony_ci int neg = 0; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (*s == '-') { 4862306a36Sopenharmony_ci neg = 1; 4962306a36Sopenharmony_ci s++; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci while (1) { 5362306a36Sopenharmony_ci d = (*s++) - '0'; 5462306a36Sopenharmony_ci if (d > 9) 5562306a36Sopenharmony_ci break; 5662306a36Sopenharmony_ci ret *= 10; 5762306a36Sopenharmony_ci ret += d; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return neg ? -ret : ret; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic __attribute__((unused)) 6462306a36Sopenharmony_ciint atoi(const char *s) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci return atol(s); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic __attribute__((unused)) 7062306a36Sopenharmony_civoid free(void *ptr) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct nolibc_heap *heap; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!ptr) 7562306a36Sopenharmony_ci return; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci heap = container_of(ptr, struct nolibc_heap, user_p); 7862306a36Sopenharmony_ci munmap(heap, heap->len); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* getenv() tries to find the environment variable named <name> in the 8262306a36Sopenharmony_ci * environment array pointed to by global variable "environ" which must be 8362306a36Sopenharmony_ci * declared as a char **, and must be terminated by a NULL (it is recommended 8462306a36Sopenharmony_ci * to set this variable to the "envp" argument of main()). If the requested 8562306a36Sopenharmony_ci * environment variable exists its value is returned otherwise NULL is 8662306a36Sopenharmony_ci * returned. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic __attribute__((unused)) 8962306a36Sopenharmony_cichar *getenv(const char *name) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci int idx, i; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (environ) { 9462306a36Sopenharmony_ci for (idx = 0; environ[idx]; idx++) { 9562306a36Sopenharmony_ci for (i = 0; name[i] && name[i] == environ[idx][i];) 9662306a36Sopenharmony_ci i++; 9762306a36Sopenharmony_ci if (!name[i] && environ[idx][i] == '=') 9862306a36Sopenharmony_ci return &environ[idx][i+1]; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic __attribute__((unused)) 10562306a36Sopenharmony_ciunsigned long getauxval(unsigned long type) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci const unsigned long *auxv = _auxv; 10862306a36Sopenharmony_ci unsigned long ret; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (!auxv) 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci while (1) { 11462306a36Sopenharmony_ci if (!auxv[0] && !auxv[1]) { 11562306a36Sopenharmony_ci ret = 0; 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (auxv[0] == type) { 12062306a36Sopenharmony_ci ret = auxv[1]; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci auxv += 2; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return ret; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic __attribute__((unused)) 13162306a36Sopenharmony_civoid *malloc(size_t len) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct nolibc_heap *heap; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* Always allocate memory with size multiple of 4096. */ 13662306a36Sopenharmony_ci len = sizeof(*heap) + len; 13762306a36Sopenharmony_ci len = (len + 4095UL) & -4096UL; 13862306a36Sopenharmony_ci heap = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 13962306a36Sopenharmony_ci -1, 0); 14062306a36Sopenharmony_ci if (__builtin_expect(heap == MAP_FAILED, 0)) 14162306a36Sopenharmony_ci return NULL; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci heap->len = len; 14462306a36Sopenharmony_ci return heap->user_p; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic __attribute__((unused)) 14862306a36Sopenharmony_civoid *calloc(size_t size, size_t nmemb) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci size_t x = size * nmemb; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (__builtin_expect(size && ((x / size) != nmemb), 0)) { 15362306a36Sopenharmony_ci SET_ERRNO(ENOMEM); 15462306a36Sopenharmony_ci return NULL; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * No need to zero the heap, the MAP_ANONYMOUS in malloc() 15962306a36Sopenharmony_ci * already does it. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci return malloc(x); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic __attribute__((unused)) 16562306a36Sopenharmony_civoid *realloc(void *old_ptr, size_t new_size) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct nolibc_heap *heap; 16862306a36Sopenharmony_ci size_t user_p_len; 16962306a36Sopenharmony_ci void *ret; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!old_ptr) 17262306a36Sopenharmony_ci return malloc(new_size); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci heap = container_of(old_ptr, struct nolibc_heap, user_p); 17562306a36Sopenharmony_ci user_p_len = heap->len - sizeof(*heap); 17662306a36Sopenharmony_ci /* 17762306a36Sopenharmony_ci * Don't realloc() if @user_p_len >= @new_size, this block of 17862306a36Sopenharmony_ci * memory is still enough to handle the @new_size. Just return 17962306a36Sopenharmony_ci * the same pointer. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci if (user_p_len >= new_size) 18262306a36Sopenharmony_ci return old_ptr; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci ret = malloc(new_size); 18562306a36Sopenharmony_ci if (__builtin_expect(!ret, 0)) 18662306a36Sopenharmony_ci return NULL; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci memcpy(ret, heap->user_p, heap->len); 18962306a36Sopenharmony_ci munmap(heap, heap->len); 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* Converts the unsigned long integer <in> to its hex representation into 19462306a36Sopenharmony_ci * buffer <buffer>, which must be long enough to store the number and the 19562306a36Sopenharmony_ci * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The 19662306a36Sopenharmony_ci * buffer is filled from the first byte, and the number of characters emitted 19762306a36Sopenharmony_ci * (not counting the trailing zero) is returned. The function is constructed 19862306a36Sopenharmony_ci * in a way to optimize the code size and avoid any divide that could add a 19962306a36Sopenharmony_ci * dependency on large external functions. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistatic __attribute__((unused)) 20262306a36Sopenharmony_ciint utoh_r(unsigned long in, char *buffer) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci signed char pos = (~0UL > 0xfffffffful) ? 60 : 28; 20562306a36Sopenharmony_ci int digits = 0; 20662306a36Sopenharmony_ci int dig; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci do { 20962306a36Sopenharmony_ci dig = in >> pos; 21062306a36Sopenharmony_ci in -= (uint64_t)dig << pos; 21162306a36Sopenharmony_ci pos -= 4; 21262306a36Sopenharmony_ci if (dig || digits || pos < 0) { 21362306a36Sopenharmony_ci if (dig > 9) 21462306a36Sopenharmony_ci dig += 'a' - '0' - 10; 21562306a36Sopenharmony_ci buffer[digits++] = '0' + dig; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } while (pos >= 0); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci buffer[digits] = 0; 22062306a36Sopenharmony_ci return digits; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* converts unsigned long <in> to an hex string using the static itoa_buffer 22462306a36Sopenharmony_ci * and returns the pointer to that string. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 22762306a36Sopenharmony_cichar *utoh(unsigned long in) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci utoh_r(in, itoa_buffer); 23062306a36Sopenharmony_ci return itoa_buffer; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* Converts the unsigned long integer <in> to its string representation into 23462306a36Sopenharmony_ci * buffer <buffer>, which must be long enough to store the number and the 23562306a36Sopenharmony_ci * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for 23662306a36Sopenharmony_ci * 4294967295 in 32-bit). The buffer is filled from the first byte, and the 23762306a36Sopenharmony_ci * number of characters emitted (not counting the trailing zero) is returned. 23862306a36Sopenharmony_ci * The function is constructed in a way to optimize the code size and avoid 23962306a36Sopenharmony_ci * any divide that could add a dependency on large external functions. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_cistatic __attribute__((unused)) 24262306a36Sopenharmony_ciint utoa_r(unsigned long in, char *buffer) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci unsigned long lim; 24562306a36Sopenharmony_ci int digits = 0; 24662306a36Sopenharmony_ci int pos = (~0UL > 0xfffffffful) ? 19 : 9; 24762306a36Sopenharmony_ci int dig; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci do { 25062306a36Sopenharmony_ci for (dig = 0, lim = 1; dig < pos; dig++) 25162306a36Sopenharmony_ci lim *= 10; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (digits || in >= lim || !pos) { 25462306a36Sopenharmony_ci for (dig = 0; in >= lim; dig++) 25562306a36Sopenharmony_ci in -= lim; 25662306a36Sopenharmony_ci buffer[digits++] = '0' + dig; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci } while (pos--); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci buffer[digits] = 0; 26162306a36Sopenharmony_ci return digits; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/* Converts the signed long integer <in> to its string representation into 26562306a36Sopenharmony_ci * buffer <buffer>, which must be long enough to store the number and the 26662306a36Sopenharmony_ci * trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for 26762306a36Sopenharmony_ci * -2147483648 in 32-bit). The buffer is filled from the first byte, and the 26862306a36Sopenharmony_ci * number of characters emitted (not counting the trailing zero) is returned. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_cistatic __attribute__((unused)) 27162306a36Sopenharmony_ciint itoa_r(long in, char *buffer) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci char *ptr = buffer; 27462306a36Sopenharmony_ci int len = 0; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (in < 0) { 27762306a36Sopenharmony_ci in = -in; 27862306a36Sopenharmony_ci *(ptr++) = '-'; 27962306a36Sopenharmony_ci len++; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci len += utoa_r(in, ptr); 28262306a36Sopenharmony_ci return len; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* for historical compatibility, same as above but returns the pointer to the 28662306a36Sopenharmony_ci * buffer. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 28962306a36Sopenharmony_cichar *ltoa_r(long in, char *buffer) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci itoa_r(in, buffer); 29262306a36Sopenharmony_ci return buffer; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* converts long integer <in> to a string using the static itoa_buffer and 29662306a36Sopenharmony_ci * returns the pointer to that string. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 29962306a36Sopenharmony_cichar *itoa(long in) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci itoa_r(in, itoa_buffer); 30262306a36Sopenharmony_ci return itoa_buffer; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* converts long integer <in> to a string using the static itoa_buffer and 30662306a36Sopenharmony_ci * returns the pointer to that string. Same as above, for compatibility. 30762306a36Sopenharmony_ci */ 30862306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 30962306a36Sopenharmony_cichar *ltoa(long in) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci itoa_r(in, itoa_buffer); 31262306a36Sopenharmony_ci return itoa_buffer; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/* converts unsigned long integer <in> to a string using the static itoa_buffer 31662306a36Sopenharmony_ci * and returns the pointer to that string. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 31962306a36Sopenharmony_cichar *utoa(unsigned long in) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci utoa_r(in, itoa_buffer); 32262306a36Sopenharmony_ci return itoa_buffer; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* Converts the unsigned 64-bit integer <in> to its hex representation into 32662306a36Sopenharmony_ci * buffer <buffer>, which must be long enough to store the number and the 32762306a36Sopenharmony_ci * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from 32862306a36Sopenharmony_ci * the first byte, and the number of characters emitted (not counting the 32962306a36Sopenharmony_ci * trailing zero) is returned. The function is constructed in a way to optimize 33062306a36Sopenharmony_ci * the code size and avoid any divide that could add a dependency on large 33162306a36Sopenharmony_ci * external functions. 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_cistatic __attribute__((unused)) 33462306a36Sopenharmony_ciint u64toh_r(uint64_t in, char *buffer) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci signed char pos = 60; 33762306a36Sopenharmony_ci int digits = 0; 33862306a36Sopenharmony_ci int dig; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci do { 34162306a36Sopenharmony_ci if (sizeof(long) >= 8) { 34262306a36Sopenharmony_ci dig = (in >> pos) & 0xF; 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci /* 32-bit platforms: avoid a 64-bit shift */ 34562306a36Sopenharmony_ci uint32_t d = (pos >= 32) ? (in >> 32) : in; 34662306a36Sopenharmony_ci dig = (d >> (pos & 31)) & 0xF; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci if (dig > 9) 34962306a36Sopenharmony_ci dig += 'a' - '0' - 10; 35062306a36Sopenharmony_ci pos -= 4; 35162306a36Sopenharmony_ci if (dig || digits || pos < 0) 35262306a36Sopenharmony_ci buffer[digits++] = '0' + dig; 35362306a36Sopenharmony_ci } while (pos >= 0); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci buffer[digits] = 0; 35662306a36Sopenharmony_ci return digits; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci/* converts uint64_t <in> to an hex string using the static itoa_buffer and 36062306a36Sopenharmony_ci * returns the pointer to that string. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 36362306a36Sopenharmony_cichar *u64toh(uint64_t in) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci u64toh_r(in, itoa_buffer); 36662306a36Sopenharmony_ci return itoa_buffer; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/* Converts the unsigned 64-bit integer <in> to its string representation into 37062306a36Sopenharmony_ci * buffer <buffer>, which must be long enough to store the number and the 37162306a36Sopenharmony_ci * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from 37262306a36Sopenharmony_ci * the first byte, and the number of characters emitted (not counting the 37362306a36Sopenharmony_ci * trailing zero) is returned. The function is constructed in a way to optimize 37462306a36Sopenharmony_ci * the code size and avoid any divide that could add a dependency on large 37562306a36Sopenharmony_ci * external functions. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_cistatic __attribute__((unused)) 37862306a36Sopenharmony_ciint u64toa_r(uint64_t in, char *buffer) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci unsigned long long lim; 38162306a36Sopenharmony_ci int digits = 0; 38262306a36Sopenharmony_ci int pos = 19; /* start with the highest possible digit */ 38362306a36Sopenharmony_ci int dig; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci do { 38662306a36Sopenharmony_ci for (dig = 0, lim = 1; dig < pos; dig++) 38762306a36Sopenharmony_ci lim *= 10; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (digits || in >= lim || !pos) { 39062306a36Sopenharmony_ci for (dig = 0; in >= lim; dig++) 39162306a36Sopenharmony_ci in -= lim; 39262306a36Sopenharmony_ci buffer[digits++] = '0' + dig; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } while (pos--); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci buffer[digits] = 0; 39762306a36Sopenharmony_ci return digits; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* Converts the signed 64-bit integer <in> to its string representation into 40162306a36Sopenharmony_ci * buffer <buffer>, which must be long enough to store the number and the 40262306a36Sopenharmony_ci * trailing zero (21 bytes for -9223372036854775808). The buffer is filled from 40362306a36Sopenharmony_ci * the first byte, and the number of characters emitted (not counting the 40462306a36Sopenharmony_ci * trailing zero) is returned. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_cistatic __attribute__((unused)) 40762306a36Sopenharmony_ciint i64toa_r(int64_t in, char *buffer) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci char *ptr = buffer; 41062306a36Sopenharmony_ci int len = 0; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (in < 0) { 41362306a36Sopenharmony_ci in = -in; 41462306a36Sopenharmony_ci *(ptr++) = '-'; 41562306a36Sopenharmony_ci len++; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci len += u64toa_r(in, ptr); 41862306a36Sopenharmony_ci return len; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/* converts int64_t <in> to a string using the static itoa_buffer and returns 42262306a36Sopenharmony_ci * the pointer to that string. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 42562306a36Sopenharmony_cichar *i64toa(int64_t in) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci i64toa_r(in, itoa_buffer); 42862306a36Sopenharmony_ci return itoa_buffer; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci/* converts uint64_t <in> to a string using the static itoa_buffer and returns 43262306a36Sopenharmony_ci * the pointer to that string. 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_cistatic __inline__ __attribute__((unused)) 43562306a36Sopenharmony_cichar *u64toa(uint64_t in) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci u64toa_r(in, itoa_buffer); 43862306a36Sopenharmony_ci return itoa_buffer; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* make sure to include all global symbols */ 44262306a36Sopenharmony_ci#include "nolibc.h" 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci#endif /* _NOLIBC_STDLIB_H */ 445