diff --git a/code/logic/fossil/io/stream.h b/code/logic/fossil/io/stream.h index 04116e8..d0646ef 100644 --- a/code/logic/fossil/io/stream.h +++ b/code/logic/fossil/io/stream.h @@ -25,7 +25,7 @@ extern "C" { * Structure representing a file stream. */ typedef struct { - FILE *file; // Pointer to the FILE structure for the stream + FILE *file; // Pointer to the FILE structure for the stream char filename[500]; // Array to store the filename } fossil_fstream_t; @@ -71,6 +71,16 @@ int32_t fossil_fstream_open(fossil_fstream_t *stream, const char *filename, cons */ void fossil_fstream_close(fossil_fstream_t *stream); +/** + * Redirect a stream to /dev/null. + * + * This function redirects the given stream to /dev/null, effectively discarding any data written to it. + * + * @param stream Pointer to the fossil_fstream_t structure to redirect. + * @return 0 on success, non-zero on failure. + */ +int32_t fossil_fstream_redirect_to_devnull(fossil_fstream_t *stream); + /** * Check if a stream is open. * @@ -418,6 +428,18 @@ namespace fossil { fossil_fstream_close(stream); } + /** + * Redirect a stream to /dev/null. + * + * This function redirects the given stream to /dev/null, effectively discarding any data written to it. + * + * @param stream Pointer to the fossil_fstream_t structure to redirect. + * @return 0 on success, non-zero on failure. + */ + static int32_t redirect_to_devnull(fossil_fstream_t *stream) { + return fossil_fstream_redirect_to_devnull(stream); + } + /** * Check if a stream is open. * diff --git a/code/logic/stream.c b/code/logic/stream.c index 20c28c1..a71653e 100644 --- a/code/logic/stream.c +++ b/code/logic/stream.c @@ -12,6 +12,7 @@ * ----------------------------------------------------------------------------- */ #include "fossil/io/stream.h" +#include "fossil/io/output.h" #include "fossil/io/error.h" #include #include @@ -86,18 +87,18 @@ static const char *fossil_fstream_mode_from_keyword(const char *keyword) { // Open a stream for file operations int32_t fossil_fstream_open(fossil_fstream_t *stream, const char *filename, const char *mode) { if (stream == NULL || filename == NULL || mode == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } if (strlen(filename) >= FOSSIL_BUFFER_MEDIUM) { - fprintf(stderr, "Error: Limit reached\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Limit reached\n"); return FOSSIL_ERROR_LIMIT_REACHED; } stream->file = fopen(filename, fossil_fstream_mode_from_keyword(mode)); if (stream->file == NULL) { - fprintf(stderr, "Error: File not found - %s\n", filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found - %s\n", filename); return FOSSIL_ERROR_FILE_NOT_FOUND; } @@ -110,21 +111,49 @@ int32_t fossil_fstream_open(fossil_fstream_t *stream, const char *filename, cons void fossil_fstream_close(fossil_fstream_t *stream) { if (stream != NULL && stream->file != NULL) { if (fclose(stream->file) != 0) { - fprintf(stderr, "Error: Failed to close file - %s\n", stream->filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Failed to close file - %s\n", stream->filename); } stream->file = NULL; } } +int32_t fossil_fstream_redirect_to_devnull(fossil_fstream_t *stream) { + if (!stream) { + return -1; // Invalid stream + } + +#ifdef _WIN32 + FILE *devnull = fopen("NUL", "w"); +#else + FILE *devnull = fopen("/dev/null", "w"); +#endif + + if (!devnull) { + return -1; // Failed to open null device + } + + if (stream->file) { + fclose(stream->file); + } + + stream->file = devnull; +#ifdef _WIN32 + snprintf(stream->filename, sizeof(stream->filename), "NUL"); +#else + snprintf(stream->filename, sizeof(stream->filename), "/dev/null"); +#endif + return 0; +} + int32_t fossil_fstream_freopen(fossil_fstream_t *stream, const char *filename, const char *mode, FILE *file) { if (stream == NULL || filename == NULL || mode == NULL || file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } FILE *new_file = freopen(filename, fossil_fstream_mode_from_keyword(mode), file); if (new_file == NULL) { - fprintf(stderr, "Error: File not found - %s\n", filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found - %s\n", filename); return FOSSIL_ERROR_FILE_NOT_FOUND; } @@ -137,14 +166,14 @@ int32_t fossil_fstream_freopen(fossil_fstream_t *stream, const char *filename, c // Read data from an open stream size_t fossil_fstream_read(fossil_fstream_t *stream, void *buffer, size_t size, size_t count) { if (stream == NULL || buffer == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } size_t bytes_read = fread(buffer, size, count, stream->file); if (bytes_read == 0 && ferror(stream->file)) { - fprintf(stderr, "Error: File corruption\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File corruption\n"); return FOSSIL_ERROR_FILE_CORRUPTION; } @@ -154,14 +183,14 @@ size_t fossil_fstream_read(fossil_fstream_t *stream, void *buffer, size_t size, // Write data to an open stream size_t fossil_fstream_write(fossil_fstream_t *stream, const void *buffer, size_t size, size_t count) { if (stream == NULL || buffer == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } size_t bytes_written = fwrite(buffer, size, count, stream->file); if (bytes_written == 0 && ferror(stream->file)) { - fprintf(stderr, "Error: File not found - %s\n", strerror(errno)); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found - %s\n", strerror(errno)); return FOSSIL_ERROR_FILE_NOT_FOUND; } @@ -171,7 +200,7 @@ size_t fossil_fstream_write(fossil_fstream_t *stream, const void *buffer, size_t // Append data to the end of an open stream int32_t fossil_fstream_append(fossil_fstream_t *stream, const void * restrict buffer, size_t size, int32_t count) { if (stream == NULL || buffer == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } @@ -179,7 +208,7 @@ int32_t fossil_fstream_append(fossil_fstream_t *stream, const void * restrict bu int32_t result = fwrite(buffer, size, count, stream->file); if (result != count) { - fprintf(stderr, "Error: File not found\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found\n"); return FOSSIL_ERROR_FILE_NOT_FOUND; } @@ -189,14 +218,14 @@ int32_t fossil_fstream_append(fossil_fstream_t *stream, const void * restrict bu // Seek to a specified position in an open stream int32_t fossil_fstream_seek(fossil_fstream_t *stream, int64_t offset, int32_t origin) { if (stream == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } int32_t result = fseek(stream->file, offset, origin); if (result != 0) { - fprintf(stderr, "Error: File not found - %s\n", strerror(errno)); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found - %s\n", strerror(errno)); return FOSSIL_ERROR_FILE_NOT_FOUND; } @@ -206,14 +235,14 @@ int32_t fossil_fstream_seek(fossil_fstream_t *stream, int64_t offset, int32_t or // Get the current position of the file pointer in an open stream int32_t fossil_fstream_tell(fossil_fstream_t *stream) { if (stream == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } long position = ftell(stream->file); if (position == -1L && ferror(stream->file)) { - fprintf(stderr, "Error: IO error from getting file position\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: IO error from getting file position\n"); return FOSSIL_ERROR_IO; } @@ -223,19 +252,19 @@ int32_t fossil_fstream_tell(fossil_fstream_t *stream) { // Save an open stream to a new file int32_t fossil_fstream_save(fossil_fstream_t *stream, const char *new_filename) { if (stream == NULL || stream->file == NULL || new_filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } if (strlen(new_filename) >= FOSSIL_BUFFER_MEDIUM) { - fprintf(stderr, "Error: Limit reached\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Limit reached\n"); return FOSSIL_ERROR_LIMIT_REACHED; } fclose(stream->file); if (rename(stream->filename, new_filename) != 0) { - fprintf(stderr, "Error: Failed to save %s\n", new_filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Failed to save %s\n", new_filename); return FOSSIL_ERROR_CNULL_POINTER; } @@ -243,7 +272,7 @@ int32_t fossil_fstream_save(fossil_fstream_t *stream, const char *new_filename) int32_t result = fossil_fstream_open(stream, new_filename, "r"); if (result != FOSSIL_ERROR_OK) { - fprintf(stderr, "Error: File not found - %s\n", strerror(errno)); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found - %s\n", strerror(errno)); return FOSSIL_ERROR_FILE_NOT_FOUND; } return result; @@ -252,19 +281,19 @@ int32_t fossil_fstream_save(fossil_fstream_t *stream, const char *new_filename) // Copy a file from the source to the destination int32_t fossil_fstream_copy(const char *source_filename, const char *destination_filename) { if (source_filename == NULL || destination_filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } FILE *source_file = fopen(source_filename, "rb"); if (source_file == NULL) { - fprintf(stderr, "Error: File not found - %s\n", source_filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found - %s\n", source_filename); return FOSSIL_ERROR_FILE_NOT_FOUND; } FILE *destination_file = fopen(destination_filename, "wb"); if (destination_file == NULL) { - fprintf(stderr, "Error: File not found - %s\n", destination_filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found - %s\n", destination_filename); fclose(source_file); return FOSSIL_ERROR_FILE_NOT_FOUND; } @@ -275,7 +304,7 @@ int32_t fossil_fstream_copy(const char *source_filename, const char *destination while ((bytesRead = fread(buffer, 1, FOSSIL_BUFFER_MEDIUM, source_file)) > 0) { size_t bytesWritten = fwrite(buffer, 1, bytesRead, destination_file); if (bytesWritten != bytesRead) { - fprintf(stderr, "Error: File not found\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: File not found\n"); fclose(source_file); fclose(destination_file); return FOSSIL_ERROR_FILE_NOT_FOUND; @@ -290,7 +319,7 @@ int32_t fossil_fstream_copy(const char *source_filename, const char *destination int32_t fossil_fstream_remove(const char *filename) { if (filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } @@ -298,18 +327,18 @@ int32_t fossil_fstream_remove(const char *filename) { return FOSSIL_ERROR_OK; // File removed successfully } - fprintf(stderr, "Error: IO error when removing file %s\n", filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: IO error when removing file %s\n", filename); return FOSSIL_ERROR_IO; } int32_t fossil_fstream_rename(const char *old_filename, const char *new_filename) { if (old_filename == NULL || new_filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } if (rename(old_filename, new_filename) != 0) { - fprintf(stderr, "Error: Failed to rename file %s\n", old_filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Failed to rename file %s\n", old_filename); return FOSSIL_ERROR_IO; } @@ -318,12 +347,12 @@ int32_t fossil_fstream_rename(const char *old_filename, const char *new_filename int32_t fossil_fstream_flush(fossil_fstream_t *stream) { if (stream == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } if (fflush(stream->file) != 0) { - fprintf(stderr, "Error: Failed to flush file\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Failed to flush file\n"); return FOSSIL_ERROR_IO; } @@ -332,12 +361,12 @@ int32_t fossil_fstream_flush(fossil_fstream_t *stream) { int32_t fossil_fstream_setpos(fossil_fstream_t *stream, int32_t pos) { if (stream == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } if (fseek(stream->file, pos, SEEK_SET) != 0) { - fprintf(stderr, "Error: Failed to set file position\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Failed to set file position\n"); return FOSSIL_ERROR_IO; } @@ -346,13 +375,13 @@ int32_t fossil_fstream_setpos(fossil_fstream_t *stream, int32_t pos) { int32_t fossil_fstream_getpos(fossil_fstream_t *stream, int32_t *pos) { if (stream == NULL || stream->file == NULL || pos == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } *pos = ftell(stream->file); if (*pos == -1L && ferror(stream->file)) { - fprintf(stderr, "Error: IO error from getting file position\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: IO error from getting file position\n"); return FOSSIL_ERROR_IO; } @@ -361,7 +390,7 @@ int32_t fossil_fstream_getpos(fossil_fstream_t *stream, int32_t *pos) { int32_t fossil_fstream_rotate(const char *filename, int32_t n) { if (filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } @@ -377,7 +406,7 @@ int32_t fossil_fstream_rotate(const char *filename, int32_t n) { snprintf(new_filename, FOSSIL_BUFFER_MEDIUM, "%s.%d", filename, i); if (fossil_fstream_rename(old_filename, new_filename) != FOSSIL_ERROR_OK) { - fprintf(stderr, "Error: Failed to rotate file %s\n", filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Failed to rotate file %s\n", filename); return FOSSIL_ERROR_IO; } } @@ -388,7 +417,7 @@ int32_t fossil_fstream_rotate(const char *filename, int32_t n) { // Create a backup of a file with a specified backup suffix int32_t fossil_fstream_backup(const char *filename, const char *backup_suffix) { if (filename == NULL || backup_suffix == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } @@ -396,7 +425,7 @@ int32_t fossil_fstream_backup(const char *filename, const char *backup_suffix) { snprintf(backup_filename, FOSSIL_BUFFER_MEDIUM + 10, "%s%s", filename, backup_suffix); if (fossil_fstream_copy(filename, backup_filename) != FOSSIL_ERROR_OK) { - fprintf(stderr, "Error: Failed to create backup for %s\n", filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Failed to create backup for %s\n", filename); return FOSSIL_ERROR_IO; } @@ -406,7 +435,7 @@ int32_t fossil_fstream_backup(const char *filename, const char *backup_suffix) { // Check if a file exists int32_t fossil_fstream_file_exists(const char *filename) { if (filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } @@ -421,7 +450,7 @@ int32_t fossil_fstream_file_exists(const char *filename) { // Get the size of an open stream int32_t fossil_fstream_get_size(fossil_fstream_t *stream) { if (stream == NULL || stream->file == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } @@ -430,7 +459,7 @@ int32_t fossil_fstream_get_size(fossil_fstream_t *stream) { rewind(stream->file); if (size == -1L && ferror(stream->file)) { - fprintf(stderr, "Error: IO error from getting file size\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: IO error from getting file size\n"); return FOSSIL_ERROR_OK; } @@ -440,7 +469,7 @@ int32_t fossil_fstream_get_size(fossil_fstream_t *stream) { // Delete a file int32_t fossil_fstream_delete(const char *filename) { if (filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return FOSSIL_ERROR_CNULL_POINTER; } @@ -448,14 +477,14 @@ int32_t fossil_fstream_delete(const char *filename) { return FOSSIL_ERROR_OK; // File deleted successfully } - fprintf(stderr, "Error: IO error when deleting file %s\n", filename); + fossil_io_fprintf(FOSSIL_STDERR, "Error: IO error when deleting file %s\n", filename); return FOSSIL_ERROR_IO; } // Detect file type (Regular file, Directory, Symbolic link) int fossil_fstream_get_type(const char *filename) { if (filename == NULL) { - fprintf(stderr, "Error: Null pointer\n"); + fossil_io_fprintf(FOSSIL_STDERR, "Error: Null pointer\n"); return -1; } diff --git a/code/tests/cases/test_stream.c b/code/tests/cases/test_stream.c index faec186..e68fda6 100644 --- a/code/tests/cases/test_stream.c +++ b/code/tests/cases/test_stream.c @@ -61,6 +61,34 @@ FOSSIL_TEST_CASE(c_test_stream_let_write_and_read_file) { fossil_fstream_close(&c_stream); } +FOSSIL_TEST_CASE(c_test_stream_redirect_to_devnull) { + const char *filename = "testfile_redirect.txt"; + const char *content = "This is a test."; + + // Create the file and write data to it + ASSUME_ITS_EQUAL_I32(0, fossil_fstream_open(&c_stream, filename, "w")); + fossil_fstream_write(&c_stream, content, strlen(content), 1); + + // Redirect the stream to /dev/null + ASSUME_ITS_EQUAL_I32(0, fossil_fstream_redirect_to_devnull(&c_stream)); + + // Attempt to write more data (should not affect the file) + const char *extra_content = "This should not be written."; + fossil_fstream_write(&c_stream, extra_content, strlen(extra_content), 1); + + // Close the stream + fossil_fstream_close(&c_stream); + + // Reopen the file and verify its content remains unchanged + char buffer[1024] = {0}; + ASSUME_ITS_EQUAL_I32(0, fossil_fstream_open(&c_stream, filename, "r")); + fossil_fstream_read(&c_stream, buffer, sizeof(buffer), 1); + fossil_fstream_close(&c_stream); + + ASSUME_ITS_EQUAL_CSTR(content, buffer); +} + + FOSSIL_TEST_CASE(c_test_stream_let_open_and_close_file) { const char *filename = "testfile.txt"; @@ -240,6 +268,7 @@ FOSSIL_TEST_CASE(c_test_stream_setpos_and_getpos) { FOSSIL_TEST_GROUP(c_file_tests) { FOSSIL_TEST_ADD(c_stream_suite, c_test_stream_let_write_and_read_file); FOSSIL_TEST_ADD(c_stream_suite, c_test_stream_let_open_and_close_file); + FOSSIL_TEST_ADD(c_stream_suite, c_test_stream_redirect_to_devnull); FOSSIL_TEST_ADD(c_stream_suite, c_test_stream_multiple_files); FOSSIL_TEST_ADD(c_stream_suite, c_test_stream_seek_and_tell); FOSSIL_TEST_ADD(c_stream_suite, c_test_stream_get_type);