#include "io_backend.h" #include #include #include // === Static variables static struct iob_context context; 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) { case IOB_MODE_STDIN: input = stdin; state = IOB_STATE_READY; return 0; case IOB_MODE_SCRIPT: if (context.args == NULL) return IOB_ERROR_BAD_ARG; input = fopen(context.args, "r"); if (input == NULL) return IOB_ERROR_CANNOT_OPEN_FILE; state = IOB_STATE_READY; return 0; case IOB_MODE_CMD: if (context.args != NULL) return IOB_ERROR_BAD_ARG; state = IOB_STATE_READY; return 0; default: 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; } }