gol

Implementation of Conway's Game of Life writen in C
git clone git://git.dimitrijedobrota.com/gol.git
Log | Files | Refs | README

commit c97829684b0f8b0c6d0b3f56c52d95004832be1f
parent c48f5196f08e800160564302abbe978a6f6b26b2
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date:   Thu, 16 Jun 2022 20:55:47 +0200

Documentation for file.c and small improvements

Diffstat:
Minclude/file.h | 2+-
Msrc/file.c | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/main.c | 2+-
3 files changed, 131 insertions(+), 56 deletions(-)

diff --git a/include/file.h b/include/file.h @@ -6,7 +6,7 @@ int file_setup(void); void load_files(void); void free_files(void); -int file_select(char *ext, char ***buffer); +int file_select_extension(char *ext, char ***buffer); void file_load_pattern(char *name, int index); void file_save_pattern(char *name, int index); diff --git a/src/file.c b/src/file.c @@ -1,8 +1,20 @@ +/** + * @file file.c + * @author Dimitrije Dobrota + * @date 16 June 2022 + * @brief This file contains functions for handling save files + * + * This file aims to provide a simple interface for interacting with the + * filesystem on Linux and Windows systems. After proper game directory has been + * selected, functions implemented here will read the list of files, filter them + * based on the extension, create new files for storing a whole game or just a + * pattern. + */ + +#include <dirent.h> #include <limits.h> #include <stdlib.h> #include <string.h> - -#include <dirent.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> @@ -20,50 +32,102 @@ #define MAKE_DIR(dir) (mkdir(dir, 0777)) #endif // _WIN32 +/** + * @brief Check if a directory at specific path exists + */ +int DirectoryExists(const char *path) { + struct stat stats; + stat(path, &stats); + + return S_ISDIR(stats.st_mode); +} + +/** + * @brief Try to change the directory to SETTINGS_DIR, if it doesn't exist + * create it. Return 0 on failure. + */ +int file_setup(void) { + char *dir; + MEM_CHECK(dir = malloc(PATH_MAX * sizeof(char))); + +#ifdef _WIN32 + strcpy(dir, SETTINGS_DIR); +#else + const char *homedir = getenv("HOME"); + sprintf(dir, "%s/%s", homedir, SETTINGS_DIR); +#endif + + if (!DirectoryExists(dir)) { + printf("Directory %s does not exists; Trying to create it...\n", dir); + if (MAKE_DIR(dir) != 0) { + printf("Cannot create the directory\n"); + return 0; + } + } + + if (chdir(dir) != 0) { + printf("Cannot change the directory\n"); + return 0; + } + return 1; +} + typedef struct file_T *file_T; + +/** + * @brief A node in a linked list of file names + */ struct file_T { - file_T next; - char *name; + file_T next; ///< pointer to the next node + char *name; ///< name of a file }; -file_T loaded_files; +static file_T loaded_files; +/** + * @brief create new file_T + * + * Allocate the memory for a new file_T. The name field will be set to NULL if + * NULL is provided as name, otherwise it will be set to a DUPLICATE of a + * string provided. + */ file_T file_new(char *name) { file_T f; - MEM_CHECK(f = malloc(sizeof(*f))); - f->next = NULL; - if (name == NULL) { - f->name = NULL; - return f; - } + MEM_CHECK(f = calloc(1, sizeof(*f))); + + if (name != NULL) + MEM_CHECK(f->name = strdup(name)); - MEM_CHECK(f->name = malloc((strlen(name) + 1) * sizeof(char))); - strcpy(f->name, name); return f; } +/** + * @brief Free the linked list of file_T + */ void file_free(file_T self) { if (self == NULL) return; + file_free(self->next); free(self->name); free(self); } +/** + * @brief Add file of a specific name to the begin of a linked list + * + * First item of the list will be skipped and unchanged. + */ file_T file_add(file_T self, char *name) { - for (; self->next != NULL; self = self->next) - ; - self->next = file_new(name); - return self->next; -} - -int DirectoryExists(const char *path) { - struct stat stats; - stat(path, &stats); - - return S_ISDIR(stats.st_mode); + file_T new = file_new(name); + new->next = self->next; + self->next = new; + return new; } +/** + * @brief Sort linked list in a lexicographical order + */ void file_sort(file_T self) { for (file_T p = self->next; p; p = p->next) for (file_T t = p->next; t; t = t->next) @@ -74,6 +138,9 @@ void file_sort(file_T self) { } } +/** + * @brief Return a new linked list of files contained in the current directory + */ file_T file_fromDirectory(void) { file_T base = file_new(NULL); @@ -94,6 +161,9 @@ file_T file_fromDirectory(void) { return n; } +/** + * @brief Check if file is in the linked list, return NULL if it's not + */ file_T file_find(file_T self, char *name) { for (; self != NULL; self = self->next) { if (!strcmp(self->name, name)) @@ -102,33 +172,13 @@ file_T file_find(file_T self, char *name) { return NULL; } -int file_setup(void) { - char *dir; - MEM_CHECK(dir = malloc(PATH_MAX * sizeof(char))); - -#ifdef _WIN32 - strcpy(dir, SETTINGS_DIR); -#else - const char *homedir = getenv("HOME"); - sprintf(dir, "%s/%s", homedir, SETTINGS_DIR); -#endif - - if (!DirectoryExists(dir)) { - printf("Directory %s does not exists; Trying to create it...\n", dir); - if (MAKE_DIR(dir) != 0) { - printf("Cannot create the directory\n"); - return 0; - } - } - - if (chdir(dir) != 0) { - printf("Cannot change the directory\n"); - return 0; - } - return 1; -} - -int file_select(char *ext, char ***buffer) { +/** + * @brief Return array of the filenames that have the specific extension + * + * Memory for the buffer is allocated automatically and should be freed with + * free() after it's no longer needed. + */ +int file_select_extension(char *ext, char ***buffer) { int maxsize = 4; int size = 0; char **tmp = NULL; @@ -157,21 +207,36 @@ int file_select(char *ext, char ***buffer) { return size; } +/** + * @brief Fill loaded_files linked list with files in the current directory, + * freeing any previous lists + */ void load_files(void) { if (loaded_files) file_free(loaded_files); loaded_files = file_fromDirectory(); } +/** + * @brief Free loaded_files linked list + */ void free_files(void) { file_free(loaded_files); } // from logic.c -extern Cell **save_cells; -extern int save_cells_s, pos_y, pos_x, evolve_index; +extern Cell **save_cells; ///< List of Cells to be saved in a pattern +extern int save_cells_s; ///< Size of save_cells +extern int pos_y; ///< Real cursor y coordinate +extern int pos_x; ///< Real cursor x coordinate +extern int evolve_index; ///< index of the current game mode // form game.c -extern int width, height; +extern int height; ///< height of the current game +extern int width; ///< width of the current game +/** + * @brief Load a pattern to the current cursor position from a file with name + * and extension .part + */ void file_load_pattern(char *name, int index) { FILE *f; char *fname; @@ -202,6 +267,10 @@ void file_load_pattern(char *name, int index) { setAt(pos_y + row, pos_x + col, val); } +/** + * @brief Save a pattern of cells referenced in save_cells array to a file with + * name and extension .part + */ void file_save_pattern(char *name, int index) { FILE *f; char *fname; @@ -227,6 +296,9 @@ void file_save_pattern(char *name, int index) { fclose(f); } +/** + * @brief Load the game from the file with name and extension .all + */ void file_load(char *name, int index) { FILE *f; char *fname; @@ -246,6 +318,9 @@ void file_load(char *name, int index) { game(h, w, evolve_index); } +/** + * @brief Save the current game to the file with name and extension .all + */ void file_save(char *name, int index) { FILE *f; char *fname; diff --git a/src/main.c b/src/main.c @@ -77,7 +77,7 @@ struct menu_T *file_menu_list(char *ext, void (*callback)(char *, int), int n; load_files(); - n = file_select(ext, &buffer); + n = file_select_extension(ext, &buffer); MEM_CHECK(file_items = malloc((n + offset) * sizeof(struct menu_T))); for (int i = 0; i < n; i++) {