X-Git-Url: https://plomlompom.com/repos/?a=blobdiff_plain;f=src%2Fcommon%2Freadwrite.c;h=94150f17b515b723fe70d43adfafae8be3455775;hb=063eb0e64a0a2122c5581a668217290eb0b01f2b;hp=c27e86143bc7feb5ff0471df654f70ff960d4a33;hpb=778534bf6946fe0fef17e353c55678d248d8d09d;p=plomrogue diff --git a/src/common/readwrite.c b/src/common/readwrite.c index c27e861..94150f1 100644 --- a/src/common/readwrite.c +++ b/src/common/readwrite.c @@ -1,126 +1,169 @@ -/* src/common/readwrite.c */ +/* src/common/readwrite.c + * + * This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3 + * or any later version. For details on its copyright, license, and warranties, + * see the file NOTICE in the root directory of the PlomRogue source package. + */ #include "readwrite.h" -#include /* size_t */ +#include /* NULL, size_t */ #include /* uint8_t, uint16_t, uint32_t, UINT32_MAX */ #include /* FILE, fseek(), sprintf(), fgets(), fgetc(), ferror(), * fputc(), fwrite(), fclose(), fopen(), clearerr() */ #include /* free() */ -#include /* strlen() */ +#include /* strlen(), memcpy(), strchr() */ #include /* access(), unlink() */ #include "rexit.h" /* exit_err(), exit_trouble() */ #include "try_malloc.h" /* try_malloc() */ -extern FILE * try_fopen(char * path, char * mode, char * f) +extern FILE * try_fopen(char * path, char * mode, const char * f) { - char * f_name = "try_fopen()"; char * msg1 = "Trouble in "; - char * msg2 = " with fopen() (mode '"; + char * msg2 = " with fopen (mode '"; char * msg3 = "') on path '"; char * msg4 = "'."; uint16_t size = strlen(msg1) + strlen(msg2) + strlen(msg3) + strlen(msg4) + strlen(f) + strlen(path) + strlen(mode) + 1; - char * msg = try_malloc(size, f_name); + char * msg = try_malloc(size, __func__); int test = sprintf(msg, "%s%s%s%s%s%s%s", msg1,f,msg2,mode,msg3,path,msg4); - exit_trouble(test < 0, f_name, "sprintf()"); + exit_trouble(test < 0, __func__, "sprintf"); FILE * file_p = fopen(path, mode); - exit_err(NULL == file_p, msg); + exit_err(!file_p, msg); free(msg); return file_p; } -extern void try_fclose(FILE * file, char * f) +extern void try_fclose(FILE * file, const char * f) { - exit_trouble(fclose(file), f, "fclose()"); + exit_trouble(fclose(file), f, "fclose"); } extern void try_fwrite(void * ptr, size_t size, size_t nmemb, FILE * stream, - char * f) + const char * f) { - exit_trouble(0 == fwrite(ptr, size, nmemb, stream), f, "fwrite()"); + exit_trouble(0 == fwrite(ptr, size, nmemb, stream), f, "fwrite"); } -extern void try_fputc(uint8_t c, FILE * file, char * f) +extern void try_fputc(uint8_t c, FILE * file, const char * f) { - exit_trouble(EOF == fputc(c, file), f, "fputc()"); + exit_trouble(EOF == fputc(c, file), f, "fputc"); } -extern int try_fgetc(FILE * file, char * f) +extern int try_fgetc(FILE * file, const char * f) { clearerr(file); /* OSX' (BSD?) fgetc() needs this to undo previous EOFs. */ int test = fgetc(file); - exit_trouble(EOF == test && ferror(file), f, "fgetc()"); + exit_trouble(EOF == test && ferror(file), f, "fgetc"); return test; } -extern char * try_fgets(char * line, int linemax, FILE * file, char * f) +extern char * try_fgets(char * line, int linemax, FILE * file, const char * f) { char * test = fgets(line, linemax, file); - exit_trouble(NULL == test && ferror(file), f, "fgets()"); + exit_trouble(!test && ferror(file), f, "fgets"); return test; } -extern void try_fclose_unlink_rename(FILE * file, char * p1, char * p2, - char * f) +extern char * build_temp_path(char * path) { - char * f_name = "try_fclose_unlink_rename()"; - try_fclose(file, f); + char * suffix_tmp = "_tmp"; + uint16_t size = strlen(path) + strlen(suffix_tmp) + 1; + char * path_tmp = try_malloc(size, __func__); + int test = sprintf(path_tmp, "%s%s", path, suffix_tmp); + exit_trouble(test < 0, __func__, "sprintf"); + return path_tmp; +} + + + +extern FILE * atomic_write_start(char * path, char ** path_tmp) +{ + *path_tmp = build_temp_path(path); + return try_fopen(*path_tmp, "w", __func__); +} + + + +extern void atomic_write_finish(FILE * file, char * path, char * path_tmp) +{ + try_fclose(file, __func__); char * msg1 = "Trouble in "; char * msg4 = "'."; - if (!access(p2, F_OK)) + if (!access(path, F_OK)) { - char * msg2 = " with unlink() on path '"; + char * msg2 = " with unlink on path '"; uint16_t size = strlen(msg1) + strlen(msg2) + strlen(msg4) - + strlen(f) + strlen(p2) + 1; - char * msg = try_malloc(size, f_name); - int test = sprintf(msg, "%s%s%s%s%s", msg1, f, msg2, p2, msg4); - exit_trouble(test < 0, f_name, "sprintf()"); - exit_err(unlink(p2), msg); + + strlen(__func__) + strlen(path) + 1; + char * msg = try_malloc(size, __func__); + int test = sprintf(msg, "%s%s%s%s%s", msg1, __func__, msg2, path, msg4); + exit_trouble(test < 0, __func__, "sprintf"); + exit_err(unlink(path), msg); free(msg); } - char * msg2 = " with rename() from '"; + char * msg2 = " with rename from '"; char * msg3 = "' to '"; - uint16_t size = strlen(msg1) + strlen(f) + strlen(msg2) + strlen(p1) - + strlen(msg3) + strlen(p2) + strlen(msg4) + 1; - char * msg = try_malloc(size, f_name); - int test = sprintf(msg, "%s%s%s%s%s%s%s", msg1,f,msg2,p1,msg3,p2,msg4); - exit_trouble(test < 0, f_name, "sprintf()"); - exit_err(rename(p1, p2), msg); + uint16_t size = strlen(msg1) + strlen(__func__) + strlen(msg2) + + + strlen(path_tmp) + strlen(msg3) + strlen(path) + + strlen(msg4) + 1; + char * msg = try_malloc(size, __func__); + int test = sprintf(msg, "%s%s%s%s%s%s%s", + msg1, __func__, msg2, path_tmp, msg3, path, msg4); + exit_trouble(test < 0, __func__, "sprintf"); + exit_err(rename(path_tmp, path), msg); free(msg); + free(path_tmp); +} + + + +extern void detect_atomic_leftover(char * path) +{ + char * path_tmp = build_temp_path(path); + char * part1 = "Found file '"; + char * part2 = "' that may be a leftover from an aborted previous attempt " + "to write '"; + char * part3 = "'. Aborting until the matter is solved by (re-)moving it."; + uint32_t size = strlen(part1) + strlen(path_tmp) + strlen(part2) + + strlen(path) + strlen(part3) + 1; + char * msg = try_malloc(size, __func__); + int test = sprintf(msg, "%s%s%s%s%s", part1, path_tmp, part2, path, part3); + exit_trouble(test < 0, __func__, "sprintf"); + exit_err(!access(path_tmp, F_OK), msg); + free(msg); + free(path_tmp); } extern uint32_t textfile_width(FILE * file) { - char * f_name = "textfile_width()"; int c = 0; uint32_t c_count = 0; uint32_t linemax = 0; while (1) { - c = try_fgetc(file, f_name); + c = try_fgetc(file, __func__); if (EOF == c) { break; } c_count++; - exit_trouble(UINT32_MAX == c_count, f_name, "too large text file line"); + exit_trouble(UINT32_MAX==c_count, __func__, "too large text file line"); if ('\n' == c) { if (c_count > linemax) @@ -134,6 +177,60 @@ extern uint32_t textfile_width(FILE * file) { /* line / lack newline chars. */ linemax = c_count; } - exit_trouble(-1 == fseek(file, 0, SEEK_SET), f_name, "fseek()"); + exit_trouble(-1 == fseek(file, 0, SEEK_SET), __func__, "fseek"); return linemax; } + + + +extern uint8_t read_file_into_queue(FILE * file, char ** queue) +{ + uint8_t ret = 0; + int test; + while (EOF != (test = try_fgetc(file, __func__))) + { + ret = 1; + if ('\0' != test) + { + if (*queue) + { + char * new_queue = try_malloc(strlen(*queue) + 1 + 1, __func__); + memcpy(new_queue, *queue, strlen(*queue)); + new_queue[strlen(*queue)] = (char) test; + new_queue[strlen(*queue) + 1] = '\0'; + free(*queue); + *queue = new_queue; + } + else + { + *queue = try_malloc(1 + 1, __func__); + (*queue)[0] = (char) test; + (*queue)[1] = '\0'; + } + } + } + return ret; +} + + + +extern char * get_message_from_queue(char ** queue) +{ + if (!(*queue)) + { + return NULL; + } + char * first_nl = strchr(*queue, '\n'); + if (!first_nl) + { + return NULL; + } + char * msg = try_malloc(first_nl - (*queue) + 1, __func__); + memcpy(msg, *queue, first_nl - (*queue)); + msg[first_nl - (*queue)] = '\0'; + char * new_queue = try_malloc(strlen(first_nl + 1) + 1, __func__); + memcpy(new_queue, first_nl + 1, strlen(first_nl + 1) + 1); + free(*queue); + *queue = new_queue; + return msg; +}