From 55ad889515de695f3cdc19e0ccbd76a3acc9fe73 Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Tue, 16 Mar 2021 11:46:46 -0400 Subject: db_games_find(): Parse games.xml --- diff --git a/src/game.c b/src/game.c index 6989b6e..f129766 100644 --- a/src/game.c +++ b/src/game.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 P. J. McDermott + * Copyright (C) 2013, 2021 P. J. McDermott * * This file is part of Dodge Balls * @@ -17,11 +17,14 @@ * along with Dodge Balls. If not, see . */ +#include #include +#include #include #include #include "game.h" #include "output.h" +#include "xml.h" struct db_game { char *id; @@ -35,6 +38,283 @@ _db_game_is_dir(const struct dirent *entry) return (entry->d_type == DT_DIR && entry->d_name[0] != '.'); } +static void XMLCALL +_db_game_xml_invalid_end(void *pv, const char *name) +{ + XML_Parser p; + + db_dbg(" (invalid)", name); + + p = (XML_Parser) pv; + + db_xml_unexpected_end_tag(p, name, ""); +} + +static void XMLCALL +_db_game_xml_invalid_start(void *pv, const char *name, + const char **attr __attribute__((__unused__))) +{ + XML_Parser p; + + db_dbg(" <%s> (invalid)", name); + + p = (XML_Parser) pv; + + db_xml_node_push(p, NULL, _db_game_xml_invalid_start, + _db_game_xml_invalid_end, NULL); +} + +static void XMLCALL +_db_game_xml_name_end(void *pv, const char *name) +{ + XML_Parser p; + + db_dbg(" (name)", name); + + p = (XML_Parser) pv; + + if (db_xml_check_tag(name, "name")) { + /* TODO */ + db_xml_node_pop(p); + } else { + db_xml_unexpected_end_tag(p, name, "name"); + } +} + +static void XMLCALL +_db_game_xml_description_end(void *pv, const char *name) +{ + XML_Parser p; + + db_dbg(" (description)", name); + + p = (XML_Parser) pv; + + if (db_xml_check_tag(name, "description")) { + /* TODO */ + db_xml_node_pop(p); + } else { + db_xml_unexpected_end_tag(p, name, "description"); + } +} + +static void XMLCALL +_db_game_xml_level_end(void *pv, const char *name) +{ + XML_Parser p; + + db_dbg(" (level)", name); + + p = (XML_Parser) pv; + + if (db_xml_check_tag(name, "level")) { + db_xml_node_pop(p); + } else { + db_xml_unexpected_end_tag(p, name, "level"); + } +} + +static void XMLCALL +_db_game_xml_levels_el_start(void *pv, const char *name, const char **attr) +{ + XML_Parser p; + struct db_game *game; + char *id; + + db_dbg(" <%s> (levels child)", name); + + p = (XML_Parser) pv; + game = db_xml_node_peek(p); + + if (db_xml_check_tag(name, "level")) { + id = NULL; + db_xml_get_string_attr(p, attr, "id", &id, 1); + if (id == NULL) { + return; + } + db_dbg(" id=\"%s\"", id); + /* TODO */ + free(id); + db_xml_node_push(p, game, _db_game_xml_invalid_start, + _db_game_xml_level_end, NULL); + } else { + db_xml_unexpected_start_tag(p, name, "level"); + } +} + +static void XMLCALL +_db_game_xml_levels_end(void *pv, const char *name) +{ + XML_Parser p; + + db_dbg(" (levels)", name); + + p = (XML_Parser) pv; + + if (db_xml_check_tag(name, "levels")) { + db_xml_node_pop(p); + } else { + db_xml_unexpected_end_tag(p, name, "levels"); + } +} + +static void XMLCALL +_db_game_xml_game_el_start(void *pv, const char *name, const char **attr) +{ + XML_Parser p; + struct db_game *game; + char *lang; + + db_dbg(" <%s> (game child)", name); + + p = (XML_Parser) pv; + game = db_xml_node_peek(p); + + if (db_xml_check_tag(name, "name")) { + lang = NULL; + db_xml_get_string_attr(p, attr, "lang", &lang, 1); + if (lang == NULL) { + return; + } + db_dbg(" lang=\"%s\"", lang); + /* TODO */ + free(lang); + db_xml_node_push(p, game, _db_game_xml_invalid_start, + _db_game_xml_name_end, NULL /* TODO */); + } else if (db_xml_check_tag(name, "description")) { + lang = NULL; + db_xml_get_string_attr(p, attr, "lang", &lang, 1); + if (lang == NULL) { + return; + } + db_dbg(" lang=\"%s\"", lang); + /* TODO */ + free(lang); + db_xml_node_push(p, game, _db_game_xml_invalid_start, + _db_game_xml_description_end, NULL /* TODO */); + } else if (db_xml_check_tag(name, "levels")) { + db_xml_node_push(p, game, _db_game_xml_levels_el_start, + _db_game_xml_levels_end, NULL); + } else { + db_xml_unexpected_start_tag(p, name, + "name, description, or levels"); + } +} + +static void XMLCALL +_db_game_xml_game_end(void *pv, const char *name) +{ + XML_Parser p; + + db_dbg(" (game)", name); + + p = (XML_Parser) pv; + + if (db_xml_check_tag(name, "game")) { + db_xml_node_pop(p); + } else { + db_xml_unexpected_end_tag(p, name, "game"); + } +} + +static void XMLCALL +_db_game_xml_game_start(void *pv, const char *name, + const char **attr __attribute__((__unused__))) +{ + XML_Parser p; + struct db_game *game; + + db_dbg(" <%s> (game)", name); + + p = (XML_Parser) pv; + game = db_xml_node_peek(p); + + if (db_xml_check_tag(name, "game")) { + db_xml_node_push(p, game, _db_game_xml_game_el_start, + _db_game_xml_game_end, NULL); + } else { + db_xml_unexpected_start_tag(p, name, "game"); + } +} + +static int +_db_game_read_info(const char *games_dir, const char *name, + struct db_game *game) +{ + XML_Parser p; + char *path; + FILE *fp; + void *buf; + size_t len; + enum XML_Status status; + + game->id = strdup(name); + if (game->id == NULL) { + return -1; + } + + p = XML_ParserCreate(NULL); + if (p == NULL) { + return -1; + } + XML_UseParserAsHandlerArg(p); + db_xml_node_push(p, game, + _db_game_xml_game_start, _db_game_xml_invalid_end, + NULL); + + path = calloc(strlen(games_dir) + 1 + strlen(name) + + strlen("/game.xml") + 1, sizeof(*path)); + sprintf(path, "%s/%s/game.xml", games_dir, name); + if (path == NULL) { + db_xml_node_pop(p); + XML_ParserFree(p); + free(path); + return -1; + } + + fp = fopen(path, "rb"); + if (fp == NULL) { + db_xml_node_pop(p); + XML_ParserFree(p); + free(path); + return -1; + } + + buf = XML_GetBuffer(p, 8192); + if (buf == NULL) { + db_xml_node_pop(p); + XML_ParserFree(p); + free(path); + fclose(fp); + return -1; + } + + db_dbg("Parsing <%s>:", path); + free(path); + + while (!feof(fp)) { + len = fread(buf, 1, 8192, fp); + status = XML_ParseBuffer(p, len, feof(fp)); + if (status == XML_STATUS_OK) { + continue; + } + db_err("Failed to parse game information (%s)", + XML_ErrorString(XML_GetErrorCode(p))); + db_xml_node_pop(p); + XML_ParserFree(p); + fclose(fp); + return -1; + } + + db_dbg("Parsing done"); + + db_xml_node_pop(p); + XML_ParserFree(p); + fclose(fp); + + return 0; +} + int db_games_find(const char *games_dir, struct db_game ***games) { @@ -58,15 +338,15 @@ db_games_find(const char *games_dir, struct db_game ***games) for (i = 0; i < n; ++i) { (*games)[i] = calloc(1, sizeof(***games)); - if ((*games)[i] == NULL) { - db_err("Failed to allocate memory"); + if ((*games)[i] == NULL || _db_game_read_info(games_dir, + entries[i]->d_name, (*games)[i]) < 0) { + db_err("Failed to get game information"); while (--i >= 0) { db_game_free((*games)[i]); } free(*games); return -1; } - (*games)[i]->id = strdup(entries[i]->d_name); free(entries[i]); } -- cgit v0.9.1