From 6416b2dac6905c1ee48df75fdf42d3f6929785db Mon Sep 17 00:00:00 2001 From: Thomas White Date: Sat, 19 Jun 2021 11:35:30 +0200 Subject: Basic REPL I/O --- meson.build | 3 +- src/repl-connection.c | 176 ++++++++++++++++++++++++++++++++++++++++++ src/repl-connection.h | 32 ++++++++ src/starlet-fixture-display.c | 26 ++++++- 4 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 src/repl-connection.c create mode 100644 src/repl-connection.h diff --git a/meson.build b/meson.build index be089d8..4b6b87d 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,7 @@ library('guile-ola', ['src/guile-ola.cpp'], # Fixture display tool executable('starlet-fixture-display', - ['src/starlet-fixture-display.c'], + ['src/starlet-fixture-display.c', + 'src/repl-connection.c'], dependencies : [gtk_dep], install : true) diff --git a/src/repl-connection.c b/src/repl-connection.c new file mode 100644 index 0000000..622e260 --- /dev/null +++ b/src/repl-connection.c @@ -0,0 +1,176 @@ +/* + * repl-connection.c + * + * Copyright © 2019-2021 Thomas White + * + * This file is part of Starlet. + * + * 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 3 of the License, 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, see . + * + */ + + +#include +#include +#include +#include +#include +#include + +#include +#define _(x) gettext(x) + +#include "repl-connection.h" + +struct _replconnection +{ + GSocketConnection *conn; + char inbuf[1024]; + char input[2048]; +}; + + +static char *strip_crap(const char *line_orig) +{ + size_t len; + char *line; + size_t outptr; + int i; + int escape_seq; + + len = strlen(line_orig); + + line = malloc(len+1); + if ( line == NULL ) return NULL; + + /* Remove non-ASCII characters and ANSI escape sequences */ + outptr = 0; + escape_seq = 0; + for ( i=0; i= 0x1f ) && (ch < 0xff) && !escape_seq ) { + line[outptr++] = ch; + } + if ( ch == 0x1b ) escape_seq = 1; + if ( escape_seq && ch == 'm' ) escape_seq = 0; + } + line[outptr] = '\0'; + + return line; +} + + +static void process_line(const char *line_orig, ReplConnection *repl) +{ + char *line = strip_crap(line_orig); + printf("%p: '%s'\n", repl, line); + free(line); +} + + +static void input_ready(GObject *source, GAsyncResult *res, gpointer vp) +{ + GError *error = NULL; + ReplConnection *repl = vp; + size_t len; + int i; + char *nl_pos; + char *remaining; + + len = g_input_stream_read_finish(G_INPUT_STREAM(source), res, &error); + repl->inbuf[len] = '\0'; + + for ( i=0; iinbuf[i] == '\0' ) { + repl->inbuf[i] = ' '; + fprintf(stderr, "Zero byte found in REPL output\n"); + } + } + + if ( strlen(repl->input) + len + 1 >= 2048 ) { + fprintf(stderr, "Too much input!\n"); + } else { + strcat(repl->input, repl->inbuf); + } + + nl_pos = strchr(repl->input, '\n'); + while ( nl_pos != NULL ) { + + size_t len_remaining = strlen(nl_pos); + + nl_pos[0] = '\0'; + process_line(repl->input, repl); + + memmove(repl->input, nl_pos+1, len_remaining); + nl_pos = strchr(repl->input, '\n'); + } + + remaining = strip_crap(repl->input); + if ( strcmp(remaining, "scheme@(guile-user)> ") == 0 ) { + printf("Prompt!\n"); + repl->input[0] = '\0'; + } + free(remaining); + + g_input_stream_read_async(g_io_stream_get_input_stream(G_IO_STREAM(repl->conn)), + repl->inbuf, 1023, G_PRIORITY_DEFAULT, NULL, + input_ready, repl); +} + + +ReplConnection *repl_connection_new(const char *socket) +{ + ReplConnection *repl; + GSocketClient *client; + GSocketAddress *addr; + GError *error = NULL; + + repl = malloc(sizeof(struct _replconnection)); + if ( repl == NULL ) return NULL; + + addr = g_unix_socket_address_new(socket); + if ( addr == NULL ) return NULL; + + client = g_socket_client_new(); + repl->conn = g_socket_client_connect(client, G_SOCKET_CONNECTABLE(addr), + NULL, &error); + if ( repl->conn == NULL ) { + fprintf(stderr, "Couldn't connect: %s\n", error->message); + return NULL; + } + + repl->input[0] = '\0'; + + g_input_stream_read_async(g_io_stream_get_input_stream(G_IO_STREAM(repl->conn)), + repl->inbuf, 1023, G_PRIORITY_DEFAULT, NULL, + input_ready, repl); + + return repl; +} + + +int repl_send(ReplConnection *repl, const char *line) +{ + GError *error = NULL; + GOutputStream *out = g_io_stream_get_output_stream(G_IO_STREAM(repl->conn)); + if ( g_output_stream_write(out, line, strlen(line), NULL, &error) == -1 ) { + fprintf(stderr, "Couldn't send: %s\n", error->message); + return 1; + } + if ( g_output_stream_write(out, "\n", 1, NULL, &error) == -1 ) { + fprintf(stderr, "Couldn't send newline: %s\n", error->message); + return 1; + } + return 0; +} diff --git a/src/repl-connection.h b/src/repl-connection.h new file mode 100644 index 0000000..8245c38 --- /dev/null +++ b/src/repl-connection.h @@ -0,0 +1,32 @@ +/* + * repl-connection.c + * + * Copyright © 2019-2021 Thomas White + * + * This file is part of Starlet. + * + * 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 3 of the License, 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, see . + * + */ + + +#ifndef REPL_CONNECTION_H +#define REPL_CONNECTION_H + +typedef struct _replconnection ReplConnection; + +extern ReplConnection *repl_connection_new(const char *socket); +extern int repl_send(ReplConnection *repl, const char *line); + +#endif /* REPL_CONNECTION_H */ diff --git a/src/starlet-fixture-display.c b/src/starlet-fixture-display.c index 2f8c29b..366e0e6 100644 --- a/src/starlet-fixture-display.c +++ b/src/starlet-fixture-display.c @@ -32,6 +32,8 @@ #include #define _(x) gettext(x) +#include "repl-connection.h" + #define OVERALL_BORDER (20.0) #define FIXTURE_BORDER (5.0) @@ -49,6 +51,7 @@ struct fixture_display struct fixture *fixtures; int n_fixtures; GtkWidget *da; + ReplConnection *repl; }; @@ -179,7 +182,11 @@ static gboolean key_press_sig(GtkWidget *da, GdkEventKey *event, struct fixture_ switch ( event->keyval ) { case GDK_KEY_Escape : - /* FIXME: Send (sel #f) */ + repl_send(fixd->repl, "(sel #f)"); + break; + + case GDK_KEY_KP_Enter : + repl_send(fixd->repl, "(go! pb)"); break; default : @@ -214,7 +221,8 @@ static gboolean redraw_cb(gpointer data) static void get_fixture_list(struct fixture_display *fixd) { - int i; + repl_send(fixd->repl, "(patched-fixture-names)"); + /* FIXME: Dummy */ int i; fixd->fixtures = malloc(32*sizeof(struct fixture)); @@ -231,6 +239,7 @@ static void show_help(const char *s) { printf(_("Syntax: %s [options]\n\n"), s); printf(_("Show fixtures in Starlet" + " -s, --socket REPL socket for Starlet process (default guile.socket).\n" " -h, --help Display this help message.\n")); } @@ -241,11 +250,13 @@ int main(int argc, char *argv[]) int c; GtkWidget *mainwindow; GtkWidget *da; + char *socket = NULL; gtk_init(&argc, &argv); const struct option longopts[] = { {"help", 0, NULL, 'h'}, + {"socket", 1, NULL, 's'}, {0, 0, NULL, 0} }; @@ -257,6 +268,10 @@ int main(int argc, char *argv[]) show_help(argv[0]); return 0; + case 's' : + socket = strdup(optarg); + break; + case 0 : break; @@ -273,6 +288,10 @@ int main(int argc, char *argv[]) bindtextdomain("starlet", LOCALEDIR); textdomain("starlet"); + if ( socket == NULL ) { + socket = strdup("guile.socket"); + } + /* Create main window */ mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(mainwindow), 1024, 768); @@ -298,7 +317,8 @@ int main(int argc, char *argv[]) gtk_widget_show_all(mainwindow); g_timeout_add(50, redraw_cb, &fixd); - + + fixd.repl = repl_connection_new(socket); get_fixture_list(&fixd); gtk_main(); -- cgit v1.2.3