diff --git a/cinera/cinera.c b/cinera/cinera.c index 09e9247..4ff6c5d 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -23,7 +23,7 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 7, - .Patch = 11 + .Patch = 12 }; #include // NOTE(matt): varargs @@ -462,15 +462,28 @@ typedef enum MBT_NONE, MBT_ASSET, + MBT_CONFIG_IDENTIFIER_ID, + MBT_CONFIG_BOOL_PAIR, + MBT_CONFIG_INT_PAIR, + MBT_CONFIG_PAIR, + MBT_CONFIG_STRING_ASSOCIATION, + MBT_CONFIG_TYPE_FIELD, + MBT_CONFIG_TYPE_SPEC, MBT_MEDIUM, MBT_NAVIGATION_BUFFER, MBT_PERSON, + MBT_PERSON_PTR, MBT_PROJECT, + MBT_PROJECT_PTR, + MBT_RESOLUTION_ERROR, MBT_STRING, + MBT_STRING_PTR, MBT_SUPPORT, MBT_TAG_OFFSET, MBT_TOKEN, MBT_TOKENS, + MBT_VARIANT, + MBT_VARIANT_STRING, } memory_book_type; typedef struct @@ -493,6 +506,12 @@ InitBook(memory_book *M, uint64_t DataWidthInBytes, uint64_t ItemsPerPage, memor M->DataWidthInBytes = DataWidthInBytes; } +void +InitBookOfPointers(memory_book *M, uint64_t ItemsPerPage, memory_book_type Type) +{ + InitBook(M, sizeof(uintptr_t), ItemsPerPage, Type); +} + memory_page * AddPage(memory_book *M) { @@ -538,9 +557,13 @@ void FreeAndReinitialiseBook(memory_book *M) { int PageSize = M->PageSize; + int DataWidthInBytes = M->DataWidthInBytes; int Type = M->Type; + FreeBook(M); + M->PageSize = PageSize; + M->DataWidthInBytes = DataWidthInBytes; M->Type = Type; } @@ -634,6 +657,12 @@ GetPlaceInBook(memory_book *M, int Index) return Result; } +void * +MakeSpaceInBook(memory_book *M) +{ + return GetPlaceInBook(M, M->ItemCount++); +} + string ExtendStringInBook(memory_book *M, string S) { @@ -723,14 +752,27 @@ PrintBook(memory_book *M) } break; case MBT_NONE: Assert(0); break; case MBT_ASSET: Assert(0); break; + case MBT_CONFIG_IDENTIFIER_ID: Assert(0); break; + case MBT_CONFIG_BOOL_PAIR: Assert(0); break; + case MBT_CONFIG_INT_PAIR: Assert(0); break; + case MBT_CONFIG_PAIR: Assert(0); break; + case MBT_CONFIG_STRING_ASSOCIATION: Assert(0); break; + case MBT_CONFIG_TYPE_FIELD: Assert(0); break; + case MBT_CONFIG_TYPE_SPEC: Assert(0); break; case MBT_MEDIUM: Assert(0); break; case MBT_NAVIGATION_BUFFER: Assert(0); break; case MBT_PERSON: Assert(0); break; + case MBT_PERSON_PTR: Assert(0); break; case MBT_PROJECT: Assert(0); break; + case MBT_PROJECT_PTR: Assert(0); break; + case MBT_RESOLUTION_ERROR: Assert(0); break; + case MBT_STRING_PTR: Assert(0); break; case MBT_SUPPORT: Assert(0); break; case MBT_TAG_OFFSET: Assert(0); break; case MBT_TOKEN: Assert(0); break; case MBT_TOKENS: Assert(0); break; + case MBT_VARIANT: Assert(0); break; + case MBT_VARIANT_STRING: Assert(0); break; } } @@ -2639,11 +2681,13 @@ FreeTemplateNavBuffers(template *T) void ClearTemplateMetadata(template *Template) { - Template->Metadata.Validity = 0; - Template->Metadata.Type = TEMPLATE_NULL; - Template->Metadata.RequiresCineraJS = FALSE; FreeTemplateNavBuffers(Template); FreeBook(&Template->Metadata.NavBuffer); + + FreeBook(&Template->Metadata.Tags); + + template_metadata Zero = {}; + Template->Metadata = Zero; } void @@ -2666,7 +2710,6 @@ void FreeTemplate(template *Template) { FreeFile(&Template->File); - FreeBook(&Template->Metadata.Tags); ClearTemplateMetadata(Template); } @@ -3710,12 +3753,11 @@ GetDirectoryPath(char *Filepath) void PushTemplateTag(template *Template, int Offset, template_tag_code TagCode, asset *Asset, navigation_buffer *NavBuffer) { - tag_offset *This = GetPlaceInBook(&Template->Metadata.Tags, Template->Metadata.Tags.ItemCount); + tag_offset *This = MakeSpaceInBook(&Template->Metadata.Tags); This->Offset = Offset; This->TagCode = TagCode; This->Asset = Asset; This->Nav = NavBuffer; - ++Template->Metadata.Tags.ItemCount; } void @@ -6202,10 +6244,8 @@ FreeCredentials(speakers *S) void WaitForInput() { -#if 0 fprintf(stderr, "Press Enter to continue...\n"); getchar(); -#endif } void @@ -6990,17 +7030,6 @@ GenerateTopicColours(neighbourhood *N, string Topic) } } -/* - * NOTE(matt); - * - * Documentation structure: - * - * section - * - * option - * description - */ - void ResetConfigIdentifierDescriptionDisplayedBools(void) { @@ -7065,7 +7094,7 @@ set base_dir at the root scope (i.e. not within a project scope) then the base_d scope, then the owner will also be set in all child project scopes. Naturally we may need this setting to vary, while also wanting the concision of writing it once. The \ base_dir is a prime example of this. To facilitate this variance, we may use variables, notably the $lineage variable, as described below. A variable written in a setting at the root \ scope, which is absorbed by a project, only gets resolved as if it had been written in the project scope.")); - config_type_specs TypeSpecs = InitTypeSpecs(); + memory_book TypeSpecs = InitTypeSpecs(); PrintTypeSpecs(&TypeSpecs, IndentationLevel); //FreeTypeSpecs(&TypeSpecs); EndSection(&IndentationLevel); @@ -7638,10 +7667,9 @@ PushNavBufferUniquely(template *Template, navigation_spec Spec) navigation_buffer *Result = GetNavBufferFromTemplate(Template, Spec); if(!Result) { - Result = GetPlaceInBook(&Template->Metadata.NavBuffer, Template->Metadata.NavBuffer.ItemCount); + Result = MakeSpaceInBook(&Template->Metadata.NavBuffer); Result->Spec = Spec; Result->Buffer.ID = BID_NAVIGATION; - ++Template->Metadata.NavBuffer.ItemCount; } return Result; } @@ -7980,14 +8008,8 @@ ConstructPlayerURL(buffer *PlayerURL, db_header_project *P, string EntryOutput) medium * MediumExists(string Medium) { - medium *ParsedMedium = GetMediumFromProject(CurrentProject, Medium); - if(ParsedMedium) - { - return ParsedMedium; - } - - fprintf(stderr, "Specified default medium \"%.*s\" not available. Valid media are:\n", (int)Medium.Length, Medium.Base); - for(int i = 0; i < CurrentProject->Medium.ItemCount; ++i) + medium *Result = GetMediumFromProject(CurrentProject, Medium); + if(!Result) { typography Typography = { @@ -8002,16 +8024,21 @@ MediumExists(string Medium) .Delimiter = ": ", .Separator = "•", }; - medium *This = GetPlaceInBook(&CurrentProject->Medium, i); - PrintMedium(&Typography, This, ": ", 2, TRUE); + + fprintf(stderr, "Specified default medium \"%.*s\" not available. Valid media are:\n", (int)Medium.Length, Medium.Base); + for(int i = 0; i < CurrentProject->Medium.ItemCount; ++i) + { + medium *This = GetPlaceInBook(&CurrentProject->Medium, i); + PrintMedium(&Typography, This, ": ", 2, TRUE); + } + fprintf(stderr, "Perhaps you'd like to add a new medium to your config file, e.g.:\n" + " medium = \"%.*s\"\n" + " {\n" + " name = \"Name of Medium\";\n" + " icon = \"🧪\";\n" + " }\n", (int)Medium.Length, Medium.Base); } - fprintf(stderr, "Perhaps you'd like to add a new medium to your config file, e.g.:\n" - " medium = \"%.*s\"\n" - " {\n" - " name = \"Name of Medium\";\n" - " icon = \"🧪\";\n" - " }\n", (int)Medium.Length, Medium.Base); - return 0; + return Result; } typedef struct @@ -10452,12 +10479,10 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template * Template->File.Buffer.Ptr = Template->File.Buffer.Location; for(int i = 0; i < Template->Metadata.Tags.ItemCount; ++i) { - int j = 0; tag_offset *Tag = GetPlaceInBook(&Template->Metadata.Tags, i); - while(Tag->Offset > j) + for(int j = 0; Tag->Offset > j; ++j) { *Master.Ptr++ = *Template->File.Buffer.Ptr++; - ++j; } // TODO(matt): Make this whole template stuff context-aware, so it can determine whether or not to HTML-encode @@ -10546,7 +10571,7 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template * { if(!Tag->Nav->Buffer.Location) { - GenerateNavigation(Config, Project, Tag->Nav); + GenerateNavigation(C, Project, Tag->Nav); } // TODO(matt): If we add project icons to the nav - and, frankly, we will want project art at some @@ -12565,85 +12590,75 @@ AtLeastNProjectsHavePublicEntries(uint8_t N) return FALSE; } -// TODO(matt): Replace with a memory_book -typedef struct -{ - string *S; - uint64_t Count; -} strings; - void -PushUniqueStringsRecursively(strings *UniqueThemes, db_header_project *P) +PushUniqueStringsRecursively(memory_book *UniqueThemes, project *P) { bool FoundMatch = FALSE; - string Theme = Wrap0i(P->Theme, sizeof(P->Theme)); - for(int i = 0; i < UniqueThemes->Count; ++i) + for(int i = 0; i < UniqueThemes->ItemCount; ++i) { - if(StringsMatch(UniqueThemes->S[i], Theme)) + string **This = GetPlaceInBook(UniqueThemes, i); + if(StringsMatch(P->Theme, **This)) { FoundMatch = TRUE; } } - if(!FoundMatch && Theme.Length > 0) + if(!FoundMatch && P->Theme.Length > 0) { - UniqueThemes->S = Fit(UniqueThemes->S, sizeof(*UniqueThemes->S), UniqueThemes->Count, 4, FALSE); - UniqueThemes->S[UniqueThemes->Count] = Theme; - ++UniqueThemes->Count; + string **This = MakeSpaceInBook(UniqueThemes); + *This = &P->Theme; } - db_header_project *Child = LocateFirstChildProject(P); - for(int i = 0; i < P->ChildCount; ++i) + for(int i = 0; i < P->Child.ItemCount; ++i) { + project *Child = GetPlaceInBook(&P->Child, i); PushUniqueStringsRecursively(UniqueThemes, Child); - Child = SkipProject(Child); } } void -PushUniqueString(strings *UniqueThemes, string GlobalTheme) +PushUniqueString(memory_book *UniqueThemes, string *GlobalTheme) { bool FoundMatch = FALSE; - for(int i = 0; i < UniqueThemes->Count; ++i) + for(int i = 0; i < UniqueThemes->ItemCount; ++i) { - if(StringsMatch(UniqueThemes->S[i], GlobalTheme)) + string **This = GetPlaceInBook(UniqueThemes, i); + if(StringsMatch(*GlobalTheme, **This)) { FoundMatch = TRUE; } } - if(!FoundMatch && GlobalTheme.Length > 0) + if(!FoundMatch && GlobalTheme->Length > 0) { - UniqueThemes->S = Fit(UniqueThemes->S, sizeof(*UniqueThemes->S), UniqueThemes->Count, 4, FALSE); - UniqueThemes->S[UniqueThemes->Count] = GlobalTheme; - ++UniqueThemes->Count; + string **This = MakeSpaceInBook(UniqueThemes); + *This = GlobalTheme; } } void -GenerateThemeLinks(buffer *IncludesSearch, db_header_project *P) +GenerateThemeLinks(buffer *IncludesSearch, project *P) { - strings UniqueThemes = {}; + memory_book UniqueThemes = {}; + InitBookOfPointers(&UniqueThemes, 4, MBT_STRING_PTR); if(P) { PushUniqueStringsRecursively(&UniqueThemes, P); } else { - PushUniqueString(&UniqueThemes, Config->GlobalTheme); - db_block_projects *ProjectsBlock = DB.Metadata.Signposts.ProjectsBlock.Ptr ? DB.Metadata.Signposts.ProjectsBlock.Ptr : LocateBlock(B_PROJ); - P = LocateFirstChildProjectOfBlock(ProjectsBlock); - for(int i = 0; i < ProjectsBlock->Count; ++i) + PushUniqueString(&UniqueThemes, &Config->GlobalTheme); + for(int i = 0; i < Config->Project.ItemCount; ++i) { + P = GetPlaceInBook(&Config->Project, i); PushUniqueStringsRecursively(&UniqueThemes, P); - P = SkipProjectAndChildren(P); } } - for(int i = 0; i < UniqueThemes.Count; ++i) + for(int i = 0; i < UniqueThemes.ItemCount; ++i) { - string ThemeID = UniqueThemes.S[i]; - string ThemeFilename = MakeString("sls", "cinera__", &ThemeID, ".css"); + string **This = GetPlaceInBook(&UniqueThemes, i); + string ThemeFilename = MakeString("sls", "cinera__", *This, ".css"); asset *CSSTheme = GetAsset(ThemeFilename, ASSET_CSS); FreeString(&ThemeFilename); buffer URL; @@ -12658,7 +12673,7 @@ GenerateThemeLinks(buffer *IncludesSearch, db_header_project *P) "\">"); } - FreeAndResetCount(UniqueThemes.S, UniqueThemes.Count); + FreeBook(&UniqueThemes); } int @@ -12711,7 +12726,7 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P "\">"); // TODO(matt): Switch the CollationBuffers->IncludesSearch to be allocated rather than claimed - GenerateThemeLinks(&CollationBuffers->IncludesSearch, StoredP); + GenerateThemeLinks(&CollationBuffers->IncludesSearch, P); asset *CSSTopics = GetAsset(Wrap0(BuiltinAssets[ASSET_CSS_TOPICS].Filename), ASSET_CSS); ConstructResolvedAssetURL(&URL, CSSTopics, PAGE_SEARCH); @@ -14877,8 +14892,7 @@ InitAll(neighbourhood *Neighbourhood, buffers *CollationBuffers, template *Bespo for(int i = 0; i < Assets.ItemCount; ++i) { - asset *This = GetPlaceInBook(&Assets, i); - UpdateAssetInDB(This); + UpdateAssetInDB(GetPlaceInBook(&Assets, i)); } DeleteStaleAssets(); //PrintAssetsBlock(0); diff --git a/cinera/cinera_config.c b/cinera/cinera_config.c index 5abed50..2b89285 100644 --- a/cinera/cinera_config.c +++ b/cinera/cinera_config.c @@ -292,7 +292,7 @@ PushToken(tokens *Set, token *Token) //PrintFunctionName("PushToken()"); if(!(Token->Type == TOKEN_NULL || Token->Type == TOKEN_COMMENT || Token->Type == TOKEN_NEWLINE)) { - token *This = GetPlaceInBook(&Set->Token, Set->Token.ItemCount); + token *This = MakeSpaceInBook(&Set->Token); This->Type = Token->Type; This->LineNumber = Set->CurrentLine; @@ -304,7 +304,6 @@ PushToken(tokens *Set, token *Token) { This->Content = Token->Content; } - ++Set->Token.ItemCount; } } @@ -336,18 +335,16 @@ PrintTokens(tokens *T) //PrintFunctionName("PrintTokens()"); for(int i = 0; i < T->Token.ItemCount; ++i) { - token *This = GetPlaceInBook(&T->Token, i); - PrintToken(This, i); + PrintToken(GetPlaceInBook(&T->Token, i), i); } } tokens * PushTokens(memory_book *TokensList) { - tokens *This = GetPlaceInBook(TokensList, TokensList->ItemCount); + tokens *This = MakeSpaceInBook(TokensList); InitBook(&This->Token, sizeof(token), 16, MBT_TOKEN); This->CurrentLine = 1; - ++TokensList->ItemCount; return This; } @@ -526,9 +523,9 @@ typedef struct project bool IgnorePrivacy; person *Owner; - _memory_book(person) Indexer; - _memory_book(person) Guest; - _memory_book(person) CoHost; + _memory_book(person *) Indexer; + _memory_book(person *) Guest; + _memory_book(person *) CoHost; _memory_book(medium) Medium; medium *DefaultMedium; @@ -776,7 +773,7 @@ bool TokenIs(tokens *T, token_type Type) { token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); - return(This->Type == Type); + return(Type == This->Type); } bool @@ -785,7 +782,7 @@ ExpectToken(tokens *T, token_type Type, token *Dest) bool Result = FALSE; token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); - if(This->Type == Type) + if(Type == This->Type) { Result = TRUE; if(Dest) @@ -832,27 +829,17 @@ typedef struct { config_identifier_id ID; bool Permeable; - uint64_t FieldCount; - config_type_field *Field; + _memory_book(config_type_field) Field; } config_type_spec; -typedef struct -{ - uint64_t Count; - config_type_spec *Spec; -} config_type_specs; - config_type_spec * -PushTypeSpec(config_type_specs *S, config_identifier_id ID, bool IsPermeable) +PushTypeSpec(memory_book *TypeSpecs, config_identifier_id ID, bool IsPermeable) { //PrintFunctionName("PushTypeSpec()"); - S->Spec = Fit(S->Spec, sizeof(*S->Spec), S->Count, 16, FALSE); - config_type_spec *Result = S->Spec + S->Count; - S->Spec[S->Count].ID = ID; - S->Spec[S->Count].FieldCount = 0; - S->Spec[S->Count].Field = 0; - S->Spec[S->Count].Permeable = IsPermeable; - ++S->Count; + config_type_spec *Result = MakeSpaceInBook(TypeSpecs); + Result->ID = ID; + InitBook(&Result->Field, sizeof(config_type_field), 4, MBT_CONFIG_TYPE_FIELD); + Result->Permeable = IsPermeable; return Result; } @@ -860,19 +847,20 @@ void PushTypeSpecField(config_type_spec *Spec, config_field_type Type, config_identifier_id ID, bool Singleton) { //PrintFunctionName("PushTypeSpecField()"); - Spec->Field = Fit(Spec->Field, sizeof(*Spec->Field), Spec->FieldCount, 4, FALSE); - Spec->Field[Spec->FieldCount].Type = Type; - Spec->Field[Spec->FieldCount].ID = ID; - Spec->Field[Spec->FieldCount].Singleton = Singleton; - Spec->Field[Spec->FieldCount].IsSetLocally = FALSE; - ++Spec->FieldCount; + config_type_field *This = MakeSpaceInBook(&Spec->Field); + This->Type = Type; + This->ID = ID; + This->Singleton = Singleton; + This->IsSetLocally = FALSE; } -config_type_specs +_memory_book(config_type_specs) InitTypeSpecs(void) { //PrintFunctionName("InitTypeSpecs()"); - config_type_specs Result = {}; + memory_book Result = {}; + InitBook(&Result, sizeof(config_type_spec), 16, MBT_CONFIG_TYPE_SPEC); + config_type_spec *Root = PushTypeSpec(&Result, IDENT_NULL, FALSE); PushTypeSpecField(Root, FT_STRING, IDENT_ASSETS_ROOT_DIR, TRUE); PushTypeSpecField(Root, FT_STRING, IDENT_ASSETS_ROOT_URL, TRUE); @@ -1085,11 +1073,12 @@ PrintTypeSpec(config_type_spec *S, int IndentationLevel) ConfigIdentifiers[S->ID].IdentifierDescriptionDisplayed = TRUE; } - for(int i = 0; i < S->FieldCount; ++i) + for(int i = 0; i < S->Field.ItemCount; ++i) { - if(!(S->ID == IDENT_NULL && S->Field[i].Type == FT_SCOPE)) + config_type_field *This = GetPlaceInBook(&S->Field, i); + if(!(S->ID == IDENT_NULL && This->Type == FT_SCOPE)) { - PrintTypeField(&S->Field[i], S->ID, IndentationLevel); + PrintTypeField(This, S->ID, IndentationLevel); } } @@ -1097,31 +1086,26 @@ PrintTypeSpec(config_type_spec *S, int IndentationLevel) } void -PrintTypeSpecs(config_type_specs *S, int IndentationLevel) +PrintTypeSpecs(memory_book *TypeSpecs, int IndentationLevel) { fprintf(stderr, "\n"); // TODO(matt): Document the fact that scopes within scopes are fully configurable, even though // we only print out the "id" of scopes, omitting their containing fields - for(int i = 0; i < S->Count; ++i) + for(int i = 0; i < TypeSpecs->ItemCount; ++i) { - PrintTypeSpec(&S->Spec[i], IndentationLevel); + PrintTypeSpec(GetPlaceInBook(TypeSpecs, i), IndentationLevel); } } void -FreeTypeSpec(config_type_spec *S) +FreeTypeSpecs(memory_book *TypeSpecs) { - FreeAndResetCount(S->Field, S->FieldCount); -} - -void -FreeTypeSpecs(config_type_specs *S) -{ - for(int i = 0; i < S->Count; ++i) + for(int i = 0; i < TypeSpecs->ItemCount; ++i) { - FreeTypeSpec(&S->Spec[i]); + config_type_spec *This = GetPlaceInBook(TypeSpecs, i); + FreeBook(&This->Field); } - FreeAndResetCount(S->Spec, S->Count); + FreeBook(TypeSpecs); } typedef struct @@ -1154,47 +1138,48 @@ typedef struct typedef struct scope_tree { config_pair ID; - uint64_t TreeCount; - struct scope_tree *Trees; - uint64_t PairCount; - config_pair *Pairs; - uint64_t IntPairCount; - config_int_pair *IntPairs; - uint64_t BoolPairCount; - config_bool_pair *BoolPairs; + _memory_book(scope_tree) Trees; + _memory_book(config_pair) Pairs; + _memory_book(config_int_pair) IntPairs; + _memory_book(config_bool_pair) BoolPairs; struct scope_tree *Parent; config_type_spec TypeSpec; //token_position Position; // NOTE(matt): We chose not to make ScopeTokens() set this value } scope_tree; config_type_spec * -GetTypeSpec(config_type_specs *S, config_identifier_id ID) +GetTypeSpec(memory_book *TypeSpecs, config_identifier_id ID) { - for(int i = 0; i < S->Count; ++i) + config_type_spec *Result = 0; + for(int i = 0; i < TypeSpecs->ItemCount; ++i) { - if(S->Spec[i].ID == ID) + config_type_spec *This = GetPlaceInBook(TypeSpecs, i); + if(This->ID == ID) { - return &S->Spec[i]; + Result = This; + break; } } - return 0; + return Result; } void -SetTypeSpec(scope_tree *Type, config_type_specs *TypeSpecs) +SetTypeSpec(scope_tree *Type, memory_book *TypeSpecs) { config_type_spec *Spec = GetTypeSpec(TypeSpecs, Type->ID.Key); //PrintTypeSpec(Spec); Type->TypeSpec.ID = Spec->ID; Type->TypeSpec.Permeable = Spec->Permeable; - Type->TypeSpec.FieldCount = Spec->FieldCount; - Type->TypeSpec.Field = malloc(Type->TypeSpec.FieldCount * sizeof(config_type_field)); - for(int i = 0; i < Type->TypeSpec.FieldCount; ++i) + InitBook(&Type->TypeSpec.Field, sizeof(config_type_field), 4, MBT_CONFIG_TYPE_FIELD); + for(int i = 0; i < Spec->Field.ItemCount; ++i) { - Type->TypeSpec.Field[i].Type = Spec->Field[i].Type; - Type->TypeSpec.Field[i].ID = Spec->Field[i].ID; - Type->TypeSpec.Field[i].Singleton = Spec->Field[i].Singleton; - Type->TypeSpec.Field[i].IsSetLocally = Spec->Field[i].IsSetLocally; + config_type_field *Src = GetPlaceInBook(&Spec->Field, i); + config_type_field *Dest = MakeSpaceInBook(&Type->TypeSpec.Field); + + Dest->Type = Src->Type; + Dest->ID = Src->ID; + Dest->Singleton = Src->Singleton; + Dest->IsSetLocally = Src->IsSetLocally; } } @@ -1204,12 +1189,13 @@ CurrentFieldIsInSpec(config_type_spec *Spec, tokens *T) config_type_field *Result = 0; if(Spec) { - for(int i = 0; i < Spec->FieldCount; ++i) + token *Token = GetPlaceInBook(&T->Token, T->CurrentIndex); + for(int i = 0; i < Spec->Field.ItemCount; ++i) { - token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); - if(!StringsDifferLv0(This->Content, ConfigIdentifiers[Spec->Field[i].ID].String)) + config_type_field *Field = GetPlaceInBook(&Spec->Field, i); + if(!StringsDifferLv0(Token->Content, ConfigIdentifiers[Field->ID].String)) { - Result = &Spec->Field[i]; + Result = Field; break; } } @@ -1217,30 +1203,15 @@ CurrentFieldIsInSpec(config_type_spec *Spec, tokens *T) return Result; } -// TODO(matt): Replace with a memory_book -typedef struct -{ - uint64_t Count; - string *String; -} string_list; - typedef struct { string Filename; - string_list Allow; - string_list Deny; + memory_book Allow; + memory_book Deny; } config_include; -void -PushString(string_list *Dest, string *Src) -{ - Dest->String = Fit(Dest->String, sizeof(*Dest->String), Dest->Count, 4, FALSE); - Dest->String[Dest->Count] = *Src; - ++Dest->Count; -} - bool -ParseMultiStringAssignment(tokens *T, string_list *Dest, config_type_field *Field) +ParseMultiStringAssignment(tokens *T, memory_book *Dest, config_type_field *Field) { ++T->CurrentIndex; token Token = {}; @@ -1253,7 +1224,8 @@ ParseMultiStringAssignment(tokens *T, string_list *Dest, config_type_field *Fiel return FALSE; } - PushString(Dest, &Token.Content); + string *This = MakeSpaceInBook(Dest); + *This = Token.Content; Field->IsSetLocally = TRUE; @@ -1268,8 +1240,7 @@ void PrintCurrentToken(colour_code C, tokens *T) { Colourise(C); - token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); - PrintToken(This, T->CurrentIndex); + PrintToken(GetPlaceInBook(&T->Token, T->CurrentIndex), T->CurrentIndex); Colourise(CS_END); } @@ -1338,17 +1309,11 @@ FreeString(string *S) S->Length = 0; } -void -FreeStringList(string_list *S) -{ - FreeAndResetCount(S->String, S->Count); -} - void FreeInclude(config_include *I) { - FreeStringList(&I->Allow); - FreeStringList(&I->Deny); + FreeBook(&I->Allow); + FreeBook(&I->Deny); free(I); I = 0; } @@ -1359,56 +1324,34 @@ IsStringEmpty(string *S) return S ? S->Length == 0 : TRUE; } -// TODO(matt): This never gets called. Probably remove -void -PrintInclude(config_include *I) -{ - PrintStringC(CS_YELLOW_BOLD, I->Filename); - fprintf(stderr, "\n AllowCount: %lu", I->Allow.Count); - fprintf(stderr, "\n DenyCount: %lu", I->Deny.Count); -#if 1 - for(int i = 0; i < I->Allow.Count; ++i) - { - fprintf(stderr, "\n Allow: "); - PrintStringC(CS_GREEN, I->Allow.String[i]); - } - for(int i = 0; i < I->Deny.Count; ++i) - { - fprintf(stderr, "\n Deny: "); - PrintStringC(CS_GREEN, I->Deny.String[i]); - } -#endif - fprintf(stderr, "\n"); -} - void FreeScopeTreeRecursively(scope_tree *T) { - FreeAndResetCount(T->Pairs, T->PairCount); - FreeAndResetCount(T->IntPairs, T->IntPairCount); - FreeAndResetCount(T->BoolPairs, T->BoolPairCount); - Free(T->TypeSpec.Field); + FreeBook(&T->Pairs); + FreeBook(&T->IntPairs); + FreeBook(&T->BoolPairs); + FreeBook(&T->TypeSpec.Field); //Free(T->Position.Filename); - for(int i = 0; i < T->TreeCount; ++i) + for(int i = 0; i < T->Trees.ItemCount; ++i) { - FreeScopeTreeRecursively(&T->Trees[i]); + FreeScopeTreeRecursively(GetPlaceInBook(&T->Trees, i)); } - FreeAndResetCount(T->Trees, T->TreeCount); + FreeBook(&T->Trees); } void FreeScopeTree(scope_tree *T) { - FreeAndResetCount(T->Pairs, T->PairCount); - FreeAndResetCount(T->IntPairs, T->IntPairCount); - FreeAndResetCount(T->BoolPairs, T->BoolPairCount); - Free(T->TypeSpec.Field); + FreeBook(&T->Pairs); + FreeBook(&T->IntPairs); + FreeBook(&T->BoolPairs); + FreeBook(&T->TypeSpec.Field); //Free(T->Position.Filename); - for(int i = 0; i < T->TreeCount; ++i) + for(int i = 0; i < T->Trees.ItemCount; ++i) { - FreeScopeTreeRecursively(&T->Trees[i]); + FreeScopeTreeRecursively(GetPlaceInBook(&T->Trees, i)); } - FreeAndResetCount(T->Trees, T->TreeCount); + FreeBook(&T->Trees); Free(T); } @@ -1545,21 +1488,21 @@ PrintScopeTree(scope_tree *T, int IndentationLevel) } bool ShouldPrependNewline = TRUE; bool ShouldFillSyntax = TRUE; - for(int i = 0; i < T->PairCount; ++i) + for(int i = 0; i < T->Pairs.ItemCount; ++i) { - PrintPair(&T->Pairs[i], " = ", ShouldFillSyntax, IndentationLevel, ShouldPrependNewline, FALSE); + PrintPair(GetPlaceInBook(&T->Pairs, i), " = ", ShouldFillSyntax, IndentationLevel, ShouldPrependNewline, FALSE); } - for(int i = 0; i < T->IntPairCount; ++i) + for(int i = 0; i < T->IntPairs.ItemCount; ++i) { - PrintIntPair(&T->IntPairs[i], " = ", ShouldFillSyntax, IndentationLevel, ShouldPrependNewline, FALSE); + PrintIntPair(GetPlaceInBook(&T->IntPairs, i), " = ", ShouldFillSyntax, IndentationLevel, ShouldPrependNewline, FALSE); } - for(int i = 0; i < T->BoolPairCount; ++i) + for(int i = 0; i < T->BoolPairs.ItemCount; ++i) { - PrintBoolPair(&T->BoolPairs[i], " = ", ShouldFillSyntax, IndentationLevel, ShouldPrependNewline, FALSE); + PrintBoolPair(GetPlaceInBook(&T->BoolPairs, i), " = ", ShouldFillSyntax, IndentationLevel, ShouldPrependNewline, FALSE); } - for(int i = 0; i < T->TreeCount; ++i) + for(int i = 0; i < T->Trees.ItemCount; ++i) { - PrintScopeTree(&T->Trees[i], IndentationLevel); + PrintScopeTree(GetPlaceInBook(&T->Trees, i), IndentationLevel); } if(T->ID.Key != IDENT_NULL) { @@ -1573,59 +1516,44 @@ PrintScopeTree(scope_tree *T, int IndentationLevel) void PushPair(scope_tree *Parent, config_pair *P) { - Parent->Pairs = Fit(Parent->Pairs, sizeof(*Parent->Pairs), Parent->PairCount, 4, FALSE); - Parent->Pairs[Parent->PairCount] = *P; - ++Parent->PairCount; + config_pair *New = MakeSpaceInBook(&Parent->Pairs); + *New = *P; } void PushIntPair(scope_tree *Parent, config_int_pair *I) { - Parent->IntPairs = Fit(Parent->IntPairs, sizeof(*Parent->IntPairs), Parent->IntPairCount, 4, FALSE); - Parent->IntPairs[Parent->IntPairCount] = *I; - ++Parent->IntPairCount; + config_int_pair *New = MakeSpaceInBook(&Parent->IntPairs); + *New = *I; } void PushBoolPair(scope_tree *Parent, config_bool_pair *B) { - Parent->BoolPairs = Fit(Parent->BoolPairs, sizeof(*Parent->BoolPairs), Parent->BoolPairCount, 4, FALSE); - Parent->BoolPairs[Parent->BoolPairCount] = *B; - ++Parent->BoolPairCount; + config_bool_pair *New = MakeSpaceInBook(&Parent->BoolPairs); + *New = *B; +} + +void +InitScopeBooks(scope_tree *Scope) +{ + InitBook(&Scope->Trees, sizeof(scope_tree), 4, MBT_CONFIG_PAIR); + InitBook(&Scope->Pairs, sizeof(config_pair), 4, MBT_CONFIG_PAIR); + InitBook(&Scope->IntPairs, sizeof(config_int_pair), 4, MBT_CONFIG_INT_PAIR); + InitBook(&Scope->BoolPairs, sizeof(config_bool_pair), 4, MBT_CONFIG_BOOL_PAIR); } scope_tree * -PushScope(config_type_specs *TypeSpecs, scope_tree *Parent, config_pair *ID) +PushScope(memory_book *TypeSpecs, scope_tree *Parent, config_pair *ID) { - // TODO(matt): I reckon what's going on here is that a scope_tree's Parent pointer gets invalidated when that scope_tree's - // Grandparent needs to reallocate its Trees pointer. - // - // So to fix it we have two options: - // 1. When realloc'ing, loop over the Trees, offsetting the Trees->Parent pointer of each Tree's child - // 2. Store this whole stuff in a memory_book-type of thing, so that pointers never get invalidated - // - // We did Option 1, but think we probably ought to use Option 2 instead. Doing so will save us having to - // remember if anything points into our memory, and to offset those pointers if so - scope_tree *Current = Parent->Trees; - Parent->Trees = Fit(Parent->Trees, sizeof(*Parent->Trees), Parent->TreeCount, 4, TRUE); - int64_t Diff = Parent->Trees - Current; - if(Diff) - { - for(int i = 0; i < Parent->TreeCount; ++i) - { - scope_tree *Child = Parent->Trees + i; - for(int j = 0; j < Child->TreeCount; ++j) - { - Child->Trees[j].Parent += Diff; - } - } - } + scope_tree *This = MakeSpaceInBook(&Parent->Trees); + InitScopeBooks(This); - Parent->Trees[Parent->TreeCount].ID = *ID; - SetTypeSpec(&Parent->Trees[Parent->TreeCount], TypeSpecs); - Parent->Trees[Parent->TreeCount].Parent = Parent; - ++Parent->TreeCount; - return(&Parent->Trees[Parent->TreeCount - 1]); + This->ID = *ID; + SetTypeSpec(This, TypeSpecs); + This->Parent = Parent; + + return(This); } config_identifier_id @@ -1657,14 +1585,17 @@ GetConfigIdentifierFromString(string S) config_type_field * FieldIsInSpec(config_type_spec *Spec, config_identifier_id ID) { - for(int i = 0; i < Spec->FieldCount; ++i) + config_type_field *Result = 0; + for(int i = 0; i < Spec->Field.ItemCount; ++i) { - if(Spec->Field[i].ID == ID) + config_type_field *This = GetPlaceInBook(&Spec->Field, i); + if(ID == This->ID) { - return &Spec->Field[i]; + Result = This; + break; } } - return 0; + return Result; } bool @@ -1676,105 +1607,123 @@ PairsMatch(config_pair *A, config_pair *B) scope_tree * GetScope(scope_tree *T, config_pair *ID, bool Singleton) { - for(int i = 0; i < T->TreeCount; ++i) + scope_tree *Result = 0; + for(int i = 0; i < T->Trees.ItemCount; ++i) { + scope_tree *This = GetPlaceInBook(&T->Trees, i); if(Singleton) { - if(T->Trees[i].ID.Key == ID->Key) + if(ID->Key == This->ID.Key) { - return &T->Trees[i]; + Result = This; + break; } } else { - if(PairsMatch(&T->Trees[i].ID, ID)) + if(PairsMatch(ID, &This->ID)) { - return &T->Trees[i]; + Result = This; + break; } } } - return 0; + return Result; } config_pair * GetAssignment(scope_tree *T, config_pair *Assignment, bool Singleton) { - for(int i = 0; i < T->PairCount; ++i) + config_pair *Result = 0; + for(int i = 0; i < T->Pairs.ItemCount; ++i) { + config_pair *This = GetPlaceInBook(&T->Pairs, i); if(Singleton) { - if(T->Pairs[i].Key == Assignment->Key) + if(Assignment->Key == This->Key) { - return &T->Pairs[i]; + Result = This; + break; } } else { - if(PairsMatch(&T->Pairs[i], Assignment)) + if(PairsMatch(Assignment, This)) { - return &T->Pairs[i]; + Result = This; + break; } } } - return 0; + return Result; } config_int_pair * GetIntAssignment(scope_tree *T, config_int_pair *Assignment, bool Singleton) { - for(int i = 0; i < T->IntPairCount; ++i) + config_int_pair *Result = 0; + for(int i = 0; i < T->IntPairs.ItemCount; ++i) { - if(T->IntPairs[i].Key == Assignment->Key) + config_int_pair *This = GetPlaceInBook(&T->IntPairs, i); + if(Assignment->Key == This->Key) { - if(Singleton || T->IntPairs[i].Value == Assignment->Value) + if(Singleton || Assignment->Value == This->Value) { - return &T->IntPairs[i]; + Result = This; + break; } } } - return 0; + return Result; } config_bool_pair * GetBoolAssignment(scope_tree *T, config_bool_pair *Assignment, bool Singleton) { - for(int i = 0; i < T->BoolPairCount; ++i) + config_bool_pair *Result = 0; + for(int i = 0; i < T->BoolPairs.ItemCount; ++i) { - if(T->BoolPairs[i].Key == Assignment->Key) + config_bool_pair *This = GetPlaceInBook(&T->BoolPairs, i); + if(Assignment->Key == This->Key) { - if(Singleton || T->BoolPairs[i].Value == Assignment->Value) + if(Singleton || Assignment->Value == This->Value) { - return &T->BoolPairs[i]; + Result = This; + break; } } } - return 0; + return Result; } -scope_tree *CopyScope(config_type_specs *TypeSpecs, scope_tree *Dest, scope_tree *Src); +scope_tree *CopyScope(memory_book *TypeSpecs, scope_tree *Dest, scope_tree *Src); void -CopyScopeContents(config_type_specs *TypeSpecs, scope_tree *Dest, scope_tree *Src) +CopyScopeContents(memory_book *TypeSpecs, scope_tree *Dest, scope_tree *Src) { - for(int i = 0; i < Src->PairCount; ++i) + for(int i = 0; i < Src->Pairs.ItemCount; ++i) { - PushPair(Dest, &Src->Pairs[i]); + config_pair *Pair = GetPlaceInBook(&Src->Pairs, i); + PushPair(Dest, Pair); } - for(int i = 0; i < Src->IntPairCount; ++i) + for(int i = 0; i < Src->IntPairs.ItemCount; ++i) { - PushIntPair(Dest, &Src->IntPairs[i]); + config_int_pair *IntPair = GetPlaceInBook(&Src->IntPairs, i); + PushIntPair(Dest, IntPair); } - for(int i = 0; i < Src->BoolPairCount; ++i) + for(int i = 0; i < Src->BoolPairs.ItemCount; ++i) { - PushBoolPair(Dest, &Src->BoolPairs[i]); + config_bool_pair *BoolPair = GetPlaceInBook(&Src->BoolPairs, i); + PushBoolPair(Dest, BoolPair); } - for(int i = 0; i < Src->TreeCount; ++i) + for(int i = 0; i < Src->Trees.ItemCount; ++i) { - CopyScope(TypeSpecs, Dest, &Src->Trees[i]); + scope_tree *Tree = GetPlaceInBook(&Src->Trees, i); + CopyScope(TypeSpecs, Dest, Tree); } } scope_tree * -CopyScope(config_type_specs *TypeSpecs, scope_tree *Dest, scope_tree *Src) +CopyScope(memory_book *TypeSpecs, scope_tree *Dest, scope_tree *Src) { Dest = PushScope(TypeSpecs, Dest, &Src->ID); CopyScopeContents(TypeSpecs, Dest, Src); @@ -1782,44 +1731,48 @@ CopyScope(config_type_specs *TypeSpecs, scope_tree *Dest, scope_tree *Src) } void -MergeScopes(config_type_specs *TypeSpecs, scope_tree *Dest, scope_tree *Src, bool Intergenerational) +MergeScopes(memory_book *TypeSpecs, scope_tree *Dest, scope_tree *Src, bool Intergenerational) { if(!Intergenerational || Dest->TypeSpec.Permeable) { - for(int i = 0; i < Src->PairCount; ++i) + for(int i = 0; i < Src->Pairs.ItemCount; ++i) { - config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, Src->Pairs[i].Key); + config_pair *Pair = GetPlaceInBook(&Src->Pairs, i); + config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, Pair->Key); if(Field) { - config_pair *ThisAssignment = GetAssignment(Dest, &Src->Pairs[i], Field->Singleton); - if(!ThisAssignment) { PushPair(Dest, &Src->Pairs[i]); } + config_pair *ThisAssignment = GetAssignment(Dest, Pair, Field->Singleton); + if(!ThisAssignment) { PushPair(Dest, Pair); } } } - for(int i = 0; i < Src->IntPairCount; ++i) + for(int i = 0; i < Src->IntPairs.ItemCount; ++i) { - config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, Src->IntPairs[i].Key); + config_int_pair *IntPair = GetPlaceInBook(&Src->IntPairs, i); + config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, IntPair->Key); if(Field) { - config_int_pair *ThisAssignment = GetIntAssignment(Dest, &Src->IntPairs[i], Field->Singleton); - if(!ThisAssignment) { PushIntPair(Dest, &Src->IntPairs[i]); } + config_int_pair *ThisAssignment = GetIntAssignment(Dest, IntPair, Field->Singleton); + if(!ThisAssignment) { PushIntPair(Dest, IntPair); } } } - for(int i = 0; i < Src->BoolPairCount; ++i) + for(int i = 0; i < Src->BoolPairs.ItemCount; ++i) { - config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, Src->BoolPairs[i].Key); + config_bool_pair *BoolPair = GetPlaceInBook(&Src->BoolPairs, i); + config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, BoolPair->Key); if(Field) { - config_bool_pair *ThisAssignment = GetBoolAssignment(Dest, &Src->BoolPairs[i], Field->Singleton); - if(!ThisAssignment) { PushBoolPair(Dest, &Src->BoolPairs[i]); } + config_bool_pair *ThisAssignment = GetBoolAssignment(Dest, BoolPair, Field->Singleton); + if(!ThisAssignment) { PushBoolPair(Dest, BoolPair); } } } - for(int i = 0; i < Src->TreeCount; ++i) + for(int i = 0; i < Src->Trees.ItemCount; ++i) { - config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, Src->Trees[i].ID.Key); - if(Field && !(Intergenerational && Src->Trees[i].ID.Key == Dest->ID.Key)) + scope_tree *Tree = GetPlaceInBook(&Src->Trees, i); + config_type_field *Field = FieldIsInSpec(&Dest->TypeSpec, Tree->ID.Key); + if(Field && !(Intergenerational && Tree->ID.Key == Dest->ID.Key)) { - scope_tree *ThisAssignment = GetScope(Dest, &Src->Trees[i].ID, Field->Singleton); - if(!ThisAssignment) { CopyScope(TypeSpecs, Dest, &Src->Trees[i]); } + scope_tree *ThisAssignment = GetScope(Dest, &Tree->ID, Field->Singleton); + if(!ThisAssignment) { CopyScope(TypeSpecs, Dest, Tree); } } } } @@ -1835,33 +1788,27 @@ typedef enum typedef struct { config_rule_type Scheme; - uint64_t Count; - config_identifier_id *ID; + _memory_book(config_identifier_id) ID; } config_include_rules; void PushRule(config_include_rules *R, config_identifier_id ID) { - for(int i = 0; i < R->Count; ++i) + for(int i = 0; i < R->ID.ItemCount; ++i) { - if(ID == R->ID[i]) + config_identifier_id *This = GetPlaceInBook(&R->ID, i); + if(ID == *This) { return; } } - R->ID = Fit(R->ID, sizeof(*R->ID), R->Count, 8, FALSE); - R->ID[R->Count] = ID; - ++R->Count; + + config_identifier_id *This = MakeSpaceInBook(&R->ID); + *This = ID; } void -FreeRules(config_include_rules *R) -{ - FreeAndResetCount(R->ID, R->Count); -} - -void -ParseRuleString(char *Filename, config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec, config_include_rules *Rules, token *RuleString) +ParseRuleString(char *Filename, memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, config_include_rules *Rules, token *RuleString) { int i = SkipWhitespaceS(&RuleString->Content, 0); config_type_field *Field = 0; @@ -1883,15 +1830,17 @@ ParseRuleString(char *Filename, config_type_specs *TypeSpecs, config_type_spec * PushRule(Rules, ID); if(i == RuleString->Content.Length && (ParentTypeSpec = GetTypeSpec(TypeSpecs, Field->ID))) { - for(int j = 0; j < ParentTypeSpec->FieldCount; ++j) + for(int j = 0; j < ParentTypeSpec->Field.ItemCount; ++j) { - PushRule(Rules, ParentTypeSpec->Field[j].ID); - config_type_spec *ThisTypeSpec = GetTypeSpec(TypeSpecs, ParentTypeSpec->Field[j].ID); + config_type_field *ParentField = GetPlaceInBook(&ParentTypeSpec->Field, j); + PushRule(Rules, ParentField->ID); + config_type_spec *ThisTypeSpec = GetTypeSpec(TypeSpecs, ParentField->ID); if(ThisTypeSpec) { - for(int k = 0; k < ThisTypeSpec->FieldCount; ++k) + for(int k = 0; k < ThisTypeSpec->Field.ItemCount; ++k) { - PushRule(Rules, ThisTypeSpec->Field[k].ID); + config_type_field *ThisField = GetPlaceInBook(&ThisTypeSpec->Field, k); + PushRule(Rules, ThisField->ID); } } } @@ -1938,7 +1887,7 @@ ParseRuleString(char *Filename, config_type_specs *TypeSpecs, config_type_spec * } rc -ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec, tokens *T, config_include_rules *Rules) +ParseIncludeRules(memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, tokens *T, config_include_rules *Rules) { uint64_t IncludeIdentifierTokenIndex = T->CurrentIndex - 3; if(TokenIs(T, TOKEN_SEMICOLON)) @@ -1957,7 +1906,7 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec { if(Rules->Scheme == CRT_DENY) { - FreeRules(Rules); + FreeBook(&Rules->ID); token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Mixture of allow and deny identifiers in \"include\" scope", 0); return DepartIncludeAssignment(T, IncludeIdentifierTokenIndex) ? RC_SCHEME_MIXTURE : RC_SYNTAX_ERROR; @@ -1968,7 +1917,7 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec { if(Rules->Scheme == CRT_ALLOW) { - FreeRules(Rules); + FreeBook(&Rules->ID); token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Mixture of allow and deny identifiers in \"include\" scope", 0); return DepartIncludeAssignment(T, IncludeIdentifierTokenIndex) ? RC_SCHEME_MIXTURE : RC_SYNTAX_ERROR; @@ -1983,15 +1932,15 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec " Valid identifiers:\n" " allow\n" " deny\n"); - FreeRules(Rules); + FreeBook(&Rules->ID); return DepartIncludeAssignment(T, IncludeIdentifierTokenIndex) ? RC_INVALID_IDENTIFIER : RC_SYNTAX_ERROR; } ++T->CurrentIndex; - if(!ExpectToken(T, TOKEN_ASSIGN, 0)) { FreeRules(Rules); return RC_SYNTAX_ERROR; } + if(!ExpectToken(T, TOKEN_ASSIGN, 0)) { FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; } token RuleString = {}; - if(!ExpectToken(T, TOKEN_STRING, &RuleString)) { FreeRules(Rules); return RC_SYNTAX_ERROR; } + if(!ExpectToken(T, TOKEN_STRING, &RuleString)) { FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; } ParseRuleString(T->File.Path, TypeSpecs, ParentTypeSpec, Rules, &RuleString); - if(!ExpectToken(T, TOKEN_SEMICOLON, 0)) { FreeRules(Rules); return RC_SYNTAX_ERROR; } + if(!ExpectToken(T, TOKEN_SEMICOLON, 0)) { FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; } } else if(TokenIs(T, TOKEN_CLOSE_BRACE)) { @@ -2000,14 +1949,14 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec } else { - FreeRules(Rules); + FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; } } } else { - FreeRules(Rules); + FreeBook(&Rules->ID); ConfigErrorExpectation(T, TOKEN_SEMICOLON, TOKEN_OPEN_BRACE); return RC_SYNTAX_ERROR; } @@ -2017,9 +1966,10 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec bool FieldIsPermitted(config_include_rules *Rules, config_type_field *Field) { - for(int i = 0; i < Rules->Count; ++i) + for(int i = 0; i < Rules->ID.ItemCount; ++i) { - if(Field->ID == Rules->ID[i]) + config_identifier_id *This = GetPlaceInBook(&Rules->ID, i); + if(Field->ID == *This) { return Rules->Scheme == CRT_ALLOW ? TRUE : FALSE; } @@ -2030,14 +1980,15 @@ FieldIsPermitted(config_include_rules *Rules, config_type_field *Field) void ResetFields(config_type_spec *S) { - for(int i = 0; i < S->FieldCount; ++i) + for(int i = 0; i < S->Field.ItemCount; ++i) { - S->Field[i].IsSetLocally = FALSE; + config_type_field *This = GetPlaceInBook(&S->Field, i); + This->IsSetLocally = FALSE; } } scope_tree * -PushDefaultScope(config_type_specs *TypeSpecs, scope_tree *Parent, config_identifier_id Key, string Value) +PushDefaultScope(memory_book *TypeSpecs, scope_tree *Parent, config_identifier_id Key, string Value) { config_pair ID = { .Key = Key, .Value = Value }; return PushScope(TypeSpecs, Parent, &ID); @@ -2059,7 +2010,7 @@ PushDefaultIntPair(scope_tree *Parent, config_identifier_id Key, uint64_t Value) #define DEFAULT_PRIVACY_CHECK_INTERVAL 60 * 4 void -SetDefaults(scope_tree *Root, config_type_specs *TypeSpecs) +SetDefaults(scope_tree *Root, memory_book *TypeSpecs) { scope_tree *SupportPatreon = PushDefaultScope(TypeSpecs, Root, IDENT_SUPPORT, Wrap0("patreon")); PushDefaultPair(SupportPatreon, IDENT_ICON, Wrap0("cinera_sprite_patreon.png")); @@ -2087,7 +2038,7 @@ SetDefaults(scope_tree *Root, config_type_specs *TypeSpecs) } scope_tree * -ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, config_type_specs *TypeSpecs, config_include_rules *Rules) +ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *TypeSpecs, config_include_rules *Rules) { scope_tree *Parent = Tree; for(T->CurrentIndex = 0; T->CurrentIndex < T->Token.ItemCount;) @@ -2309,6 +2260,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, config_type_sp { int IncludePathTokenIndex = T->CurrentIndex - 1; config_include_rules Rules = {}; + InitBook(&Rules.ID, sizeof(config_identifier_id), 4, MBT_CONFIG_IDENTIFIER_ID); switch(ParseIncludeRules(TypeSpecs, &Parent->TypeSpec, T, &Rules)) { case RC_SUCCESS: @@ -2335,7 +2287,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, config_type_sp if(I) { Parent = ScopeTokens(Parent, TokensList, I, TypeSpecs, &Rules); - FreeRules(&Rules); + FreeBook(&Rules.ID); if(!Parent) { return 0; @@ -2480,10 +2432,8 @@ typedef struct typedef struct { - uint64_t ErrorCount; - resolution_error *Errors; - uint64_t WarningCount; - resolution_error *Warnings; + _memory_book(resolution_error) Errors; + _memory_book(resolution_error) Warnings; } resolution_errors; void @@ -2491,61 +2441,64 @@ PushError(resolution_errors *E, severity Severity, token_position *Position, con { if(Severity == S_WARNING) { - E->Warnings = Fit(E->Warnings, sizeof(*E->Warnings), E->WarningCount, 16, TRUE); + resolution_error *This = MakeSpaceInBook(&E->Warnings); if(Position) { - E->Warnings[E->WarningCount].Position = *Position; + This->Position = *Position; } - E->Warnings[E->WarningCount].Variable = Variable; - ++E->WarningCount; + This->Variable = Variable; } else { - E->Errors = Fit(E->Errors, sizeof(*E->Errors), E->ErrorCount, 16, TRUE); + resolution_error *This = MakeSpaceInBook(&E->Errors); if(Position) { - E->Errors[E->ErrorCount].Position = *Position; + This->Position = *Position; } - E->Errors[E->ErrorCount].Variable = Variable; - ++E->ErrorCount; + This->Variable = Variable; } } resolution_error * GetError(resolution_errors *E, severity Severity, token_position *Position, config_identifier_id Variable) { + resolution_error *Result = 0; if(Severity == S_WARNING) { - for(int i = 0; i < E->WarningCount; ++i) + for(int i = 0; i < E->Warnings.ItemCount; ++i) { - if(E->Warnings[i].Position.Filename == Position->Filename && - E->Warnings[i].Position.LineNumber == Position->LineNumber && - E->Warnings[i].Variable == Variable) + resolution_error *This = GetPlaceInBook(&E->Warnings, i); + if(Position->Filename == This->Position.Filename && + Position->LineNumber == This->Position.LineNumber && + Variable == This->Variable) { - return &E->Warnings[i]; + Result = This; + break; } } } else { - for(int i = 0; i < E->ErrorCount; ++i) + for(int i = 0; i < E->Errors.ItemCount; ++i) { - if(E->Errors[i].Position.Filename == Position->Filename && - E->Errors[i].Position.LineNumber == Position->LineNumber && - E->Errors[i].Variable == Variable) + resolution_error *This = GetPlaceInBook(&E->Errors, i); + if(Position->Filename == This->Position.Filename && + Position->LineNumber == This->Position.LineNumber && + Variable == This->Variable) { - return &E->Errors[i]; + Result = This; + break; } } } - return 0; + return Result; } void FreeErrors(resolution_errors *E) { - FreeAndResetCount(E->Errors, E->ErrorCount); - FreeAndResetCount(E->Warnings, E->WarningCount); + FreeAndReinitialiseBook(&E->Errors); + FreeAndReinitialiseBook(&E->Warnings); } string @@ -2601,25 +2554,33 @@ string DeriveLineageOfProject(config *C, scope_tree *Project) { string Result = {}; - string_list StringList = {}; + memory_book StringList = {}; + InitBookOfPointers(&StringList, 4, MBT_STRING_PTR); if(Project) { - PushString(&StringList, &Project->ID.Value); - Project = Project->Parent; - } - while(Project && Project->ID.Key == IDENT_PROJECT) - { - string Slash = Wrap0("/"); - PushString(&StringList, &Slash); - PushString(&StringList, &Project->ID.Value); + string **Writer = MakeSpaceInBook(&StringList); + *Writer = &Project->ID.Value; Project = Project->Parent; } - for(int i = StringList.Count - 1; i >= 0; --i) + string Slash = Wrap0("/"); + while(Project && Project->ID.Key == IDENT_PROJECT) { - Result = ExtendStringInBook(&C->ResolvedVariables, StringList.String[i]); + string **Writer = MakeSpaceInBook(&StringList); + *Writer = &Slash; + + Writer = MakeSpaceInBook(&StringList); + *Writer = &Project->ID.Value; + + Project = Project->Parent; } - FreeStringList(&StringList); + + for(int i = StringList.ItemCount - 1; i >= 0; --i) + { + string **Reader = GetPlaceInBook(&StringList, i); + Result = ExtendStringInBook(&C->ResolvedVariables, **Reader);; + } + FreeBook(&StringList); return Result; } @@ -2634,27 +2595,33 @@ string DeriveLineageWithoutOriginOfProject(config *C, scope_tree *Project) { string Result = {}; - string_list StringList = {}; + memory_book StringList = {}; if(Project->Parent && Project->Parent->ID.Key == IDENT_PROJECT) { - PushString(&StringList, &Project->ID.Value); - Project = Project->Parent; - } - while(Project->Parent && Project->Parent->ID.Key == IDENT_PROJECT) - { - string Slash = Wrap0("/"); - PushString(&StringList, &Slash); - PushString(&StringList, &Project->ID.Value); + string **Writer = MakeSpaceInBook(&StringList); + *Writer = &Project->ID.Value; Project = Project->Parent; } - if(StringList.Count > 0) + string Slash = Wrap0("/"); + while(Project->Parent && Project->Parent->ID.Key == IDENT_PROJECT) { - for(int i = StringList.Count - 1; i >= 0; --i) + string **Writer = MakeSpaceInBook(&StringList); + *Writer = &Slash; + + Writer = MakeSpaceInBook(&StringList); + *Writer = &Project->ID.Value; + Project = Project->Parent; + } + + if(StringList.ItemCount > 0) + { + for(int i = StringList.ItemCount - 1; i >= 0; --i) { - Result = ExtendStringInBook(&C->ResolvedVariables, StringList.String[i]); + string **Reader = GetPlaceInBook(&StringList, i); + Result = ExtendStringInBook(&C->ResolvedVariables, **Reader); } - FreeStringList(&StringList); + FreeBook(&StringList); } else { @@ -2724,13 +2691,14 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_ case IDENT_OWNER: { bool Processed = FALSE; - for(int i = 0; i < Scope->PairCount; ++i) + for(int i = 0; i < Scope->Pairs.ItemCount; ++i) { - if(Scope->Pairs[i].Key == Variable) + config_pair *Pair = GetPlaceInBook(&Scope->Pairs, i); + if(Variable == Pair->Key) { - if(GetPerson(C, E, &Scope->Pairs[i])) + if(GetPerson(C, E, Pair)) { - Result = ExtendStringInBook(&C->ResolvedVariables, Scope->Pairs[i].Value); + Result = ExtendStringInBook(&C->ResolvedVariables, Pair->Value); Processed = TRUE; break; } @@ -2738,7 +2706,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_ { if(!GetError(E, S_WARNING, Position, Variable)) { - ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Owner set, but the person does not exist: ", &Scope->Pairs[i].Value); + ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Owner set, but the person does not exist: ", &Pair->Value); PushError(E, S_WARNING, Position, Variable); } Processed = TRUE; @@ -2897,36 +2865,30 @@ HasImageFileExtension(string Path) ExtensionMatches(Path, EXT_PNG); } +typedef uint64_t variant; typedef struct { string Path; - uint64_t *Variants; - uint64_t VariantsCount; + _memory_book(variant) Variants; } variant_string; -typedef struct -{ - variant_string *Variants; - uint64_t Count; -} variant_strings; - void -PushVariantUniquely(resolution_errors *E, variant_strings *VS, string Path, uint64_t Variants, config_identifier_id Identifier) +PushVariantUniquely(resolution_errors *E, memory_book *VariantStrings, string Path, variant Variants, config_identifier_id Identifier) { if(Path.Length > 0) { bool FoundPath = FALSE; - for(int i = 0; i < VS->Count; ++i) + for(int i = 0; i < VariantStrings->ItemCount; ++i) { - variant_string *This = VS->Variants + i; - if(StringsMatch(This->Path, Path)) + variant_string *ThisVariantString = GetPlaceInBook(VariantStrings, i); + if(StringsMatch(ThisVariantString->Path, Path)) { FoundPath = TRUE; bool FoundVariantsMatch = FALSE; - for(int VariantsIndex = 0; VariantsIndex < This->VariantsCount; ++VariantsIndex) + for(int VariantsIndex = 0; VariantsIndex < ThisVariantString->Variants.ItemCount; ++VariantsIndex) { - uint64_t *Test = This->Variants + VariantsIndex; - if(*Test == Variants) + variant Test = *(variant *)GetPlaceInBook(&ThisVariantString->Variants, VariantsIndex); + if(Test == Variants) { FoundVariantsMatch = TRUE; } @@ -2934,9 +2896,8 @@ PushVariantUniquely(resolution_errors *E, variant_strings *VS, string Path, uint if(!FoundVariantsMatch) { - This->Variants = Fit(This->Variants, sizeof(*This->Variants), This->VariantsCount, 4, TRUE); - This->Variants[This->VariantsCount] = Variants; - ++This->VariantsCount; + variant *ThisVariant = MakeSpaceInBook(&ThisVariantString->Variants); + *ThisVariant = Variants; PushError(E, S_ERROR, 0, Identifier); } } @@ -2944,14 +2905,12 @@ PushVariantUniquely(resolution_errors *E, variant_strings *VS, string Path, uint if(!FoundPath) { - VS->Variants = Fit(VS->Variants, sizeof(*VS->Variants), VS->Count, 8, TRUE); - variant_string *New = VS->Variants + VS->Count; - New->Path = Path; - New->Variants = Fit(New->Variants, sizeof(*New->Variants), New->VariantsCount, 4, TRUE); - New->Variants[New->VariantsCount] = Variants; - ++New->VariantsCount; + variant_string *NewVariantString = MakeSpaceInBook(VariantStrings); + NewVariantString->Path = Path; - ++VS->Count; + InitBook(&NewVariantString->Variants, sizeof(variant), 4, MBT_VARIANT); + variant *NewVariants = MakeSpaceInBook(&NewVariantString->Variants); + *NewVariants = Variants; } } } @@ -2960,21 +2919,19 @@ typedef struct { string String0; string String1; - project **Projects; - uint64_t ProjectCount; + _memory_book(project *) Projects; } config_string_association; typedef struct { - config_string_association *Associations; config_identifier_id ID0; config_identifier_id ID1; - uint64_t Count; + _memory_book(config_string_association) Associations; } config_string_associations; typedef struct { - variant_strings VariantStrings; + _memory_book(variant_string) VariantStrings; config_string_associations HMMLDirs; config_string_associations BaseDirAndSearchLocation; config_string_associations BaseDirAndPlayerLocation; @@ -2984,11 +2941,11 @@ void PushMedium(config *C, resolution_errors *E, config_verifiers *V, project *P, scope_tree *MediumTree) { // TODO(matt): Do we need to warn about incomplete medium information? - medium *Medium = GetPlaceInBook(&P->Medium, P->Medium.ItemCount); + medium *Medium = MakeSpaceInBook(&P->Medium); Medium->ID = ResolveString(C, E, MediumTree, &MediumTree->ID, FALSE); - for(int i = 0; i < MediumTree->PairCount; ++i) + for(int i = 0; i < MediumTree->Pairs.ItemCount; ++i) { - config_pair *This = MediumTree->Pairs + i; + config_pair *This = GetPlaceInBook(&MediumTree->Pairs, i); switch(This->Key) { case IDENT_ICON: { Medium->Icon = ResolveString(C, E, MediumTree, This, FALSE); } break; @@ -3000,9 +2957,9 @@ PushMedium(config *C, resolution_errors *E, config_verifiers *V, project *P, sco } } - for(int i = 0; i < MediumTree->IntPairCount; ++i) + for(int i = 0; i < MediumTree->IntPairs.ItemCount; ++i) { - config_int_pair *This = MediumTree->IntPairs + i; + config_int_pair *This = GetPlaceInBook(&MediumTree->IntPairs, i); switch(This->Key) { case IDENT_ICON_TYPE: { Medium->IconType = This->Value; } break; @@ -3011,9 +2968,9 @@ PushMedium(config *C, resolution_errors *E, config_verifiers *V, project *P, sco } } - for(int i = 0; i < MediumTree->BoolPairCount; ++i) + for(int i = 0; i < MediumTree->BoolPairs.ItemCount; ++i) { - config_bool_pair *This = MediumTree->BoolPairs + i; + config_bool_pair *This = GetPlaceInBook(&MediumTree->BoolPairs, i); switch(This->Key) { case IDENT_HIDDEN: { Medium->Hidden = This->Value; } break; @@ -3050,8 +3007,6 @@ PushMedium(config *C, resolution_errors *E, config_verifiers *V, project *P, sco default: break; } } - - ++P->Medium.ItemCount; } medium * @@ -3073,11 +3028,11 @@ GetMediumFromProject(project *P, string ID) void PushSupport(config *C, resolution_errors *E, config_verifiers *V, person *P, scope_tree *SupportTree) { - support *Support = GetPlaceInBook(&P->Support, P->Support.ItemCount); + support *Support = MakeSpaceInBook(&P->Support); Support->ID = ResolveString(C, E, SupportTree, &SupportTree->ID, FALSE); - for(int i = 0; i < SupportTree->PairCount; ++i) + for(int i = 0; i < SupportTree->Pairs.ItemCount; ++i) { - config_pair *This = SupportTree->Pairs + i; + config_pair *This = GetPlaceInBook(&SupportTree->Pairs, i); switch(This->Key) { case IDENT_ICON: { Support->Icon = StripSlashes(ResolveString(C, E, SupportTree, This, FALSE), P_REL); } break; @@ -3088,9 +3043,9 @@ PushSupport(config *C, resolution_errors *E, config_verifiers *V, person *P, sco } } - for(int i = 0; i < SupportTree->IntPairCount; ++i) + for(int i = 0; i < SupportTree->IntPairs.ItemCount; ++i) { - config_int_pair *This = SupportTree->IntPairs + i; + config_int_pair *This = GetPlaceInBook(&SupportTree->IntPairs, i); switch(This->Key) { case IDENT_ICON_TYPE: { Support->IconType = This->Value; } break; @@ -3127,8 +3082,6 @@ PushSupport(config *C, resolution_errors *E, config_verifiers *V, person *P, sco default: break; } } - - ++P->Support.ItemCount; } void @@ -3136,27 +3089,27 @@ PushPersonOntoConfig(config *C, resolution_errors *E, config_verifiers *V, scope { //PrintFunctionName("PushPersonOntoConfig()"); //PrintScopeTree(PersonTree); - person *This = GetPlaceInBook(&C->Person, C->Person.ItemCount); + person *This = MakeSpaceInBook(&C->Person); This->ID = ResolveString(C, E, PersonTree, &PersonTree->ID, FALSE); - for(int i = 0; i < PersonTree->PairCount; ++i) + for(int i = 0; i < PersonTree->Pairs.ItemCount; ++i) { - if(PersonTree->Pairs[i].Key == IDENT_NAME) + config_pair *Pair = GetPlaceInBook(&PersonTree->Pairs, i); + if(IDENT_NAME == Pair->Key) { - This->Name = ResolveString(C, E, PersonTree, &PersonTree->Pairs[i], FALSE); + This->Name = ResolveString(C, E, PersonTree, Pair, FALSE); } - else if(PersonTree->Pairs[i].Key == IDENT_HOMEPAGE) + else if(IDENT_HOMEPAGE == Pair->Key) { - This->Homepage = ResolveString(C, E, PersonTree, &PersonTree->Pairs[i], FALSE); + This->Homepage = ResolveString(C, E, PersonTree, Pair, FALSE); } } InitBook(&This->Support, sizeof(support), 2, MBT_SUPPORT); - for(int i = 0; i < PersonTree->TreeCount; ++i) + for(int i = 0; i < PersonTree->Trees.ItemCount; ++i) { - PushSupport(C, E, V, This, &PersonTree->Trees[i]); + scope_tree *ThisSupport = GetPlaceInBook(&PersonTree->Trees, i); + PushSupport(C, E, V, This, ThisSupport); } - - ++C->Person.ItemCount; } void @@ -3169,21 +3122,18 @@ PushPersonOntoProject(config *C, resolution_errors *E, project *P, config_pair * { case IDENT_INDEXER: { - person **Indexer = GetPlaceInBook(&P->Indexer, P->Indexer.ItemCount); + person **Indexer = MakeSpaceInBook(&P->Indexer); *Indexer = Person; - ++P->Indexer.ItemCount; } break; case IDENT_COHOST: { - person **CoHost = GetPlaceInBook(&P->CoHost, P->CoHost.ItemCount); + person **CoHost = MakeSpaceInBook(&P->CoHost); *CoHost = Person; - ++P->CoHost.ItemCount; } break; case IDENT_GUEST: { - person **Guest = GetPlaceInBook(&P->Guest, P->Guest.ItemCount); + person **Guest = MakeSpaceInBook(&P->Guest); *Guest = Person; - ++P->Guest.ItemCount; } break; default:; } @@ -3195,28 +3145,28 @@ void PushProjectOntoProject(config *C, resolution_errors *E, config_verifiers *V void AddProjectToAssociation(config_string_association *A, project *P) { - A->Projects = Fit(A->Projects, sizeof(*A->Projects), A->ProjectCount, 4, TRUE); - A->Projects[A->ProjectCount] = P; - ++A->ProjectCount; + project **This = MakeSpaceInBook(&A->Projects); + *This = P; } void PushAssociation(config_string_associations *HMMLDirs, string *S0, string *S1, project *P) { - HMMLDirs->Associations = Fit(HMMLDirs->Associations, sizeof(*HMMLDirs->Associations), HMMLDirs->Count, 8, TRUE); - if(S0) { HMMLDirs->Associations[HMMLDirs->Count].String0 = *S0; } - if(S1) { HMMLDirs->Associations[HMMLDirs->Count].String1 = *S1; } - AddProjectToAssociation(&HMMLDirs->Associations[HMMLDirs->Count], P); - ++HMMLDirs->Count; + config_string_association *This = MakeSpaceInBook(&HMMLDirs->Associations); + InitBookOfPointers(&This->Projects, 4, MBT_PROJECT_PTR); + + if(S0) { This->String0 = *S0; } + if(S1) { This->String1 = *S1; } + AddProjectToAssociation(This, P); } config_string_association * GetAssociation(config_string_associations *Set, string String0, string String1) { config_string_association *Result = 0; - for(int i = 0; i < Set->Count; ++i) + for(int i = 0; i < Set->Associations.ItemCount; ++i) { - config_string_association *This = Set->Associations + i; + config_string_association *This = GetPlaceInBook(&Set->Associations, i); if(StringsMatch(String0, This->String0) && StringsMatch(String1, This->String1)) { Result = This; @@ -3230,9 +3180,9 @@ config_string_association * GetGlobalPathAssociation(config_string_associations *Set, string Path) { config_string_association *Result = 0; - for(int i = 0; i < Set->Count; ++i) + for(int i = 0; i < Set->Associations.ItemCount; ++i) { - config_string_association *This = Set->Associations + i; + config_string_association *This = GetPlaceInBook(&Set->Associations, i); if(StringsMatchSized(Path, This->String0.Length, This->String0)) { Path = TrimString(Path, This->String0.Length, 0); @@ -3260,11 +3210,12 @@ SetUniqueHMMLDir(config *C, resolution_errors *E, config_string_associations *HM { string Result = StripSlashes(ResolveString(C, E, ProjectTree, HMMLDir, TRUE), P_ABS); bool Clashed = FALSE; - for(int i = 0; i < HMMLDirs->Count; ++i) + for(int i = 0; i < HMMLDirs->Associations.ItemCount; ++i) { - if(StringsMatch(HMMLDirs->Associations[i].String0, Result)) + config_string_association *This = GetPlaceInBook(&HMMLDirs->Associations, i); + if(StringsMatch(Result, This->String0)) { - AddProjectToAssociation(&HMMLDirs->Associations[i], P); + AddProjectToAssociation(This, P); PushError(E, S_ERROR, &HMMLDir->Position, IDENT_HMML_DIR); Clashed = TRUE; break; @@ -3282,10 +3233,10 @@ void PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, scope_tree *ProjectTree) { InitBook(&P->Medium, sizeof(medium), 8, MBT_MEDIUM); - InitBook(&P->Indexer, sizeof(person), 4, MBT_PERSON); - InitBook(&P->CoHost, sizeof(person), 4, MBT_PERSON); - InitBook(&P->Guest, sizeof(person), 4, MBT_PERSON); InitBook(&P->Child, sizeof(project), 8, MBT_PROJECT); + InitBookOfPointers(&P->Indexer, 4, MBT_PERSON_PTR); + InitBookOfPointers(&P->CoHost, 4, MBT_PERSON_PTR); + InitBookOfPointers(&P->Guest, 4, MBT_PERSON_PTR); config_string_associations *HMMLDirs = &V->HMMLDirs; P->ID = ResolveString(C, E, ProjectTree, &ProjectTree->ID, FALSE); @@ -3298,17 +3249,18 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc ResetPen(&C->ResolvedVariables); P->Lineage = DeriveLineageOfProject(C, ProjectTree); - for(int i = 0; i < ProjectTree->TreeCount; ++i) + for(int i = 0; i < ProjectTree->Trees.ItemCount; ++i) { - if(ProjectTree->Trees[i].ID.Key == IDENT_MEDIUM) + scope_tree *This = GetPlaceInBook(&ProjectTree->Trees, i); + if(This->ID.Key == IDENT_MEDIUM) { - PushMedium(C, E, V, P, &ProjectTree->Trees[i]); + PushMedium(C, E, V, P, This); } } - for(int i = 0; i < ProjectTree->PairCount; ++i) + for(int i = 0; i < ProjectTree->Pairs.ItemCount; ++i) { - config_pair *This = ProjectTree->Pairs + i; + config_pair *This = GetPlaceInBook(&ProjectTree->Pairs, i); switch(This->Key) { case IDENT_DEFAULT_MEDIUM: @@ -3411,9 +3363,9 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc } } - for(int i = 0; i < ProjectTree->IntPairCount; ++i) + for(int i = 0; i < ProjectTree->IntPairs.ItemCount; ++i) { - config_int_pair *This = ProjectTree->IntPairs + i; + config_int_pair *This = GetPlaceInBook(&ProjectTree->IntPairs, i); switch(This->Key) { case IDENT_GENRE: { P->Genre = This->Value; } break; @@ -3425,9 +3377,9 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc } } - for(int i = 0; i < ProjectTree->BoolPairCount; ++i) + for(int i = 0; i < ProjectTree->BoolPairs.ItemCount; ++i) { - config_bool_pair *This = ProjectTree->BoolPairs + i; + config_bool_pair *This = GetPlaceInBook(&ProjectTree->BoolPairs, i); switch(This->Key) { case IDENT_DENY_BESPOKE_TEMPLATES: @@ -3440,9 +3392,9 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc } } - for(int i = 0; i < ProjectTree->TreeCount; ++i) + for(int i = 0; i < ProjectTree->Trees.ItemCount; ++i) { - scope_tree *This = ProjectTree->Trees + i; + scope_tree *This = GetPlaceInBook(&ProjectTree->Trees, i); if(This->ID.Key == IDENT_PROJECT) { PushProjectOntoProject(C, E, V, P, This); @@ -3519,12 +3471,10 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc void PushProjectOntoProject(config *C, resolution_errors *E, config_verifiers *Verifiers, project *Parent, scope_tree *ProjectTree) { - project *P = GetPlaceInBook(&Parent->Child, Parent->Child.ItemCount); + project *P = MakeSpaceInBook(&Parent->Child); PushProject(C, E, Verifiers, P, ProjectTree); P->Parent = Parent; - - ++Parent->Child.ItemCount; } project * @@ -3536,7 +3486,7 @@ GetProjectFromProject(project *Parent, string ID) for(int i = 0; i < Parent->Child.ItemCount; ++i) { project *This = GetPlaceInBook(&Parent->Child, i); - if(StringsMatch(This->ID, ID)) + if(StringsMatch(ID, This->ID)) { Result = This; break; @@ -3549,11 +3499,9 @@ GetProjectFromProject(project *Parent, string ID) void PushProjectOntoConfig(config *C, resolution_errors *E, config_verifiers *Verifiers, scope_tree *ProjectTree) { - project *P = GetPlaceInBook(&C->Project, C->Project.ItemCount); + project *P = MakeSpaceInBook(&C->Project); PushProject(C, E, Verifiers, P, ProjectTree); - - ++C->Project.ItemCount; } project * @@ -3565,7 +3513,7 @@ GetProjectFromConfig(config *C, string ID) for(int i = 0; i < C->Project.ItemCount; ++i) { project *This = GetPlaceInBook(&C->Project, i); - if(StringsMatch(This->ID, ID)) + if(StringsMatch(ID, This->ID)) { Result = This; break; @@ -3578,10 +3526,10 @@ GetProjectFromConfig(config *C, string ID) void PrintAssociationClashes(config_string_associations *A) { - for(int i = 0; i < A->Count; ++i) + for(int i = 0; i < A->Associations.ItemCount; ++i) { - config_string_association *Association = A->Associations + i; - if(Association->ProjectCount > 1) + config_string_association *Association = GetPlaceInBook(&A->Associations, i); + if(Association->Projects.ItemCount > 1) { ConfigError(0, 0, S_ERROR, "Multiple projects share the same:", 0); @@ -3594,13 +3542,13 @@ PrintAssociationClashes(config_string_associations *A) PrintPair(&Assoc1, ": ", FALSE, IndentLevel, TRUE, FALSE); } fprintf(stderr, "\n"); - for(int j = 0; j < Association->ProjectCount; ++j) + for(int j = 0; j < Association->Projects.ItemCount; ++j) { - project *P = Association->Projects[j]; + project **P = GetPlaceInBook(&Association->Projects, j); fprintf(stderr, " "); - if(P) + if(*P) { - PrintStringC(CS_CYAN, P->Lineage); + PrintStringC(CS_CYAN, (*P)->Lineage); } else { @@ -3658,18 +3606,18 @@ PrintVariants(uint64_t V, colour_code ColourCode, string Margin) } void -PrintVariantInconsistencies(variant_strings *V) +PrintVariantInconsistencies(memory_book *VariantStrings) { - for(int i = 0; i < V->Count; ++i) + for(int i = 0; i < VariantStrings->ItemCount; ++i) { - variant_string *This = V->Variants + i; - if(This->VariantsCount > 1) + variant_string *ThisVariantsString = GetPlaceInBook(VariantStrings, i); + if(ThisVariantsString->Variants.ItemCount > 1) { - ConfigError(0, 0, S_ERROR, "Sprite has inconsistently set variants ", &This->Path); - for(int j = 0; j < This->VariantsCount; ++j) + ConfigError(0, 0, S_ERROR, "Sprite has inconsistently set variants ", &ThisVariantsString->Path); + for(int j = 0; j < ThisVariantsString->Variants.ItemCount; ++j) { string Margin = Wrap0(" "); - uint64_t V = This->Variants[j]; + variant V = *(variant *)GetPlaceInBook(&ThisVariantsString->Variants, j); PrintVariants(V, j % 2 ? CS_CYAN_BOLD : CS_YELLOW_BOLD, Margin); fprintf(stderr, "\n"); } @@ -3680,21 +3628,23 @@ PrintVariantInconsistencies(variant_strings *V) void FreeAssociations(config_string_associations *A) { - for(int i = 0; i < A->Count; ++i) + for(int i = 0; i < A->Associations.ItemCount; ++i) { - FreeAndResetCount(A->Associations[i].Projects, A->Associations[i].ProjectCount); + config_string_association *This = GetPlaceInBook(&A->Associations, i); + FreeBook(&This->Projects); } - FreeAndResetCount(A->Associations, A->Count); + FreeBook(&A->Associations); } void -FreeVariants(variant_strings *V) +FreeVariants(memory_book *VariantStrings) { - for(int i = 0; i < V->Count; ++i) + for(int i = 0; i < VariantStrings->ItemCount; ++i) { - FreeAndResetCount(V->Variants[i].Variants, V->Variants[i].VariantsCount); + variant_string *This = GetPlaceInBook(VariantStrings, i); + FreeBook(&This->Variants); } - FreeAndResetCount(V->Variants, V->Count); + FreeBook(VariantStrings); } void @@ -3706,178 +3656,6 @@ FreeVerifiers(config_verifiers *Verifiers) FreeVariants(&Verifiers->VariantStrings); } -config * -ResolveVariables(scope_tree *S) -{ - Assert(LOG_COUNT == ArrayCount(LogLevelStrings)); - config *Result = calloc(1, sizeof(config)); - InitBook(&Result->ResolvedVariables, 1, Kilobytes(1), MBT_STRING); - InitBook(&Result->Person, sizeof(person), 8, MBT_PERSON); - InitBook(&Result->Project, sizeof(project), 8, MBT_PROJECT); - resolution_errors Errors = {}; - config_verifiers Verifiers = {}; - Verifiers.HMMLDirs.ID0 = IDENT_HMML_DIR; - Verifiers.BaseDirAndSearchLocation.ID0 = IDENT_BASE_DIR; - Verifiers.BaseDirAndSearchLocation.ID1 = IDENT_SEARCH_LOCATION; - Verifiers.BaseDirAndPlayerLocation.ID0 = IDENT_BASE_DIR; - Verifiers.BaseDirAndPlayerLocation.ID1 = IDENT_PLAYER_LOCATION; - - for(int i = 0; i < S->PairCount; ++i) - { - switch(S->Pairs[i].Key) - { - case IDENT_DB_LOCATION: - { Result->DatabaseLocation = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], TRUE), P_ABS); } break; - case IDENT_GLOBAL_SEARCH_DIR: - { - Result->GlobalSearchDir = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], TRUE), P_ABS); - if(Result->GlobalSearchDir.Length > MAX_BASE_DIR_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->GlobalSearchDir, MAX_BASE_DIR_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_GLOBAL_SEARCH_URL: - { - Result->GlobalSearchURL = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], TRUE), P_ABS); - if(Result->GlobalSearchURL.Length > MAX_BASE_URL_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->GlobalSearchURL, MAX_BASE_URL_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_GLOBAL_TEMPLATES_DIR: - { Result->GlobalTemplatesDir = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], TRUE), P_ABS); } break; - case IDENT_GLOBAL_SEARCH_TEMPLATE: - { Result->GlobalSearchTemplatePath = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], FALSE), P_REL); } break; - case IDENT_GLOBAL_THEME: - { - Result->GlobalTheme = ResolveString(Result, &Errors, S, &S->Pairs[i], FALSE); - if(Result->GlobalTheme.Length > MAX_THEME_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->GlobalTheme, MAX_THEME_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_ASSETS_ROOT_DIR: - { - Result->AssetsRootDir = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], TRUE), P_ABS); - if(Result->AssetsRootDir.Length > MAX_ROOT_DIR_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->AssetsRootDir, MAX_ROOT_DIR_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_ASSETS_ROOT_URL: - { - Result->AssetsRootURL = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], TRUE), P_ABS); - if(Result->AssetsRootURL.Length > MAX_ROOT_URL_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->AssetsRootURL, MAX_ROOT_URL_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_CSS_PATH: - { - Result->CSSDir = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], FALSE), P_REL); - if(Result->CSSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->CSSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_IMAGES_PATH: - { - Result->ImagesDir = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], FALSE), P_REL); - if(Result->ImagesDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->ImagesDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_JS_PATH: - { - Result->JSDir = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], FALSE), P_REL); - if(Result->JSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) - { - ConfigErrorSizing(S->Pairs[i].Position.Filename, S->Pairs[i].Position.LineNumber, S->Pairs[i].Key, - &Result->JSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); - PushError(&Errors, S_ERROR, 0, S->Pairs[i].Key); - } - } break; - case IDENT_QUERY_STRING: - { Result->QueryString = ResolveString(Result, &Errors, S, &S->Pairs[i], FALSE); } break; - case IDENT_CACHE_DIR: - { Result->CacheDir = StripSlashes(ResolveString(Result, &Errors, S, &S->Pairs[i], TRUE), P_ABS); } break; - default: break; - } - } - - int SecondsPerMinute = 60; - for(int i = 0; i < S->IntPairCount; ++i) - { - switch(S->IntPairs[i].Key) - { - case IDENT_PRIVACY_CHECK_INTERVAL: - { Result->PrivacyCheckInterval = SecondsPerMinute * S->IntPairs[i].Value; } break; - case IDENT_LOG_LEVEL: - { Result->LogLevel = S->IntPairs[i].Value; } break; - default: break; - } - } - - for(int i = 0; i < S->TreeCount; ++i) - { - if(S->Trees[i].ID.Key == IDENT_PERSON) - { - PushPersonOntoConfig(Result, &Errors, &Verifiers, &S->Trees[i]); - } - } - - for(int i = 0; i < S->TreeCount; ++i) - { - if(S->Trees[i].ID.Key == IDENT_PROJECT) - { - PushProjectOntoConfig(Result, &Errors, &Verifiers, &S->Trees[i]); - } - } - - config_string_association *BaseDirAndSearchLocation = GetGlobalPathAssociation(&Verifiers.BaseDirAndSearchLocation, Result->GlobalSearchDir); - if(BaseDirAndSearchLocation) - { - PushError(&Errors, S_ERROR, 0, IDENT_GLOBAL_SEARCH_DIR); - AddProjectToAssociation(BaseDirAndSearchLocation, 0); - } - - // TODO(matt): Mandate that, if a GlobalSearchDir or GlobalSearchURL is set, then both must be set - if(!Result->GlobalTheme.Length) - { - ConfigErrorUnset(IDENT_GLOBAL_THEME); - PushError(&Errors, S_ERROR, 0, IDENT_GLOBAL_THEME); - } - - if(Errors.ErrorCount > 0) - { - PrintAssociationClashes(&Verifiers.HMMLDirs); - PrintAssociationClashes(&Verifiers.BaseDirAndSearchLocation); - PrintAssociationClashes(&Verifiers.BaseDirAndPlayerLocation); - PrintVariantInconsistencies(&Verifiers.VariantStrings); - Free(Result); - } - - FreeVerifiers(&Verifiers); - FreeErrors(&Errors); - - return Result; -} - void PrintLogLevel(char *Title, log_level Level, char *Delimiter, uint64_t Indentation, bool AppendNewline) { @@ -4198,8 +3976,7 @@ PrintPerson(person *P, config_identifier_id Role, typography *Typography) for(int i = 0; i < P->Support.ItemCount; ++i) { - support *This = GetPlaceInBook(&P->Support, i); - PrintSupport(This, Typography, IndentationLevel, &RowsRequired); + PrintSupport(GetPlaceInBook(&P->Support, i), Typography, IndentationLevel, &RowsRequired); } } @@ -4463,8 +4240,7 @@ PrintProject(project *P, typography *T, int Ancestors, int IndentationLevel, int ++Ancestors; for(int i = 0; i < P->Child.ItemCount; ++i) { - project *This = GetPlaceInBook(&P->Child, i); - PrintProject(This, T, Ancestors, IndentationLevel, TerminalColumns); + PrintProject(GetPlaceInBook(&P->Child, i), T, Ancestors, IndentationLevel, TerminalColumns); } --Ancestors; } @@ -4534,8 +4310,7 @@ PrintConfig(config *C, bool ShouldClearTerminal) PrintTitle("People", TermCols); for(int i = 0; i < C->Person.ItemCount; ++i) { - person *This = GetPlaceInBook(&C->Person, i); - PrintPerson(This, IDENT_NULL, &Typography); + PrintPerson(GetPlaceInBook(&C->Person, i), IDENT_NULL, &Typography); } fprintf(stderr, "\n"); @@ -4564,34 +4339,236 @@ FreeProject(project *P) FreeTemplate(&P->PlayerTemplate); } -void -FreeConfig(config *C) -{ - if(C) - { - for(int i = 0; i < C->Person.ItemCount; ++i) - { - person *Person = GetPlaceInBook(&C->Person, i); - FreeBook(&Person->Support); - } - FreeBook(&C->Person); - for(int i = 0; i < C->Project.ItemCount; ++i) - { - FreeProject(GetPlaceInBook(&C->Project, i)); - } - FreeBook(&C->Project); - FreeBook(&C->ResolvedVariables); - FreeTemplate(&C->SearchTemplate); +// NOTE(matt): Making this a #define permits Free() to null out the incoming C +#define FreeConfig(C)\ +{\ + if(C)\ + {\ + for(int i = 0; i < C->Person.ItemCount; ++i)\ + {\ + person *Person = GetPlaceInBook(&C->Person, i);\ + FreeBook(&Person->Support);\ + }\ + FreeBook(&C->Person);\ + for(int i = 0; i < C->Project.ItemCount; ++i)\ + {\ + FreeProject(GetPlaceInBook(&C->Project, i));\ + }\ + FreeBook(&C->Project);\ + FreeBook(&C->ResolvedVariables);\ + FreeTemplate(&C->SearchTemplate);\ +\ + Free(C);\ + }\ +}\ - Free(C); +config_verifiers +InitVerifiers(void) +{ + config_verifiers Result = {}; + InitBook(&Result.VariantStrings, sizeof(variant_string), 8, MBT_VARIANT_STRING); + + Result.HMMLDirs.ID0 = IDENT_HMML_DIR; + InitBook(&Result.HMMLDirs.Associations, sizeof(config_string_association), 8, MBT_CONFIG_STRING_ASSOCIATION); + + Result.BaseDirAndSearchLocation.ID0 = IDENT_BASE_DIR; + Result.BaseDirAndSearchLocation.ID1 = IDENT_SEARCH_LOCATION; + InitBook(&Result.BaseDirAndSearchLocation.Associations, sizeof(config_string_association), 8, MBT_CONFIG_STRING_ASSOCIATION); + + Result.BaseDirAndPlayerLocation.ID0 = IDENT_BASE_DIR; + Result.BaseDirAndPlayerLocation.ID1 = IDENT_PLAYER_LOCATION; + InitBook(&Result.BaseDirAndPlayerLocation.Associations, sizeof(config_string_association), 8, MBT_CONFIG_STRING_ASSOCIATION); + return Result; +} + +config * +ResolveVariables(scope_tree *S) +{ + Assert(LOG_COUNT == ArrayCount(LogLevelStrings)); + config *Result = calloc(1, sizeof(config)); + InitBook(&Result->ResolvedVariables, 1, Kilobytes(1), MBT_STRING); + InitBook(&Result->Person, sizeof(person), 8, MBT_PERSON); + InitBook(&Result->Project, sizeof(project), 8, MBT_PROJECT); + + resolution_errors Errors = {}; + InitBook(&Errors.Warnings, sizeof(resolution_error), 16, MBT_RESOLUTION_ERROR); + InitBook(&Errors.Errors, sizeof(resolution_error), 16, MBT_RESOLUTION_ERROR); + + config_verifiers Verifiers = InitVerifiers(); + + for(int i = 0; i < S->Pairs.ItemCount; ++i) + { + config_pair *Pair = GetPlaceInBook(&S->Pairs, i); + switch(Pair->Key) + { + case IDENT_DB_LOCATION: + { Result->DatabaseLocation = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); } break; + case IDENT_GLOBAL_SEARCH_DIR: + { + Result->GlobalSearchDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); + if(Result->GlobalSearchDir.Length > MAX_BASE_DIR_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->GlobalSearchDir, MAX_BASE_DIR_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_GLOBAL_SEARCH_URL: + { + Result->GlobalSearchURL = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); + if(Result->GlobalSearchURL.Length > MAX_BASE_URL_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->GlobalSearchURL, MAX_BASE_URL_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_GLOBAL_TEMPLATES_DIR: + { Result->GlobalTemplatesDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); } break; + case IDENT_GLOBAL_SEARCH_TEMPLATE: + { Result->GlobalSearchTemplatePath = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL); } break; + case IDENT_GLOBAL_THEME: + { + Result->GlobalTheme = ResolveString(Result, &Errors, S, Pair, FALSE); + if(Result->GlobalTheme.Length > MAX_THEME_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->GlobalTheme, MAX_THEME_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_ASSETS_ROOT_DIR: + { + Result->AssetsRootDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); + if(Result->AssetsRootDir.Length > MAX_ROOT_DIR_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->AssetsRootDir, MAX_ROOT_DIR_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_ASSETS_ROOT_URL: + { + Result->AssetsRootURL = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); + if(Result->AssetsRootURL.Length > MAX_ROOT_URL_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->AssetsRootURL, MAX_ROOT_URL_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_CSS_PATH: + { + Result->CSSDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL); + if(Result->CSSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->CSSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_IMAGES_PATH: + { + Result->ImagesDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL); + if(Result->ImagesDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->ImagesDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_JS_PATH: + { + Result->JSDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL); + if(Result->JSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) + { + ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, + &Result->JSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); + PushError(&Errors, S_ERROR, 0, Pair->Key); + } + } break; + case IDENT_QUERY_STRING: + { Result->QueryString = ResolveString(Result, &Errors, S, Pair, FALSE); } break; + case IDENT_CACHE_DIR: + { Result->CacheDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); } break; + default: break; + } } + + int SecondsPerMinute = 60; + for(int i = 0; i < S->IntPairs.ItemCount; ++i) + { + config_int_pair *IntPair = GetPlaceInBook(&S->IntPairs, i); + switch(IntPair->Key) + { + case IDENT_PRIVACY_CHECK_INTERVAL: + { Result->PrivacyCheckInterval = SecondsPerMinute * IntPair->Value; } break; + case IDENT_LOG_LEVEL: + { Result->LogLevel = IntPair->Value; } break; + default: break; + } + } + + for(int i = 0; i < S->Trees.ItemCount; ++i) + { + scope_tree *Tree = GetPlaceInBook(&S->Trees, i); + if(Tree->ID.Key == IDENT_PERSON) + { + PushPersonOntoConfig(Result, &Errors, &Verifiers, Tree); + } + } + + for(int i = 0; i < S->Trees.ItemCount; ++i) + { + scope_tree *Tree = GetPlaceInBook(&S->Trees, i); + if(Tree->ID.Key == IDENT_PROJECT) + { + PushProjectOntoConfig(Result, &Errors, &Verifiers, Tree); + } + } + + config_string_association *BaseDirAndSearchLocation = GetGlobalPathAssociation(&Verifiers.BaseDirAndSearchLocation, Result->GlobalSearchDir); + if(BaseDirAndSearchLocation) + { + PushError(&Errors, S_ERROR, 0, IDENT_GLOBAL_SEARCH_DIR); + AddProjectToAssociation(BaseDirAndSearchLocation, 0); + } + + // TODO(matt): Mandate that, if a GlobalSearchDir or GlobalSearchURL is set, then both must be set + if(!Result->GlobalTheme.Length) + { + ConfigErrorUnset(IDENT_GLOBAL_THEME); + PushError(&Errors, S_ERROR, 0, IDENT_GLOBAL_THEME); + } + + if(Errors.Errors.ItemCount > 0) + { + PrintAssociationClashes(&Verifiers.HMMLDirs); + PrintAssociationClashes(&Verifiers.BaseDirAndSearchLocation); + PrintAssociationClashes(&Verifiers.BaseDirAndPlayerLocation); + PrintVariantInconsistencies(&Verifiers.VariantStrings); + FreeConfig(Result); + } + + FreeVerifiers(&Verifiers); + FreeErrors(&Errors); + + return Result; } config * ParseConfig(string Path, memory_book *TokensList) { //PrintFunctionName("ParseConfig()"); - config_type_specs TypeSpecs = InitTypeSpecs(); + _memory_book(config_type_spec) TypeSpecs = InitTypeSpecs(); + +#if 0 + MEM_LOOP_PRE_FREE("InitTypeSpecs") + FreeTypeSpecs(&TypeSpecs); + MEM_LOOP_PRE_WORK() + TypeSpecs = InitTypeSpecs(); + MEM_LOOP_POST("InitTypeSpecs") +#endif config *Result = 0; tokens *T = Tokenise(TokensList, Path); @@ -4607,6 +4584,7 @@ ParseConfig(string Path, memory_book *TokensList) if(T) { scope_tree *ScopeTree = calloc(1, sizeof(scope_tree)); + InitScopeBooks(ScopeTree); SetTypeSpec(ScopeTree, &TypeSpecs); SetDefaults(ScopeTree, &TypeSpecs); ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0); @@ -4620,6 +4598,7 @@ ParseConfig(string Path, memory_book *TokensList) MEM_LOOP_PRE_WORK() T = Tokenise(TokensList, Path); ScopeTree = calloc(1, sizeof(scope_tree)); + InitScopeBooks(ScopeTree); SetTypeSpec(ScopeTree, &TypeSpecs); SetDefaults(ScopeTree, &TypeSpecs); ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0);