From abc86aaa8f91977fcd7046923298c68cfe8f08f6 Mon Sep 17 00:00:00 2001 From: Marrub Date: Fri, 21 Oct 2016 15:05:29 -0400 Subject: [PATCH] Add Manifest module. --- lithos_c/Makefile | 2 + lithos_c/inc/Lth.h | 1 + lithos_c/inc/Lth_context.h | 31 ++- lithos_c/inc/Lth_manifest.h | 84 ++++++++ lithos_c/src/context.c | 118 ++++++----- lithos_c/src/manifest.c | 405 ++++++++++++++++++++++++++++++++++++ lithos_fs/Base.lthm | 3 + lithos_tools/createfs.lua | 40 ++++ 8 files changed, 630 insertions(+), 54 deletions(-) create mode 100644 lithos_c/inc/Lth_manifest.h create mode 100644 lithos_c/src/manifest.c create mode 100644 lithos_fs/Base.lthm create mode 100755 lithos_tools/createfs.lua diff --git a/lithos_c/Makefile b/lithos_c/Makefile index ce1912c..44bb39c 100644 --- a/lithos_c/Makefile +++ b/lithos_c/Makefile @@ -43,6 +43,7 @@ SOURCES= \ $(SRC)/draw.c \ $(SRC)/font.c \ $(SRC)/main.c \ + $(SRC)/manifest.c \ $(SRC)/stdlib.c \ $(SRC)/token.c \ $(SRC)/tokenstream.c \ @@ -60,6 +61,7 @@ HEADERS= \ $(INC)/Lth_hashmap.h \ $(INC)/Lth_hudmessage.h \ $(INC)/Lth_linklist.h \ + $(INC)/Lth_manifest.h \ $(INC)/Lth_stdlib.h \ $(INC)/Lth_token.h \ $(INC)/Lth_tokenstream.h \ diff --git a/lithos_c/inc/Lth.h b/lithos_c/inc/Lth.h index 2cd75e9..aaf787a 100644 --- a/lithos_c/inc/Lth.h +++ b/lithos_c/inc/Lth.h @@ -22,6 +22,7 @@ #include "Lth_font.h" #include "Lth_hudmessage.h" #include "Lth_linklist.h" +#include "Lth_manifest.h" #include "Lth_stdlib.h" #include "Lth_token.h" #include "Lth_tokenstream.h" diff --git a/lithos_c/inc/Lth_context.h b/lithos_c/inc/Lth_context.h index 1eec161..b4e2bec 100644 --- a/lithos_c/inc/Lth_context.h +++ b/lithos_c/inc/Lth_context.h @@ -15,6 +15,22 @@ #include "Lth_types.h" #include "Lth_font.h" +#include "Lth_manifest.h" + +#define Lth_ContextResource(ctx, type, key) \ + ((type *)Lth_ContextResourceFind((ctx), (key))) + +#define Lth_ContextManifestLoad_extern(ctx, ...) \ + ( \ + ((ctx)->rsrc ? (Lth_ResourceMapDestroy((ctx)->rsrc)) : (void)0), \ + (ctx)->rsrc = Lth_ManifestLoad_extern(__VA_ARGS__) \ + ) + +#define Lth_ContextManifestLoad_static(ctx, ...) \ + ( \ + ((ctx)->rsrc ? (Lth_ResourceMapDestroy((ctx)->rsrc)) : (void)0), \ + (ctx)->rsrc = Lth_ManifestLoad_static(__VA_ARGS__) \ + ) // Type Definitions ----------------------------------------------------------| @@ -24,12 +40,14 @@ // // internal data // clip -// lastmap // map +// rsrcBase +// rsrc +// lastmap // // read-only -// w: width of screen -// h: height of screen +// w: width of screen +// h: height of screen // // read-write // hid: HUD ID range @@ -40,6 +58,7 @@ typedef struct Lth_Context { struct { Lth_Rect rects[16]; int num; } clip; struct { Lth_LinkList *head, *tail; } map; + Lth_ResourceMap *rsrcBase, *rsrc; Lth_IVec2 lastmap; int w, h; @@ -53,10 +72,14 @@ typedef struct Lth_Context // Extern Functions ----------------------------------------------------------| Lth_Context *Lth_ContextNew(int w, int h, Lth_HID hidBase, Lth_HID hidEnd); -void Lth_ContextMap(Lth_Context *ctx, struct Lth_Window *window); void Lth_ContextDestroy(Lth_Context *ctx); void Lth_ContextRun(Lth_Context *ctx); + +void Lth_ContextMap(Lth_Context *ctx, struct Lth_Window *window); + void Lth_ContextClipPush(Lth_Context *ctx, int x, int y, int w, int h); void Lth_ContextClipPop(Lth_Context *ctx); +void *Lth_ContextResourceFind(Lth_Context *ctx, char const *key); + #endif//lithos3__Lth_context_h diff --git a/lithos_c/inc/Lth_manifest.h b/lithos_c/inc/Lth_manifest.h new file mode 100644 index 0000000..7cdb870 --- /dev/null +++ b/lithos_c/inc/Lth_manifest.h @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------------- +// +// Copyright © 2016 Project Golan +// +// See "LICENSE" for more information. +// +//----------------------------------------------------------------------------- +// +// Resource manifests. +// +//----------------------------------------------------------------------------- + +#ifndef lithos3__Lth_manifest_h +#define lithos3__Lth_manifest_h + +#include "Lth_hashmap.h" +#include "Lth_types.h" + +#define Lth_ManifestNew(...) \ + ((Lth_Manifest[]){ \ + __VA_ARGS__, \ + Lth_Resource(NULL, 0) \ + }) + +#define Lth_Resource(name, val) \ + _Generic((val)+0, \ + int: Lth_ManifestNew_Integ, \ + _Accum: Lth_ManifestNew_Fixed, \ + char const *: Lth_ManifestNew_Strng \ + )((name), (val)) + + +// Type Definitions ----------------------------------------------------------| + +// +// Lth_ResourceType +// +typedef enum Lth_ResourceType +{ + Lth_ResourceType_Integ, + Lth_ResourceType_Fixed, + Lth_ResourceType_Strng, + Lth_ResourceType_Max +} Lth_ResourceType; + +// +// Lth_Manifest +// +typedef struct Lth_Manifest +{ + int type; + size_t keyhash; + union + { + int integ; + _Accum fixed; + char *strng; + }; +} Lth_Manifest; + +// +// Lth_ResourceMap +// +typedef struct Lth_ResourceMap +{ + Lth_Vector(int) vecInteg; + Lth_Vector(_Accum) vecFixed; + Lth_Vector(char *) vecStrng; + Lth_HashMap map; +} Lth_ResourceMap; + + +// Extern Functions ----------------------------------------------------------| + +void Lth_ResourceMapDestroy(Lth_ResourceMap *rsrc); + +Lth_ScriptCall Lth_ResourceMap *Lth_ManifestLoad_extern(char const *fname); +Lth_ScriptCall Lth_ResourceMap *Lth_ManifestLoad_static(Lth_Manifest *manifest); + +Lth_Manifest Lth_ManifestNew_Integ(char const *key, int value); +Lth_Manifest Lth_ManifestNew_Fixed(char const *key, _Accum value); +Lth_Manifest Lth_ManifestNew_Strng(char const *key, char const *value); + +#endif//lithos3__Lth_manifest_h diff --git a/lithos_c/src/context.c b/lithos_c/src/context.c index aefa9f0..7bd9012 100644 --- a/lithos_c/src/context.c +++ b/lithos_c/src/context.c @@ -17,6 +17,22 @@ #include +// Static Functions ----------------------------------------------------------| + +// +// Lth_ContextSetup +// +static void Lth_ContextSetup(Lth_Context *ctx, void *ctrl_) +{ + Lth_Control *ctrl = ctrl_; + + Lth_ListForEach(Lth_Control *owner, ctrl->descendants) + Lth_ContextSetup(ctx, owner); + + ctrl->ctx = ctx; +} + + // Extern Functions ----------------------------------------------------------| // @@ -35,20 +51,53 @@ Lth_Context *Lth_ContextNew(int w, int h, Lth_HID hidBase, Lth_HID hidEnd) ctx->mapspace.x = 24; ctx->mapspace.y = 16; + ctx->rsrcBase = Lth_ManifestLoad_static(Lth_ManifestNew( + Lth_Resource("Base.Resource1", 999) + )); + return ctx; } // -// Lth_ContextSetup +// Lth_ContextDestroy // -void Lth_ContextSetup(Lth_Context *ctx, void *ctrl_) +void Lth_ContextDestroy(Lth_Context *ctx) { - Lth_Control *ctrl = ctrl_; + if(ctx == NULL) + return; - Lth_ListForEach(Lth_Control *owner, ctrl->descendants) - Lth_ContextSetup(ctx, owner); + if(ctx->map.head) + { + Lth_ListFor(Lth_Control *owner, ctx->map.head) + { + Lth_ListRemove(list); + if(owner) Lth_ControlDestroy(owner); + list = next; + } + } - ctrl->ctx = ctx; + Lth_ResourceMapDestroy(ctx->rsrc); + Lth_ResourceMapDestroy(ctx->rsrcBase); + + free(ctx->rsrc); + free(ctx->rsrcBase); + + free(ctx); +} + +// +// Lth_ContextRun +// +void Lth_ContextRun(Lth_Context *ctx) +{ + Lth_assert(ctx != NULL); + + ACS_SetHudSize(ctx->w, ctx->h, true); + ctx->hid.cur = ctx->hid.base; + + if(ctx->map.head) + Lth_ListForEach(Lth_Control *owner, ctx->map.head) + Lth_ControlRun(owner); } // @@ -69,42 +118,6 @@ void Lth_ContextMap(Lth_Context *ctx, Lth_Window *ctrl) Lth_ListInsertTail(&ctrl->link, ctrl, &ctx->map.head, &ctx->map.tail); } -// -// Lth_ContextDestroy -// -void Lth_ContextDestroy(Lth_Context *ctx) -{ - if(ctx == NULL) - return; - - if(ctx->map.head) - { - Lth_ListFor(Lth_Control *owner, ctx->map.head) - { - Lth_ListRemove(list); - if(owner) Lth_ControlDestroy(owner); - list = next; - } - } - - free(ctx); -} - -// -// Lth_ContextRun -// -void Lth_ContextRun(Lth_Context *ctx) -{ - Lth_assert(ctx != NULL); - - ACS_SetHudSize(ctx->w, ctx->h, true); - ctx->hid.cur = ctx->hid.base; - - if(ctx->map.head) - Lth_ListForEach(Lth_Control *owner, ctx->map.head) - Lth_ControlRun(owner); -} - // // Lth_ContextClipPush // @@ -116,18 +129,13 @@ void Lth_ContextClipPush(Lth_Context *ctx, int x, int y, int w, int h) if(!(rect.x == 0 && rect.y == 0 && rect.w == 0 && rect.h == 0)) { - if(rect.x < x) rect.x = x; - if(rect.y < y) rect.y = y; + if(rect.x < x) rect.x = x; + if(rect.y < y) rect.y = y; if(rect.x + rect.w > x + w) rect.w = w; if(rect.y + rect.h > y + h) rect.h = h; } else - { - rect.x = x; - rect.y = y; - rect.h = h; - rect.w = w; - } + rect = (Lth_Rect){ x, y, w, h }; ctx->clip.rects[ctx->clip.num] = rect; ACS_SetHudClipRect(rect.x, rect.y, rect.w, rect.h); @@ -144,4 +152,14 @@ void Lth_ContextClipPop(Lth_Context *ctx) ACS_SetHudClipRect(rect.x, rect.y, rect.w, rect.h); } +// +// Lth_ContextResourceFind +// +void *Lth_ContextResourceFind(Lth_Context *ctx, char const *key) +{ + void *p = Lth_HashMapFind(&ctx->rsrc->map, key); + if(p) return p; + else return Lth_HashMapFind(&ctx->rsrcBase->map, key); +} + // EOF diff --git a/lithos_c/src/manifest.c b/lithos_c/src/manifest.c new file mode 100644 index 0000000..2e4d58c --- /dev/null +++ b/lithos_c/src/manifest.c @@ -0,0 +1,405 @@ +//----------------------------------------------------------------------------- +// +// Copyright © 2016 Project Golan +// +// See "LICENSE" for more information. +// +//----------------------------------------------------------------------------- +// +// Resource manifests. +// +//----------------------------------------------------------------------------- + +#include "Lth.h" + +// Define fixed so it is not aliased (this breaks our code). +#define fixed +#include +#undef fixed + +#include +#include +#include + +#define GenAlloc(name, type) \ + if(rsrc->vec##name.size) \ + rsrc->vec##name.data = calloc(rsrc->vec##name.size, sizeof(type)); \ + \ + size_t iter##name = 0 + +#define GenSpecCase(name, var, i, expr) \ + case Lth_ResourceType_##name: \ + rsrc->vec##name.data[iter##name] = iter->var; \ + rsrc->map.elem.data[i ].keyhash = iter->keyhash; \ + rsrc->map.elem.data[i++].value = expr; \ + break + +#define GenRsrcCase(name, var, i) \ + GenSpecCase(name, var, i, &rsrc->vec##name.data[iter##name++]) + +#define GenManifestValue(name, value, setexpr) \ + (Lth_Manifest){ \ + .type = Lth_ResourceType_##name, \ + .keyhash = Lth_Hash_char(key), \ + .value = (setexpr) \ + } + +#define GenValueGetter(name, value, setexpr) \ + if(repr->manifest.size + 1 > repr->manifest.bufsz) \ + repr->manifest.data = realloc(repr->manifest.data, \ + sizeof(Lth_Manifest) * (repr->manifest.bufsz += 32)); \ + \ + repr->manifest.data[repr->manifest.size++] = (Lth_Manifest){ \ + .type = Lth_ResourceType_##name, \ + .keyhash = key, \ + .value = (setexpr) \ + } + +#define ManifestError(repr, str) \ + if(1) \ + { \ + fprintf(stderr, "%s (in %s): %s\n", __func__, (repr)->fname, str); \ + repr->err = true; \ + longjmp(ManifestJmpBuf, ManifestJmpBufToken); \ + } \ + else ((void)0) + + +// Type Definitions ----------------------------------------------------------| + +// +// ManifestState +// +typedef struct ManifestState +{ + char *block; + char *data; + bool err; + char const *fname; + Lth_TokenStream *stream; + Lth_Vector(Lth_Manifest) manifest; +} ManifestState; + + +// Static Objects ------------------------------------------------------------| + +static jmp_buf ManifestJmpBuf; +static int const ManifestJmpBufToken = 30; + + +// Static Functions ----------------------------------------------------------| + +// +// ManifestGetInteg +// +static void ManifestGetInteg(ManifestState *repr, size_t key, char const *str) +{ + // integer-constant + char *end; + int value = strtoi(str, &end, 0); + + if(*end != '\0') + ManifestError(repr, "bad integral value"); + + GenValueGetter(Integ, integ, value); +} + +// +// ManifestGetFixed +// +static void ManifestGetFixed(ManifestState *repr, size_t key, char const *str) +{ + // fixed-constant + char *end; + _Accum value = strtofxk(str, &end); + + if(*end != '\0') + ManifestError(repr, "bad fixed-point value"); + + GenValueGetter(Fixed, fixed, value); +} + +// +// ManifestGetStrng +// +static void ManifestGetStrng(ManifestState *repr, size_t key, char const *str) +{ + // string-constant + GenValueGetter(Strng, strng, Lth_strdup(str)); +} + +// +// ManifestGetHeaderNameSequence +// +static void ManifestGetHeaderNameSequence(ManifestState *repr) +{ + // header-name-sequence: + // identifier + // header-name-sequence . identifier + + ACS_BeginPrint(); + + do + { + Lth_Token const *tok = Lth_TokenStreamPeek(repr->stream); + + // identifier + if(tok->type != Lth_TOK_Identi) + ManifestError(repr, "expected identifier"); + + Lth_PrintString(tok->str); + + Lth_TokenStreamBump(repr->stream); + } + Lth_pfor(Lth_TokenStreamDrop(repr->stream, Lth_TOK_Dot), ACS_PrintChar('.')); +} + +// +// ManifestGetInitializer +// +static void ManifestGetInitializer(ManifestState *repr, size_t key) +{ + // initializer: + // integer-constant + // fixed-constant + // string-constant + + switch(Lth_TokenStreamPeek(repr->stream)->type) + { + case Lth_TOK_Number: + __with(char const *str = Lth_TokenStreamBump(repr->stream)->str;) + if(!Lth_strcontains(str, '.')) + ManifestGetInteg(repr, key, str); + else + ManifestGetFixed(repr, key, str); + break; + case Lth_TOK_String: + ManifestGetStrng(repr, key, Lth_TokenStreamBump(repr->stream)->str); + break; + default: + ManifestError(repr, "expected initializer"); + break; + } +} + +// +// ManifestGetDecl_Object +// +static void ManifestGetDecl_Object(ManifestState *repr) +{ + // obj-decl-terminator: + // '\n' + // ; + + // object-declaration: + // identifier = initializer obj-decl-terminator + + // identifier + if(Lth_TokenStreamPeek(repr->stream)->type != Lth_TOK_Identi) + ManifestError(repr, "exptected declarator"); + + // Build the key name. Format is: "blockname.identifier" + __with(char const *name = Lth_TokenStreamBump(repr->stream)->str;) + { + ACS_BeginPrint(); + + Lth_PrintString(repr->block); + ACS_PrintChar('.'); + Lth_PrintString(name); + } + + size_t key = Lth_Hash_str(ACS_EndStrParam()); + + repr->stream->skipeol = false; + + // = + if(!Lth_TokenStreamDrop(repr->stream, Lth_TOK_Equals)) + ManifestError(repr, "expected '='"); + + // initializer + ManifestGetInitializer(repr, key); + + // obj-decl-terminator + if(!Lth_TokenStreamDrop(repr->stream, Lth_TOK_LnEnd) && + !Lth_TokenStreamDrop(repr->stream, Lth_TOK_Semico)) + ManifestError(repr, "expected newline or ';'"); + + repr->stream->skipeol = true; +} + +// +// ManifestGetDecl_Header +// +static void ManifestGetDecl_Header(ManifestState *repr) +{ + // header-declaration: + // [ header-name-sequence ] + + // [ + if(!Lth_TokenStreamDrop(repr->stream, Lth_TOK_BrackO)) + ManifestError(repr, "expected '['"); + + // header-name-sequence + ManifestGetHeaderNameSequence(repr); + repr->block = Lth_strealoc_str(repr->block, ACS_EndStrParam()); + + // ] + if(!Lth_TokenStreamDrop(repr->stream, Lth_TOK_BrackC)) + ManifestError(repr, "expected ']'"); +} + +// +// ManifestGetDecl +// +Lth_ScriptCall static void ManifestGetDecl(ManifestState *repr) +{ + switch(Lth_TokenStreamPeek(repr->stream)->type) + { + case Lth_TOK_BrackO: ManifestGetDecl_Header(repr); break; + default: ManifestGetDecl_Object(repr); break; + } +} + +// +// ManifestClose +// +static void ManifestClose(ManifestState *repr) +{ + Lth_TokenStreamClose(repr->stream); + free(repr->data); + free(repr->block); + free(repr->manifest.data); +} + + +// Extern Functions ----------------------------------------------------------| + +// +// Lth_ResourceMapDestroy +// +void Lth_ResourceMapDestroy(Lth_ResourceMap *rsrc) +{ + if(rsrc == NULL) return; + + Lth_HashMapFree(&rsrc->map); + + if(rsrc->vecStrng.data) + Lth_VectorForEach(char **, rsrc->vecStrng) + free(*itr); + + free(rsrc->vecInteg.data); + free(rsrc->vecFixed.data); + free(rsrc->vecStrng.data); + + free(rsrc); +} + +// +// Lth_ManifestLoad_extern +// +Lth_ScriptCall Lth_ResourceMap *Lth_ManifestLoad_extern(char const *fname) +{ + ManifestState repr = {}; + + repr.fname = fname; + repr.data = Lth_strdup_str(Lth_strlocal(Lth_strentdup(repr.fname))); + repr.stream = Lth_TokenStreamOpen(repr.data, strlen(repr.data)); + repr.block = Lth_strdup("Base"); + + Lth_assert(repr.stream != NULL); + + if(strcmp(repr.data, repr.fname) == 0) + { + fprintf(stderr, "%s: No file named '%s'.", __func__, fname); + ManifestClose(&repr); + return NULL; + } + + if(setjmp(ManifestJmpBuf) != ManifestJmpBufToken) + for(;;) + if(Lth_TokenStreamPeek(repr.stream)->type != Lth_TOK_EOF) + ManifestGetDecl(&repr); + else + break; + + Lth_ResourceMap *rsrc = NULL; + + if(!repr.err) + rsrc = Lth_ManifestLoad_static(repr.manifest.data); + + ManifestClose(&repr); + + return rsrc; +} + +// +// Lth_ManifestLoad_static +// +Lth_ScriptCall Lth_ResourceMap *Lth_ManifestLoad_static(Lth_Manifest *manifest) +{ + Lth_ResourceMap *rsrc = calloc(1, sizeof(Lth_ResourceMap)); + Lth_assert(rsrc != NULL); + + size_t count = 0; + + // If keyhash is 0, it was a NULL string, thus a terminator for this list. + + // Get the size of each vector and the total size for the map. + for(Lth_Manifest *iter = manifest; iter->keyhash; iter++, count++) + switch(iter->type) + { + case Lth_ResourceType_Integ: rsrc->vecInteg.size++; break; + case Lth_ResourceType_Fixed: rsrc->vecFixed.size++; break; + case Lth_ResourceType_Strng: rsrc->vecStrng.size++; break; + default: break; + } + + // Allocate each data vector and make an iterator for it. + GenAlloc(Integ, int); + GenAlloc(Fixed, _Accum); + GenAlloc(Strng, char *); + + // Allocate the hash map. + Lth_HashMapAlloc(&rsrc->map, count); + + // Iterate over all of the data vectors, adding them to the map, and + // adding data to them. + __with(size_t i = 0;) + for(Lth_Manifest *iter = manifest; iter->keyhash; iter++) + switch(iter->type) + { + GenRsrcCase(Integ, integ, i); + GenRsrcCase(Fixed, fixed, i); + GenRsrcCase(Strng, strng, i); + } + + // Build the map. + Lth_HashMapBuild(&rsrc->map); + return rsrc; +} + +// +// Lth_ManifestNew_Integ +// +Lth_Manifest Lth_ManifestNew_Integ(char const *key, int value) +{ + return GenManifestValue(Integ, integ, value); +} + +// +// Lth_ManifestNew_Fixed +// +Lth_Manifest Lth_ManifestNew_Fixed(char const *key, _Accum value) +{ + return GenManifestValue(Fixed, fixed, value); +} + +// +// Lth_ManifestNew_Strng +// +Lth_Manifest Lth_ManifestNew_Strng(char const *key, char const *value) +{ + return GenManifestValue(Strng, strng, Lth_strdup(value)); +} + +// EOF diff --git a/lithos_fs/Base.lthm b/lithos_fs/Base.lthm new file mode 100644 index 0000000..3606a01 --- /dev/null +++ b/lithos_fs/Base.lthm @@ -0,0 +1,3 @@ +Resource1 = 0x30 + +// EOF diff --git a/lithos_tools/createfs.lua b/lithos_tools/createfs.lua new file mode 100755 index 0000000..c3f92cd --- /dev/null +++ b/lithos_tools/createfs.lua @@ -0,0 +1,40 @@ +#!/usr/bin/env lua + +local lfs = require("lfs") + +function procLine(ln) + ln = ln:gsub('\\', "\\\\") + ln = ln:gsub('\"', "\\\"") + return ln +end + +function procFile(out, dir, fname) + out:write("\"" .. dir .. '/' .. fname .. "\" =") + for ln in io.lines(dir .. '/' .. fname) do + out:write("\n \"" .. procLine(ln) .. "\\n\"") + end + out:write(";\n"); +end + +function procDir(out, dir) + for fname in lfs.dir(dir) do + local attr = lfs.attributes(dir .. '/' .. fname) + + if fname:sub(1, 1) ~= '.' then + if attr.mode == "directory" then + procDir(out, dir .. '/' .. fname) + elseif attr.mode == "file" then + procFile(out, dir, fname) + end + end + end +end + +function main(out) + out:write("[default]\n\n") + procDir(out, "lithos_fs") +end + +main(io.open("language.fs.txt", "w")) + +-- EOF