[openwrt/openwrt] ucode-mod-uline: add support for querying window size from terminal if ioctl fails
LEDE Commits
lede-commits at lists.infradead.org
Fri Feb 28 08:36:17 PST 2025
nbd pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/8835ecf29b0610dc00bdd6e15578ec52699184c2
commit 8835ecf29b0610dc00bdd6e15578ec52699184c2
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Thu Feb 27 11:21:22 2025 +0100
ucode-mod-uline: add support for querying window size from terminal if ioctl fails
This is useful for running the cli on a serial console
Signed-off-by: Felix Fietkau <nbd at nbd.name>
---
package/utils/ucode-mod-uline/src/private.h | 14 +++++++-
package/utils/ucode-mod-uline/src/uline.c | 43 +++++++++++++++++-------
package/utils/ucode-mod-uline/src/uline.h | 3 +-
package/utils/ucode-mod-uline/src/vt100.c | 51 ++++++++++++++++++-----------
4 files changed, 78 insertions(+), 33 deletions(-)
diff --git a/package/utils/ucode-mod-uline/src/private.h b/package/utils/ucode-mod-uline/src/private.h
index fa38d06737..e53ec22e03 100644
--- a/package/utils/ucode-mod-uline/src/private.h
+++ b/package/utils/ucode-mod-uline/src/private.h
@@ -52,6 +52,7 @@ enum vt100_escape {
VT100_CURSOR_WORD_LEFT,
VT100_CURSOR_RIGHT,
VT100_CURSOR_WORD_RIGHT,
+ VT100_CURSOR_POS,
VT100_HOME,
VT100_END,
VT100_INSERT,
@@ -63,7 +64,7 @@ enum vt100_escape {
};
ssize_t utf8_nsyms(const char *str, size_t len);
-enum vt100_escape vt100_esc_decode(const char *str);
+enum vt100_escape vt100_esc_decode(const char *str, uint32_t *data);
// helpers:
void __vt100_csi_num(FILE *out, int num, char code);
@@ -191,4 +192,15 @@ static inline void vt100_ding(FILE *out)
fflush(out);
}
+static inline void vt100_request_window_size(FILE *out)
+{
+ fputs(
+ "\e7" /* save cursor position */
+ "\e[r" /* reset margins */
+ "\e[999;999H" /* move cursor to bottom right */
+ "\e[6n" /* report cursor position */
+ "\e8", /* restore cursor position */
+ out);
+}
+
#endif
diff --git a/package/utils/ucode-mod-uline/src/uline.c b/package/utils/ucode-mod-uline/src/uline.c
index 26cea6fa24..17d1d69bc2 100644
--- a/package/utils/ucode-mod-uline/src/uline.c
+++ b/package/utils/ucode-mod-uline/src/uline.c
@@ -101,13 +101,16 @@ update_window_size(struct uline_state *s, bool init)
#ifdef TIOCGWINSZ
struct winsize ws = {};
- if (!ioctl(fileno(s->output), TIOCGWINSZ, &ws)) {
- if (ws.ws_col)
- cols = ws.ws_col;
- if (ws.ws_row)
- rows = ws.ws_row;
- }
+ if (s->ioctl_winsize &&
+ !ioctl(fileno(s->output), TIOCGWINSZ, &ws) &&
+ ws.ws_col && ws.ws_row) {
+ cols = ws.ws_col;
+ rows = ws.ws_row;
+ } else
#endif
+ {
+ s->ioctl_winsize = false;
+ }
s->sigwinch_count = sigwinch_count;
if (s->cols == cols && s->rows == rows)
@@ -534,7 +537,7 @@ move_word_right(struct uline_state *s, struct linebuf *line)
}
static bool
-process_esc(struct uline_state *s, enum vt100_escape esc)
+process_esc(struct uline_state *s, enum vt100_escape esc, uint32_t data)
{
struct linebuf *line = &s->line;
@@ -552,6 +555,15 @@ process_esc(struct uline_state *s, enum vt100_escape esc)
return move_right(s, line);
case VT100_CURSOR_WORD_RIGHT:
return move_word_right(s, line);
+ case VT100_CURSOR_POS:
+ if (s->rows == (data & 0xffff) &&
+ s->cols == data >> 16)
+ return false;
+ s->rows = data & 0xffff;
+ s->cols = data >> 16;
+ s->full_update = true;
+ s->cb->event(s, EDITLINE_EV_WINDOW_CHANGED);
+ return true;
case VT100_HOME:
line->pos = 0;
return true;
@@ -682,9 +694,9 @@ process_ctrl(struct uline_state *s, char c)
linebuf_reset(line);
return true;
case KEY_SOH:
- return process_esc(s, VT100_HOME);
+ return process_esc(s, VT100_HOME, 0);
case KEY_ENQ:
- return process_esc(s, VT100_END);
+ return process_esc(s, VT100_END, 0);
case KEY_VT:
// TODO: kill
return false;
@@ -718,18 +730,19 @@ static void
process_char(struct uline_state *s, char c)
{
enum vt100_escape esc;
+ uint32_t data = 0;
check_key_repeat(s, c);
if (s->esc_idx >= 0) {
s->esc_seq[s->esc_idx++] = c;
s->esc_seq[s->esc_idx] = 0;
- esc = vt100_esc_decode(s->esc_seq);
+ esc = vt100_esc_decode(s->esc_seq, &data);
if (esc == VT100_INCOMPLETE &&
s->esc_idx < (int)sizeof(s->esc_seq) - 1)
return;
s->esc_idx = -1;
- if (!process_esc(s, esc))
+ if (!process_esc(s, esc, data))
return;
} else if (s->cb->key_input &&
!check_utf8(s, (unsigned char )c) &&
@@ -901,7 +914,7 @@ void uline_init(struct uline_state *s, const struct uline_cb *cb,
s->utf8 = utf8;
s->input = in_fd;
s->output = out_stream;
- update_window_size(s, true);
+ s->ioctl_winsize = true;
reset_input_state(s);
#ifdef USE_SYSTEM_WCHAR
@@ -916,6 +929,12 @@ void uline_init(struct uline_state *s, const struct uline_cb *cb,
s->has_termios = true;
termios_set_native_mode(s);
}
+
+ update_window_size(s, true);
+ if (!s->ioctl_winsize) {
+ vt100_request_window_size(s->output);
+ fflush(s->output);
+ }
}
void uline_free(struct uline_state *s)
diff --git a/package/utils/ucode-mod-uline/src/uline.h b/package/utils/ucode-mod-uline/src/uline.h
index 6f7b75542f..514675e799 100644
--- a/package/utils/ucode-mod-uline/src/uline.h
+++ b/package/utils/ucode-mod-uline/src/uline.h
@@ -82,12 +82,13 @@ struct uline_state {
unsigned int rows, cols;
struct pos cursor_pos;
struct pos end_pos;
+ bool ioctl_winsize;
bool full_update;
bool stop;
bool utf8;
- char esc_seq[8];
+ char esc_seq[32];
int8_t esc_idx;
uint8_t utf8_cont;
};
diff --git a/package/utils/ucode-mod-uline/src/vt100.c b/package/utils/ucode-mod-uline/src/vt100.c
index b13e6a6722..f81b11d3ad 100644
--- a/package/utils/ucode-mod-uline/src/vt100.c
+++ b/package/utils/ucode-mod-uline/src/vt100.c
@@ -7,10 +7,10 @@
#include "uline.h"
#include "private.h"
-enum vt100_escape vt100_esc_decode(const char *str)
+enum vt100_escape vt100_esc_decode(const char *str, uint32_t *data)
{
- unsigned long code;
- size_t idx;
+ unsigned long code, code2;
+ char *err;
switch (*(str++)) {
case 0:
@@ -45,23 +45,36 @@ enum vt100_escape vt100_esc_decode(const char *str)
case '0' ... '4':
case '6' ... '9':
str--;
- idx = strspn(str, "0123456789");
- if (!str[idx])
+ code = strtoul(str, &err, 10);
+ switch (*err) {
+ case 0:
return VT100_INCOMPLETE;
- if (str[idx] != '~')
- return VT100_UNKNOWN;
- code = strtoul(str, NULL, 10);
- switch (code) {
- case 1:
- return VT100_HOME;
- case 3:
- return VT100_DELETE;
- case 4:
- return VT100_END;
- case 200:
- case 201:
- // paste start/end
- return VT100_IGNORE;
+ case '~':
+ switch (code) {
+ case 1:
+ return VT100_HOME;
+ case 3:
+ return VT100_DELETE;
+ case 4:
+ return VT100_END;
+ case 200:
+ case 201:
+ // paste start/end
+ return VT100_IGNORE;
+ default:
+ return VT100_UNKNOWN;
+ }
+ case ';':
+ code2 = strtoul(err + 1, &err, 10);
+ switch (*err) {
+ case 0:
+ return VT100_INCOMPLETE;
+ case 'R':
+ *data = (code2 << 16) | (code & 0xffff);
+ return VT100_CURSOR_POS;
+ default:
+ return VT100_UNKNOWN;
+ }
default:
return VT100_UNKNOWN;
}
More information about the lede-commits
mailing list