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:
Charlie Gordon 2024-03-20 20:07:39 +01:00
parent 3eaea6c4cf
commit 0536b42693
7 changed files with 1621 additions and 485 deletions

172
cutils.c
View file

@ -35,20 +35,19 @@
#include "cutils.h"
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
#define NANOSEC 1000000000
#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;
if (buf_size <= 0)
return;
for(;;) {
c = *str++;
char c = *str++;
if (c == 0 || q >= buf + buf_size - 1)
break;
*q++ = c;
@ -57,10 +56,9 @@ void pstrcpy(char *buf, int buf_size, const char *str)
}
/* 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;
len = strlen(buf);
size_t len = strlen(buf);
if (len < buf_size)
pstrcpy(buf + len, buf_size - len, s);
return buf;
@ -105,11 +103,6 @@ void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
s->realloc_func = realloc_func;
}
void dbuf_init(DynBuf *s)
{
dbuf_init2(s, NULL, NULL);
}
/* return < 0 if error */
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));
}
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
const char *fmt, ...)
static int dbuf_vprintf_default(DynBuf *s, const char *fmt, va_list ap)
{
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;
char buf[128];
int len;
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
len = (*dbuf_vprintf_fun)(s, fmt, ap);
va_end(ap);
if (len < sizeof(buf)) {
/* 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;
return len;
}
void dbuf_free(DynBuf *s)
@ -589,6 +612,7 @@ overflow:
/* 2 <= base <= 36 */
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_SINGLE_CASE_FAST 1 // special case single digit numbers
@ -600,7 +624,7 @@ char const digits36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
else \
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;
uint64_t buf = 0;
@ -615,7 +639,7 @@ size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
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;
dest += len;
@ -641,8 +665,9 @@ size_t u32toa(char buf[minimum_length(11)], uint32_t n)
#define TEN_POW_7 10000000
if (n >= TEN_POW_7) {
uint32_t quo = n / TEN_POW_7;
size_t len;
n %= TEN_POW_7;
size_t len = u7toa_shift(buf, quo);
len = u7toa_shift(buf, quo);
return u07toa_shift(buf, n, len);
}
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)
{
if (likely(n < 0x100000000))
return u32toa(buf, n);
size_t len;
if (likely(n < 0x100000000))
return u32toa(buf, (uint32_t)n);
if (n >= TEN_POW_7) {
uint64_t n1 = n / TEN_POW_7;
n %= 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;
len = u7toa_shift(buf, quo);
len = u07toa_shift(buf, n1, len);
len = u07toa_shift(buf, (uint32_t)n1, len);
} 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)
{
if (likely(n >= 0))
return u32toa(buf, n);
return u32toa(buf, (uint32_t)n);
buf[0] = '-';
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)
{
if (likely(n >= 0))
return u64toa(buf, n);
return u64toa(buf, (uint64_t)n);
buf[0] = '-';
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];
if (shift) {
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;
char *end = buf + len;
n >>= shift;
@ -729,13 +755,14 @@ size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
} else {
size_t len = 2;
size_t last = n % base;
n /= base;
uint32_t nbase = base;
char *end;
n /= base;
while (n >= nbase) {
nbase *= base;
len++;
}
char *end = buf + len;
end = buf + len;
*end-- = '\0';
*end-- = digits36[last];
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[1] = '\0';
return 1;
}
uint64_t mask = (1 << shift) - 1;
size_t len = (64 - clz64(n) + shift - 1) / shift;
size_t last = n & mask;
char *end = buf + len;
n >>= shift;
*end-- = '\0';
*end-- = digits36[last];
while (n >= base) {
size_t quo = n & mask;
} else {
uint64_t mask = (1 << shift) - 1;
size_t len = (size_t)((64 - clz64(n) + shift - 1) / shift);
size_t last = n & mask;
char *end = buf + len;
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];
return len;
} else
if (likely(n < 0x100000000)) {
return u32toa_radix(buf, (uint32_t)n, base);
} else {
if (likely(n < 0x100000000))
return u32toa_radix(buf, n, base);
size_t last = n % base;
n /= base;
uint64_t nbase = base;
size_t len = 2;
char *end;
n /= base;
while (n >= nbase) {
nbase *= base;
len++;
}
char *end = buf + len;
end = buf + len;
*end-- = '\0';
*end-- = digits36[last];
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)
{
if (likely(n >= 0))
return u64toa_radix(buf, n, base);
return u64toa_radix(buf, (uint64_t)n, base);
buf[0] = '-';
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 */
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;
size_t m4, i, lt, gt, span, span2;
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)
return 0;
if (r == ETIMEDOUT)
return -1;
if (r != ETIMEDOUT)
abort();
abort();
/* Pacify some compilers. */
return -1;
}

