From 9144dbb427f8f71b1ef146c7fdb42b2570f94cb6 Mon Sep 17 00:00:00 2001 From: Oxore Date: Sat, 3 Aug 2019 12:10:09 +0300 Subject: Implement json parser for texts --- .gitignore | 1 + Makefile | 10 +++- dat/texts.json | 90 ++++++++++++++++++++++++++++++++++ include/text.h | 1 + src/target/tetris.c | 7 ++- src/text.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 dat/texts.json diff --git a/.gitignore b/.gitignore index 3bb2401..ee1ed17 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ tetris test *.o +*.d *.swp *.out build diff --git a/Makefile b/Makefile index a34e428..9ef57fa 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ QQ=@ TARGET_TETRIS:=tetris TARGET_TEST:=test +CJSON:=deps/cJSON MUNIT:=deps/munit LIBF8:=deps/libf8 @@ -21,6 +22,7 @@ ifdef PREFIX INCLUDE+=$(PREFIX)/include endif INCLUDE+=include +INCLUDE+=$(CJSON) INCLUDE+=$(MUNIT) INCLUDE+=$(LIBF8) INCLUDE:=$(INCLUDE:%=-I%) @@ -64,7 +66,8 @@ ifndef NOTEST all: $(TARGET_TEST) endif -$(TARGET_TETRIS): $(OBJECTS) $(TARGET)/$(TARGET_TETRIS).c.o $(LIBF8)/libf8.a +$(TARGET_TETRIS): $(OBJECTS) $(TARGET)/$(TARGET_TETRIS).c.o $(LIBF8)/libf8.a \ + $(CJSON)/cJSON.o $(QQ) echo " LD $@" $(Q) $(CC) -o $@ $^ $(LDFLAGS_TETRIS) @@ -84,6 +87,10 @@ $(TARGET): $(LIBF8)/libf8.a: $(LIBF8) make -C $< +$(CJSON)/cJSON.c.o: $(CJSON)/cJSON.c + $(QQ) echo " CC $@" + $(Q) $(CC) -c $(CFLAGS) -o $@ $< + $(MUNIT)/munit.c.o: $(MUNIT)/munit.c $(QQ) echo " CC $@" $(Q) $(CC) -c $(CFLAGS) -o $@ $< @@ -97,5 +104,6 @@ $(BUILD)/%.c.o: $(SRC)/%.c clean: $(Q) $(RM) -rfv $(TARGET_TETRIS) $(TARGET_TEST) $(BUILD) $(Q) $(RM) -rfv $(MUNIT)/*.d $(MUNIT)/*.o + $(Q) $(RM) -rfv $(CJSON)/*.d $(CJSON)/*.o .PHONY: all clean diff --git a/dat/texts.json b/dat/texts.json new file mode 100644 index 0000000..1266aee --- /dev/null +++ b/dat/texts.json @@ -0,0 +1,90 @@ +[ + { + "type" : "score.value", + "scene" : "game", + "font" : "Arial", + "size" : 20, + "x" : 350, + "y" : 10 + }, + { + "type" : "score", + "scene" : "game", + "text" : "Score: ", + "font" : "Arial", + "size" : 20, + "x" : 270, + "y" : 10 + }, + { + "type" : "level.value", + "scene" : "game", + "font" : "Arial", + "size" : 20, + "x" : 350, + "y" : 44 + }, + { + "type" : "level", + "scene" : "game", + "text" : "Level: ", + "font" : "Arial", + "size" : 20, + "x" : 270, + "y" : 44 + }, + { + "type" : "", + "scene" : "game", + "text" : "Next Shape: ", + "font" : "Arial", + "size" : 20, + "x" : 270, + "y" : 80 + }, + { + "type" : "", + "scene" : "menu", + "text" : "TETRIS", + "font" : "Arial", + "size" : 36, + "x" : 290, + "y" : 100 + }, + { + "type" : "", + "scene" : "menu", + "text" : "Press \"S\" to start", + "font" : "Arial", + "size" : 20, + "x" : 276, + "y" : 200 + }, + { + "type" : "pause", + "scene" : "game", + "text" : "PAUSED", + "font" : "Arial", + "size" : 36, + "x" : 60, + "y" : 188 + }, + { + "type" : "title", + "scene" : "game_over", + "text" : "Game Over", + "font" : "Arial", + "size" : 36, + "x" : 42, + "y" : 188 + }, + { + "type" : "press_key", + "scene" : "game_over", + "text" : "press any key", + "font" : "Arial", + "size" : 24, + "x" : 57, + "y" : 240 + } +] diff --git a/include/text.h b/include/text.h index d8d9a47..53e3f77 100644 --- a/include/text.h +++ b/include/text.h @@ -12,4 +12,5 @@ typedef struct text { } Text; struct idlist *load_texts(char *filename); +struct idlist *load_texts_from_json(const char *filename); void text_destroy(void *text); diff --git a/src/target/tetris.c b/src/target/tetris.c index 3ca17ff..e090120 100644 --- a/src/target/tetris.c +++ b/src/target/tetris.c @@ -94,7 +94,11 @@ int main() painter_update_field(fld.id, &fld); painter_update_field(nxt.id, &nxt); - texts = load_texts("dat/texts.yaml"); + texts = load_texts_from_json("dat/texts.json"); + if (texts == NULL) { + goto cleanup_load_texts; + } + LIST_FOREACH(texts, text) { register_text(text->obj); } @@ -113,6 +117,7 @@ int main() list_destroy(texts); +cleanup_load_texts: painter_destroy_drawables(); field_deinit(&fld); field_deinit(&nxt); diff --git a/src/text.c b/src/text.c index 9bace21..4674a7e 100644 --- a/src/text.c +++ b/src/text.c @@ -1,13 +1,149 @@ #include #include +#include #include #include #include +#include #include "idlist.h" #include "vector.h" #include "text.h" +static char *load_data_from_file(const char *filename) +{ + int ret = 0; + FILE *file = NULL; + char *data = NULL; + + file = fopen(filename, "rb"); + if (file == NULL) { + perror(filename); + return NULL; + } + + ret |= fseek(file, 0, SEEK_END); + long file_size = ftell(file); + ret |= fseek(file, 0, SEEK_SET); + if (ret == -1 || file_size == -1) { + perror("fseek/ftell"); + goto cleanup_close; + } + + data = calloc(file_size + 1, sizeof(char)); + if (data == NULL) { + perror("calloc"); + goto cleanup_close; + } + + size_t nbyte = fread(data, sizeof(char), file_size, file); + if (nbyte == 0) { + perror("fread"); + goto cleanup_free; + } + + goto cleanup_close; + +cleanup_free: + free(data); + data = NULL; + +cleanup_close: + fclose(file); + return data; +} + +static char *texts_cjson_get_string(cJSON *object, const char *key) +{ + char *string = NULL; + cJSON *item = cJSON_GetObjectItem(object, key); + if (cJSON_IsString(item)) { + char *value = cJSON_GetStringValue(item); + if (value != NULL) { + size_t size = strlen(value) + 1; + string = calloc(size, sizeof(char)); + if (string != NULL) + strncpy(string, value, size); + } + } + return string; +} + +static wchar_t *texts_cjson_get_string_utf32(cJSON *object, const char *key) +{ + wchar_t *string = NULL; + cJSON *item = cJSON_GetObjectItem(object, key); + if (cJSON_IsString(item)) { + char *value = cJSON_GetStringValue(item); + if (value != NULL) { + size_t size = utf8_strlen(value) + 1; + string = calloc(size, sizeof(wchar_t)); + if (string != NULL) + utf8to32_strcpy(string, value); + } + } + return string; +} + +static int texts_cjson_get_int(cJSON *object, const char *key) +{ + int value = 0; + cJSON *item = cJSON_GetObjectItem(object, key); + if (cJSON_IsNumber(item)) + value = item->valueint; + return value; +} + +struct idlist *load_texts_from_json(const char *filename) +{ + struct cJSON_Hooks hooks = (struct cJSON_Hooks){ + .malloc_fn = malloc, + .free_fn = free, + }; + cJSON_InitHooks(&hooks); + + char *data = load_data_from_file(filename); + if (data == NULL) { + return NULL; + } + + struct idlist *texts = NULL; + struct idlist *texts_node = texts; + + cJSON *json_data = cJSON_Parse(data); + if (cJSON_IsArray(json_data)) { + size_t array_size = cJSON_GetArraySize(json_data); + for (size_t i = 0; i < array_size; i++) { + cJSON *item = cJSON_GetArrayItem(json_data, i); + if (cJSON_IsObject(item)) { + + /* Allocate texts node to be filled */ + + if (!texts) { + texts_node = texts = list_new(); + } else { + texts_node = list_append(texts); + } + texts_node->obj = calloc(1, sizeof(struct text)); + struct text *text = texts_node->obj; + + /* Fill the node */ + + text->type = texts_cjson_get_string(item, "type"); + text->scene = texts_cjson_get_string(item, "scene"); + text->text = texts_cjson_get_string_utf32(item, "text"); + text->font = texts_cjson_get_string(item, "font"); + text->size = texts_cjson_get_int(item, "size"); + text->pos.x = texts_cjson_get_int(item, "x"); + text->pos.y = texts_cjson_get_int(item, "y"); + } + } + } + free(data); + cJSON_Delete(json_data); + return texts; +} + static FILE *openFile(char *filename) { FILE *file; -- cgit v1.2.3