summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2019-08-03 12:10:09 +0300
committerOxore <oxore@protonmail.com>2019-08-03 22:14:38 +0300
commit9144dbb427f8f71b1ef146c7fdb42b2570f94cb6 (patch)
tree83992871ca9fc3875559b47df9003bdd883e1e79
parent6161ec503292d00e83674ee8bba179e5e8ea0b4b (diff)
Implement json parser for texts
-rw-r--r--.gitignore1
-rw-r--r--Makefile10
-rw-r--r--dat/texts.json90
-rw-r--r--include/text.h1
-rw-r--r--src/target/tetris.c7
-rw-r--r--src/text.c136
6 files changed, 243 insertions, 2 deletions
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 <f8.h>
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <yaml.h>
+#include <cJSON.h>
#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;