Add custom printf version
- add `js_snprintf`, `js_printf`... to handle extra conversions: - support for wxx length modifier - support for `%b` and `%B` - `%oa` and `%#oa` to convert `JSAtom` values - `%ps` to convert `JSString` values - add `dbuf_vprintf_fun` replaceable `dbuf_printf` handler - change `JS_DumpString` to `JS_FormatString` to convert `JSSAtom` to quoted strings - change `JS_AtomGetStrRT` to `JS_FormatAtom` to convert `JSAtom` to strings - change `JS_AtomGetStr` to return direct string pointer for builtin atoms - remove `print_atom` - use custom conversions for trace messages and error messages - add support for `%b`, `%B` and `w` length modifier in `std.printf` - remove error handlers: `JS_ThrowTypeErrorAtom` and `JS_ThrowSyntaxErrorAtom` - add `is_lower_ascii()` and `to_lower_ascii()` - add floating point conversions and wide string conversions - unbreak compilation: prevent name collision on pow10 - minimize `vsnprintf` calls in `dbuf_vprintf_default`
This commit is contained in:
parent
3eaea6c4cf
commit
0536b42693
7 changed files with 1621 additions and 485 deletions
172
cutils.c
172
cutils.c
|
@ -35,20 +35,19 @@
|
||||||
#include "cutils.h"
|
#include "cutils.h"
|
||||||
|
|
||||||
#undef NANOSEC
|
#undef NANOSEC
|
||||||
#define NANOSEC ((uint64_t) 1e9)
|
#define NANOSEC 1000000000
|
||||||
|
|
||||||
#pragma GCC visibility push(default)
|
#pragma GCC visibility push(default)
|
||||||
|
|
||||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
void pstrcpy(char *buf, size_t buf_size, const char *str)
|
||||||
{
|
{
|
||||||
int c;
|
|
||||||
char *q = buf;
|
char *q = buf;
|
||||||
|
|
||||||
if (buf_size <= 0)
|
if (buf_size <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
c = *str++;
|
char c = *str++;
|
||||||
if (c == 0 || q >= buf + buf_size - 1)
|
if (c == 0 || q >= buf + buf_size - 1)
|
||||||
break;
|
break;
|
||||||
*q++ = c;
|
*q++ = c;
|
||||||
|
@ -57,10 +56,9 @@ void pstrcpy(char *buf, int buf_size, const char *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* strcat and truncate. */
|
/* strcat and truncate. */
|
||||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
char *pstrcat(char *buf, size_t buf_size, const char *s)
|
||||||
{
|
{
|
||||||
int len;
|
size_t len = strlen(buf);
|
||||||
len = strlen(buf);
|
|
||||||
if (len < buf_size)
|
if (len < buf_size)
|
||||||
pstrcpy(buf + len, buf_size - len, s);
|
pstrcpy(buf + len, buf_size - len, s);
|
||||||
return buf;
|
return buf;
|
||||||
|
@ -105,11 +103,6 @@ void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
|
||||||
s->realloc_func = realloc_func;
|
s->realloc_func = realloc_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbuf_init(DynBuf *s)
|
|
||||||
{
|
|
||||||
dbuf_init2(s, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return < 0 if error */
|
/* return < 0 if error */
|
||||||
int dbuf_realloc(DynBuf *s, size_t new_size)
|
int dbuf_realloc(DynBuf *s, size_t new_size)
|
||||||
{
|
{
|
||||||
|
@ -178,29 +171,59 @@ int dbuf_putstr(DynBuf *s, const char *str)
|
||||||
return dbuf_put(s, (const uint8_t *)str, strlen(str));
|
return dbuf_put(s, (const uint8_t *)str, strlen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
static int dbuf_vprintf_default(DynBuf *s, const char *fmt, va_list ap)
|
||||||
const char *fmt, ...)
|
{
|
||||||
|
char buf[128];
|
||||||
|
va_list arg;
|
||||||
|
size_t size, avail, ulen;
|
||||||
|
int len;
|
||||||
|
char *dest;
|
||||||
|
|
||||||
|
dest = buf;
|
||||||
|
size = sizeof buf;
|
||||||
|
avail = s->allocated_size - s->size;
|
||||||
|
if (avail > size) {
|
||||||
|
dest = (char *)(s->buf + s->size);
|
||||||
|
size = avail;
|
||||||
|
}
|
||||||
|
va_copy(arg, ap);
|
||||||
|
len = vsnprintf(dest, size, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
return len;
|
||||||
|
|
||||||
|
ulen = (size_t)len;
|
||||||
|
if (ulen >= avail) {
|
||||||
|
if (dbuf_realloc(s, s->size + ulen + 1))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (dest == buf && ulen < sizeof buf) {
|
||||||
|
memcpy(s->buf + s->size, buf, ulen + 1);
|
||||||
|
} else
|
||||||
|
if (ulen >= avail) {
|
||||||
|
avail = s->allocated_size - s->size;
|
||||||
|
va_copy(arg, ap);
|
||||||
|
vsnprintf((char *)(s->buf + s->size), avail, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
}
|
||||||
|
s->size += ulen;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replaceable formatter */
|
||||||
|
int (*dbuf_vprintf_fun)(DynBuf *s, const char *fmt, va_list ap) = dbuf_vprintf_default;
|
||||||
|
|
||||||
|
__attribute__((format(printf, 2, 3)))
|
||||||
|
int dbuf_printf(DynBuf *s, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char buf[128];
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
len = vsnprintf(buf, sizeof(buf), fmt, ap);
|
len = (*dbuf_vprintf_fun)(s, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (len < sizeof(buf)) {
|
return len;
|
||||||
/* fast case */
|
|
||||||
return dbuf_put(s, (uint8_t *)buf, len);
|
|
||||||
} else {
|
|
||||||
if (dbuf_realloc(s, s->size + len + 1))
|
|
||||||
return -1;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
|
|
||||||
fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
s->size += len;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbuf_free(DynBuf *s)
|
void dbuf_free(DynBuf *s)
|
||||||
|
@ -589,6 +612,7 @@ overflow:
|
||||||
|
|
||||||
/* 2 <= base <= 36 */
|
/* 2 <= base <= 36 */
|
||||||
char const digits36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
char const digits36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
|
char const digits36_upper[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
#define USE_SPECIAL_RADIX_10 1 // special case base 10 radix conversions
|
#define USE_SPECIAL_RADIX_10 1 // special case base 10 radix conversions
|
||||||
#define USE_SINGLE_CASE_FAST 1 // special case single digit numbers
|
#define USE_SINGLE_CASE_FAST 1 // special case single digit numbers
|
||||||
|
@ -600,7 +624,7 @@ char const digits36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||||
else \
|
else \
|
||||||
buf = (buf << 8) | (c)
|
buf = (buf << 8) | (c)
|
||||||
|
|
||||||
size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
|
static size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
|
||||||
{
|
{
|
||||||
size_t len = 1;
|
size_t len = 1;
|
||||||
uint64_t buf = 0;
|
uint64_t buf = 0;
|
||||||
|
@ -615,7 +639,7 @@ size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
|
static size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
dest += len;
|
dest += len;
|
||||||
|
@ -641,8 +665,9 @@ size_t u32toa(char buf[minimum_length(11)], uint32_t n)
|
||||||
#define TEN_POW_7 10000000
|
#define TEN_POW_7 10000000
|
||||||
if (n >= TEN_POW_7) {
|
if (n >= TEN_POW_7) {
|
||||||
uint32_t quo = n / TEN_POW_7;
|
uint32_t quo = n / TEN_POW_7;
|
||||||
|
size_t len;
|
||||||
n %= TEN_POW_7;
|
n %= TEN_POW_7;
|
||||||
size_t len = u7toa_shift(buf, quo);
|
len = u7toa_shift(buf, quo);
|
||||||
return u07toa_shift(buf, n, len);
|
return u07toa_shift(buf, n, len);
|
||||||
}
|
}
|
||||||
return u7toa_shift(buf, n);
|
return u7toa_shift(buf, n);
|
||||||
|
@ -650,30 +675,31 @@ size_t u32toa(char buf[minimum_length(11)], uint32_t n)
|
||||||
|
|
||||||
size_t u64toa(char buf[minimum_length(21)], uint64_t n)
|
size_t u64toa(char buf[minimum_length(21)], uint64_t n)
|
||||||
{
|
{
|
||||||
if (likely(n < 0x100000000))
|
|
||||||
return u32toa(buf, n);
|
|
||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
if (likely(n < 0x100000000))
|
||||||
|
return u32toa(buf, (uint32_t)n);
|
||||||
|
|
||||||
if (n >= TEN_POW_7) {
|
if (n >= TEN_POW_7) {
|
||||||
uint64_t n1 = n / TEN_POW_7;
|
uint64_t n1 = n / TEN_POW_7;
|
||||||
n %= TEN_POW_7;
|
n %= TEN_POW_7;
|
||||||
if (n1 >= TEN_POW_7) {
|
if (n1 >= TEN_POW_7) {
|
||||||
uint32_t quo = n1 / TEN_POW_7;
|
uint32_t quo = (uint32_t)(n1 / TEN_POW_7);
|
||||||
n1 %= TEN_POW_7;
|
n1 %= TEN_POW_7;
|
||||||
len = u7toa_shift(buf, quo);
|
len = u7toa_shift(buf, quo);
|
||||||
len = u07toa_shift(buf, n1, len);
|
len = u07toa_shift(buf, (uint32_t)n1, len);
|
||||||
} else {
|
} else {
|
||||||
len = u7toa_shift(buf, n1);
|
len = u7toa_shift(buf, (uint32_t)n1);
|
||||||
}
|
}
|
||||||
return u07toa_shift(buf, n, len);
|
return u07toa_shift(buf, (uint32_t)n, len);
|
||||||
}
|
}
|
||||||
return u7toa_shift(buf, n);
|
return u7toa_shift(buf, (uint32_t)n);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i32toa(char buf[minimum_length(12)], int32_t n)
|
size_t i32toa(char buf[minimum_length(12)], int32_t n)
|
||||||
{
|
{
|
||||||
if (likely(n >= 0))
|
if (likely(n >= 0))
|
||||||
return u32toa(buf, n);
|
return u32toa(buf, (uint32_t)n);
|
||||||
|
|
||||||
buf[0] = '-';
|
buf[0] = '-';
|
||||||
return 1 + u32toa(buf + 1, -(uint32_t)n);
|
return 1 + u32toa(buf + 1, -(uint32_t)n);
|
||||||
|
@ -682,7 +708,7 @@ size_t i32toa(char buf[minimum_length(12)], int32_t n)
|
||||||
size_t i64toa(char buf[minimum_length(22)], int64_t n)
|
size_t i64toa(char buf[minimum_length(22)], int64_t n)
|
||||||
{
|
{
|
||||||
if (likely(n >= 0))
|
if (likely(n >= 0))
|
||||||
return u64toa(buf, n);
|
return u64toa(buf, (uint64_t)n);
|
||||||
|
|
||||||
buf[0] = '-';
|
buf[0] = '-';
|
||||||
return 1 + u64toa(buf + 1, -(uint64_t)n);
|
return 1 + u64toa(buf + 1, -(uint64_t)n);
|
||||||
|
@ -713,7 +739,7 @@ size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
|
||||||
shift = radix_shift[base & 63];
|
shift = radix_shift[base & 63];
|
||||||
if (shift) {
|
if (shift) {
|
||||||
uint32_t mask = (1 << shift) - 1;
|
uint32_t mask = (1 << shift) - 1;
|
||||||
size_t len = (32 - clz32(n) + shift - 1) / shift;
|
size_t len = (size_t)((32 - clz32(n) + shift - 1) / shift);
|
||||||
size_t last = n & mask;
|
size_t last = n & mask;
|
||||||
char *end = buf + len;
|
char *end = buf + len;
|
||||||
n >>= shift;
|
n >>= shift;
|
||||||
|
@ -729,13 +755,14 @@ size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
|
||||||
} else {
|
} else {
|
||||||
size_t len = 2;
|
size_t len = 2;
|
||||||
size_t last = n % base;
|
size_t last = n % base;
|
||||||
n /= base;
|
|
||||||
uint32_t nbase = base;
|
uint32_t nbase = base;
|
||||||
|
char *end;
|
||||||
|
n /= base;
|
||||||
while (n >= nbase) {
|
while (n >= nbase) {
|
||||||
nbase *= base;
|
nbase *= base;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
char *end = buf + len;
|
end = buf + len;
|
||||||
*end-- = '\0';
|
*end-- = '\0';
|
||||||
*end-- = digits36[last];
|
*end-- = digits36[last];
|
||||||
while (n >= base) {
|
while (n >= base) {
|
||||||
|
@ -762,33 +789,36 @@ size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
|
||||||
buf[0] = digits36[n];
|
buf[0] = digits36[n];
|
||||||
buf[1] = '\0';
|
buf[1] = '\0';
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else {
|
||||||
uint64_t mask = (1 << shift) - 1;
|
uint64_t mask = (1 << shift) - 1;
|
||||||
size_t len = (64 - clz64(n) + shift - 1) / shift;
|
size_t len = (size_t)((64 - clz64(n) + shift - 1) / shift);
|
||||||
size_t last = n & mask;
|
size_t last = n & mask;
|
||||||
char *end = buf + len;
|
char *end = buf + len;
|
||||||
n >>= shift;
|
|
||||||
*end-- = '\0';
|
|
||||||
*end-- = digits36[last];
|
|
||||||
while (n >= base) {
|
|
||||||
size_t quo = n & mask;
|
|
||||||
n >>= shift;
|
n >>= shift;
|
||||||
*end-- = digits36[quo];
|
*end-- = '\0';
|
||||||
|
*end-- = digits36[last];
|
||||||
|
while (n >= base) {
|
||||||
|
size_t quo = n & mask;
|
||||||
|
n >>= shift;
|
||||||
|
*end-- = digits36[quo];
|
||||||
|
}
|
||||||
|
*end = digits36[n];
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
*end = digits36[n];
|
} else
|
||||||
return len;
|
if (likely(n < 0x100000000)) {
|
||||||
|
return u32toa_radix(buf, (uint32_t)n, base);
|
||||||
} else {
|
} else {
|
||||||
if (likely(n < 0x100000000))
|
|
||||||
return u32toa_radix(buf, n, base);
|
|
||||||
size_t last = n % base;
|
size_t last = n % base;
|
||||||
n /= base;
|
|
||||||
uint64_t nbase = base;
|
uint64_t nbase = base;
|
||||||
size_t len = 2;
|
size_t len = 2;
|
||||||
|
char *end;
|
||||||
|
n /= base;
|
||||||
while (n >= nbase) {
|
while (n >= nbase) {
|
||||||
nbase *= base;
|
nbase *= base;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
char *end = buf + len;
|
end = buf + len;
|
||||||
*end-- = '\0';
|
*end-- = '\0';
|
||||||
*end-- = digits36[last];
|
*end-- = digits36[last];
|
||||||
while (n >= base) {
|
while (n >= base) {
|
||||||
|
@ -813,7 +843,7 @@ size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned int base)
|
||||||
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
|
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
|
||||||
{
|
{
|
||||||
if (likely(n >= 0))
|
if (likely(n >= 0))
|
||||||
return u64toa_radix(buf, n, base);
|
return u64toa_radix(buf, (uint64_t)n, base);
|
||||||
|
|
||||||
buf[0] = '-';
|
buf[0] = '-';
|
||||||
return 1 + u64toa_radix(buf + 1, -(uint64_t)n, base);
|
return 1 + u64toa_radix(buf + 1, -(uint64_t)n, base);
|
||||||
|
@ -1008,7 +1038,14 @@ static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)
|
||||||
/* pointer based version with local stack and insertion sort threshhold */
|
/* pointer based version with local stack and insertion sort threshhold */
|
||||||
void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
|
void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
|
||||||
{
|
{
|
||||||
struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;
|
struct {
|
||||||
|
uint8_t *base;
|
||||||
|
size_t count;
|
||||||
|
int depth;
|
||||||
|
#if SIZE_MAX > UINT_MAX
|
||||||
|
int pad;
|
||||||
|
#endif
|
||||||
|
} stack[50], *sp = stack;
|
||||||
uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;
|
uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;
|
||||||
size_t m4, i, lt, gt, span, span2;
|
size_t m4, i, lt, gt, span, span2;
|
||||||
int c, depth;
|
int c, depth;
|
||||||
|
@ -1391,12 +1428,9 @@ int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) {
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (r == ETIMEDOUT)
|
if (r != ETIMEDOUT)
|
||||||
return -1;
|
abort();
|
||||||
|
|
||||||
abort();
|
|
||||||
|
|
||||||
/* Pacify some compilers. */
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
63
cutils.h
63
cutils.h
|
@ -25,6 +25,7 @@
|
||||||
#ifndef CUTILS_H
|
#ifndef CUTILS_H
|
||||||
#define CUTILS_H
|
#define CUTILS_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
@ -72,24 +73,27 @@ static void *__builtin_frame_address(unsigned int level) {
|
||||||
|
|
||||||
// https://stackoverflow.com/a/6849629
|
// https://stackoverflow.com/a/6849629
|
||||||
#undef FORMAT_STRING
|
#undef FORMAT_STRING
|
||||||
#if _MSC_VER >= 1400
|
#ifdef _MSC_VER
|
||||||
# include <sal.h>
|
# if _MSC_VER >= 1400
|
||||||
# if _MSC_VER > 1400
|
# include <sal.h>
|
||||||
# define FORMAT_STRING(p) _Printf_format_string_ p
|
# if _MSC_VER > 1400
|
||||||
# else
|
# define FORMAT_STRING(p) _Printf_format_string_ p
|
||||||
# define FORMAT_STRING(p) __format_string p
|
# else
|
||||||
# endif /* FORMAT_STRING */
|
# define FORMAT_STRING(p) __format_string p
|
||||||
#else
|
# endif
|
||||||
# define FORMAT_STRING(p) p
|
# endif
|
||||||
#endif /* _MSC_VER */
|
#endif /* _MSC_VER */
|
||||||
|
#ifndef FORMAT_STRING
|
||||||
|
# define FORMAT_STRING(p) p
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#define INF INFINITY
|
#define INF INFINITY
|
||||||
#define NEG_INF -INFINITY
|
#define NEG_INF (-INFINITY)
|
||||||
#else
|
#else
|
||||||
#define INF (1.0/0.0)
|
#define INF (1.0/0.0)
|
||||||
#define NEG_INF (-1.0/0.0)
|
#define NEG_INF (-1.0/0.0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define xglue(x, y) x ## y
|
#define xglue(x, y) x ## y
|
||||||
|
@ -126,8 +130,8 @@ enum {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pstrcpy(char *buf, int buf_size, const char *str);
|
void pstrcpy(char *buf, size_t buf_size, const char *str);
|
||||||
char *pstrcat(char *buf, int buf_size, const char *s);
|
char *pstrcat(char *buf, size_t buf_size, const char *s);
|
||||||
int strstart(const char *str, const char *val, const char **ptr);
|
int strstart(const char *str, const char *val, const char **ptr);
|
||||||
int has_suffix(const char *str, const char *suffix);
|
int has_suffix(const char *str, const char *suffix);
|
||||||
|
|
||||||
|
@ -191,6 +195,7 @@ static inline int64_t min_int64(int64_t a, int64_t b)
|
||||||
static inline int clz32(unsigned int a)
|
static inline int clz32(unsigned int a)
|
||||||
{
|
{
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
// XXX: unsigned int _lzcnt_u32(unsigned int a)
|
||||||
unsigned long index;
|
unsigned long index;
|
||||||
_BitScanReverse(&index, a);
|
_BitScanReverse(&index, a);
|
||||||
return 31 - index;
|
return 31 - index;
|
||||||
|
@ -203,6 +208,7 @@ static inline int clz32(unsigned int a)
|
||||||
static inline int clz64(uint64_t a)
|
static inline int clz64(uint64_t a)
|
||||||
{
|
{
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
// XXX: unsigned int _lzcnt_u64(unsigned __int64 a)
|
||||||
unsigned long index;
|
unsigned long index;
|
||||||
_BitScanReverse64(&index, a);
|
_BitScanReverse64(&index, a);
|
||||||
return 63 - index;
|
return 63 - index;
|
||||||
|
@ -215,6 +221,7 @@ static inline int clz64(uint64_t a)
|
||||||
static inline int ctz32(unsigned int a)
|
static inline int ctz32(unsigned int a)
|
||||||
{
|
{
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
// XXX: unsigned int _tzcnt_u32 (unsigned int a)
|
||||||
unsigned long index;
|
unsigned long index;
|
||||||
_BitScanForward(&index, a);
|
_BitScanForward(&index, a);
|
||||||
return index;
|
return index;
|
||||||
|
@ -227,6 +234,7 @@ static inline int ctz32(unsigned int a)
|
||||||
static inline int ctz64(uint64_t a)
|
static inline int ctz64(uint64_t a)
|
||||||
{
|
{
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
// XXX: unsigned int _tzcnt_u64 (unsigned __int64 a)
|
||||||
unsigned long index;
|
unsigned long index;
|
||||||
_BitScanForward64(&index, a);
|
_BitScanForward64(&index, a);
|
||||||
return index;
|
return index;
|
||||||
|
@ -310,7 +318,7 @@ static inline void put_u8(uint8_t *tab, uint8_t val)
|
||||||
#ifndef bswap16
|
#ifndef bswap16
|
||||||
static inline uint16_t bswap16(uint16_t x)
|
static inline uint16_t bswap16(uint16_t x)
|
||||||
{
|
{
|
||||||
return (x >> 8) | (x << 8);
|
return (uint16_t)((x >> 8) | (x << 8));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -337,7 +345,7 @@ static inline uint64_t bswap64(uint64_t v)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void inplace_bswap16(uint8_t *tab) {
|
static inline void inplace_bswap16(uint8_t *tab) {
|
||||||
put_u16(tab, bswap16(get_u16(tab)));
|
put_u16(tab, bswap16((uint16_t)get_u16(tab)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void inplace_bswap32(uint8_t *tab) {
|
static inline void inplace_bswap32(uint8_t *tab) {
|
||||||
|
@ -352,12 +360,15 @@ typedef struct DynBuf {
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t allocated_size;
|
size_t allocated_size;
|
||||||
BOOL error; /* true if a memory allocation error occurred */
|
BOOL error; /* true if a memory allocation error occurred */
|
||||||
|
#if SIZE_MAX > UINT_MAX
|
||||||
|
int pad; /* prevent alignment warning */
|
||||||
|
#endif
|
||||||
DynBufReallocFunc *realloc_func;
|
DynBufReallocFunc *realloc_func;
|
||||||
void *opaque; /* for realloc_func */
|
void *opaque; /* for realloc_func */
|
||||||
} DynBuf;
|
} DynBuf;
|
||||||
|
|
||||||
void dbuf_init(DynBuf *s);
|
|
||||||
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
|
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
|
||||||
|
static inline void dbuf_init(DynBuf *s) { dbuf_init2(s, NULL, NULL); }
|
||||||
int dbuf_realloc(DynBuf *s, size_t new_size);
|
int dbuf_realloc(DynBuf *s, size_t new_size);
|
||||||
int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len);
|
int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len);
|
||||||
int dbuf_put(DynBuf *s, const void *data, size_t len);
|
int dbuf_put(DynBuf *s, const void *data, size_t len);
|
||||||
|
@ -376,8 +387,9 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
|
||||||
{
|
{
|
||||||
return dbuf_put(s, (uint8_t *)&val, 8);
|
return dbuf_put(s, (uint8_t *)&val, 8);
|
||||||
}
|
}
|
||||||
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
|
__attribute__((format(printf, 2, 3)))
|
||||||
FORMAT_STRING(const char *fmt), ...);
|
int dbuf_printf(DynBuf *s, FORMAT_STRING(const char *fmt), ...);
|
||||||
|
extern int (*dbuf_vprintf_fun)(DynBuf *s, const char *fmt, va_list ap);
|
||||||
void dbuf_free(DynBuf *s);
|
void dbuf_free(DynBuf *s);
|
||||||
static inline BOOL dbuf_error(DynBuf *s) {
|
static inline BOOL dbuf_error(DynBuf *s) {
|
||||||
return s->error;
|
return s->error;
|
||||||
|
@ -450,15 +462,24 @@ static inline int from_hex(int c)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t is_lower_ascii(uint8_t c) {
|
||||||
|
return c >= 'a' && c <= 'z';
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint8_t is_upper_ascii(uint8_t c) {
|
static inline uint8_t is_upper_ascii(uint8_t c) {
|
||||||
return c >= 'A' && c <= 'Z';
|
return c >= 'A' && c <= 'Z';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t to_lower_ascii(uint8_t c) {
|
||||||
|
return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint8_t to_upper_ascii(uint8_t c) {
|
static inline uint8_t to_upper_ascii(uint8_t c) {
|
||||||
return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
|
return c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern char const digits36[36];
|
extern char const digits36[36];
|
||||||
|
extern char const digits36_upper[36];
|
||||||
size_t u32toa(char buf[minimum_length(11)], uint32_t n);
|
size_t u32toa(char buf[minimum_length(11)], uint32_t n);
|
||||||
size_t i32toa(char buf[minimum_length(12)], int32_t n);
|
size_t i32toa(char buf[minimum_length(12)], int32_t n);
|
||||||
size_t u64toa(char buf[minimum_length(21)], uint64_t n);
|
size_t u64toa(char buf[minimum_length(21)], uint64_t n);
|
||||||
|
|
|
@ -185,7 +185,7 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
double double_arg;
|
double double_arg;
|
||||||
const char *string_arg;
|
const char *string_arg;
|
||||||
/* Use indirect call to dbuf_printf to prevent gcc warning */
|
/* Use indirect call to dbuf_printf to prevent gcc warning */
|
||||||
int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf;
|
int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = dbuf_printf;
|
||||||
|
|
||||||
js_std_dbuf_init(ctx, &dbuf);
|
js_std_dbuf_init(ctx, &dbuf);
|
||||||
|
|
||||||
|
@ -225,7 +225,9 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
goto missing;
|
goto missing;
|
||||||
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
||||||
goto fail;
|
goto fail;
|
||||||
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
|
if (q > fmtbuf + sizeof(fmtbuf) - 11)
|
||||||
|
goto invalid;
|
||||||
|
q += i32toa(q, int32_arg);
|
||||||
fmt++;
|
fmt++;
|
||||||
} else {
|
} else {
|
||||||
while (my_isdigit(*fmt)) {
|
while (my_isdigit(*fmt)) {
|
||||||
|
@ -243,7 +245,9 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
goto missing;
|
goto missing;
|
||||||
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
|
||||||
goto fail;
|
goto fail;
|
||||||
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
|
if (q > fmtbuf + sizeof(fmtbuf) - 11)
|
||||||
|
goto invalid;
|
||||||
|
q += i32toa(q, int32_arg);
|
||||||
fmt++;
|
fmt++;
|
||||||
} else {
|
} else {
|
||||||
while (my_isdigit(*fmt)) {
|
while (my_isdigit(*fmt)) {
|
||||||
|
@ -254,10 +258,33 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we only support the "l" modifier for 64 bit numbers */
|
/* we only support the "l" modifier for 64 bit numbers
|
||||||
mod = ' ';
|
and the w# length modifier with a bitlength of 1 to 64
|
||||||
if (*fmt == 'l') {
|
*/
|
||||||
mod = *fmt++;
|
// XXX: should use value changing conversions
|
||||||
|
mod = *fmt;
|
||||||
|
if (mod == 'w') {
|
||||||
|
int bitwidth;
|
||||||
|
if (q >= fmtbuf + sizeof(fmtbuf) - 4)
|
||||||
|
goto invalid;
|
||||||
|
*q++ = *fmt++;
|
||||||
|
if (!(*fmt >= '1' && *fmt <= '9'))
|
||||||
|
goto invalid;
|
||||||
|
bitwidth = *fmt - '0';
|
||||||
|
*q++ = *fmt++;
|
||||||
|
if (*fmt >= '0' && *fmt <= '9') {
|
||||||
|
bitwidth = bitwidth * 10 + *fmt - '0';
|
||||||
|
*q++ = *fmt++;
|
||||||
|
}
|
||||||
|
if (bitwidth > 32)
|
||||||
|
mod = 'l';
|
||||||
|
} else
|
||||||
|
if (mod == 'l') {
|
||||||
|
fmt++;
|
||||||
|
if (q >= fmtbuf + sizeof(fmtbuf) - 3)
|
||||||
|
goto invalid;
|
||||||
|
*q++ = 'l';
|
||||||
|
*q++ = 'l';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* type */
|
/* type */
|
||||||
|
@ -286,10 +313,14 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
if ((unsigned)int32_arg > 0x10FFFF)
|
if ((unsigned)int32_arg > 0x10FFFF)
|
||||||
int32_arg = 0xFFFD;
|
int32_arg = 0xFFFD;
|
||||||
/* ignore conversion flags, width and precision */
|
/* ignore conversion flags, width and precision */
|
||||||
|
// XXX: Hash modifier could output pretty Unicode character
|
||||||
|
// XXX: `l` length modifier is implicit
|
||||||
len = utf8_encode(cbuf, int32_arg);
|
len = utf8_encode(cbuf, int32_arg);
|
||||||
dbuf_put(&dbuf, cbuf, len);
|
dbuf_put(&dbuf, cbuf, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'o':
|
case 'o':
|
||||||
|
@ -298,27 +329,12 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
case 'X':
|
case 'X':
|
||||||
if (i >= argc)
|
if (i >= argc)
|
||||||
goto missing;
|
goto missing;
|
||||||
|
// XXX: should handle BigInt values
|
||||||
if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
|
if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (mod == 'l') {
|
if (mod == 'l') {
|
||||||
/* 64 bit number */
|
/* 64 bit number */
|
||||||
#if defined(_WIN32)
|
|
||||||
if (q >= fmtbuf + sizeof(fmtbuf) - 3)
|
|
||||||
goto invalid;
|
|
||||||
q[2] = q[-1];
|
|
||||||
q[-1] = 'I';
|
|
||||||
q[0] = '6';
|
|
||||||
q[1] = '4';
|
|
||||||
q[3] = '\0';
|
|
||||||
dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);
|
dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);
|
||||||
#else
|
|
||||||
if (q >= fmtbuf + sizeof(fmtbuf) - 2)
|
|
||||||
goto invalid;
|
|
||||||
q[1] = q[-1];
|
|
||||||
q[-1] = q[0] = 'l';
|
|
||||||
q[2] = '\0';
|
|
||||||
dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
|
dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
|
||||||
}
|
}
|
||||||
|
@ -328,6 +344,10 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
if (i >= argc)
|
if (i >= argc)
|
||||||
goto missing;
|
goto missing;
|
||||||
/* XXX: handle strings containing null characters */
|
/* XXX: handle strings containing null characters */
|
||||||
|
// XXX: # could output encoded string
|
||||||
|
// XXX: null values should output as `<null>`
|
||||||
|
// XXX: undefined values should output as `<undefined>`
|
||||||
|
// XXX: `l` length modifier is implicit
|
||||||
string_arg = JS_ToCString(ctx, argv[i++]);
|
string_arg = JS_ToCString(ctx, argv[i++]);
|
||||||
if (!string_arg)
|
if (!string_arg)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -351,6 +371,8 @@ static JSValue js_printf_internal(JSContext *ctx,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '%':
|
case '%':
|
||||||
|
if (q != fmtbuf + 2) // accept only %%
|
||||||
|
goto invalid;
|
||||||
dbuf_putc(&dbuf, '%');
|
dbuf_putc(&dbuf, '%');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
1092
quickjs-printf.c
Normal file
1092
quickjs-printf.c
Normal file
File diff suppressed because it is too large
Load diff
63
quickjs-printf.h
Normal file
63
quickjs-printf.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* QuickJS Javascript printf functions
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 Charlie Gordon
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QUICKJS_PRINTF
|
||||||
|
#define QUICKJS_PRINTF
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef TEST_QUICKJS
|
||||||
|
#define JS_EXTERN
|
||||||
|
#define __js_printf_like(f, a) __attribute__((format(printf, f-1, a-1)))
|
||||||
|
#define DynBuf void
|
||||||
|
#define JSContext void
|
||||||
|
#define JSRuntime void
|
||||||
|
#define js_snprintf(ctx, ...) qjs_snprintf(__VA_ARGS__)
|
||||||
|
#define js_printf(ctx, ...) qjs_printf(__VA_ARGS__)
|
||||||
|
#define js_printf_RT(rt, ...) qjs_printf_RT(__VA_ARGS__)
|
||||||
|
#define js_fprintf(ctx, ...) qjs_fprintf(__VA_ARGS__)
|
||||||
|
#define js_fprintf_RT(rt, ...) qjs_fprintf_RT(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define __js_printf_like(f, a) __attribute__((format(printf, f, a)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__js_printf_like(4, 5)
|
||||||
|
int js_snprintf(JSContext *ctx, char *dest, size_t size, const char *fmt, ...);
|
||||||
|
int js_vsnprintf(JSContext *ctx, char *dest, size_t size, const char *fmt, va_list ap);
|
||||||
|
int dbuf_vprintf_ext(DynBuf *s, const char *fmt, va_list ap);
|
||||||
|
__js_printf_like(2, 3)
|
||||||
|
int js_printf(JSContext *ctx, const char *fmt, ...);
|
||||||
|
int js_vprintf(JSContext *ctx, const char *fmt, va_list ap);
|
||||||
|
__js_printf_like(2, 3)
|
||||||
|
int js_printf_RT(JSRuntime *rt, const char *fmt, ...);
|
||||||
|
int js_vprintf_RT(JSRuntime *rt, const char *fmt, va_list ap);
|
||||||
|
__js_printf_like(3, 4)
|
||||||
|
int js_fprintf(JSContext *ctx, FILE *fp, const char *fmt, ...);
|
||||||
|
int js_vfprintf(JSContext *ctx, FILE *fp, const char *fmt, va_list ap);
|
||||||
|
__js_printf_like(3, 4)
|
||||||
|
int js_fprintf_RT(JSRuntime *rt, FILE *fp, const char *fmt, ...);
|
||||||
|
int js_vfprintf_RT(JSRuntime *rt, FILE *fp, const char *fmt, va_list ap);
|
||||||
|
|
||||||
|
#endif // QUICKJS_PRINTF
|
|
@ -152,7 +152,7 @@ size_t i64toa_##v(char buf[minimum_length(22)], int64_t n) \
|
||||||
else \
|
else \
|
||||||
buf = (buf << 8) | (c)
|
buf = (buf << 8) | (c)
|
||||||
|
|
||||||
size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
|
static size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
|
||||||
{
|
{
|
||||||
size_t len = 1;
|
size_t len = 1;
|
||||||
uint64_t buf = 0;
|
uint64_t buf = 0;
|
||||||
|
@ -167,7 +167,7 @@ size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
|
static size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
dest += len;
|
dest += len;
|
||||||
|
@ -193,8 +193,9 @@ size_t u32toa_shift(char buf[minimum_length(11)], uint32_t n)
|
||||||
#define TEN_POW_7 10000000
|
#define TEN_POW_7 10000000
|
||||||
if (n >= TEN_POW_7) {
|
if (n >= TEN_POW_7) {
|
||||||
uint32_t quo = n / TEN_POW_7;
|
uint32_t quo = n / TEN_POW_7;
|
||||||
|
size_t len;
|
||||||
n %= TEN_POW_7;
|
n %= TEN_POW_7;
|
||||||
size_t len = u7toa_shift(buf, quo);
|
len = u7toa_shift(buf, quo);
|
||||||
return u07toa_shift(buf, n, len);
|
return u07toa_shift(buf, n, len);
|
||||||
}
|
}
|
||||||
return u7toa_shift(buf, n);
|
return u7toa_shift(buf, n);
|
||||||
|
@ -202,24 +203,25 @@ size_t u32toa_shift(char buf[minimum_length(11)], uint32_t n)
|
||||||
|
|
||||||
size_t u64toa_shift(char buf[minimum_length(21)], uint64_t n)
|
size_t u64toa_shift(char buf[minimum_length(21)], uint64_t n)
|
||||||
{
|
{
|
||||||
if (likely(n < 0x100000000))
|
|
||||||
return u32toa_shift(buf, n);
|
|
||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
if (likely(n < 0x100000000))
|
||||||
|
return u32toa_shift(buf, (uint32_t)n);
|
||||||
|
|
||||||
if (n >= TEN_POW_7) {
|
if (n >= TEN_POW_7) {
|
||||||
uint64_t n1 = n / TEN_POW_7;
|
uint64_t n1 = n / TEN_POW_7;
|
||||||
n %= TEN_POW_7;
|
n %= TEN_POW_7;
|
||||||
if (n1 >= TEN_POW_7) {
|
if (n1 >= TEN_POW_7) {
|
||||||
uint32_t quo = n1 / TEN_POW_7;
|
uint32_t quo = (uint32_t)(n1 / TEN_POW_7);
|
||||||
n1 %= TEN_POW_7;
|
n1 %= TEN_POW_7;
|
||||||
len = u7toa_shift(buf, quo);
|
len = u7toa_shift(buf, quo);
|
||||||
len = u07toa_shift(buf, n1, len);
|
len = u07toa_shift(buf, (uint32_t)n1, len);
|
||||||
} else {
|
} else {
|
||||||
len = u7toa_shift(buf, n1);
|
len = u7toa_shift(buf, (uint32_t)n1);
|
||||||
}
|
}
|
||||||
return u07toa_shift(buf, n, len);
|
return u07toa_shift(buf, (uint32_t)n, len);
|
||||||
}
|
}
|
||||||
return u7toa_shift(buf, n);
|
return u7toa_shift(buf, (uint32_t)n);
|
||||||
}
|
}
|
||||||
|
|
||||||
define_i32toa(shift)
|
define_i32toa(shift)
|
||||||
|
@ -878,7 +880,7 @@ size_t u32toa_radix_length(char buf[minimum_length(33)], uint32_t n, unsigned ba
|
||||||
shift = radix_shift[base & 63];
|
shift = radix_shift[base & 63];
|
||||||
if (shift) {
|
if (shift) {
|
||||||
uint32_t mask = (1 << shift) - 1;
|
uint32_t mask = (1 << shift) - 1;
|
||||||
size_t len = (32 - clz32(n) + shift - 1) / shift;
|
size_t len = (size_t)((32 - clz32(n) + shift - 1) / shift);
|
||||||
size_t last = n & mask;
|
size_t last = n & mask;
|
||||||
char *end = buf + len;
|
char *end = buf + len;
|
||||||
n >>= shift;
|
n >>= shift;
|
||||||
|
@ -893,14 +895,15 @@ size_t u32toa_radix_length(char buf[minimum_length(33)], uint32_t n, unsigned ba
|
||||||
return len;
|
return len;
|
||||||
} else {
|
} else {
|
||||||
size_t len = 2;
|
size_t len = 2;
|
||||||
size_t last = n % base;
|
|
||||||
n /= base;
|
|
||||||
uint32_t nbase = base;
|
uint32_t nbase = base;
|
||||||
|
size_t last = n % base;
|
||||||
|
char *end;
|
||||||
|
n /= base;
|
||||||
while (n >= nbase) {
|
while (n >= nbase) {
|
||||||
nbase *= base;
|
nbase *= base;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
char *end = buf + len;
|
end = buf + len;
|
||||||
*end-- = '\0';
|
*end-- = '\0';
|
||||||
*end-- = digits36[last];
|
*end-- = digits36[last];
|
||||||
while (n >= base) {
|
while (n >= base) {
|
||||||
|
@ -927,33 +930,36 @@ size_t u64toa_radix_length(char buf[minimum_length(65)], uint64_t n, unsigned ba
|
||||||
buf[0] = digits36[n];
|
buf[0] = digits36[n];
|
||||||
buf[1] = '\0';
|
buf[1] = '\0';
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else {
|
||||||
uint64_t mask = (1 << shift) - 1;
|
uint64_t mask = (1 << shift) - 1;
|
||||||
size_t len = (64 - clz64(n) + shift - 1) / shift;
|
size_t len = (size_t)((64 - clz64(n) + shift - 1) / shift);
|
||||||
size_t last = n & mask;
|
size_t last = n & mask;
|
||||||
char *end = buf + len;
|
char *end = buf + len;
|
||||||
n >>= shift;
|
|
||||||
*end-- = '\0';
|
|
||||||
*end-- = digits36[last];
|
|
||||||
while (n >= base) {
|
|
||||||
size_t quo = n & mask;
|
|
||||||
n >>= shift;
|
n >>= shift;
|
||||||
*end-- = digits36[quo];
|
*end-- = '\0';
|
||||||
|
*end-- = digits36[last];
|
||||||
|
while (n >= base) {
|
||||||
|
size_t quo = n & mask;
|
||||||
|
n >>= shift;
|
||||||
|
*end-- = digits36[quo];
|
||||||
|
}
|
||||||
|
*end = digits36[n];
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
*end = digits36[n];
|
} else
|
||||||
return len;
|
if (likely(n < 0x100000000)) {
|
||||||
|
return u32toa_radix_length(buf, (uint32_t)n, base);
|
||||||
} else {
|
} else {
|
||||||
if (likely(n < 0x100000000))
|
|
||||||
return u32toa_radix_length(buf, n, base);
|
|
||||||
size_t last = n % base;
|
size_t last = n % base;
|
||||||
n /= base;
|
|
||||||
uint64_t nbase = base;
|
uint64_t nbase = base;
|
||||||
size_t len = 2;
|
size_t len = 2;
|
||||||
|
char *end;
|
||||||
|
n /= base;
|
||||||
while (n >= nbase) {
|
while (n >= nbase) {
|
||||||
nbase *= base;
|
nbase *= base;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
char *end = buf + len;
|
end = buf + len;
|
||||||
*end-- = '\0';
|
*end-- = '\0';
|
||||||
*end-- = digits36[last];
|
*end-- = digits36[last];
|
||||||
while (n >= base) {
|
while (n >= base) {
|
||||||
|
|
Loading…
Reference in a new issue