From 3bcd741d568453676643eac46ecf6749022fbc42 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Thu, 8 Jan 2026 15:02:33 +0100 Subject: [PATCH 1/3] doc: finished --- src/io_backend/io_backend.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/io_backend/io_backend.h b/src/io_backend/io_backend.h index 34d85f3..0bcfdca 100644 --- a/src/io_backend/io_backend.h +++ b/src/io_backend/io_backend.h @@ -29,17 +29,14 @@ struct iob_context { */ int iob_init(struct iob_context *context); -/* TODO - * - * - * +/* @brief Closes the opened buffers and exits the modules gracefully */ -void iob_close(); +void iob_close(void); -/*i TODO - * - * +/* @brief reads at most one line of the input and stores it into *stream * + * @param stream is a pointer that will be set to a string to parse + * @return the number of read characters if positive, the error code otherwise */ ssize_t stream_read(char** stream); From 464dbe8e1797e35c2e8649e5e28bae0bde426d20 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Thu, 8 Jan 2026 16:15:29 +0100 Subject: [PATCH 2/3] feat: finished io_backend --- src/io_backend/io_backend.c | 88 ++++++++++++++++++++++++++++++++----- src/io_backend/io_backend.h | 24 ++++++++-- 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/io_backend/io_backend.c b/src/io_backend/io_backend.c index ee6b09b..7e7c1c3 100644 --- a/src/io_backend/io_backend.c +++ b/src/io_backend/io_backend.c @@ -1,34 +1,102 @@ #include "io_backend.h" #include +#include +#include + +// === Static variables static struct iob_context context; -static FILE *input; +static FILE *input = NULL; +static char *stream_buf = NULL; +static size_t stream_buf_size = 0; +static enum iob_state state = IOB_STATE_NOT_INITIALIZED; + +// === Functions int iob_init(struct iob_context *ctx) { + if (state != IOB_STATE_NOT_INITIALIZED) + return IOB_ERROR_MODULE_NOT_INITIALIZED; + context = *ctx; switch (context.mode) { - IOB_MODE_STDIN: + case IOB_MODE_STDIN: input = stdin; + state = IOB_STATE_READY; return 0; - IOB_MODE_SCRIPT: + case IOB_MODE_SCRIPT: if (context.args == NULL) - return -2; + return IOB_ERROR_BAD_ARG; input = fopen(context.args, "r"); if (input == NULL) - return -4; + return IOB_ERROR_CANNOT_OPEN_FILE; + state = IOB_STATE_READY; + return 0; - IOB_MODE_CMD: + case IOB_MODE_CMD: if (context.args != NULL) - return -2; - else - return 0; + return IOB_ERROR_BAD_ARG; + state = IOB_STATE_READY; + return 0; default: - return -1; + return IOB_ERROR_BAD_ARG; + } +} + +void iob_close(void) +{ + fclose(input); + if ((context.mode == IOB_MODE_STDIN || context.mode == IOB_MODE_SCRIPT) + && stream_buf != NULL) + { + free(stream_buf); + stream_buf_size = 0; + } + state = IOB_STATE_NOT_INITIALIZED; +} + +ssize_t stream_read(char **stream) +{ + // Check args + if (stream == NULL) + return IOB_ERROR_BAD_ARG; + + // Check env + if (state == IOB_STATE_NOT_INITIALIZED) + return IOB_ERROR_MODULE_NOT_INITIALIZED; + if (state == IOB_STATE_FINISHED) + return 0; + if (state == IOB_STATE_ERROR) + return IOB_ERROR_GENERIC; + + // Use input + if (context.mode == IOB_MODE_STDIN || context.mode == IOB_MODE_SCRIPT) + { + ssize_t nread = getline(&stream_buf, &stream_buf_size, input); + if (nread == -1) + { + state = IOB_STATE_FINISHED; + return 0; + } + else if (nread < 0) + state = IOB_STATE_ERROR; + + return nread; + } + // Use args + else if (context.mode == IOB_MODE_CMD) + { + *stream = context.args; + return strlen(context.args); + } + else + { + *stream = NULL; + return IOB_ERROR_GENERIC; } } diff --git a/src/io_backend/io_backend.h b/src/io_backend/io_backend.h index 0bcfdca..c2079f0 100644 --- a/src/io_backend/io_backend.h +++ b/src/io_backend/io_backend.h @@ -3,6 +3,13 @@ #include +// Error codes +#define IOB_ERROR_GENERIC -1 +#define IOB_ERROR_BAD_ARG -2 +#define IOB_ERROR_MODULE_NOT_INITIALIZED -3 +#define IOB_ERROR_MODULE_ALREADY_INITALIZED -4 +#define IOB_ERROR_CANNOT_OPEN_FILE -5 + enum iob_mode { IOB_MODE_NULL = 0, IOB_MODE_STDIN, @@ -10,11 +17,18 @@ enum iob_mode { IOB_MODE_CMD }; +enum iob_state { + IOB_STATE_NOT_INITIALIZED, + IOB_STATE_READY, + IOB_STATE_FINISHED, + IOB_STATE_ERROR +}; + /* @struct iob_context * @var mode * @var args contains - * the script name when mode is set to IOB_SCRIPT, - * the command to execute when mode is set to IOB_CMD, + * the script name when mode is set to IOB_MODE_SCRIPT, + * the command to execute when mode is set to IOB_MODE_CMD */ struct iob_context { enum iob_mode mode; @@ -29,14 +43,16 @@ struct iob_context { */ int iob_init(struct iob_context *context); -/* @brief Closes the opened buffers and exits the modules gracefully +/* @brief Closes the opened buffers and the module gracefully */ void iob_close(void); /* @brief reads at most one line of the input and stores it into *stream * * @param stream is a pointer that will be set to a string to parse - * @return the number of read characters if positive, the error code otherwise + * @return the number of read characters if positive, + * zero if finished (reached EOF), + * the error code otherwise */ ssize_t stream_read(char** stream); From 78967f3ef62438e9a3abaaa69704338e3b01757b Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Thu, 8 Jan 2026 16:59:37 +0100 Subject: [PATCH 3/3] test: iob_init and iob_close tests (+ small typo fix in src) --- src/io_backend/io_backend.c | 2 +- src/io_backend/io_backend.h | 2 +- tests/unit/io_backend/io_backend.c | 122 +++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 tests/unit/io_backend/io_backend.c diff --git a/src/io_backend/io_backend.c b/src/io_backend/io_backend.c index 7e7c1c3..97fe974 100644 --- a/src/io_backend/io_backend.c +++ b/src/io_backend/io_backend.c @@ -17,7 +17,7 @@ static enum iob_state state = IOB_STATE_NOT_INITIALIZED; int iob_init(struct iob_context *ctx) { if (state != IOB_STATE_NOT_INITIALIZED) - return IOB_ERROR_MODULE_NOT_INITIALIZED; + return IOB_ERROR_MODULE_ALREADY_INITIALIZED; context = *ctx; diff --git a/src/io_backend/io_backend.h b/src/io_backend/io_backend.h index c2079f0..cd5ec8a 100644 --- a/src/io_backend/io_backend.h +++ b/src/io_backend/io_backend.h @@ -7,7 +7,7 @@ #define IOB_ERROR_GENERIC -1 #define IOB_ERROR_BAD_ARG -2 #define IOB_ERROR_MODULE_NOT_INITIALIZED -3 -#define IOB_ERROR_MODULE_ALREADY_INITALIZED -4 +#define IOB_ERROR_MODULE_ALREADY_INITIALIZED -4 #define IOB_ERROR_CANNOT_OPEN_FILE -5 enum iob_mode { diff --git a/tests/unit/io_backend/io_backend.c b/tests/unit/io_backend/io_backend.c new file mode 100644 index 0000000..8640cdb --- /dev/null +++ b/tests/unit/io_backend/io_backend.c @@ -0,0 +1,122 @@ +#include +#include + +#include + +#include + +TestSuite(IO_Backend); + +// IOB Init + +Test(IO_Backend, init_null) +{ + struct iob_context ctx = { + .iob_mode = IOB_MODE_NULL; + .args = NULL; + }; + int actual = iob_init(ctx); + int expected = IOB_ERROR_BAD_ARG; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); +} + +Test(IO_Backend, init_stdin) +{ + struct iob_context ctx = { + .iob_mode = IOB_MODE_STDIN; + .args = NULL; + }; + int actual = iob_init(ctx); + int expected = 0; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); + iob_close(); +} + +// WARNING: this one could fail because of iob_close in the previous test +// Same applies for other tests +Test(IO_Backend, init_script) +{ + char* script_name = "script.tmp" + struct iob_context ctx = { + .iob_mode = IOB_MODE_SCRIPT; + .args = script_name; + }; + // Create file + FILE* f = fopen(script_name, "w"); + fclose(f); + + int actual = iob_init(ctx); + int expected = 0; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); + iob_close(); + remove(script_name); +} + +Test(IO_Backend, init_script_not_a_file) +{ + char* script_name = "not_a_file.tmp" + struct iob_context ctx = { + .iob_mode = IOB_MODE_SCRIPT; + .args = script_name; + }; + int actual = iob_init(ctx); + int expected = IOB_ERROR_CANNOT_OPEN_FILE; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); +} + +Test(IO_Backend, init_script_null) +{ + struct iob_context ctx = { + .iob_mode = IOB_MODE_SCRIPT; + .args = NULL; + }; + int actual = iob_init(ctx); + int expected = IOB_ERROR_CANNOT_OPEN_FILE; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); +} + +Test(IO_Backend, init_cmd) +{ + char* cmd = "iamacommand --yesido" + struct iob_context ctx = { + .iob_mode = IOB_MODE_CMD; + .args = cmd; + }; + int actual = iob_init(ctx); + int expected = 0; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); + iob_close(); +} + +Test(IO_Backend, init_cmd_null) +{ + struct iob_context ctx = { + .iob_mode = IOB_MODE_CMD; + .args = NULL; + }; + int actual = iob_init(ctx); + int expected = IOB_ERROR_BAD_ARG; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); +} + +Test(IO_Backend, init_already_init) +{ + char* cmd = "iamacommand --yesido" + struct iob_context ctx = { + .iob_mode = IOB_MODE_CMD; + .args = cmd; + }; + iob_init(ctx); + int actual = iob_init(ctx); + int expected = IOB_ERROR_ALREADY_INITIALIZED; + cr_expect(actual == expected, "Expected: %d. Got: %d", expected, actual); + iob_close(); +} + +Test(IO_Backend, close_not_init) +{ + iob_close(); // Shouldn't do anything +} + +// IOB Stream +// TODO