Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect if stdout is a console in quickjs-libc #642

Merged
merged 1 commit into from
Oct 31, 2024

Conversation

bnoordhuis
Copy link
Contributor

Use regular libc stdio (fwrite) when stdout is redirected, don't call WriteConsoleA because that circumvents the redirection.

Fixes: #635

putchar(' ');
str = JS_ToCStringLen(ctx, &len, argv[i]);
if (!str)
return JS_EXCEPTION;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functional change which IMO is an improvement: exceptions no longer cause truncated output

JS_FreeCString(ctx, str);
s = JS_ToCString(ctx, argv[i]);
if (s) {
dbuf_printf(&b, "%s%s", &" "[!i], s);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My brain is not parsing those arguments, what's the sorcery here? 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It prints a space only when i != 0. When i == 0, it passes a pointer to the nul byte because !0 == 1 :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL, nice trick!

quickjs-libc.c Show resolved Hide resolved
quickjs-libc.c Outdated
Comment on lines 3936 to 3955
#ifdef _WIN32
handle = (HANDLE)_get_osfhandle(/*STDOUT_FILENO*/1); // don't CloseHandle
if (GetFileType(handle) != FILE_TYPE_CHAR)
goto fallback;
if (!GetConsoleMode(handle, &mode))
goto fallback;
handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (handle == INVALID_HANDLE_VALUE)
goto fallback;
mode = GetConsoleOutputCP();
SetConsoleOutputCP(CP_UTF8);
WriteConsoleA(handle, b.buf, b.size, NULL, NULL);
SetConsoleOutputCP(mode);
FlushFileBuffers(handle);
goto done;
fallback:
#endif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For casual readers of this code that are unfamiliar with legacy system intricacies, could you add a comment explaining why we need to special case console output on Windows?

I wish we used a more general approach such as detecting the condition once at startup and setting up the system handle 1 or the stdout stream to have the expected behavior for all output calls. Hacking this behavior in js_print seems incorrect, we should have a lower level API that wraps all output to stdout.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add that comment.

detecting the condition once at startup

That's worse because it doesn't handle runtime changes (and from 15 years of node and libuv bug reports I can tell you people do do stuff like reopening stdout at runtime)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, another potential issue: shouldn't you move the call to FlushFileBuffers(handle) before restoring the console mode with SetConsoleOutputCP(mode)? flushing the buffers before the mode change might also be necessary.

This hack really stinks: what if QuickJS is run in a different shell (like cygwin of the old days) or via a remote connection to a Windows host?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't you move the call to FlushFileBuffers(handle) before restoring the console mode with SetConsoleOutputCP(mode)?

I don't think it matters but I wouldn't mind being proven wrong.

what if QuickJS is run in a different shell (like cygwin of the old days) or via a remote connection to a Windows host?

We'll just wait for the bug reports to come in :-)

Use regular libc stdio (fwrite) when stdout is redirected, don't
call WriteConsoleA because that circumvents the redirection.

Fixes: quickjs-ng#635
@bnoordhuis bnoordhuis merged commit c53a0a8 into quickjs-ng:master Oct 31, 2024
3 checks passed
@bnoordhuis bnoordhuis deleted the fix635 branch October 31, 2024 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

qjs fails to output content via stdout to pipe or non-console receiver
3 participants