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
148
cutils.c
148
cutils.c
|
@ -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,9 +789,9 @@ size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
|
|||
buf[0] = digits36[n];
|
||||
buf[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
char *end = buf + len;
|
||||
n >>= shift;
|
||||
|
@ -777,18 +804,21 @@ size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
|
|||
}
|
||||
*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();
|
||||
|
||||
/* Pacify some compilers. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
45
cutils.h
45
cutils.h
|
@ -25,6 +25,7 @@
|
|||
#ifndef CUTILS_H
|
||||
#define CUTILS_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
@ -72,21 +73,24 @@ static void *__builtin_frame_address(unsigned int level) {
|
|||
|
||||
// https://stackoverflow.com/a/6849629
|
||||
#undef FORMAT_STRING
|
||||
#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 /* FORMAT_STRING */
|
||||
#else
|
||||
# define FORMAT_STRING(p) 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 NEG_INF (-INFINITY)
|
||||
#else
|
||||
#define INF (1.0/0.0)
|
||||
#define NEG_INF (-1.0/0.0)
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
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 \
|
||||
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,9 +930,9 @@ size_t u64toa_radix_length(char buf[minimum_length(65)], uint64_t n, unsigned ba
|
|||
buf[0] = digits36[n];
|
||||
buf[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
char *end = buf + len;
|
||||
n >>= shift;
|
||||
|
@ -942,18 +945,21 @@ size_t u64toa_radix_length(char buf[minimum_length(65)], uint64_t n, unsigned ba
|
|||
}
|
||||
*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) {
|
||||
|
|
Loading…
Reference in a new issue