1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 19:19:53 +00:00

Add eprintf and make printf a C function.

This allows some more optimizations when printing to
buffers or when output is disabled. It also makes printf
more consistent with print and prin (Same with eprintf).
This commit is contained in:
Calvin Rose 2019-10-19 10:30:29 -05:00
parent d47804d222
commit 8dd8af742a
2 changed files with 83 additions and 22 deletions

View File

@ -1182,18 +1182,11 @@
(file/close f)
nil)
(defn printf
"Print formatted strings to stdout or (dyn :out), followed by
a new line."
[f & args]
(prin (buffer/format @"" f ;args)))
(defn pp
"Pretty print to stdout or (dyn :out)."
[x]
(print (buffer/format @"" (dyn :pretty-format "%q") x)))
###
###
### Pattern Matching

View File

@ -390,13 +390,13 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
Janet x = janet_dyn(name);
switch (janet_type(x)) {
default:
goto err;
/* Other values simply do nothing */
return janet_wrap_nil();
case JANET_BUFFER: {
/* Special case buffer */
JanetBuffer *buf = janet_unwrap_buffer(x);
for (int32_t i = 0; i < argc; ++i) {
const uint8_t *vstr = janet_to_string(argv[i]);
janet_buffer_push_string(buf, vstr);
janet_to_string_b(buf, argv[i]);
}
if (newline)
janet_buffer_push_u8(buf, '\n');
@ -407,25 +407,31 @@ static Janet cfun_io_print_impl(int32_t argc, Janet *argv,
break;
case JANET_ABSTRACT: {
void *abstract = janet_unwrap_abstract(x);
if (janet_abstract_type(abstract) != &cfun_io_filetype) goto err;
if (janet_abstract_type(abstract) != &cfun_io_filetype)
return janet_wrap_nil();
IOFile *iofile = abstract;
f = iofile->file;
break;
}
}
for (int32_t i = 0; i < argc; ++i) {
int32_t j, len;
const uint8_t *vstr = janet_to_string(argv[i]);
len = janet_string_length(vstr);
for (j = 0; j < len; ++j) {
putc(vstr[j], f);
int32_t len;
const uint8_t *vstr;
if (janet_checktype(argv[i], JANET_BUFFER)) {
JanetBuffer *b = janet_unwrap_buffer(argv[i]);
vstr = b->data;
len = b->count;
} else {
vstr = janet_to_string(argv[i]);
len = janet_string_length(vstr);
}
if (1 != fwrite(vstr, len, 1, f)) {
janet_panicf("could not print %d bytes to (dyn :%s)", len, name);
}
}
if (newline)
putc('\n', f);
return janet_wrap_nil();
err:
janet_panicf("expected (dyn :%s) to be a file, buffer, or nil; got %v", name, x);
}
static Janet cfun_io_print(int32_t argc, Janet *argv) {
@ -444,6 +450,55 @@ static Janet cfun_io_eprin(int32_t argc, Janet *argv) {
return cfun_io_print_impl(argc, argv, 0, "err", stderr);
}
static Janet cfun_io_printf_impl(int32_t argc, Janet *argv,
const char *name, FILE *dflt_file) {
FILE *f;
janet_arity(argc, 1, -1);
const char *fmt = janet_getcstring(argv, 0);
Janet x = janet_dyn(name);
switch (janet_type(x)) {
default:
/* Other values simply do nothing */
return janet_wrap_nil();
case JANET_BUFFER: {
/* Special case buffer */
JanetBuffer *buf = janet_unwrap_buffer(x);
janet_buffer_format(buf, fmt, 0, argc, argv);
return janet_wrap_nil();
}
case JANET_NIL:
f = dflt_file;
break;
case JANET_ABSTRACT: {
void *abstract = janet_unwrap_abstract(x);
if (janet_abstract_type(abstract) != &cfun_io_filetype)
return janet_wrap_nil();
IOFile *iofile = abstract;
f = iofile->file;
break;
}
}
JanetBuffer *buf = janet_buffer(10);
janet_buffer_format(buf, fmt, 0, argc, argv);
if (1 != fwrite(buf->data, buf->count, 1, f)) {
janet_panicf("could not print %d bytes to file", buf->count, name);
}
/* Clear buffer to make things easier for GC */
buf->count = 0;
buf->capacity = 0;
free(buf->data);
buf->data = NULL;
return janet_wrap_nil();
}
static Janet cfun_io_printf(int32_t argc, Janet *argv) {
return cfun_io_printf_impl(argc, argv, "out", stdout);
}
static Janet cfun_io_eprintf(int32_t argc, Janet *argv) {
return cfun_io_printf_impl(argc, argv, "err", stderr);
}
void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...) {
va_list args;
va_start(args, format);
@ -451,6 +506,9 @@ void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...)
JanetType xtype = janet_type(x);
switch (xtype) {
default:
/* Other values simply do nothing */
break;
case JANET_NIL:
case JANET_ABSTRACT: {
FILE *f = dflt_file;
JanetBuffer buffer;
@ -460,10 +518,10 @@ void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...)
janet_formatb(&buffer, format, args);
if (xtype == JANET_ABSTRACT) {
void *abstract = janet_unwrap_abstract(x);
if (janet_abstract_type(abstract) == &cfun_io_filetype) {
IOFile *iofile = abstract;
f = iofile->file;
}
if (janet_abstract_type(abstract) != &cfun_io_filetype)
break;
IOFile *iofile = abstract;
f = iofile->file;
}
fwrite(buffer.data, buffer.count, 1, f);
janet_buffer_deinit(&buffer);
@ -492,6 +550,11 @@ static const JanetReg io_cfuns[] = {
JDOC("(prin & xs)\n\n"
"Same as print, but does not add trailing newline.")
},
{
"printf", cfun_io_printf,
JDOC("(printf fmt & xs)\n\n"
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :out stdout).")
},
{
"eprin", cfun_io_eprin,
JDOC("(eprin & xs)\n\n"
@ -502,6 +565,11 @@ static const JanetReg io_cfuns[] = {
JDOC("(eprint & xs)\n\n"
"Same as print, but uses (dyn :err stderr) instead of (dyn :out stdout).")
},
{
"eprintf", cfun_io_eprintf,
JDOC("(eprintf fmt & xs)\n\n"
"Prints output formatted as if with (string/format fmt ;xs) to (dyn :err stderr).")
},
{
"file/open", cfun_io_fopen,
JDOC("(file/open path &opt mode)\n\n"