View file

@ -25,6 +25,7 @@
#ifndef CUTILS_H
#define CUTILS_H
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
@ -72,24 +73,27 @@ static void *__builtin_frame_address(unsigned int level) {
// https://stackoverflow.com/a/6849629
#undef FORMAT_STRING
#if _MSC_VER >= 1400
# include <sal.h>
# if _MSC_VER > 1400
# define FORMAT_STRING(p) _Printf_format_string_ p
# else
# define FORMAT_STRING(p) __format_string p
# endif /* FORMAT_STRING */
#else
# define FORMAT_STRING(p) p
#ifdef _MSC_VER
# if _MSC_VER >= 1400
# include <sal.h>
# if _MSC_VER > 1400
# define FORMAT_STRING(p) _Printf_format_string_ p
# else
# define FORMAT_STRING(p) __format_string p
# endif
# endif
#endif /* _MSC_VER */
#ifndef FORMAT_STRING
# define FORMAT_STRING(p) p
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#include <math.h>
#define INF INFINITY
#define NEG_INF -INFINITY
#define INF INFINITY
#define NEG_INF (-INFINITY)
#else
#define INF (1.0/0.0)
#define NEG_INF (-1.0/0.0)
#define INF (1.0/0.0)
#define NEG_INF (-1.0/0.0)
#endif
#define xglue(x, y) x ## y
@ -126,8 +130,8 @@ enum {
};
#endif
void pstrcpy(char *buf, int buf_size, const char *str);
char *pstrcat(char *buf, int buf_size, const char *s);
void pstrcpy(char *buf, size_t buf_size, const char *str);
char *pstrcat(char *buf, size_t buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr);
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)
{
#if defined(_MSC_VER) && !defined(__clang__)
// XXX: unsigned int _lzcnt_u32(unsigned int a)
unsigned long index;
_BitScanReverse(&index, a);
return 31 - index;
@ -203,6 +208,7 @@ static inline int clz32(unsigned int a)
static inline int clz64(uint64_t a)
{
#if defined(_MSC_VER) && !defined(__clang__)
// XXX: unsigned int _lzcnt_u64(unsigned __int64 a)
unsigned long index;
_BitScanReverse64(&index, a);
return 63 - index;
@ -215,6 +221,7 @@ static inline int clz64(uint64_t a)
static inline int ctz32(unsigned int a)
{
#if defined(_MSC_VER) && !defined(__clang__)
// XXX: unsigned int _tzcnt_u32 (unsigned int a)
unsigned long index;
_BitScanForward(&index, a);
return index;
@ -227,6 +234,7 @@ static inline int ctz32(unsigned int a)
static inline int ctz64(uint64_t a)
{
#if defined(_MSC_VER) && !defined(__clang__)
// XXX: unsigned int _tzcnt_u64 (unsigned __int64 a)
unsigned long index;
_BitScanForward64(&index, a);
return index;
@ -310,7 +318,7 @@ static inline void put_u8(uint8_t *tab, uint8_t val)
#ifndef bswap16
static inline uint16_t bswap16(uint16_t x)
{
return (x >> 8) | (x << 8);
return (uint16_t)((x >> 8) | (x << 8));
}
#endif
@ -337,7 +345,7 @@ static inline uint64_t bswap64(uint64_t v)
#endif
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) {
@ -352,12 +360,15 @@ typedef struct DynBuf {
size_t size;
size_t allocated_size;
BOOL error; /* true if a memory allocation error occurred */
#if SIZE_MAX > UINT_MAX
int pad; /* prevent alignment warning */
#endif
DynBufReallocFunc *realloc_func;
void *opaque; /* for realloc_func */
} DynBuf;
void dbuf_init(DynBuf *s);
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_write(DynBuf *s, size_t offset, 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);
}
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
FORMAT_STRING(const char *fmt), ...);
__attribute__((format(printf, 2, 3)))
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);
static inline BOOL dbuf_error(DynBuf *s) {
return s->error;
@ -450,15 +462,24 @@ static inline int from_hex(int c)
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) {
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) {
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_upper[36];
size_t u32toa(char buf[minimum_length(11)], uint32_t n);
size_t i32toa(char buf[minimum_length(12)], int32_t n);
size_t u64toa(char buf[minimum_length(21)], uint64_t n);

View file

@ -185,7 +185,7 @@ static JSValue js_printf_internal(JSContext *ctx,
double double_arg;
const char *string_arg;
/* 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);
@ -225,7 +225,9 @@ static JSValue js_printf_internal(JSContext *ctx,
goto missing;
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
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++;
} else {
while (my_isdigit(*fmt)) {
@ -243,7 +245,9 @@ static JSValue js_printf_internal(JSContext *ctx,
goto missing;
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
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++;
} else {
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 */
mod = ' ';
if (*fmt == 'l') {
mod = *fmt++;
/* we only support the "l" modifier for 64 bit numbers
and the w# length modifier with a bitlength of 1 to 64
*/
// 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 */
@ -286,10 +313,14 @@ static JSValue js_printf_internal(JSContext *ctx,
if ((unsigned)int32_arg > 0x10FFFF)
int32_arg = 0xFFFD;
/* 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);
dbuf_put(&dbuf, cbuf, len);
break;
case 'b':
case 'B':
case 'd':
case 'i':
case 'o':
@ -298,27 +329,12 @@ static JSValue js_printf_internal(JSContext *ctx,
case 'X':
if (i >= argc)
goto missing;
// XXX: should handle BigInt values
if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
goto fail;
if (mod == 'l') {
/* 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);
#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 {
dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
}
@ -328,6 +344,10 @@ static JSValue js_printf_internal(JSContext *ctx,
if (i >= argc)
goto missing;
/* 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++]);
if (!string_arg)
goto fail;
@ -351,6 +371,8 @@ static JSValue js_printf_internal(JSContext *ctx,
break;
case '%':
if (q != fmtbuf + 2) // accept only %%
goto invalid;
dbuf_putc(&dbuf, '%');
break;

1092
quickjs-printf.c Normal file

File diff suppressed because it is too large Load diff

63
quickjs-printf.h Normal file
View 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

578
quickjs.c

File diff suppressed because it is too large Load diff

View file

@ -152,7 +152,7 @@ size_t i64toa_##v(char buf[minimum_length(22)], int64_t n) \
else \
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;
uint64_t buf = 0;
@ -167,7 +167,7 @@ size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
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;
dest += len;
@ -193,8 +193,9 @@ size_t u32toa_shift(char buf[minimum_length(11)], uint32_t n)
#define TEN_POW_7 10000000
if (n >= TEN_POW_7) {
uint32_t quo = n / TEN_POW_7;
size_t len;
n %= TEN_POW_7;
size_t len = u7toa_shift(buf, quo);
len = u7toa_shift(buf, quo);
return u07toa_shift(buf, n, len);
}
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)
{
if (likely(n < 0x100000000))
return u32toa_shift(buf, n);
size_t len;
if (likely(n < 0x100000000))
return u32toa_shift(buf, (uint32_t)n);
if (n >= TEN_POW_7) {
uint64_t n1 = n / TEN_POW_7;
n %= 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;
len = u7toa_shift(buf, quo);
len = u07toa_shift(buf, n1, len);
len = u07toa_shift(buf, (uint32_t)n1, len);
} 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)
@ -878,7 +880,7 @@ size_t u32toa_radix_length(char buf[minimum_length(33)], uint32_t n, unsigned ba
shift = radix_shift[base & 63];
if (shift) {
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;
char *end = buf + len;
n >>= shift;
@ -893,14 +895,15 @@ size_t u32toa_radix_length(char buf[minimum_length(33)], uint32_t n, unsigned ba
return len;
} else {
size_t len = 2;
size_t last = n % base;
n /= base;
uint32_t nbase = base;
size_t last = n % base;
char *end;
n /= base;
while (n >= nbase) {
nbase *= base;
len++;
}
char *end = buf + len;
end = buf + len;
*end-- = '\0';
*end-- = digits36[last];
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[1] = '\0';
return 1;
}
uint64_t mask = (1 << shift) - 1;
size_t len = (64 - clz64(n) + shift - 1) / shift;
size_t last = n & mask;
char *end = buf + len;
n >>= shift;
*end-- = '\0';
*end-- = digits36[last];
while (n >= base) {
size_t quo = n & mask;
} else {
uint64_t mask = (1 << shift) - 1;
size_t len = (size_t)((64 - clz64(n) + shift - 1) / shift);
size_t last = n & mask;
char *end = buf + len;
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];
return len;
} else
if (likely(n < 0x100000000)) {
return u32toa_radix_length(buf, (uint32_t)n, base);
} else {
if (likely(n < 0x100000000))
return u32toa_radix_length(buf, n, base);
size_t last = n % base;
n /= base;
uint64_t nbase = base;
size_t len = 2;
char *end;
n /= base;
while (n >= nbase) {
nbase *= base;
len++;
}
char *end = buf + len;
end = buf + len;
*end-- = '\0';
*end-- = digits36[last];
while (n >= base) {