From b9082c113c43afe5c6a11c2b72f845ee2f8c6aea Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Wed, 14 Aug 2013 12:58:48 +0200 Subject: [PATCH] Built error checking into file reading/writing routines and calls of them. --- src/main.c | 48 ++++++++++++----------- src/map_objects.c | 48 +++++++++++++---------- src/map_objects.h | 5 ++- src/misc.c | 23 +++++------ src/readwrite.c | 98 +++++++++++++++++++++++++++++++++++++---------- src/readwrite.h | 16 +++++--- 6 files changed, 158 insertions(+), 80 deletions(-) diff --git a/src/main.c b/src/main.c index 7096f6c..d2fb9bf 100644 --- a/src/main.c +++ b/src/main.c @@ -13,9 +13,7 @@ * draw_log_win() */ #include "keybindings.h" /* for initkeybindings(), get_action_key() */ -#include "readwrite.h" /* for read_uint16_bigendian, read_uint32_bigendian, - * write_uint32_bigendian - */ +#include "readwrite.h" /* for [read/write]_uint[8/16/32][_bigendian]() */ #include "map_objects.h" /* for structs Monster, Item, Player, * init_map_object_defs(), read_map_objects(), * build_map_objects() @@ -62,19 +60,22 @@ int main(int argc, char *argv[]) world.monster = 0; world.item = 0; init_map_object_defs(&world, "defs"); + uint8_t fail = 0; /* For interactive mode, try to load world state from savefile. */ FILE * file; if (1 == world.interactive && 0 == access("savefile", F_OK)) { file = fopen("savefile", "r"); - world.seed = read_uint32_bigendian(file); - world.turn = read_uint32_bigendian(file); - player.pos.y = read_uint16_bigendian(file) - 1; - player.pos.x = read_uint16_bigendian(file) - 1; - player.hitpoints = fgetc(file); - read_map_objects(&world, &world.monster, file); - read_map_objects(&world, &world.item, file); + fail = fail | read_uint32_bigendian(file, &world.seed); + fail = fail | read_uint32_bigendian(file, &world.turn); + fail = fail | read_uint16_bigendian(file, &player.pos.y); + fail = fail | read_uint16_bigendian(file, &player.pos.x); + player.pos.y--; + player.pos.x--; + fail = fail | read_uint8(file, &player.hitpoints); + fail = fail | read_map_objects(&world, &world.monster, file); + fail = fail | read_map_objects(&world, &world.item, file); fclose(file); } @@ -85,20 +86,23 @@ int main(int argc, char *argv[]) if (0 == world.interactive) { file = fopen("record", "r"); - world.seed = read_uint32_bigendian(file); + fail = fail | read_uint32_bigendian(file, &world.seed); + } + + /* For interactive-mode in newly started world, generate a start seed + * from the current time. + */ + else + { + file = fopen("record", "w"); + world.seed = time(NULL); + fail = fail | write_uint32_bigendian(world.seed, file); + fclose(file); } + } + + exit_err(fail, &world, "Failure initializing game."); - /* For interactive-mode in newly started world, generate a start seed - * from the current time. - */ - else - { - file = fopen("record", "w"); - world.seed = time(NULL); - write_uint32_bigendian(world.seed, file); - fclose(file); - } - } /* Generate map from seed and, if newly generated world, start positions of * actors. diff --git a/src/map_objects.c b/src/map_objects.c index 4340694..c4b9048 100644 --- a/src/map_objects.c +++ b/src/map_objects.c @@ -4,7 +4,7 @@ #include /* for malloc(), calloc(), free(), atoi() */ #include /* for FILE typedef */ #include /* for strchr(), strlen(), memcpy() */ -#include "readwrite.h" /* for all the map object (def) loading/saving */ +#include "readwrite.h" /* for [read/write]_uint[8/16/23][_bigendian]() */ #include "misc.h" /* for textfile_sizes(), find_passable_pos() */ #include "main.h" /* for World struct */ @@ -23,8 +23,8 @@ static void build_map_objects_itemdata(struct MapObjDef * map_obj_def, void * start); static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def, void * start); -static void write_map_objects_monsterdata(void * start, FILE * file); -static void read_map_objects_monsterdata( void * start, FILE * file); +static uint8_t write_map_objects_monsterdata(void * start, FILE * file); +static uint8_t read_map_objects_monsterdata( void * start, FILE * file); @@ -68,18 +68,18 @@ static void build_map_objects_monsterdata(struct MapObjDef * map_obj_def, -static void write_map_objects_monsterdata(void * start, FILE * file) +static uint8_t write_map_objects_monsterdata(void * start, FILE * file) { struct Monster * m = (struct Monster *) start; - fputc(m->hitpoints, file); + return write_uint8(m->hitpoints, file); } -static void read_map_objects_monsterdata (void * start, FILE * file) +static uint8_t read_map_objects_monsterdata (void * start, FILE * file) { struct Monster * m = (struct Monster *) start; - m->hitpoints = fgetc(file); + return read_uint8(file, &m->hitpoints); } @@ -137,43 +137,48 @@ extern void init_map_object_defs(struct World * world, char * filename) -extern void write_map_objects(struct World * world, void * start, FILE * file) +extern uint8_t write_map_objects(struct World * world, void * start, + FILE * file) { struct MapObj * map_obj; struct MapObjDef * mod; + uint8_t fail = 0; for (map_obj = start; map_obj != 0; map_obj = map_obj->next) { - fputc(map_obj->type, file); - write_uint16_bigendian(map_obj->pos.y + 1, file); - write_uint16_bigendian(map_obj->pos.x + 1, file); + fail = fail | write_uint8(map_obj->type, file); + fail = fail | write_uint16_bigendian(map_obj->pos.y + 1, file); + fail = fail | write_uint16_bigendian(map_obj->pos.x + 1, file); mod = get_map_obj_def(world, map_obj->type); if ('m' == mod->m_or_i) { - write_map_objects_monsterdata(map_obj, file); + fail = fail | write_map_objects_monsterdata(map_obj, file); } } - write_uint16_bigendian(0, file); + return (fail | write_uint16_bigendian(0, file)); } -extern void read_map_objects(struct World * world, void * start, FILE * file) +extern uint8_t read_map_objects(struct World * world, void * start, FILE * file) { struct MapObj * map_obj; struct MapObjDef * mod; size_t size; - char type; + uint8_t type; char first = 1; long pos; + uint16_t read_uint16 = 0; + uint8_t fail = 0; while (1) { pos = ftell(file); - if (0 == read_uint16_bigendian(file)) + fail = fail | read_uint16_bigendian(file, &read_uint16); + if (0 == read_uint16) { break; } fseek(file, pos, SEEK_SET); - type = fgetc(file); + fail = fail | read_uint8(file, &type); mod = get_map_obj_def(world, type); if ('m' == mod->m_or_i) { @@ -185,17 +190,20 @@ extern void read_map_objects(struct World * world, void * start, FILE * file) } map_obj = get_next_map_obj(start, &first, size, map_obj); map_obj->type = type; - map_obj->pos.y = read_uint16_bigendian(file) - 1; - map_obj->pos.x = read_uint16_bigendian(file) - 1; + fail = fail | read_uint16_bigendian(file, &map_obj->pos.y); + fail = fail | read_uint16_bigendian(file, &map_obj->pos.x); + map_obj->pos.y--; + map_obj->pos.x--; if ('m' == mod->m_or_i) { - read_map_objects_monsterdata(map_obj, file); + fail = fail | read_map_objects_monsterdata(map_obj, file); } } if (!first) { map_obj->next = 0; } + return fail; } diff --git a/src/map_objects.h b/src/map_objects.h index a5156f4..7fcf1c7 100644 --- a/src/map_objects.h +++ b/src/map_objects.h @@ -88,8 +88,9 @@ extern void * build_map_objects(struct World * world, void * start, char def_id, /* Write to/read from file chain of map objects starting/to start in memory at * "start". */ -extern void write_map_objects(struct World * world, void * start, FILE * file); -extern void read_map_objects(struct World * world, void * start, FILE * file); +extern uint8_t write_map_objects(struct World * world, void * start, + FILE * file); +extern uint8_t read_map_objects(struct World * world, void * start, FILE * file); diff --git a/src/misc.c b/src/misc.c index 0bb50a7..ec05acc 100644 --- a/src/misc.c +++ b/src/misc.c @@ -10,15 +10,14 @@ #include "keybindings.h" /* for get_action_key(), save_keybindings(), * keyswin_move_selection(), keyswin_mod_key() */ -#include "readwrite.h" /* for write_uint16_bigendian(), write_uint32_bigendian() - */ +#include "readwrite.h" /* for [read/write]_uint[8/16/32][_bigendian]() */ #include "map_objects.h" /* for struct Monster, write_map_objects(), */ #include "map_object_actions.h" /* for is_passable(), move_monster() */ #include "map.h" /* for map_scroll(),map_center_player(), Map struct,dir enum */ #include "main.h" /* for World struct */ #include "yx_uint16.h" /* for yx_uint16 */ #include "rrand.h" /* for rrand(), rrand_seed() */ - +#include "rexit.h" /* for exit_err() */ extern void textfile_sizes(FILE * file, uint16_t * linemax_p, @@ -115,7 +114,7 @@ extern void turn_over(struct World * world, char action) if (1 == world->interactive) { FILE * file = fopen("record", "a"); - fputc(action, file); + exit_err(write_uint8(action, file), world, "Record writing failure."); fclose(file); } world->turn++; @@ -133,14 +132,16 @@ extern void turn_over(struct World * world, char action) extern void save_game(struct World * world) { + uint8_t fail; FILE * file = fopen("savefile", "w"); - write_uint32_bigendian(world->seed, file); - write_uint32_bigendian(world->turn, file); - write_uint16_bigendian(world->player->pos.y + 1, file); - write_uint16_bigendian(world->player->pos.x + 1, file); - fputc(world->player->hitpoints, file); - write_map_objects(world, world->monster, file); - write_map_objects(world, world->item, file); + fail = write_uint32_bigendian(world->seed, file); + fail = fail | write_uint32_bigendian(world->turn, file); + fail = fail | write_uint16_bigendian(world->player->pos.y + 1, file); + fail = fail | write_uint16_bigendian(world->player->pos.x + 1, file); + fail = fail | write_uint8(world->player->hitpoints, file); + fail = fail | write_map_objects(world, world->monster, file); + fail = fail | write_map_objects(world, world->item, file); + exit_err(fail, world, "Error saving game."); fclose(file); } diff --git a/src/readwrite.c b/src/readwrite.c index 40fc63f..6d24992 100644 --- a/src/readwrite.c +++ b/src/readwrite.c @@ -6,40 +6,98 @@ -extern uint16_t read_uint16_bigendian(FILE * file) +/* Read/write "x" from/to "file" as bigendian representation of "size" bits. */ +static uint8_t read_uintX_bigendian(FILE * file, uint32_t * x, uint8_t size); +static uint8_t write_uintX_bigendian(FILE * file, uint32_t x, uint8_t size); + + + +static uint8_t read_uintX_bigendian(FILE * file, uint32_t * x, uint8_t size) +{ + if (0 != size % 8) + { + return 1; + } + int16_t bitshift = size - 8; + + * x = 0; + int test; + for (; bitshift >= 0; bitshift = bitshift - 8) + { + test = fgetc(file); + if (EOF == test) + { + return 1; + } + * x = * x + ((uint32_t) test << bitshift); + } + return 0; +} + + + +static uint8_t write_uintX_bigendian(FILE * file, uint32_t x, uint8_t size) +{ + if (0 != size % 8) + { + return 1; + } + int16_t bitshift = size - 8; + + for (; bitshift >= 0; bitshift = bitshift - 8) + { + if (EOF == fputc((x >> bitshift) & 0xFF, file)) + { + return 1; + } + } + return 0; +} + + + +extern uint8_t read_uint8(FILE * file, uint8_t * x) +{ + uint32_t y = * x; + uint8_t fail = read_uintX_bigendian(file, &y, 8); + * x = (uint8_t) y; + return fail; +} + + + +extern uint8_t read_uint16_bigendian(FILE * file, uint16_t * x) +{ + uint32_t y = * x; + uint8_t fail = read_uintX_bigendian(file, &y, 16); + * x = (uint16_t) y; + return fail; +} + + + +extern uint8_t read_uint32_bigendian(FILE * file, uint32_t * x) { - uint16_t x; - x = (uint16_t) fgetc(file) << 8; - x = x + (uint16_t) fgetc(file); - return x; + return read_uintX_bigendian(file, x, 32); } -extern uint32_t read_uint32_bigendian(FILE * file) +extern uint8_t write_uint8(uint8_t x, FILE * file) { - uint32_t x; - x = (uint32_t) fgetc(file) << 24; - x = x + ( (uint32_t) fgetc(file) << 16 ); - x = x + ( (uint32_t) fgetc(file) << 8 ); - x = x + (uint32_t) fgetc(file); - return x; + return write_uintX_bigendian(file, x, 8); } -extern void write_uint16_bigendian(uint16_t x, FILE * file) +extern uint8_t write_uint16_bigendian(uint16_t x, FILE * file) { - fputc( x >> 8, file ); - fputc( x & 0xFF, file ); + return write_uintX_bigendian(file, x, 16); } -extern void write_uint32_bigendian(uint32_t x, FILE * file) +extern uint8_t write_uint32_bigendian(uint32_t x, FILE * file) { - fputc( x >> 24, file); - fputc( ( x >> 16 ) & 0xFF, file); - fputc( ( x >> 8 ) & 0xFF, file); - fputc( x & 0xFF, file); + return write_uintX_bigendian(file, x, 32); } diff --git a/src/readwrite.h b/src/readwrite.h index a0c8dba..42a7c3a 100644 --- a/src/readwrite.h +++ b/src/readwrite.h @@ -1,6 +1,6 @@ /* readwrite.h: * - * Routines for reading/writing multibyte data from/to files. They ensure a + * Routines for reading/writing (multi-)byte data from/to files. They ensure a * defined endianness. */ @@ -14,9 +14,15 @@ -extern uint16_t read_uint16_bigendian(FILE * file); -extern uint32_t read_uint32_bigendian(FILE * file); -extern void write_uint16_bigendian(uint16_t x, FILE * file); -extern void write_uint32_bigendian(uint32_t x, FILE * file); +/* Each function returns 0 on success and 1 on failure. "x" is the value to be + * written to "file" for write_* functions and for read_* functions the pointer + * to where the value read from "file" is to be written. + */ +extern uint8_t read_uint8(FILE * file, uint8_t * x); +extern uint8_t read_uint16_bigendian(FILE * file, uint16_t * x); +extern uint8_t read_uint32_bigendian(FILE * file, uint32_t * x); +extern uint8_t write_uint8(uint8_t x, FILE * file); +extern uint8_t write_uint16_bigendian(uint16_t x, FILE * file); +extern uint8_t write_uint32_bigendian(uint32_t x, FILE * file); #endif -- 2.30.2