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 --- src/repl-connection.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 src/repl-connection.c (limited to 'src/repl-connection.c') 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; +} -- cgit v1.2.3