]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
terminal-util: don't process the same data twice when reading back bg color info
authorLennart Poettering <lennart@poettering.net>
Wed, 10 Jul 2024 14:06:30 +0000 (16:06 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 19 Jul 2024 09:41:42 +0000 (11:41 +0200)
If we only read partial information from the tty we ended up parsing it
again and again, confusing the state machine. hence, return how much
data we actually processed and drop it from the buffer.

src/basic/terminal-util.c

index 9d3e0ae07be4c498fd6f8fda5950a0de666a9cc8..ad22599553252e8204a1a029128df84267ead8ce 100644 (file)
@@ -1601,7 +1601,8 @@ typedef struct BackgroundColorContext {
 static int scan_background_color_response(
                 BackgroundColorContext *context,
                 const char *buf,
-                size_t size) {
+                size_t size,
+                size_t *ret_processed) {
 
         assert(context);
         assert(buf || size == 0);
@@ -1677,8 +1678,12 @@ static int scan_background_color_response(
 
                 case BACKGROUND_BLUE:
                         if (c == '\x07') {
-                                if (context->blue_bits > 0)
+                                if (context->blue_bits > 0) {
+                                        if (ret_processed)
+                                                *ret_processed = i + 1;
+
                                         return 1; /* success! */
+                                }
 
                                 context->state = BACKGROUND_TEXT;
                         } else if (c == '\x1b')
@@ -1695,8 +1700,12 @@ static int scan_background_color_response(
                         break;
 
                 case BACKGROUND_STRING_TERMINATOR:
-                        if (c == '\\')
+                        if (c == '\\') {
+                                if (ret_processed)
+                                        *ret_processed = i + 1;
+
                                 return 1; /* success! */
+                        }
 
                         context->state = c == ']' ? BACKGROUND_ESCAPE : BACKGROUND_TEXT;
                         break;
@@ -1711,6 +1720,9 @@ static int scan_background_color_response(
                 }
         }
 
+        if (ret_processed)
+                *ret_processed = size;
+
         return 0; /* all good, but not enough data yet */
 }
 
@@ -1753,34 +1765,41 @@ int get_default_background_color(double *ret_red, double *ret_green, double *ret
         BackgroundColorContext context = {};
 
         for (;;) {
-                usec_t n = now(CLOCK_MONOTONIC);
+                if (buf_full == 0) {
+                        usec_t n = now(CLOCK_MONOTONIC);
 
-                if (n >= end) {
-                        r = -EOPNOTSUPP;
-                        goto finish;
-                }
+                        if (n >= end) {
+                                r = -EOPNOTSUPP;
+                                goto finish;
+                        }
 
-                r = fd_wait_for_event(STDIN_FILENO, POLLIN, usec_sub_unsigned(end, n));
-                if (r < 0)
-                        goto finish;
-                if (r == 0) {
-                        r = -EOPNOTSUPP;
-                        goto finish;
-                }
+                        r = fd_wait_for_event(STDIN_FILENO, POLLIN, usec_sub_unsigned(end, n));
+                        if (r < 0)
+                                goto finish;
+                        if (r == 0) {
+                                r = -EOPNOTSUPP;
+                                goto finish;
+                        }
 
-                ssize_t l;
-                l = read(STDIN_FILENO, buf, sizeof(buf) - buf_full);
-                if (l < 0) {
-                        r = -errno;
-                        goto finish;
-                }
+                        ssize_t l = read(STDIN_FILENO, buf, sizeof(buf));
+                        if (l < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
 
-                buf_full += l;
-                assert(buf_full <= sizeof(buf));
+                        assert((size_t) l <= sizeof(buf));
+                        buf_full = l;
+                }
 
-                r = scan_background_color_response(&context, buf, buf_full);
+                size_t processed;
+                r = scan_background_color_response(&context, buf, buf_full, &processed);
                 if (r < 0)
                         goto finish;
+
+                assert(processed <= buf_full);
+                buf_full -= processed;
+                memmove(buf, buf + processed, buf_full);
+
                 if (r > 0) {
                         assert(context.red_bits > 0);
                         *ret_red = (double) context.red / ((UINT64_C(1) << context.red_bits) - 1);