mirror of
https://gitlab.com/dosowisko.net/libsuperderpy.git
synced 2025-02-08 14:16:44 +01:00
fix memory leaks and other mem-bugs
This commit is contained in:
parent
51b08cee76
commit
686514fba5
5 changed files with 109 additions and 74 deletions
|
@ -23,7 +23,7 @@
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
SYMBOL_INTERNAL struct Gamestate* AddNewGamestate(struct Game *game) {
|
SYMBOL_INTERNAL struct Gamestate* AddNewGamestate(struct Game *game, const char* name) {
|
||||||
struct Gamestate *tmp = game->_priv.gamestates;
|
struct Gamestate *tmp = game->_priv.gamestates;
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
game->_priv.gamestates = malloc(sizeof(struct Gamestate));
|
game->_priv.gamestates = malloc(sizeof(struct Gamestate));
|
||||||
|
@ -35,7 +35,7 @@ SYMBOL_INTERNAL struct Gamestate* AddNewGamestate(struct Game *game) {
|
||||||
tmp->next = malloc(sizeof(struct Gamestate));
|
tmp->next = malloc(sizeof(struct Gamestate));
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
tmp->name = NULL;
|
tmp->name = strdup(name);
|
||||||
tmp->handle = NULL;
|
tmp->handle = NULL;
|
||||||
tmp->loaded = false;
|
tmp->loaded = false;
|
||||||
tmp->paused = false;
|
tmp->paused = false;
|
||||||
|
@ -68,8 +68,7 @@ SYMBOL_EXPORT void LoadGamestate(struct Game *game, const char* name) {
|
||||||
}
|
}
|
||||||
gs->pending_load = true;
|
gs->pending_load = true;
|
||||||
} else {
|
} else {
|
||||||
gs = AddNewGamestate(game);
|
gs = AddNewGamestate(game, name);
|
||||||
gs->name = strdup(name);
|
|
||||||
gs->pending_load = true;
|
gs->pending_load = true;
|
||||||
gs->showLoading = true;
|
gs->showLoading = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,23 +137,55 @@ SYMBOL_INTERNAL void GamestateProgress(struct Game *game) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void* AddGarbage(struct Game *game, void* data) {
|
SYMBOL_INTERNAL struct libsuperderpy_list* AddToList(struct libsuperderpy_list *list, void* data) {
|
||||||
if (!game->_priv.garbage) {
|
if (!list) {
|
||||||
game->_priv.garbage = malloc(sizeof(struct libsuperderpy_list));
|
list = malloc(sizeof(struct libsuperderpy_list));
|
||||||
game->_priv.garbage->data = data;
|
list->data = data;
|
||||||
game->_priv.garbage->next = NULL;
|
list->next = NULL;
|
||||||
} else {
|
} else {
|
||||||
struct libsuperderpy_list *garbage = malloc(sizeof(struct libsuperderpy_list));
|
struct libsuperderpy_list *elem = malloc(sizeof(struct libsuperderpy_list));
|
||||||
garbage->next = game->_priv.garbage;
|
elem->next = list;
|
||||||
garbage->data = data;
|
elem->data = data;
|
||||||
game->_priv.garbage = garbage;
|
list = elem;
|
||||||
}
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYMBOL_INTERNAL struct libsuperderpy_list* RemoveFromList(struct libsuperderpy_list **list, bool (*identity)(struct libsuperderpy_list* elem, void* data), void* data) {
|
||||||
|
struct libsuperderpy_list *prev = NULL, *tmp = *list, *start = *list;
|
||||||
|
void* d = NULL;
|
||||||
|
while (tmp) {
|
||||||
|
if (identity(tmp, data)) {
|
||||||
|
if (prev) {
|
||||||
|
prev->next = tmp->next;
|
||||||
|
d = tmp->data;
|
||||||
|
free(tmp);
|
||||||
|
return d;
|
||||||
|
} else {
|
||||||
|
start = tmp->next;
|
||||||
|
d = tmp->data;
|
||||||
|
free(tmp);
|
||||||
|
*list = start;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = tmp;
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYMBOL_INTERNAL void* AddGarbage(struct Game *game, void* data) {
|
||||||
|
game->_priv.garbage = AddToList(game->_priv.garbage, data);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void ClearGarbage(struct Game *game) {
|
SYMBOL_INTERNAL void ClearGarbage(struct Game *game) {
|
||||||
|
struct libsuperderpy_list *tmp;
|
||||||
while (game->_priv.garbage) {
|
while (game->_priv.garbage) {
|
||||||
free(game->_priv.garbage->data);
|
free(game->_priv.garbage->data);
|
||||||
game->_priv.garbage = game->_priv.garbage->next;
|
tmp = game->_priv.garbage->next;
|
||||||
|
free(game->_priv.garbage);
|
||||||
|
game->_priv.garbage = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,8 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
||||||
game->config.height = atoi(GetConfigOptionDefault(game, "SuperDerpy", "height", "720"));
|
game->config.height = atoi(GetConfigOptionDefault(game, "SuperDerpy", "height", "720"));
|
||||||
if (game->config.height<180) game->config.height=180;
|
if (game->config.height<180) game->config.height=180;
|
||||||
|
|
||||||
|
game->_priv.showconsole = game->config.debug;
|
||||||
|
|
||||||
if(!al_init_image_addon()) {
|
if(!al_init_image_addon()) {
|
||||||
fprintf(stderr, "failed to initialize image addon!\n");
|
fprintf(stderr, "failed to initialize image addon!\n");
|
||||||
/*al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
|
/*al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
|
||||||
|
@ -167,8 +169,6 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
||||||
al_set_mixer_gain(game->audio.music, game->config.music/10.0);
|
al_set_mixer_gain(game->audio.music, game->config.music/10.0);
|
||||||
al_set_mixer_gain(game->audio.voice, game->config.voice/10.0);
|
al_set_mixer_gain(game->audio.voice, game->config.voice/10.0);
|
||||||
|
|
||||||
game->_priv.showconsole = game->config.debug;
|
|
||||||
|
|
||||||
setlocale(LC_NUMERIC, "C");
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
|
||||||
game->_priv.argc = argc;
|
game->_priv.argc = argc;
|
||||||
|
@ -328,7 +328,6 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game *game) {
|
||||||
tmp=game->_priv.gamestates;
|
tmp=game->_priv.gamestates;
|
||||||
|
|
||||||
while (tmp) {
|
while (tmp) {
|
||||||
|
|
||||||
if ((tmp->pending_start) && (tmp->loaded)) {
|
if ((tmp->pending_start) && (tmp->loaded)) {
|
||||||
PrintConsole(game, "Starting gamestate \"%s\"...", tmp->name);
|
PrintConsole(game, "Starting gamestate \"%s\"...", tmp->name);
|
||||||
al_stop_timer(game->_priv.timer);
|
al_stop_timer(game->_priv.timer);
|
||||||
|
@ -415,8 +414,10 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game *game) {
|
||||||
SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
||||||
game->shuttingdown = true;
|
game->shuttingdown = true;
|
||||||
|
|
||||||
|
ClearGarbage(game);
|
||||||
|
|
||||||
// in case of restart
|
// in case of restart
|
||||||
struct Gamestate *tmp = game->_priv.gamestates;
|
struct Gamestate *tmp = game->_priv.gamestates, *pom;
|
||||||
while (tmp) {
|
while (tmp) {
|
||||||
if (tmp->started) {
|
if (tmp->started) {
|
||||||
PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
|
PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
|
||||||
|
@ -429,14 +430,20 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
||||||
dlclose(tmp->handle);
|
dlclose(tmp->handle);
|
||||||
tmp->loaded = false;
|
tmp->loaded = false;
|
||||||
}
|
}
|
||||||
tmp=tmp->next;
|
free(tmp->name);
|
||||||
|
pom = tmp->next;
|
||||||
|
free(tmp);
|
||||||
|
tmp=pom;
|
||||||
}
|
}
|
||||||
|
|
||||||
al_clear_to_color(al_map_rgb(0,0,0));
|
al_clear_to_color(al_map_rgb(0,0,0));
|
||||||
PrintConsole(game, "Shutting down...");
|
PrintConsole(game, "Shutting down...");
|
||||||
DrawConsole(game);
|
DrawConsole(game);
|
||||||
al_flip_display();
|
al_flip_display();
|
||||||
al_rest(0.1);
|
while (game->_priv.garbage) {
|
||||||
|
free(game->_priv.garbage->data);
|
||||||
|
game->_priv.garbage = game->_priv.garbage->next;
|
||||||
|
}
|
||||||
(*game->_priv.loading.Unload)(game, game->_priv.loading.data);
|
(*game->_priv.loading.Unload)(game, game->_priv.loading.data);
|
||||||
al_destroy_timer(game->_priv.timer);
|
al_destroy_timer(game->_priv.timer);
|
||||||
Console_Unload(game);
|
Console_Unload(game);
|
||||||
|
@ -452,8 +459,9 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
||||||
al_shutdown_ttf_addon();
|
al_shutdown_ttf_addon();
|
||||||
al_shutdown_font_addon();
|
al_shutdown_font_addon();
|
||||||
char** argv = game->_priv.argv;
|
char** argv = game->_priv.argv;
|
||||||
|
bool restart = game->restart;
|
||||||
free(game);
|
free(game);
|
||||||
if (game->restart) {
|
if (restart) {
|
||||||
execv(argv[0], argv); // FIXME: on OSX there's chdir called which might break it
|
execv(argv[0], argv); // FIXME: on OSX there's chdir called which might break it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
100
src/timeline.c
100
src/timeline.c
|
@ -50,6 +50,7 @@ SYMBOL_EXPORT void TM_Process(struct Timeline* timeline) {
|
||||||
struct TM_Action *tmp = timeline->queue;
|
struct TM_Action *tmp = timeline->queue;
|
||||||
timeline->queue = timeline->queue->next;
|
timeline->queue = timeline->queue->next;
|
||||||
(*tmp->function)(timeline->game, tmp, TM_ACTIONSTATE_DESTROY);
|
(*tmp->function)(timeline->game, tmp, TM_ACTIONSTATE_DESTROY);
|
||||||
|
TM_DestroyArgs(tmp->arguments);
|
||||||
free(tmp->name);
|
free(tmp->name);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
}
|
}
|
||||||
|
@ -101,6 +102,7 @@ SYMBOL_EXPORT void TM_Process(struct Timeline* timeline) {
|
||||||
tmp = pom;
|
tmp = pom;
|
||||||
pom = pom->next;
|
pom = pom->next;
|
||||||
} else {
|
} else {
|
||||||
|
TM_DestroyArgs(pom->arguments);
|
||||||
free(pom->name);
|
free(pom->name);
|
||||||
free(pom);
|
free(pom);
|
||||||
tmp2 = tmp;
|
tmp2 = tmp;
|
||||||
|
@ -264,19 +266,30 @@ SYMBOL_EXPORT struct TM_Action* TM_AddBackgroundAction(struct Timeline* timeline
|
||||||
|
|
||||||
/*! \brief Predefined action used by TM_AddQueuedBackgroundAction */
|
/*! \brief Predefined action used by TM_AddQueuedBackgroundAction */
|
||||||
SYMBOL_INTERNAL bool runinbackground(struct Game* game, struct TM_Action* action, enum TM_ActionState state) {
|
SYMBOL_INTERNAL bool runinbackground(struct Game* game, struct TM_Action* action, enum TM_ActionState state) {
|
||||||
if (state != TM_ACTIONSTATE_RUNNING) return false;
|
int* delay = (int*) TM_GetArg(action->arguments, 1);
|
||||||
int* delay = (int*) action->arguments->next->value;
|
char* name = (char*) TM_GetArg(action->arguments, 2);
|
||||||
char* name = (char*) action->arguments->next->next->value;
|
struct Timeline *timeline = (struct Timeline*) TM_GetArg(action->arguments, 3);
|
||||||
struct Timeline *timeline = (struct Timeline*) action->arguments->next->next->next->value;
|
struct TM_Arguments *arguments = (struct TM_Arguments*) TM_GetArg(action->arguments, 4);
|
||||||
TM_AddBackgroundAction(timeline, action->arguments->value, action->arguments->next->next->next->next, *delay, name);
|
bool *used = (bool*) TM_GetArg(action->arguments, 5);
|
||||||
free(name);
|
if (state == TM_ACTIONSTATE_START) {
|
||||||
|
TM_AddBackgroundAction(timeline, TM_GetArg(action->arguments, 0), arguments, *delay, name);
|
||||||
|
*used = true;
|
||||||
|
}
|
||||||
|
if (state == TM_ACTIONSTATE_DESTROY) {
|
||||||
|
free(name);
|
||||||
|
free(delay);
|
||||||
|
if (!(*used)) {
|
||||||
|
TM_DestroyArgs(arguments);
|
||||||
|
}
|
||||||
|
free(used);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_EXPORT struct TM_Action* TM_AddQueuedBackgroundAction(struct Timeline* timeline, bool (*func)(struct Game*, struct TM_Action*, enum TM_ActionState), struct TM_Arguments* args, int delay, char* name) {
|
SYMBOL_EXPORT struct TM_Action* TM_AddQueuedBackgroundAction(struct Timeline* timeline, bool (*func)(struct Game*, struct TM_Action*, enum TM_ActionState), struct TM_Arguments* args, int delay, char* name) {
|
||||||
TM_WrapArg(int, del, delay);
|
TM_WrapArg(int, del, delay);
|
||||||
struct TM_Arguments* arguments = TM_AddToArgs(NULL, 4, (void*) func, del, strdup(name), (void*) timeline);
|
TM_WrapArg(bool, used, false);
|
||||||
arguments->next->next->next->next = args;
|
struct TM_Arguments* arguments = TM_AddToArgs(NULL, 6, (void*) func, del, strdup(name), (void*) timeline, args, used);
|
||||||
return TM_AddAction(timeline, *runinbackground, arguments, "TM_BackgroundAction");
|
return TM_AddAction(timeline, *runinbackground, arguments, "TM_BackgroundAction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,63 +307,37 @@ SYMBOL_EXPORT void TM_AddDelay(struct Timeline* timeline, int delay) {
|
||||||
|
|
||||||
SYMBOL_EXPORT void TM_CleanQueue(struct Timeline* timeline) {
|
SYMBOL_EXPORT void TM_CleanQueue(struct Timeline* timeline) {
|
||||||
PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning queue", timeline->name);
|
PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning queue", timeline->name);
|
||||||
struct TM_Action *tmp, *tmp2, *pom = timeline->queue;
|
struct TM_Action *tmp, *pom = timeline->queue;
|
||||||
tmp = NULL;
|
|
||||||
while (pom!=NULL) {
|
while (pom!=NULL) {
|
||||||
if (pom->active) {
|
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
|
||||||
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
|
if (pom->timer) {
|
||||||
if (pom->timer) {
|
al_stop_timer(pom->timer);
|
||||||
al_stop_timer(pom->timer);
|
al_destroy_timer(pom->timer);
|
||||||
al_destroy_timer(pom->timer);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TM_DestroyArgs(pom->arguments);
|
|
||||||
pom->arguments = NULL;
|
|
||||||
}
|
|
||||||
if ((!tmp) || (tmp->next==pom)) {
|
|
||||||
tmp = pom;
|
|
||||||
pom = pom->next;
|
|
||||||
} else {
|
|
||||||
free(pom->name);
|
|
||||||
free(pom);
|
|
||||||
tmp2 = tmp;
|
|
||||||
if (!tmp) pom=timeline->queue->next;
|
|
||||||
else pom=tmp->next;
|
|
||||||
tmp = tmp2;
|
|
||||||
}
|
}
|
||||||
|
TM_DestroyArgs(pom->arguments);
|
||||||
|
tmp = pom->next;
|
||||||
|
free(pom->name);
|
||||||
|
free(pom);
|
||||||
|
pom = tmp;
|
||||||
}
|
}
|
||||||
// TODO: it shouldn't be needed, but is. Debug!
|
|
||||||
timeline->queue = NULL;
|
timeline->queue = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_EXPORT void TM_CleanBackgroundQueue(struct Timeline* timeline) {
|
SYMBOL_EXPORT void TM_CleanBackgroundQueue(struct Timeline* timeline) {
|
||||||
PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning background queue", timeline->name);
|
PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning background queue", timeline->name);
|
||||||
struct TM_Action *tmp, *tmp2, *pom = timeline->background;
|
struct TM_Action *tmp, *pom = timeline->background;
|
||||||
tmp = NULL;
|
|
||||||
while (pom!=NULL) {
|
while (pom!=NULL) {
|
||||||
if (pom->active) {
|
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
|
||||||
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
|
if (pom->timer) {
|
||||||
if (pom->timer) {
|
al_stop_timer(pom->timer);
|
||||||
al_stop_timer(pom->timer);
|
|
||||||
al_destroy_timer(pom->timer);
|
al_destroy_timer(pom->timer);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
TM_DestroyArgs(pom->arguments);
|
|
||||||
pom->arguments = NULL;
|
|
||||||
}
|
|
||||||
if ((!tmp) || (tmp->next==pom)) {
|
|
||||||
tmp = pom;
|
|
||||||
pom = pom->next;
|
|
||||||
} else {
|
|
||||||
free(pom->name);
|
|
||||||
free(pom);
|
|
||||||
tmp2 = tmp;
|
|
||||||
if (!tmp) pom=timeline->background->next;
|
|
||||||
else pom=tmp->next;
|
|
||||||
tmp = tmp2;
|
|
||||||
}
|
}
|
||||||
|
TM_DestroyArgs(pom->arguments);
|
||||||
|
tmp = pom->next;
|
||||||
|
free(pom->name);
|
||||||
|
free(pom);
|
||||||
|
pom = tmp;
|
||||||
}
|
}
|
||||||
// TODO: it shouldn't be needed, but is. Debug!
|
|
||||||
timeline->background = NULL;
|
timeline->background = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,6 +376,13 @@ SYMBOL_EXPORT struct TM_Arguments* TM_AddToArgs(struct TM_Arguments* args, int n
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SYMBOL_EXPORT void* TM_GetArg(struct TM_Arguments *args, int num) {
|
||||||
|
for (int i=0; i<num; i++) {
|
||||||
|
args = args->next;
|
||||||
|
}
|
||||||
|
return args->value;
|
||||||
|
}
|
||||||
|
|
||||||
SYMBOL_EXPORT void TM_DestroyArgs(struct TM_Arguments* args) {
|
SYMBOL_EXPORT void TM_DestroyArgs(struct TM_Arguments* args) {
|
||||||
struct TM_Arguments *pom;
|
struct TM_Arguments *pom;
|
||||||
while (args) {
|
while (args) {
|
||||||
|
|
|
@ -92,6 +92,8 @@ void TM_CleanBackgroundQueue(struct Timeline*);
|
||||||
void TM_Destroy(struct Timeline*);
|
void TM_Destroy(struct Timeline*);
|
||||||
/*! \brief Add data to TM_Arguments queue. */
|
/*! \brief Add data to TM_Arguments queue. */
|
||||||
struct TM_Arguments* TM_AddToArgs(struct TM_Arguments* args, int num, ...);
|
struct TM_Arguments* TM_AddToArgs(struct TM_Arguments* args, int num, ...);
|
||||||
|
/*! \brief Get nth argument from TM_Arguments queue (counted from 0). */
|
||||||
|
void* TM_GetArg(struct TM_Arguments *args, int num);
|
||||||
/*! \brief Destroy TM_Arguments queue. */
|
/*! \brief Destroy TM_Arguments queue. */
|
||||||
void TM_DestroyArgs(struct TM_Arguments* args);
|
void TM_DestroyArgs(struct TM_Arguments* args);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue