Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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 ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -3569,6 +3569,9 @@ function stream_isatty($stream): bool {}
#ifdef PHP_WIN32
/** @param resource $stream */
function sapi_windows_vt100_support($stream, ?bool $enable = null): bool {}

/** @param resource $stream */
function sapi_windows_console_size($stream): array|bool {}
#endif

/** @param resource $stream */
Expand Down
8 changes: 7 additions & 1 deletion ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions ext/standard/streamsfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,48 @@ PHP_FUNCTION(sapi_windows_vt100_support)
}
}
}

PHP_FUNCTION(sapi_windows_console_size)
{
zval *zsrc;
php_stream *stream;
zend_long fileno;
int width, height;
zval ztmp;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_RESOURCE(zsrc)
ZEND_PARSE_PARAMETERS_END();

php_stream_from_zval(stream, zsrc);

/* get the fd.
* NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag when casting.
* It is only used here so that the buffered data warning is not displayed.
*/
if (php_stream_can_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0);
} else if (php_stream_can_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL) == SUCCESS) {
php_stream_cast(stream, PHP_STREAM_AS_FD | PHP_STREAM_CAST_INTERNAL, (void*)&fileno, 0);
Comment on lines +1796 to +1799
Copy link
Member Author

Choose a reason for hiding this comment

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

I had copied this code from sapi_windows_vt100_support() without thinking. Now I had a closer look, and wondered why we even try to cast to PHP_STREAM_AS_FD_FOR_SELECT (we don't actually want to select). Looking at the implementation of php_stdiop_cast() it's clear: this cast won't flush (what we indeed don't want), but other possibly castable stream might not implement PHP_STREAM_AS_FD_FOR_SELECT . So these two cast attempts make some sense (although they rely on a leaky abstraction).

Then I wondered why we first check if we can cast and then actually do cast. Regarding the implementation that makes not much sense, but for the sake of abstraction it is correct. On the other hand, asking whether we can cast to PHP_STREAM_AS_FD actually flushes (for stdio stream), so this is somewhat (s/somewhat/completely) broken anyway.

Well, probably best to leave as is for now.

} else {
php_error_docref(NULL, E_WARNING, "not able to analyze the specified stream");
Copy link
Member Author

Choose a reason for hiding this comment

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

After reading https://bugs.php.net/bug.php?id=79805, I think the warning should be dropped (we only warn about this when sapi_windows_vt100_support() is used as setter).

RETURN_FALSE;
}

if (!php_win32_console_fileno_is_console(fileno)) {
RETURN_FALSE;
}

if (!php_win32_console_size(fileno, &width, &height)) {
RETURN_FALSE;
}

array_init(return_value);
ZVAL_LONG(&ztmp, width);
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &ztmp);
ZVAL_LONG(&ztmp, height);
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &ztmp);
}
#endif

#ifdef HAVE_SHUTDOWN
Expand Down
11 changes: 11 additions & 0 deletions win32/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,14 @@ PHP_WINUTIL_API BOOL php_win32_console_is_cli_sapi(void)
return strlen(sapi_module.name) >= sizeof("cli") - 1 && !strncmp(sapi_module.name, "cli", sizeof("cli") - 1);
}/*}}}*/

PHP_WINUTIL_API BOOL php_win32_console_size(zend_long fileno, int *width, int *height)
{
HANDLE handle = (HANDLE) _get_osfhandle(fileno);
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (!GetConsoleScreenBufferInfo(handle, &csbi)) {
return 0;
}
*width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
*height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
return 1;
}
3 changes: 3 additions & 0 deletions win32/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,7 @@ PHP_WINUTIL_API BOOL php_win32_console_is_own(void);
/* Check whether the current SAPI is run on console. */
PHP_WINUTIL_API BOOL php_win32_console_is_cli_sapi(void);

/* Gets the width and height of a console. */
PHP_WINUTIL_API BOOL php_win32_console_size(zend_long fileno, int *width, int *height);

#endif
Loading