Skip to content

Commit ead95a7

Browse files
committed
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`
1 parent 83726bb commit ead95a7

File tree

6 files changed

+904
-393
lines changed

6 files changed

+904
-393
lines changed

cutils.c

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -178,29 +178,43 @@ int dbuf_putstr(DynBuf *s, const char *str)
178178
return dbuf_put(s, (const uint8_t *)str, strlen(str));
179179
}
180180

181-
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
182-
const char *fmt, ...)
181+
static int dbuf_vprintf_default(DynBuf *s, const char *fmt, va_list ap)
182+
{
183+
va_list arg;
184+
size_t avail = s->allocated_size - s->size;
185+
int len;
186+
187+
va_copy(arg, ap);
188+
len = vsnprintf((char *)(s->buf + s->size), avail, fmt, arg);
189+
va_end(arg);
190+
191+
if (len >= 0) {
192+
if ((size_t)len >= avail) {
193+
if (dbuf_realloc(s, s->size + len + 1))
194+
return -1;
195+
avail = s->allocated_size - s->size;
196+
va_copy(arg, ap);
197+
vsnprintf((char *)(s->buf + s->size), avail, fmt, arg);
198+
va_end(arg);
199+
}
200+
s->size += len;
201+
}
202+
return len;
203+
}
204+
205+
/* replaceable formatter */
206+
int (*dbuf_vprintf_fun)(DynBuf *s, const char *fmt, va_list ap) = dbuf_vprintf_default;
207+
208+
__attribute__((format(printf, 2, 3)))
209+
int dbuf_printf(DynBuf *s, const char *fmt, ...)
183210
{
184211
va_list ap;
185-
char buf[128];
186212
int len;
187213

188214
va_start(ap, fmt);
189-
len = vsnprintf(buf, sizeof(buf), fmt, ap);
215+
len = (*dbuf_vprintf_fun)(s, fmt, ap);
190216
va_end(ap);
191-
if (len < sizeof(buf)) {
192-
/* fast case */
193-
return dbuf_put(s, (uint8_t *)buf, len);
194-
} else {
195-
if (dbuf_realloc(s, s->size + len + 1))
196-
return -1;
197-
va_start(ap, fmt);
198-
vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,
199-
fmt, ap);
200-
va_end(ap);
201-
s->size += len;
202-
}
203-
return 0;
217+
return len;
204218
}
205219

206220
void dbuf_free(DynBuf *s)

cutils.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#ifndef CUTILS_H
2626
#define CUTILS_H
2727

28+
#include <stdarg.h>
2829
#include <stdlib.h>
2930
#include <string.h>
3031
#include <inttypes.h>
@@ -376,8 +377,9 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
376377
{
377378
return dbuf_put(s, (uint8_t *)&val, 8);
378379
}
379-
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
380-
FORMAT_STRING(const char *fmt), ...);
380+
__attribute__((format(printf, 2, 3)))
381+
int dbuf_printf(DynBuf *s, FORMAT_STRING(const char *fmt), ...);
382+
extern int (*dbuf_vprintf_fun)(DynBuf *s, const char *fmt, va_list ap);
381383
void dbuf_free(DynBuf *s);
382384
static inline BOOL dbuf_error(DynBuf *s) {
383385
return s->error;

quickjs-libc.c

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ static JSValue js_printf_internal(JSContext *ctx,
184184
int64_t int64_arg;
185185
double double_arg;
186186
const char *string_arg;
187-
/* Use indirect call to dbuf_printf to prevent gcc warning */
188-
int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf;
189187

190188
js_std_dbuf_init(ctx, &dbuf);
191189

@@ -225,7 +223,9 @@ static JSValue js_printf_internal(JSContext *ctx,
225223
goto missing;
226224
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
227225
goto fail;
228-
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
226+
if (q > fmtbuf + sizeof(fmtbuf) - 11)
227+
goto invalid;
228+
q += i32toa(q, int32_arg);
229229
fmt++;
230230
} else {
231231
while (my_isdigit(*fmt)) {
@@ -243,7 +243,9 @@ static JSValue js_printf_internal(JSContext *ctx,
243243
goto missing;
244244
if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
245245
goto fail;
246-
q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
246+
if (q > fmtbuf + sizeof(fmtbuf) - 11)
247+
goto invalid;
248+
q += i32toa(q, int32_arg);
247249
fmt++;
248250
} else {
249251
while (my_isdigit(*fmt)) {
@@ -254,10 +256,33 @@ static JSValue js_printf_internal(JSContext *ctx,
254256
}
255257
}
256258

257-
/* we only support the "l" modifier for 64 bit numbers */
258-
mod = ' ';
259-
if (*fmt == 'l') {
260-
mod = *fmt++;
259+
/* we only support the "l" modifier for 64 bit numbers
260+
and the w# length modifier with a bitlength of 1 to 64
261+
*/
262+
// XXX: should use value changing conversions
263+
mod = *fmt;
264+
if (mod == 'w') {
265+
int bitwidth;
266+
if (q >= fmtbuf + sizeof(fmtbuf) - 4)
267+
goto invalid;
268+
*q++ = *fmt++;
269+
if (!(*fmt >= '1' && *fmt <= '9'))
270+
goto invalid;
271+
bitwidth = *fmt - '0';
272+
*q++ = *fmt++;
273+
if (*fmt >= '0' && *fmt <= '9') {
274+
bitwidth = bitwidth * 10 + *fmt - '0';
275+
*q++ = *fmt++;
276+
}
277+
if (bitwidth > 32)
278+
mod = 'l';
279+
} else
280+
if (mod == 'l') {
281+
fmt++;
282+
if (q >= fmtbuf + sizeof(fmtbuf) - 3)
283+
goto invalid;
284+
*q++ = 'l';
285+
*q++ = 'l';
261286
}
262287

263288
/* type */
@@ -285,10 +310,14 @@ static JSValue js_printf_internal(JSContext *ctx,
285310
if ((unsigned)int32_arg > 0x10FFFF)
286311
int32_arg = 0xFFFD;
287312
/* ignore conversion flags, width and precision */
313+
// XXX: Hash modifier could output pretty Unicode character
314+
// XXX: `l` length modifier is implicit
288315
len = unicode_to_utf8(cbuf, int32_arg);
289316
dbuf_put(&dbuf, cbuf, len);
290317
break;
291318

319+
case 'b':
320+
case 'B':
292321
case 'd':
293322
case 'i':
294323
case 'o':
@@ -297,40 +326,29 @@ static JSValue js_printf_internal(JSContext *ctx,
297326
case 'X':
298327
if (i >= argc)
299328
goto missing;
329+
// XXX: should handle BigInt values
300330
if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
301331
goto fail;
302332
if (mod == 'l') {
303333
/* 64 bit number */
304-
#if defined(_WIN32)
305-
if (q >= fmtbuf + sizeof(fmtbuf) - 3)
306-
goto invalid;
307-
q[2] = q[-1];
308-
q[-1] = 'I';
309-
q[0] = '6';
310-
q[1] = '4';
311-
q[3] = '\0';
312-
dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);
313-
#else
314-
if (q >= fmtbuf + sizeof(fmtbuf) - 2)
315-
goto invalid;
316-
q[1] = q[-1];
317-
q[-1] = q[0] = 'l';
318-
q[2] = '\0';
319-
dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
320-
#endif
334+
dbuf_printf(&dbuf, fmtbuf, (int64_t)int64_arg);
321335
} else {
322-
dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
336+
dbuf_printf(&dbuf, fmtbuf, (int)int64_arg);
323337
}
324338
break;
325339

326340
case 's':
327341
if (i >= argc)
328342
goto missing;
329343
/* XXX: handle strings containing null characters */
344+
// XXX: # could output encoded string
345+
// XXX: null values should output as `<null>`
346+
// XXX: undefined values should output as `<undefined>`
347+
// XXX: `l` length modifier is implicit
330348
string_arg = JS_ToCString(ctx, argv[i++]);
331349
if (!string_arg)
332350
goto fail;
333-
dbuf_printf_fun(&dbuf, fmtbuf, string_arg);
351+
dbuf_printf(&dbuf, fmtbuf, string_arg);
334352
JS_FreeCString(ctx, string_arg);
335353
break;
336354

@@ -346,10 +364,12 @@ static JSValue js_printf_internal(JSContext *ctx,
346364
goto missing;
347365
if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
348366
goto fail;
349-
dbuf_printf_fun(&dbuf, fmtbuf, double_arg);
367+
dbuf_printf(&dbuf, fmtbuf, double_arg);
350368
break;
351369

352370
case '%':
371+
if (q != fmtbuf + 2) // accept only %%
372+
goto invalid;
353373
dbuf_putc(&dbuf, '%');
354374
break;
355375

0 commit comments

Comments
 (0)