diff --git a/Makefile b/Makefile index d2673e8..4f65785 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,9 @@ LDLIBS := $$(pkg-config --cflags --libs readline) -lboost_system %.o: %.cpp ${COMPILE.cpp} $< -o $@ -main: lisp_balance.yy.o main.o +main: lisp_balance.yy.o main.o io.o shell.o ${LINK.cpp} -o fu-shell $+ ${LDLIBS} clean: - rm *.o + -rm *.yy.* + -rm *.o diff --git a/io.cpp b/io.cpp new file mode 100644 index 0000000..a785812 --- /dev/null +++ b/io.cpp @@ -0,0 +1,66 @@ +#include "io.h" + +#include + +#include + +inline int fu_fd; +inline const char * prompt1; +inline const char * prompt2 = " > "; + +extern "C" +void put_response(fu_response_header_t h, const char * const s) { + if (!s) { + puts(""); + return; + } + + if (!h.error_code) { + fputs("\033[32m", stdout); + } else { + fputs("\033[31m", stdout); + } + fputs(s, stdout); + + fputs("\033[0m\n", stdout); +} + +extern "C" +void fu_transmit(const char * const s) { + std::string message = s; + message = std::string() + (char)0x47 + (char)(message.size() / 256) + (char)(message.size() % 256) + message; + write(fu_fd, message.c_str(), message.size()); +} + +extern "C" +const char * const fu_recieve(fu_response_header_t &header) { + static char buff[MAX_CHUNK]; + static std::string r; + + const int e = read(fu_fd, (void*)(&header), sizeof(fu_response_header_t)); + if (e != sizeof(fu_response_header_t)) { + return NULL; + } + + r = ""; + + for (int i = 0; i < header.high; i++) { + const int e2 = read(fu_fd, buff, MAX_CHUNK); + if (e2 != MAX_CHUNK) { + return NULL; + } + r.append(buff, MAX_CHUNK); + } + + const int e3 = read(fu_fd, buff, header.low); + if (e3 != header.low) { + return NULL; + } + r.append(buff, header.low); + + return r.c_str(); +} + +char * fu_readline(bool is_1) { + return readline(is_1 ? prompt1 : prompt2); +} diff --git a/io.h b/io.h new file mode 100644 index 0000000..6923f6b --- /dev/null +++ b/io.h @@ -0,0 +1,41 @@ +/* Reading from and writting to the server. + * NOTE: the IO has no clue we are using sockets. + */ +#ifndef FU_IO_H +#define FU_IO_H + +#include + +/* The script-fu server protocol uses leading bytes + * to communicate meta information for clients. + * YYY: https://docs.gimp.org/2.10/en/gimp-filters-script-fu.html#plug-in-script-fu-console + */ +struct alignas(1) fu_response_header_t { + char magic_byte; // ^G + char error_code; // 0 on success + char high; + char low; +}; + +/* Number of bytes fu_response_header::high and fu_response_header::low encode, + * as defined by the script-fu documentation. + */ +const int MAX_CHUNK = 256; + +/* Socket file descriptor + */ +extern int fu_fd; + +#define PS1 "> " /* default value for prompt1 */ +extern const char * prompt1; +extern const char * prompt2; + +extern "C" { + void fu_transmit(const char * const s); + const char * const fu_recieve(fu_response_header_t &header); + void put_response(fu_response_header_t h, const char * const s); +} + +char * fu_readline(bool is_1 = true); + +#endif diff --git a/lisp_balance.h b/lisp_balance.h index 47707df..7f7a290 100644 --- a/lisp_balance.h +++ b/lisp_balance.h @@ -6,4 +6,6 @@ enum { PARTIAL, // the provided statement is not closed BROKEN, // the provided is all fucked'n'shieet }; + +void lb_set_input(char * const s); #endif diff --git a/lisp_balance.l b/lisp_balance.l index d241fc4..1939ed2 100644 --- a/lisp_balance.l +++ b/lisp_balance.l @@ -22,6 +22,7 @@ %option noyywrap %option nodefault +%option prefix="lb_" %x LITERAL %% diff --git a/main.cpp b/main.cpp index 4536ea0..4649265 100644 --- a/main.cpp +++ b/main.cpp @@ -1,120 +1,65 @@ #include #include -#include -#include +#include +#include -#include "lisp_balance.h" -#include "lisp_balance.yy.h" +#include +#include +#include +#include +#include +#include -using namespace boost::asio; +#include "io.h" +#include "shell.h" -#define PS1 "> " +#define PORT 10'008 /* default port */ -io_service hio_service; -ip::tcp::socket hsocket(hio_service); +bool fu_connect(const int port) { + struct sockaddr_in server_addr; + char buffer[1024] = {0}; -bool fu_connect() { - ip::tcp::endpoint endpoint(ip::address::from_string("127.0.0.1"), 10008); - hsocket.connect(endpoint); + if ((fu_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("Socket creation failed"); + return false; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr.s_addr = INADDR_ANY; + + if (connect(fu_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("Connection failed"); + return false; + } return true; } -char * transmit(const char * const s) { - static char reply[1024]; - try { - std::string message = s; - message = std::string() + (char)0x47 + (char)(message.size() / 256) + (char)(message.size() % 256) + message; - boost::system::error_code error; - write(hsocket, buffer(message), error); - if (error) { - throw boost::system::system_error(error); - } +bool init(int argc, char * * argv) { - size_t reply_length = hsocket.read_some(buffer(reply), error); - if (error) { - throw boost::system::system_error(error); - } - return reply; - } catch (std::exception& e) { - puts(e.what()); - return NULL; + prompt1 = getenv("FU_PS1"); + if (not prompt1) { + prompt1 = PS1; } + + const int port = + (argc > 1) + ? + std::stoi(argv[1]) + : + PORT + ; + + if (not fu_connect(port)) { + return false; + } + + return true; } -int special(const char * const l) { - if (!strcmp(l, ".exit")) { - return 1; - } else if (!strcmp(l, ".connect ")) { - } else if (!strcmp(l, ".ping")) { - } - - return 0; -} - -void put_response(const char * const s) { - /* The script-fu server protocol uses leading bytes - * to communicate meta information for clients - * YYY: https://docs.gimp.org/2.10/en/gimp-filters-script-fu.html#plug-in-script-fu-console - */ - enum { - MAGIC_BYTE, - ERROR_CODE, - LEN_HIGH, - LEN_LOW, - LEADING_META_SIZE, - }; - const char * const msg = s + LEADING_META_SIZE; - - printf("high: %d low: %d", s[LEN_HIGH], s[LEN_LOW]); - - if (!s[ERROR_CODE]) { - fputs("\033[32m", stdout); - } else { - fputs("\033[31m", stdout); - } - - for (int i = 0, h = s[LEN_HIGH]; i != h; i++) { - puts("f"); - fwrite((msg + LEADING_META_SIZE) + (i*256), 256, sizeof(char), stdout); - } - fwrite(msg + (s[LEN_HIGH]*256), s[LEN_LOW], sizeof(char), stdout); - - fputs("\033[0m", stdout); -} - -bool fu_judge(const char * const input) { - bool r; - if (special(input)) { - return true; - } - - char * const cpy = strdup(input); - lb_set_input(input); - - const int p = lb_parse(); - switch (p) { - default: { - r = false; - }; - } - - put_response(transmit(input)); - free(cpy); - return r; -} - -bool fu_interpret() { - bool r; - char * input = readline(PS1); - r = fu_judge(); - - free(input); - return r; -} - -signed main() { - if (not fu_connect()) { +signed main(int argc, char * * argv) { + if(not init(argc, argv)) { return 1; } diff --git a/shell.cpp b/shell.cpp new file mode 100644 index 0000000..4f533c1 --- /dev/null +++ b/shell.cpp @@ -0,0 +1,74 @@ +#include "shell.h" +#include "io.h" + +#include +#include +#include +#include + +extern "C" { +#include "lisp_balance.h" +#include "lisp_balance.yy.h" +} + +extern "C" +int fu_shell_meta(const char * const l) { + if (!strcmp(l, ".exit")) { + return 1; + } else if (!strcmp(l, ".connect ")) { + } else if (!strcmp(l, ".read ")) { + } else if (!strcmp(l, ".ping")) { + } + + return 0; +} + +extern "C" +bool fu_judge(const char * const input) { + bool r; + if (fu_shell_meta(input)) { + return true; + } + + char * const cpy = strdup(input); + lb_set_input(cpy); + + const int p = lb_lex(); + switch (p) { + case FULL: { + try { + fu_transmit(input); + fu_response_header_t h; + const char * const m = fu_recieve(h); + put_response(h, m); + } catch (std::exception& e) { + puts(e.what()); + return NULL; + } + r = true; + } break; + case PARTIAL: { + char * b = fu_readline(); + std::string e = std::string() + input + b; + free(b); + r = fu_judge(e.c_str()); + } break; + case BROKEN: { + puts("Wow budy!"); + r = true; + } break; + } + + free(cpy); + return r; +} + +extern "C" +bool fu_interpret() { + bool r; + char * input = fu_readline(false); + r = fu_judge(input); + + free(input); + return r; +} diff --git a/shell.h b/shell.h new file mode 100644 index 0000000..5189c4a --- /dev/null +++ b/shell.h @@ -0,0 +1,10 @@ +#ifndef FU_SHELL_H +#define FU_SHELL_H + +extern "C" { + int fu_shell_meta(const char * const l); + bool fu_judge(const char * const input); + bool fu_interpret(); +} + +#endif