summaryrefslogtreecommitdiffstats
path: root/src/game.c
diff options
context:
space:
mode:
authorPatrick McDermott <patrick.mcdermott@libiquity.com>2021-03-16 11:46:46 (EDT)
committer Patrick McDermott <patrick.mcdermott@libiquity.com>2021-03-16 17:13:50 (EDT)
commit55ad889515de695f3cdc19e0ccbd76a3acc9fe73 (patch)
treee166f4ca6443729d146008a8499d7bbc8f5bfd56 /src/game.c
parent71e445c1ffd01b371c9b3060a57c866dc85e3e00 (diff)
downloaddodge-balls-55ad889515de695f3cdc19e0ccbd76a3acc9fe73.zip
dodge-balls-55ad889515de695f3cdc19e0ccbd76a3acc9fe73.tar.gz
dodge-balls-55ad889515de695f3cdc19e0ccbd76a3acc9fe73.tar.bz2
db_games_find(): Parse games.xml
Diffstat (limited to 'src/game.c')
-rw-r--r--src/game.c288
1 files changed, 284 insertions, 4 deletions
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 <http://www.gnu.org/licenses/>.
*/
+#include <expat.h>
#include <dirent.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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(" </%s> (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(" </%s> (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(" </%s> (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(" </%s> (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(" </%s> (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(" </%s> (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]);
}