aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas White <taw@physics.org>2021-06-19 11:35:30 +0200
committerThomas White <taw@physics.org>2021-06-19 19:49:05 +0200
commit6416b2dac6905c1ee48df75fdf42d3f6929785db (patch)
treef35d2f5849d1f72508bc5380687303e065e12c9e
parent602cbebc5fb1a78b6cf9930cb56db3ca4e7ac2ab (diff)
Basic REPL I/O
-rw-r--r--meson.build3
-rw-r--r--src/repl-connection.c176
-rw-r--r--src/repl-connection.h32
-rw-r--r--src/starlet-fixture-display.c26
4 files changed, 233 insertions, 4 deletions
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 <taw@bitwiz.me.uk>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
+
+#include <libintl.h>
+#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<len; i++ ) {
+ char ch = line_orig[i];
+ if ( (ch >= 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; i<len; i++ ) {
+ if ( repl->inbuf[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 <taw@bitwiz.me.uk>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#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 <libintl.h>
#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();