summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2023-05-05 16:22:11 -0400
committerRay Strode <rstrode@redhat.com>2023-05-05 16:33:30 -0400
commit1559e1d78101d772b2fc57ee761aef8ce5595520 (patch)
tree56bf710efc7b46fc99b93e38934071648af8e81b
parentfcaa382d535edb12461fbbc9942dc49b549d091b (diff)
wip! Add ply-terminal-buffer objectplymouth-terminal-buffer
We're going to need to do at least basic parsing of terminal text so we can show the console to the user in color when they hit escape and VTs are disabled. This commit adds the start of a class to do this basic parsing. The way it works is the terminal text is inject into the object and all escape sequences are filtered out. When a color control sequence is found, the current color is noted, along with which characters it applies to. A list of the text spans and their color attributes is then iteratable using a an api.
-rw-r--r--src/libply-splash-core/meson.build2
-rw-r--r--src/libply-splash-core/ply-terminal-buffer.c174
-rw-r--r--src/libply-splash-core/ply-terminal-buffer.h58
3 files changed, 234 insertions, 0 deletions
diff --git a/src/libply-splash-core/meson.build b/src/libply-splash-core/meson.build
index 69636b13..0fa7102b 100644
--- a/src/libply-splash-core/meson.build
+++ b/src/libply-splash-core/meson.build
@@ -7,6 +7,7 @@ libply_splash_core_sources = files(
'ply-pixel-display.c',
'ply-renderer.c',
'ply-terminal.c',
+ 'ply-terminal-buffer.c',
'ply-text-display.c',
'ply-text-progress-bar.c',
'ply-text-step-bar.c',
@@ -60,6 +61,7 @@ libply_splash_core_headers = files(
'ply-renderer-plugin.h',
'ply-renderer.h',
'ply-terminal.h',
+ 'ply-terminal-buffer.h',
'ply-text-display.h',
'ply-text-progress-bar.h',
'ply-text-step-bar.h',
diff --git a/src/libply-splash-core/ply-terminal-buffer.c b/src/libply-splash-core/ply-terminal-buffer.c
new file mode 100644
index 00000000..729a3b71
--- /dev/null
+++ b/src/libply-splash-core/ply-terminal-buffer.c
@@ -0,0 +1,174 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define PLY_TERMINAL_COLOR_ATTRIBUTE_OFFSET 30
+
+typedef struct
+{
+ ply_terminal_color_t color;
+ size_t start_index;
+ size_t span_length;
+} ply_text_attribute_t;
+
+struct _ply_terminal_buffer
+{
+ ply_buffer_t *text_buffer;
+ ply_list_t *attributes;
+};
+
+typedef enum
+{
+ PLY_TERMINAL_BUFFER_PARSER_STATE_UNESCAPED,
+ PLY_TERMINAL_BUFFER_PARSER_STATE_ESCAPED,
+ PLY_TERMINAL_BUFFER_PARSER_STATE_CONTROL_SEQUENCE,
+ PLY_TERMINAL_BUFFER_PARSER_STATE_CONTROL_SEQUENCE_PARAMETER
+} ply_terminal_buffer_parser_state_t;
+
+
+ply_terminal_buffer_t *
+ply_terminal_buffer_new (void)
+{
+ ply_terminal_buffer_t *terminal_buffer = calloc (1, sizeof(ply_terminal_buffer_t));
+
+ terminal_buffer->text_buffer = ply_buffer_new ();
+
+ return buffer;
+}
+
+void
+ply_terminal_buffer_free (ply_terminal_buffer_t *terminal_buffer)
+{
+ ply_list_node_t *node;
+
+ ply_buffer_free (terminal_buffer->text_buffer);
+ ply_list_foreach (terminal_buffer->attributes, node) {
+ ply_text_attribute_t *attribute;
+ attribute = ply_list_node_get_data (node);
+ free (attribute);
+ }
+ ply_list_free (terminal_buffer->attributes);
+ free (terminal_buffer);
+}
+
+void
+ply_terminal_buffer_inject (ply_terminal_buffer_t *buffer,
+ const char *input,
+ size_t length)
+{
+ ply_terminal_buffer_parser_state_t state = PLY_TERMINAL_BUFFER_PARSER_STATE_UNESCAPED;
+ ply_terminal_color_t color = PLY_TERMINAL_COLOR_WHITE;
+ size_t i = 0, end_index;
+ size_t parameter_start = 0;
+
+ start_index = ply_buffer_get_size (buffer->text_buffer);
+ end_index = start_index;
+
+ while (i < length) {
+ switch (state) {
+ case PLY_TERMINAL_BUFFER_PARSER_STATE_UNESCAPED:
+ if (input[i] == '\033') {
+ state = PLY_TERMINAL_BUFFER_PARSER_STATE_ESCAPED;
+ } else {
+ ply_buffer_append (buffer->text_buffer, "%c", input[i]);
+ end_index++;
+ }
+ break;
+ case PLY_TERMINAL_BUFFER_PARSER_STATE_ESCAPED:
+ if (input[i] == '[') {
+ state = PLY_TERMINAL_BUFFER_PARSER_STATE_CONTROL_SEQUENCE;
+ }
+ break;
+ case PLY_TERMINAL_BUFFER_PARSER_STATE_CONTROL_SEQUENCE:
+ if (isdigit (input[i])) {
+ parameter_start = i;
+ state = PLY_TERMINAL_BUFFER_PARSER_STATE_CONTROL_SEQUENCE_PARAMETER;
+ }
+ break;
+ case PLY_TERMINAL_BUFFER_PARSER_STATE_CONTROL_SEQUENCE_PARAMETER:
+ if (input[i] == ';' || input[i] == 'm') {
+ int parameter_value;
+
+ parameter_value = atoi (&input[parameter_start]) - PLY_TERMINAL_COLOR_ATTRIBUTE_OFFSET;
+ if (parameter_value >= PLY_TERMINAL_COLOR_BLACK && parameter_value <= PLY_TERMINAL_COLOR_WHITE) {
+ color = (ply_terminal_color_t) (parameter_value);
+ }
+ }
+
+ if (input[i] == ';') {
+ parameter_start = i + 1;
+ } else if (input[i] == 'm') {
+ if (end_index > start_index) {
+ ply_text_attribute_t *attribute;
+
+ attribute = calloc (1, sizeof(ply_text_attribute_t));
+ attribute->color = color;
+ attribute->start_index = start_index;
+ attribute->span_length = end_index - start_index;
+
+ ply_list_append_data (buffer->attributes, attribute);
+ }
+ state = PLY_TERMINAL_BUFFER_PARSER_STATE_UNESCAPED;
+ }
+ break;
+ }
+ i++;
+ }
+
+ if (state == PLY_TERMINAL_BUFFER_PARSER_STATE_CONTROL_SEQUENCE_PARAMETER &&
+ end_index > start_index) {
+ ply_text_attribute_t *attribute;
+
+ attribute = calloc (1, sizeof(ply_text_attribute_t));
+ attribute->color = color;
+ attribute->start_index = start_index;
+ attribute->span_length = end_index - start_index;
+
+ ply_list_append_data (buffer->attributes, attribute);
+ }
+}
+
+void
+ply_terminal_buffer_iter_init (ply_terminal_buffer_iter_t *iter,
+ ply_terminal_buffer_t *buffer)
+{
+ iter->buffer = buffer;
+ iter->node = ply_list_get_First_node (buffer->attributes);
+}
+
+int
+ply_terminal_buffer_iter_next (ply_terminal_buffer_iter_t *iter,
+ ply_text_attribute_t **attribute,
+ const char **text,
+ size_t *start_index,
+ size_t *end_index)
+{
+ ply_terminal_buffer_t *buffer;
+ ply_text_attribute_t *current_attribute, *next_attribute;
+ const char *bytes;
+
+ if (iter->node == NULL) {
+ return false;
+ }
+
+ buffer = iter->buffer;
+ bytes = ply_terminal_buffer_get_bytes (buffer);
+
+ current_attribute = ply_list_node_get_data (iter->node);
+ *text = bytes + current_attribute->start_index;
+ *attribute = current_attribute;
+ *start_index = current_attribute->start_index;
+
+ iter->node = ply_list_get_next_node (buffer->attributes, iter->node);
+
+ if (iter->node != NULL) {
+ next_attribute = ply_list_node_get_data (iter->node);
+ *end_index = next_attribute->start_index - 1;
+ } else {
+ size_t last_index = ply_buffer_get_size (buffer) - 1;
+ *end_index = last_index;
+ }
+
+ return true;
+}
diff --git a/src/libply-splash-core/ply-terminal-buffer.h b/src/libply-splash-core/ply-terminal-buffer.h
new file mode 100644
index 00000000..37ac4d01
--- /dev/null
+++ b/src/libply-splash-core/ply-terminal-buffer.h
@@ -0,0 +1,58 @@
+/* ply-terminal-buffer.h - APIs for handling terminal text
+ *
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ */
+#ifndef PLY_TERMINAL_BUFFER_H
+#define PLY_TERMINAL_BUFFER_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "ply-buffer.h"
+#include "ply-event-loop.h"
+
+typedef struct _ply_terminal_buffer ply_terminal_buffer_t;
+
+typedef struct
+{
+ ply_terminal_buffer_t *buffer;
+ ply_list_node_t *node;
+} ply_terminal_buffer_iter_t;
+
+#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+ply_terminal_buffer_t *ply_terminal_buffer_new (void) :
+ void ply_terminal_buffer_free (ply_terminal_buffer_t *terminal_buffer);
+
+void ply_terminal_buffer_inject (ply_terminal_buffer_t *buffer,
+ const char *input,
+ size_t length);
+void ply_terminal_buffer_iter_init (ply_terminal_buffer_iter_t *iter,
+ ply_terminal_buffer_t *buffer);
+int ply_terminal_buffer_iter_next (ply_terminal_buffer_iter_t *iter,
+ ply_text_attribute_t **attribute,
+ const char **text,
+ size_t *start_index,
+ size_t *end_index);
+
+#endif
+
+#endif /* PLY_TERMINAL_BUFFER_H */