Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added `filename:dirname/1`, `filename:basename/1,2`, `filename:extension/1`, `filename:rootname/1,2` and `filename:join/2`
- Added `init:get_arguments/0`
- Added `console:print_err/1` to write to standard error
- Added Erlang distribution over serial (uart)
- Added WASM32 JIT backend for Emscripten platform
- Added `network:wifi_scan/0,1` to ESP32 network driver to scan available APs when in sta or sta+ap mode.
Expand Down Expand Up @@ -54,6 +55,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`header_continuation` / `trailer_header_continuation` response events are no longer emitted

### Fixed
- Route `io:put_chars(standard_error, ...)` and `io:format(standard_error, ...)` to stderr instead
of aliasing them to standard_io (diagnostics no longer pollute an escript's stdout)
- Stop using deprecated `term_from_int32` on STM32 platform
- Stop using deprecated `term_from_int32` on RP2 platform
- Stop using deprecated `term_from_int32` on ESP32 platform
Expand Down
5 changes: 5 additions & 0 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ were using the `0x210000` offset.
* Instantiate with `const module = await AtomVM({ arguments: [...] })`
* The old implicit global-script pattern is no longer supported
* `AtomVM.worker.js` is no longer emitted; only `AtomVM.mjs` and `AtomVM.wasm` are needed
- `io:put_chars(standard_error, ...)` (and `io:format/3`, `io:fwrite/3` targeting
`standard_error`) now write directly to the OS standard error stream via `console:print_err/1`,
instead of being routed through the process group leader as an alias for `standard_io`. Code or
tests that captured `standard_error` output by swapping the group leader must instead redirect
or intercept the underlying stderr stream, or pass an explicit pid/device.

## v0.6.4 -> v0.6.5

Expand Down
13 changes: 12 additions & 1 deletion libs/eavmlib/src/console.erl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
%%-----------------------------------------------------------------------------
-module(console).

-export([start/0, puts/1, puts/2, flush/0, flush/1, print/1]).
-export([start/0, puts/1, puts/2, flush/0, flush/1, print/1, print_err/1]).

%%-----------------------------------------------------------------------------
%% @param Text the string data to write to the console
Expand Down Expand Up @@ -74,6 +74,17 @@ flush(Console) ->
print(_Text) ->
erlang:nif_error(undefined).

%%-----------------------------------------------------------------------------
%% @param Text the data to write to the standard error
%% @returns ok if the data was written, or {error, Reason}, if there was
%% an error.
%% @doc Write a string to the console's standard error.
%% @end
%%-----------------------------------------------------------------------------
-spec print_err(Text :: iodata()) -> ok | {error, term()}.
print_err(_Text) ->
erlang:nif_error(undefined).

%% Internal operations

%% @private
Expand Down
2 changes: 1 addition & 1 deletion libs/estdlib/src/io.erl
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ put_chars(standard_io, Chars) ->
execute_request(Leader, {put_chars, unicode, Chars})
end;
put_chars(standard_error, Chars) ->
put_chars(standard_io, Chars).
console:print_err(Chars).

%% @private
convert_request({requests, Requests}) ->
Expand Down
35 changes: 27 additions & 8 deletions src/libAtomVM/nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ static term nif_atomvm_get_start_beam(Context *ctx, int argc, term argv[]);
static term nif_atomvm_read_priv(Context *ctx, int argc, term argv[]);
static term nif_atomvm_get_creation(Context *ctx, int argc, term argv[]);
static term nif_console_print(Context *ctx, int argc, term argv[]);
static term nif_console_print_err(Context *ctx, int argc, term argv[]);
static term nif_base64_encode(Context *ctx, int argc, term argv[]);
static term nif_base64_decode(Context *ctx, int argc, term argv[]);
static term nif_base64_encode_to_string(Context *ctx, int argc, term argv[]);
Expand Down Expand Up @@ -827,6 +828,10 @@ static const struct Nif console_print_nif = {
.base.type = NIFFunctionType,
.nif_ptr = nif_console_print
};
static const struct Nif console_print_err_nif = {
.base.type = NIFFunctionType,
.nif_ptr = nif_console_print_err
};
static const struct Nif base64_encode_nif = {
.base.type = NIFFunctionType,
.nif_ptr = nif_base64_encode
Expand Down Expand Up @@ -5635,16 +5640,14 @@ static term nif_atomvm_get_creation(Context *ctx, int argc, term argv[])
return term_make_maybe_boxed_int64(ctx->global->creation, &ctx->heap);
}

static term nif_console_print(Context *ctx, int argc, term argv[])
static term console_print_to(FILE *stream, Context *ctx, term argv[])
{
UNUSED(argc);

term t = argv[0];
if (term_is_binary(t)) {
const char *data = term_binary_data(t);
unsigned long n = term_binary_size(t);
fprintf(stdout, "%.*s", (int) n, data);
fflush(stdout);
size_t n = term_binary_size(t);
fwrite(data, 1, n, stream);
fflush(stream);
} else {
size_t size;
switch (interop_iolist_size(t, &size)) {
Expand All @@ -5655,6 +5658,10 @@ static term nif_console_print(Context *ctx, int argc, term argv[])
case InteropBadArg:
RAISE_ERROR(BADARG_ATOM);
}
if (size == 0) {
fflush(stream);
return OK_ATOM;
}
char *buf = malloc(size);
if (IS_NULL_PTR(buf)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
Expand All @@ -5669,13 +5676,25 @@ static term nif_console_print(Context *ctx, int argc, term argv[])
free(buf);
RAISE_ERROR(BADARG_ATOM);
}
fprintf(stdout, "%.*s", (int) size, buf);
fflush(stdout);
fwrite(buf, 1, size, stream);
fflush(stream);
free(buf);
}
return OK_ATOM;
}

static term nif_console_print(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
return console_print_to(stdout, ctx, argv);
}

static term nif_console_print_err(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
return console_print_to(stderr, ctx, argv);
}

// clang-format off
static const char b64_table[64] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
Expand Down
1 change: 1 addition & 0 deletions src/libAtomVM/nifs.gperf
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ code_server:type_resolver/2, IF_HAVE_JIT(&code_server_type_resolver_nif)
code_server:import_resolver/2, IF_HAVE_JIT(&code_server_import_resolver_nif)
code_server:set_native_code/3, IF_HAVE_JIT(&code_server_set_native_code_nif)
console:print/1, &console_print_nif
console:print_err/1, &console_print_err_nif
base64:encode/1, &base64_encode_nif
base64:encode/2, &base64_encode_nif
base64:decode/1, &base64_decode_nif
Expand Down
Loading