]> rtime.felk.cvut.cz Git - sojka/sterm.git/commitdiff
Ignore CPR ANSI control sequence in exit_on_escapeseq()
authorMichal Sojka <michal.sojka@cvut.cz>
Sat, 4 Jan 2020 16:43:02 +0000 (17:43 +0100)
committerMichal Sojka <michal.sojka@cvut.cz>
Sat, 4 Jan 2020 16:43:02 +0000 (17:43 +0100)
In some cases (e.g. Debian's initramfs) the device sends DSR (Device
Status Report) ANSI control sequences as a response to pressing Enter.
Some terminals (e.g. gnome terminal) respond to this by CPR (Cursor
Position Response) sequence, which appears as typed from keyboard. See
https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_output_sequences.

This complicates exiting sterm, because the exit escape sequence \n~.
must by typed very quickly (actually copy&pasted) so that CPR doesn't
appear between \n and ~..

This commit causes the CPR sequence to be ignored when detecting exit
sequence.

Fixes #2.

sterm.c

diff --git a/sterm.c b/sterm.c
index 6d38cd80166f162e19e81fb4a99518d5671bd2be..368256c60da63160d927db43e833761392ad4269 100644 (file)
--- a/sterm.c
+++ b/sterm.c
@@ -114,12 +114,35 @@ int dtr_rts_arg(const char option, const char *optarg)
        return val;
 }
 
+// See DSR and CPR at
+// https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal_output_sequences
+bool is_cpr_control_seq(char c)
+{
+       static enum state { CSI_ESC, CSI_BRACKET, PAR_N, PAR_M, FIN_R } state;
+
+       switch (state) {
+       case CSI_ESC:      state = (c == 0x1b) ? CSI_BRACKET : CSI_ESC; break;
+       case CSI_BRACKET:  state = (c == '[')  ? PAR_N : CSI_ESC; break;
+       case PAR_N:        state = (c == ';')  ? PAR_M : (c >= '0' && c <= '9' ? PAR_N : CSI_ESC); break;
+       case PAR_M:        state = (c == 'R')  ? FIN_R : (c >= '0' && c <= '9' ? PAR_M : CSI_ESC); break;
+       case FIN_R: break;
+       }
+       if (state == FIN_R) {
+               state = CSI_ESC;
+               return true;
+
+       } else
+               return state != CSI_ESC;
+}
+
 void exit_on_escapeseq(const char *buf, int len)
 {
        static const char escseq[] = "\r~.";
        static const char *state = escseq+1;
        int i;
        for (i = 0; i < len; i++) {
+               if (is_cpr_control_seq(buf[i]))
+                       continue;
                if (buf[i] == *state) {
                        state++;
                        if (*state == 0)