/* savegame.c - save/load game etc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include "game.h" gint parse_save_game(gchar *sgame, gchar **rules, gint *score, gint **board, gint **next) { struct stat buf; gchar *sdata, *psdata, *srules; FILE *f; gint i, val; gint rw, rh, rc, rn, rd, rlen; if (stat(sgame, &buf) != 0 || !S_ISREG(buf.st_mode) || buf.st_size < 20 || (f = fopen(sgame, "r")) == NULL) { return 0; } sdata = g_malloc(buf.st_size); if (fread(sdata, 1, buf.st_size, f) != (size_t) buf.st_size) { g_free (sdata); return 0; } fclose(f); rlen = rules_get_str_len(); srules = g_malloc(rlen + 1); srules[rlen] = 0; memcpy(srules, sdata, rlen); if (!rules_get_from_str(srules, &rw, &rh, &rc, &rn, &rd) || sscanf(sdata + rlen, "%010u", score) != 1 || buf.st_size != rlen + 10 + rw * rh * 2 + rn * 2) { printf("[%s]\n", srules); g_free (srules); g_free (sdata); return 0; } g_free (srules); *board = g_malloc(rw * rh * sizeof(gint)); *next = g_malloc(rn * sizeof(gint)); psdata = sdata + rlen + 10; for (i = 0; i < rw * rh; i++, psdata += 2) { if (sscanf(psdata, "%02d", &val) != 1 || val < 0 || val > rc) { g_free (*next); g_free (*board); g_free (sdata); return 0; } (*board)[i] = val; } for (i = 0; i < rn; i++, psdata += 2) { if (sscanf(psdata, "%02d", &val) != 1 || val < 0 || val > rc) { g_free (*next); g_free (*board); g_free (sdata); return 0; } (*next)[i] = val; } *rules = g_strndup(sdata, rlen); g_free (sdata); return 1; } /* check that save game name is in form YYYY-MM-DD-HHMMSS.sav and have correct content return string "DD.MM.YYYY HH:MM:SS (score)" on success, NULL on failure */ gchar *is_valid_save_game(gchar *name, gchar *path) { guint i, y, m, d, h, min, s; gint score, *board, *next; gchar *sgame; gchar *rules; if ((i = sscanf(name, "%04u-%02u-%02u-%02u%02u%02u", &y, &m, &d, &h, &min, &s)) != 6 || !m || m > 12 || !d || d > 31 || h > 23 || min > 59 || s > 61 || (strcmp(name + strlen(name) - 4, ".sav") != 0)) { return NULL; } sgame=g_strconcat(path, G_DIR_SEPARATOR_S, name, NULL); i = parse_save_game(sgame, &rules, &score, &board, &next); g_free (sgame); if (!i) return NULL; g_free (rules); g_free (board); g_free (next); return g_strdup_printf("%02d.%02d.%04d %02d:%02d:%02d (%d)", d, m, y, h, min, s, score); /* FIXME: return rules back return g_strdup_printf("%02d.%02d.%04d %02d:%02d:%02d (%d [%dx%d %d %d %d])", d, m, y, h, min, s, score, rules.xsize, rules.ysize, rules.colors, rules.next, rules.destroy); */ } gint get_saved_games(gchar ***gamelist) { gchar *datapath; struct stat buf; struct dirent *dir_entry; DIR *directory; gchar **games = NULL, *game; gint num = 0; datapath = g_strconcat(getenv("HOME"), G_DIR_SEPARATOR_S, ".gtkballs", NULL); if (stat(datapath, &buf) != 0) { /* no ~/.gtkballs */ if (mkdir(datapath, 0700) != 0) { /* and cannot create it... */ g_free (datapath); return -1; } } else if (!S_ISDIR(buf.st_mode)) { /* ~/.gtkballs is not a directory */ g_free (datapath); return -1; } if ((directory = opendir(datapath))) { while ((dir_entry = readdir(directory))) { if ((game = is_valid_save_game(dir_entry->d_name, datapath)) != NULL) { num++; games = g_realloc(games, sizeof(gchar *) * num * 2); games[(num - 1) * 2] = game; games[(num - 1) * 2 + 1] = g_strdup_printf("%s%s%s", datapath, G_DIR_SEPARATOR_S, dir_entry->d_name); } } closedir(directory); } g_free (datapath); *gamelist = games; return num; } gchar *save_game(gchar *rules, gint score, gint *board, gint *nextcolors) { FILE *f; gchar *fname; time_t nowtime; gchar ftime[]="0000-00-00-000000"; gint i; nowtime = time(NULL); strftime(ftime, sizeof(ftime), "%Y-%m-%d-%H%M%S", localtime(&nowtime)); fname = g_strconcat(getenv("HOME"), G_DIR_SEPARATOR_S, ".gtkballs", G_DIR_SEPARATOR_S, ftime, ".sav", NULL); if ((f = fopen(fname, "w")) != NULL) { chmod(fname, 0600); /* TODO: check for errors ! */ fprintf(f, rules); fprintf(f, "%010d", score); for (i = 0; i < rules_get_width() * rules_get_height(); i++) { fprintf(f, "%02d", board[i]); } for (i = 0; i < rules_get_next(); i++) { fprintf(f, "%02d", nextcolors[i]); } fclose(f); } else { return fname; } g_free (fname); return NULL; }