gol

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

commitc97829684b0f8b0c6d0b3f56c52d95004832be1f
parentc48f5196f08e800160564302abbe978a6f6b26b2
authorDimitrije Dobrota <mail@dimitrijedobrota.com>
dateThu, 16 Jun 2022 18:55:47 +0200

Documentation for file.c and small improvements

Diffstat:
Minclude/file.h|+-
Msrc/file.c|+++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/main.c|+-

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++) {