aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/interestingtimes.c68
-rw-r--r--lib/lib.c9
-rw-r--r--lib/lib.h12
-rw-r--r--lib/linestack.c2
4 files changed, 68 insertions, 23 deletions
diff --git a/lib/interestingtimes.c b/lib/interestingtimes.c
index 8f8b35c2..ed8a0751 100644
--- a/lib/interestingtimes.c
+++ b/lib/interestingtimes.c
@@ -46,6 +46,38 @@ int terminal_size(unsigned *xx, unsigned *yy)
return x || y;
}
+// Wrapper that parses results from ANSI probe. If block|2 query size and
+// send ANSI probe if we can't. (Probe queries xterm size through
+// serial connection, when local TTY doesn't know and only remote end knows.)
+// Otherwise acts like scan_key()
+int scan_key_getsize(char *scratch, int block, unsigned *xx, unsigned *yy)
+{
+ int key;
+
+ if (block&2) {
+ struct pollfd pfd;
+
+ if (terminal_size(xx, yy)) {
+ if (!(block&1)) return -2;
+ } else {
+ // Send probe: bookmark cursor position, jump to bottom right,
+ // query position, return cursor to bookmarked position.
+ xprintf("\e[s\e[999C\e[999B\e[6n\e[u");
+
+ // Wait up to a quarter second for a result
+ memset(&pfd, 0, sizeof(struct pollfd));
+ pfd.events = POLLIN;
+ xpoll(&pfd, 0, 250);
+ }
+ }
+ while (512&(key = scan_key(scratch, block&1))) {
+ if (xx) *xx = (key>>10)&1023;
+ if (yy) *yy = (key>>20)&1023;
+ }
+
+ return key;
+}
+
// Reset terminal to known state, saving copy of old state if old != NULL.
int set_terminal(int fd, int raw, struct termios *old)
{
@@ -80,16 +112,23 @@ int set_terminal(int fd, int raw, struct termios *old)
return tcsetattr(fd, TCSANOW, &termio);
}
+struct scan_key_list {
+ char *name, *seq;
+} static const scan_key_list[] = TAGGED_ARRAY(KEY,
+ // up down right left pgup pgdn home end ins
+ {"UP", "\033[A"}, {"DOWN", "\033[B"}, {"RIGHT", "\033[C"}, {"LEFT", "\033[D"},
+ {"PGUP", "\033[5~"}, {"PGDN", "\033[6~"}, {"HOME", "\033OH"},
+ {"END", "\033OF"}, {"INSERT", "\033[2~"}
+);
+
// Scan stdin for a keypress, parsing known escape sequences
-// Returns: 0-255=literal, -1=EOF, -2=NONE, 256-...=index into seq
+// Returns: 0-255=literal, -1=EOF, -2=NONE, 256-...=index into scan_key_list
+// >512 is x<<9+y<<21
// scratch space is necessary because last char of !seq could start new seq
// Zero out first byte of scratch before first call to scan_key
// block=0 allows fetching multiple characters before updating display
int scan_key(char *scratch, int block)
{
- // up down right left pgup pgdn home end ins
- char *seqs[] = {"\033[A", "\033[B", "\033[C", "\033[D", "\033[5~", "\033[6~",
- "\033OH", "\033OF", "\033[2~", 0};
struct pollfd pfd;
int maybe, i, j;
char *test;
@@ -99,10 +138,24 @@ int scan_key(char *scratch, int block)
pfd.events = POLLIN;
pfd.revents = 0;
- // check sequences
maybe = 0;
if (*scratch) {
- for (i = maybe = 0; (test = seqs[i]); i++) {
+ int pos[6];
+ unsigned x, y;
+
+ // Check for return from terminal size probe
+ memset(pos, 0, 6*sizeof(int));
+ sscanf(scratch+1, "\033%n[%n%3u%n,%n%3u%nR%n", pos, pos+1, &y,
+ pos+2, pos+3, &x, pos+4, pos+5);
+ if (pos[5]) {
+ // Recognized X/Y position, consume and return
+ *scratch = 0;
+ return 512+(x<<10)+(y<<20);
+ } else for (i=0; i<6; i++) if (pos[i]==*scratch) maybe = 1;
+
+ // Check sequences
+ for (i = 0; i<ARRAY_LEN(scan_key_list); i++) {
+ test = scan_key_list[i].seq;
for (j = 0; j<*scratch; j++) if (scratch[j+1] != test[j]) break;
if (j == *scratch) {
maybe = 1;
@@ -113,6 +166,7 @@ int scan_key(char *scratch, int block)
}
}
}
+
// If current data can't be a known sequence, return next raw char
if (!maybe) break;
}
@@ -122,6 +176,8 @@ int scan_key(char *scratch, int block)
// 30 miliseconds is about the gap between characters at 300 baud
if (maybe || !block) if (!xpoll(&pfd, 1, 30*maybe)) break;
+ // Read 1 byte so we don't overshoot sequence match. (We can deviate
+ // and fail to match, but match consumes entire buffer.)
if (1 != read(0, scratch+1+*scratch, 1)) return -1;
++*scratch;
}
diff --git a/lib/lib.c b/lib/lib.c
index a16439e7..5ee7325c 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -516,13 +516,12 @@ void loopfiles_rw(char **argv, int flags, int permissions, int failok,
// Inability to open a file prints a warning, but doesn't exit.
if (!strcmp(*argv, "-")) fd=0;
- else if (0>(fd = open(*argv, flags, permissions)) && !failok) {
+ else if (0>(fd = open(*argv, flags, permissions)) && !failok)
perror_msg("%s", *argv);
- toys.exitval = 1;
- continue;
+ else {
+ function(fd, *argv);
+ if (flags & O_CLOEXEC) close(fd);
}
- function(fd, *argv);
- if (flags & O_CLOEXEC) close(fd);
} while (*++argv);
}
diff --git a/lib/lib.h b/lib/lib.h
index 19992b98..5f70c8cc 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -216,6 +216,7 @@ int draw_rstr(char *start, int width, int (*escout)(FILE *out, wchar_t wc));
// interestingtimes.c
int xgettty(void);
int terminal_size(unsigned *xx, unsigned *yy);
+int scan_key_getsize(char *scratch, int block, unsigned *xx, unsigned *yy);
int set_terminal(int fd, int raw, struct termios *old);
int scan_key(char *scratch, int block);
void tty_esc(char *s);
@@ -223,17 +224,6 @@ void tty_jump(int x, int y);
void tty_reset(void);
void tty_sigreset(int i);
-// Results from scan_key()
-#define KEY_UP 256
-#define KEY_DOWN 257
-#define KEY_RIGHT 258
-#define KEY_LEFT 259
-#define KEY_PGUP 260
-#define KEY_PGDN 261
-#define KEY_HOME 262
-#define KEY_END 263
-#define KEY_INSERT 264
-
// net.c
int xsocket(int domain, int type, int protocol);
void xsetsockopt(int fd, int level, int opt, void *val, socklen_t len);
diff --git a/lib/linestack.c b/lib/linestack.c
index b06c97e7..cc6b6724 100644
--- a/lib/linestack.c
+++ b/lib/linestack.c
@@ -88,7 +88,7 @@ int crunch_str(char **str, int width, FILE *out,
for (end = start = *str; *end;) {
wchar_t wc;
- if (width>=0 && columns+lowlen>width) break;
+ if (columns+lowlen>width) break;
bytes = mbrtowc(&wc, end, 99, 0);
if (bytes<0 || wc<32 || (col = wcwidth(wc))<0) {