cinera.c: Sanitise Memory

Fixes / Improvements:

•   Switch all growable arrays to use memory_book, rather than realloc()
•   Lift a bunch of hardcoded string lengths and item counts
•   malloc() the MemoryArena rather than calloc(), thus saving 3 MiB
•   Reorganise HMMLToBuffers() to return from one place, the end
•   Print indexing errors in the same style as config errors / warnings

Diagnoses:

•   Identified sources of "non-freed" memory usage and marked them +MEM.
    This may aid future work on further reducing memory / cycle usage.

New config settings:

•   suppress_prompts boolean
This commit is contained in:
Matt Mascarenhas 2020-06-24 13:29:18 +01:00
parent 6da970d48c
commit 2748687839
2 changed files with 2819 additions and 2420 deletions

File diff suppressed because it is too large Load Diff

View File

@ -343,7 +343,7 @@ tokens *
PushTokens(memory_book *TokensList) PushTokens(memory_book *TokensList)
{ {
tokens *This = MakeSpaceInBook(TokensList); tokens *This = MakeSpaceInBook(TokensList);
InitBook(&This->Token, sizeof(token), 16, MBT_TOKEN); This->Token = InitBook(MBT_TOKEN, 16);
This->CurrentLine = 1; This->CurrentLine = 1;
return This; return This;
} }
@ -562,6 +562,7 @@ typedef struct
string QueryString; string QueryString;
bool RespectingPrivacy; bool RespectingPrivacy;
bool SuppressingPrompts;
time_t PrivacyCheckInterval; time_t PrivacyCheckInterval;
uint8_t LogLevel; uint8_t LogLevel;
@ -648,7 +649,8 @@ Tokenise(memory_book *TokensList, string Path)
Advancement = 2; Advancement = 2;
T.Type = TOKEN_NULL; T.Type = TOKEN_NULL;
string Char = { .Base = B->Ptr, .Length = 2 }; string Char = { .Base = B->Ptr, .Length = 2 };
ConfigError(Result->File.Path, Result->CurrentLine, S_WARNING, "Mismatched closing multiline comment marker: ", &Char); string Filepath = Wrap0(Result->File.Path);
ConfigError(&Filepath, Result->CurrentLine, S_WARNING, "Mismatched closing multiline comment marker: ", &Char);
} }
else if(!StringsDifferS(TokenStrings[TOKEN_DOUBLEQUOTE], B)) else if(!StringsDifferS(TokenStrings[TOKEN_DOUBLEQUOTE], B))
{ {
@ -730,13 +732,14 @@ Tokenise(memory_book *TokensList, string Path)
T.Type = TOKEN_NULL; T.Type = TOKEN_NULL;
string Char = GetUTF8Character(B->Ptr, B->Size - (B->Ptr - B->Location)); string Char = GetUTF8Character(B->Ptr, B->Size - (B->Ptr - B->Location));
Advancement = Char.Length; Advancement = Char.Length;
string Filepath = Wrap0(Result->File.Path);
if(Char.Base) if(Char.Base)
{ {
ConfigError(Result->File.Path, Result->CurrentLine, S_WARNING, "Unhandled character (ignored): ", &Char); ConfigError(&Filepath, Result->CurrentLine, S_WARNING, "Unhandled character (ignored): ", &Char);
} }
else else
{ {
ConfigErrorInt(Result->File.Path, Result->CurrentLine, S_WARNING, "Malformed UTF-8 bytes encountered (skipped): ", Char.Length); ConfigErrorInt(&Filepath, Result->CurrentLine, S_WARNING, "Malformed UTF-8 bytes encountered (skipped): ", Char.Length);
} }
} }
@ -838,7 +841,7 @@ PushTypeSpec(memory_book *TypeSpecs, config_identifier_id ID, bool IsPermeable)
//PrintFunctionName("PushTypeSpec()"); //PrintFunctionName("PushTypeSpec()");
config_type_spec *Result = MakeSpaceInBook(TypeSpecs); config_type_spec *Result = MakeSpaceInBook(TypeSpecs);
Result->ID = ID; Result->ID = ID;
InitBook(&Result->Field, sizeof(config_type_field), 4, MBT_CONFIG_TYPE_FIELD); Result->Field = InitBook(MBT_CONFIG_TYPE_FIELD, 4);
Result->Permeable = IsPermeable; Result->Permeable = IsPermeable;
return Result; return Result;
} }
@ -858,8 +861,7 @@ _memory_book(config_type_specs)
InitTypeSpecs(void) InitTypeSpecs(void)
{ {
//PrintFunctionName("InitTypeSpecs()"); //PrintFunctionName("InitTypeSpecs()");
memory_book Result = {}; memory_book Result = InitBook(MBT_CONFIG_TYPE_SPEC, 16);
InitBook(&Result, sizeof(config_type_spec), 16, MBT_CONFIG_TYPE_SPEC);
config_type_spec *Root = PushTypeSpec(&Result, IDENT_NULL, FALSE); 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_DIR, TRUE);
@ -909,6 +911,7 @@ InitTypeSpecs(void)
PushTypeSpecField(Root, FT_BOOLEAN, IDENT_DENY_BESPOKE_TEMPLATES, TRUE); PushTypeSpecField(Root, FT_BOOLEAN, IDENT_DENY_BESPOKE_TEMPLATES, TRUE);
PushTypeSpecField(Root, FT_BOOLEAN, IDENT_IGNORE_PRIVACY, TRUE); PushTypeSpecField(Root, FT_BOOLEAN, IDENT_IGNORE_PRIVACY, TRUE);
PushTypeSpecField(Root, FT_BOOLEAN, IDENT_SINGLE_BROWSER_TAB, TRUE); PushTypeSpecField(Root, FT_BOOLEAN, IDENT_SINGLE_BROWSER_TAB, TRUE);
PushTypeSpecField(Root, FT_BOOLEAN, IDENT_SUPPRESS_PROMPTS, TRUE);
PushTypeSpecField(Root, FT_NUMBER, IDENT_PRIVACY_CHECK_INTERVAL, TRUE); PushTypeSpecField(Root, FT_NUMBER, IDENT_PRIVACY_CHECK_INTERVAL, TRUE);
PushTypeSpecField(Root, FT_SCOPE, IDENT_INCLUDE, FALSE); PushTypeSpecField(Root, FT_SCOPE, IDENT_INCLUDE, FALSE);
PushTypeSpecField(Root, FT_SCOPE, IDENT_MEDIUM, FALSE); PushTypeSpecField(Root, FT_SCOPE, IDENT_MEDIUM, FALSE);
@ -1170,7 +1173,7 @@ SetTypeSpec(scope_tree *Type, memory_book *TypeSpecs)
//PrintTypeSpec(Spec); //PrintTypeSpec(Spec);
Type->TypeSpec.ID = Spec->ID; Type->TypeSpec.ID = Spec->ID;
Type->TypeSpec.Permeable = Spec->Permeable; Type->TypeSpec.Permeable = Spec->Permeable;
InitBook(&Type->TypeSpec.Field, sizeof(config_type_field), 4, MBT_CONFIG_TYPE_FIELD); Type->TypeSpec.Field = InitBook(MBT_CONFIG_TYPE_FIELD, 4);
for(int i = 0; i < Spec->Field.ItemCount; ++i) for(int i = 0; i < Spec->Field.ItemCount; ++i)
{ {
config_type_field *Src = GetPlaceInBook(&Spec->Field, i); config_type_field *Src = GetPlaceInBook(&Spec->Field, i);
@ -1537,10 +1540,10 @@ PushBoolPair(scope_tree *Parent, config_bool_pair *B)
void void
InitScopeBooks(scope_tree *Scope) InitScopeBooks(scope_tree *Scope)
{ {
InitBook(&Scope->Trees, sizeof(scope_tree), 4, MBT_CONFIG_PAIR); Scope->Trees = InitBook(MBT_SCOPE_TREE, 4);
InitBook(&Scope->Pairs, sizeof(config_pair), 4, MBT_CONFIG_PAIR); Scope->Pairs = InitBook(MBT_CONFIG_PAIR, 4);
InitBook(&Scope->IntPairs, sizeof(config_int_pair), 4, MBT_CONFIG_INT_PAIR); Scope->IntPairs = InitBook(MBT_CONFIG_INT_PAIR, 4);
InitBook(&Scope->BoolPairs, sizeof(config_bool_pair), 4, MBT_CONFIG_BOOL_PAIR); Scope->BoolPairs = InitBook(MBT_CONFIG_BOOL_PAIR, 4);
} }
scope_tree * scope_tree *
@ -1816,7 +1819,7 @@ PushRule(config_include_rules *R, config_identifier_id ID)
} }
void void
ParseRuleString(char *Filename, memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, config_include_rules *Rules, token *RuleString) ParseRuleString(string *Filename, memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, config_include_rules *Rules, token *RuleString)
{ {
int i = SkipWhitespaceS(&RuleString->Content, 0); int i = SkipWhitespaceS(&RuleString->Content, 0);
config_type_field *Field = 0; config_type_field *Field = 0;
@ -1908,6 +1911,7 @@ ParseIncludeRules(memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, toke
++T->CurrentIndex; ++T->CurrentIndex;
for(; T->CurrentIndex < T->Token.ItemCount;) for(; T->CurrentIndex < T->Token.ItemCount;)
{ {
string Filepath = Wrap0(T->File.Path);
if(TokenIs(T, TOKEN_IDENTIFIER)) if(TokenIs(T, TOKEN_IDENTIFIER))
{ {
if(TokenEquals(T, "allow")) if(TokenEquals(T, "allow"))
@ -1916,7 +1920,7 @@ ParseIncludeRules(memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, toke
{ {
FreeBook(&Rules->ID); FreeBook(&Rules->ID);
token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); 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); ConfigError(&Filepath, This->LineNumber, S_WARNING, "Mixture of allow and deny identifiers in \"include\" scope", 0);
return DepartIncludeAssignment(T, IncludeIdentifierTokenIndex) ? RC_SCHEME_MIXTURE : RC_SYNTAX_ERROR; return DepartIncludeAssignment(T, IncludeIdentifierTokenIndex) ? RC_SCHEME_MIXTURE : RC_SYNTAX_ERROR;
} }
Rules->Scheme = CRT_ALLOW; Rules->Scheme = CRT_ALLOW;
@ -1927,7 +1931,7 @@ ParseIncludeRules(memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, toke
{ {
FreeBook(&Rules->ID); FreeBook(&Rules->ID);
token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); 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); ConfigError(&Filepath, This->LineNumber, S_WARNING, "Mixture of allow and deny identifiers in \"include\" scope", 0);
return DepartIncludeAssignment(T, IncludeIdentifierTokenIndex) ? RC_SCHEME_MIXTURE : RC_SYNTAX_ERROR; return DepartIncludeAssignment(T, IncludeIdentifierTokenIndex) ? RC_SCHEME_MIXTURE : RC_SYNTAX_ERROR;
} }
Rules->Scheme = CRT_DENY; Rules->Scheme = CRT_DENY;
@ -1935,7 +1939,7 @@ ParseIncludeRules(memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, toke
else else
{ {
token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); token *This = GetPlaceInBook(&T->Token, T->CurrentIndex);
ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Invalid identifier in \"include\" scope: ", &This->Content); ConfigError(&Filepath, This->LineNumber, S_WARNING, "Invalid identifier in \"include\" scope: ", &This->Content);
fprintf(stderr, fprintf(stderr,
" Valid identifiers:\n" " Valid identifiers:\n"
" allow\n" " allow\n"
@ -1947,7 +1951,7 @@ ParseIncludeRules(memory_book *TypeSpecs, config_type_spec *ParentTypeSpec, toke
if(!ExpectToken(T, TOKEN_ASSIGN, 0)) { FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; } if(!ExpectToken(T, TOKEN_ASSIGN, 0)) { FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; }
token RuleString = {}; token RuleString = {};
if(!ExpectToken(T, TOKEN_STRING, &RuleString)) { FreeBook(&Rules->ID); 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); ParseRuleString(&Filepath, TypeSpecs, ParentTypeSpec, Rules, &RuleString);
if(!ExpectToken(T, TOKEN_SEMICOLON, 0)) { FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; } if(!ExpectToken(T, TOKEN_SEMICOLON, 0)) { FreeBook(&Rules->ID); return RC_SYNTAX_ERROR; }
} }
else if(TokenIs(T, TOKEN_CLOSE_BRACE)) else if(TokenIs(T, TOKEN_CLOSE_BRACE))
@ -2051,6 +2055,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
scope_tree *Parent = Tree; scope_tree *Parent = Tree;
for(T->CurrentIndex = 0; T->CurrentIndex < T->Token.ItemCount;) for(T->CurrentIndex = 0; T->CurrentIndex < T->Token.ItemCount;)
{ {
string Filepath = Wrap0(T->File.Path);
if(TokenIs(T, TOKEN_IDENTIFIER)) if(TokenIs(T, TOKEN_IDENTIFIER))
{ {
config_type_field *Field = CurrentFieldIsInSpec(&Parent->TypeSpec, T); config_type_field *Field = CurrentFieldIsInSpec(&Parent->TypeSpec, T);
@ -2061,7 +2066,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
if(Field->IsSetLocally && Field->Singleton) if(Field->IsSetLocally && Field->Singleton)
{ {
token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); token *This = GetPlaceInBook(&T->Token, T->CurrentIndex);
ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Field already set: ", &This->Content); ConfigError(&Filepath, This->LineNumber, S_WARNING, "Field already set: ", &This->Content);
} }
// NOTE(matt): If we get rid of FT_BARE, then the ++T->CurrentIndex that all cases perform could happen // NOTE(matt): If we get rid of FT_BARE, then the ++T->CurrentIndex that all cases perform could happen
// right here // right here
@ -2098,7 +2103,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
BoolPair.Position.LineNumber = Value.LineNumber; BoolPair.Position.LineNumber = Value.LineNumber;
if(!ExpectToken(T, TOKEN_SEMICOLON, 0)) { FreeScopeTree(Tree); return 0; } if(!ExpectToken(T, TOKEN_SEMICOLON, 0)) { FreeScopeTree(Tree); return 0; }
bool Bool = GetBoolFromString(T->File.Path, &Value); bool Bool = GetBoolFromString(&Filepath, &Value);
if(Bool != -1) if(Bool != -1)
{ {
BoolPair.Value = Bool; BoolPair.Value = Bool;
@ -2128,7 +2133,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
if(Field->ID == IDENT_NUMBERING_SCHEME) if(Field->ID == IDENT_NUMBERING_SCHEME)
{ {
numbering_scheme NumberingScheme = GetNumberingSchemeFromString(T->File.Path, &Value); numbering_scheme NumberingScheme = GetNumberingSchemeFromString(&Filepath, &Value);
if(NumberingScheme != NS_COUNT) if(NumberingScheme != NS_COUNT)
{ {
IntPair.Value = NumberingScheme; IntPair.Value = NumberingScheme;
@ -2146,7 +2151,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
} }
else if(Field->ID == IDENT_LOG_LEVEL) else if(Field->ID == IDENT_LOG_LEVEL)
{ {
log_level LogLevel = GetLogLevelFromString(T->File.Path, &Value); log_level LogLevel = GetLogLevelFromString(&Filepath, &Value);
if(LogLevel != LOG_COUNT) if(LogLevel != LOG_COUNT)
{ {
IntPair.Value = LogLevel; IntPair.Value = LogLevel;
@ -2164,7 +2169,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
} }
else if(Field->ID == IDENT_GENRE) else if(Field->ID == IDENT_GENRE)
{ {
genre Genre = GetGenreFromString(T->File.Path, &Value); genre Genre = GetGenreFromString(&Filepath, &Value);
if(Genre != GENRE_COUNT) if(Genre != GENRE_COUNT)
{ {
IntPair.Value = Genre; IntPair.Value = Genre;
@ -2182,7 +2187,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
} }
else if(Field->ID == IDENT_ICON_TYPE) else if(Field->ID == IDENT_ICON_TYPE)
{ {
icon_type IconType = GetIconTypeFromString(T->File.Path, &Value); icon_type IconType = GetIconTypeFromString(&Filepath, &Value);
if(IconType != IT_COUNT) if(IconType != IT_COUNT)
{ {
IntPair.Value = IconType; IntPair.Value = IconType;
@ -2200,7 +2205,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
} }
else if(Field->ID == IDENT_ART_VARIANTS || Field->ID == IDENT_ICON_VARIANTS) else if(Field->ID == IDENT_ART_VARIANTS || Field->ID == IDENT_ICON_VARIANTS)
{ {
int64_t ArtVariants = ParseArtVariantsString(T->File.Path, &Value); int64_t ArtVariants = ParseArtVariantsString(&Filepath, &Value);
if(ArtVariants != -1) if(ArtVariants != -1)
{ {
IntPair.Value = ArtVariants; IntPair.Value = ArtVariants;
@ -2268,7 +2273,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
{ {
int IncludePathTokenIndex = T->CurrentIndex - 1; int IncludePathTokenIndex = T->CurrentIndex - 1;
config_include_rules Rules = {}; config_include_rules Rules = {};
InitBook(&Rules.ID, sizeof(config_identifier_id), 4, MBT_CONFIG_IDENTIFIER_ID); Rules.ID = InitBook(MBT_CONFIG_IDENTIFIER_ID, 4);
switch(ParseIncludeRules(TypeSpecs, &Parent->TypeSpec, T, &Rules)) switch(ParseIncludeRules(TypeSpecs, &Parent->TypeSpec, T, &Rules))
{ {
case RC_SUCCESS: case RC_SUCCESS:
@ -2304,7 +2309,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
else else
{ {
token *This = GetPlaceInBook(&T->Token, IncludePathTokenIndex); token *This = GetPlaceInBook(&T->Token, IncludePathTokenIndex);
ConfigFileIncludeError(T->File.Path, This->LineNumber, Wrap0(IncludePath)); ConfigFileIncludeError(&Filepath, This->LineNumber, Wrap0(IncludePath));
} }
Free(IncludePath); Free(IncludePath);
} break; } break;
@ -2392,14 +2397,14 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
else else
{ {
token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); token *This = GetPlaceInBook(&T->Token, T->CurrentIndex);
ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Field not allowed: ", &This->Content); ConfigError(&Filepath, This->LineNumber, S_WARNING, "Field not allowed: ", &This->Content);
DepartAssignment(T); DepartAssignment(T);
} }
} }
else else
{ {
token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); token *This = GetPlaceInBook(&T->Token, T->CurrentIndex);
ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Invalid field: ", &This->Content); ConfigError(&Filepath, This->LineNumber, S_WARNING, "Invalid field: ", &This->Content);
if(!DepartAssignment(T)) if(!DepartAssignment(T))
{ {
FreeScopeTree(Tree); FreeScopeTree(Tree);
@ -2412,7 +2417,7 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
if(!Parent->Parent) if(!Parent->Parent)
{ {
token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); token *This = GetPlaceInBook(&T->Token, T->CurrentIndex);
ConfigError(T->File.Path, This->LineNumber, S_ERROR, "Syntax error: Unpaired closing brace", 0); ConfigError(&Filepath, This->LineNumber, S_ERROR, "Syntax error: Unpaired closing brace", 0);
FreeScopeTree(Tree); FreeScopeTree(Tree);
return 0; return 0;
} }
@ -2552,7 +2557,8 @@ GetPerson(config *C, resolution_errors *E, config_pair *PersonID)
if(!GetError(E, S_WARNING, &PersonID->Position, IDENT_PERSON)) if(!GetError(E, S_WARNING, &PersonID->Position, IDENT_PERSON))
{ {
ConfigError(PersonID->Position.Filename, PersonID->Position.LineNumber, S_WARNING, "Could not find person: ", &PersonID->Value); string Filepath = Wrap0(PersonID->Position.Filename);
ConfigError(&Filepath, PersonID->Position.LineNumber, S_WARNING, "Could not find person: ", &PersonID->Value);
PushError(E, S_WARNING, &PersonID->Position, IDENT_PERSON); PushError(E, S_WARNING, &PersonID->Position, IDENT_PERSON);
} }
return 0; return 0;
@ -2562,8 +2568,7 @@ string
DeriveLineageOfProject(config *C, scope_tree *Project) DeriveLineageOfProject(config *C, scope_tree *Project)
{ {
string Result = {}; string Result = {};
memory_book StringList = {}; memory_book StringList = InitBookOfPointers(MBT_STRING_PTR, 4);
InitBookOfPointers(&StringList, 4, MBT_STRING_PTR);
if(Project) if(Project)
{ {
string **Writer = MakeSpaceInBook(&StringList); string **Writer = MakeSpaceInBook(&StringList);
@ -2642,6 +2647,7 @@ string
ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_identifier_id Variable, token_position *Position) ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_identifier_id Variable, token_position *Position)
{ {
string Result = {}; string Result = {};
string Filepath = Wrap0(Position->Filename);
switch(Variable) switch(Variable)
{ {
case IDENT_LINEAGE: case IDENT_LINEAGE:
@ -2655,7 +2661,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_
string This = Wrap0(ConfigIdentifiers[Variable].String); string This = Wrap0(ConfigIdentifiers[Variable].String);
if(!GetError(E, S_WARNING, Position, Variable)) if(!GetError(E, S_WARNING, Position, Variable))
{ {
ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This); ConfigError(&Filepath, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This);
PushError(E, S_WARNING, Position, Variable); PushError(E, S_WARNING, Position, Variable);
} }
} }
@ -2671,7 +2677,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_
string This = Wrap0(ConfigIdentifiers[Variable].String); string This = Wrap0(ConfigIdentifiers[Variable].String);
if(!GetError(E, S_WARNING, Position, Variable)) if(!GetError(E, S_WARNING, Position, Variable))
{ {
ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This); ConfigError(&Filepath, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This);
PushError(E, S_WARNING, Position, Variable); PushError(E, S_WARNING, Position, Variable);
} }
} }
@ -2691,7 +2697,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_
string This = Wrap0(ConfigIdentifiers[Variable].String); string This = Wrap0(ConfigIdentifiers[Variable].String);
if(!GetError(E, S_WARNING, Position, Variable)) if(!GetError(E, S_WARNING, Position, Variable))
{ {
ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This); ConfigError(&Filepath, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This);
PushError(E, S_WARNING, Position, Variable); PushError(E, S_WARNING, Position, Variable);
} }
} }
@ -2714,7 +2720,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_
{ {
if(!GetError(E, S_WARNING, Position, Variable)) if(!GetError(E, S_WARNING, Position, Variable))
{ {
ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Owner set, but the person does not exist: ", &Pair->Value); ConfigError(&Filepath, Position->LineNumber, S_WARNING, "Owner set, but the person does not exist: ", &Pair->Value);
PushError(E, S_WARNING, Position, Variable); PushError(E, S_WARNING, Position, Variable);
} }
Processed = TRUE; Processed = TRUE;
@ -2725,7 +2731,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_
{ {
if(!GetError(E, S_WARNING, Position, Variable)) if(!GetError(E, S_WARNING, Position, Variable))
{ {
ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "No owner set", 0); ConfigError(&Filepath, Position->LineNumber, S_WARNING, "No owner set", 0);
PushError(E, S_WARNING, Position, Variable); PushError(E, S_WARNING, Position, Variable);
} }
} }
@ -2749,7 +2755,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_
string This = Wrap0(ConfigIdentifiers[Variable].String); string This = Wrap0(ConfigIdentifiers[Variable].String);
if(!GetError(E, S_WARNING, Position, Variable)) if(!GetError(E, S_WARNING, Position, Variable))
{ {
ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This); ConfigError(&Filepath, Position->LineNumber, S_WARNING, "Variable could not be resolved: ", &This);
PushError(E, S_WARNING, Position, Variable); PushError(E, S_WARNING, Position, Variable);
} }
} }
@ -2759,7 +2765,7 @@ ResolveLocalVariable(config *C, resolution_errors *E, scope_tree *Scope, config_
if(!GetError(E, S_WARNING, Position, Variable)) if(!GetError(E, S_WARNING, Position, Variable))
{ {
string This = Wrap0(ConfigIdentifiers[Variable].String); string This = Wrap0(ConfigIdentifiers[Variable].String);
ConfigError(Position->Filename, Position->LineNumber, S_WARNING, "Unhandled local variable: ", &This); ConfigError(&Filepath, Position->LineNumber, S_WARNING, "Unhandled local variable: ", &This);
PushError(E, S_WARNING, Position, Variable); PushError(E, S_WARNING, Position, Variable);
} }
} break; } break;
@ -2916,7 +2922,7 @@ PushVariantUniquely(resolution_errors *E, memory_book *VariantStrings, string Pa
variant_string *NewVariantString = MakeSpaceInBook(VariantStrings); variant_string *NewVariantString = MakeSpaceInBook(VariantStrings);
NewVariantString->Path = Path; NewVariantString->Path = Path;
InitBook(&NewVariantString->Variants, sizeof(variant), 4, MBT_VARIANT); NewVariantString->Variants = InitBook(MBT_VARIANT, 4);
variant *NewVariants = MakeSpaceInBook(&NewVariantString->Variants); variant *NewVariants = MakeSpaceInBook(&NewVariantString->Variants);
*NewVariants = Variants; *NewVariants = Variants;
} }
@ -3112,7 +3118,7 @@ PushPersonOntoConfig(config *C, resolution_errors *E, config_verifiers *V, scope
} }
} }
InitBook(&This->Support, sizeof(support), 2, MBT_SUPPORT); This->Support = InitBook(MBT_SUPPORT, 2);
for(int i = 0; i < PersonTree->Trees.ItemCount; ++i) for(int i = 0; i < PersonTree->Trees.ItemCount; ++i)
{ {
scope_tree *ThisSupport = GetPlaceInBook(&PersonTree->Trees, i); scope_tree *ThisSupport = GetPlaceInBook(&PersonTree->Trees, i);
@ -3161,7 +3167,7 @@ void
PushAssociation(config_string_associations *HMMLDirs, string *S0, string *S1, project *P) PushAssociation(config_string_associations *HMMLDirs, string *S0, string *S1, project *P)
{ {
config_string_association *This = MakeSpaceInBook(&HMMLDirs->Associations); config_string_association *This = MakeSpaceInBook(&HMMLDirs->Associations);
InitBookOfPointers(&This->Projects, 4, MBT_PROJECT_PTR); This->Projects = InitBookOfPointers(MBT_PROJECT_PTR, 4);
if(S0) { This->String0 = *S0; } if(S0) { This->String0 = *S0; }
if(S1) { This->String1 = *S1; } if(S1) { This->String1 = *S1; }
@ -3240,17 +3246,18 @@ SetUniqueHMMLDir(config *C, resolution_errors *E, config_string_associations *HM
void void
PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, scope_tree *ProjectTree) PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, scope_tree *ProjectTree)
{ {
InitBook(&P->Medium, sizeof(medium), 8, MBT_MEDIUM); P->Medium = InitBook(MBT_MEDIUM, 8);
InitBook(&P->Child, sizeof(project), 8, MBT_PROJECT); P->Child = InitBook(MBT_PROJECT, 8);
InitBookOfPointers(&P->Indexer, 4, MBT_PERSON_PTR); P->Indexer = InitBookOfPointers(MBT_PERSON_PTR, 4);
InitBookOfPointers(&P->CoHost, 4, MBT_PERSON_PTR); P->CoHost = InitBookOfPointers(MBT_PERSON_PTR, 4);
InitBookOfPointers(&P->Guest, 4, MBT_PERSON_PTR); P->Guest = InitBookOfPointers(MBT_PERSON_PTR, 4);
config_string_associations *HMMLDirs = &V->HMMLDirs; config_string_associations *HMMLDirs = &V->HMMLDirs;
P->ID = ResolveString(C, E, ProjectTree, &ProjectTree->ID, FALSE); P->ID = ResolveString(C, E, ProjectTree, &ProjectTree->ID, FALSE);
if(P->ID.Length > MAX_PROJECT_ID_LENGTH) if(P->ID.Length > MAX_PROJECT_ID_LENGTH)
{ {
ConfigErrorSizing(ProjectTree->ID.Position.Filename, ProjectTree->ID.Position.LineNumber, IDENT_PROJECT, &P->ID, MAX_PROJECT_ID_LENGTH); string Filepath = Wrap0(ProjectTree->ID.Position.Filename);
ConfigErrorSizing(&Filepath, ProjectTree->ID.Position.LineNumber, IDENT_PROJECT, &P->ID, MAX_PROJECT_ID_LENGTH);
PushError(E, S_ERROR, 0, IDENT_PROJECT); PushError(E, S_ERROR, 0, IDENT_PROJECT);
} }
@ -3269,6 +3276,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
for(int i = 0; i < ProjectTree->Pairs.ItemCount; ++i) for(int i = 0; i < ProjectTree->Pairs.ItemCount; ++i)
{ {
config_pair *This = GetPlaceInBook(&ProjectTree->Pairs, i); config_pair *This = GetPlaceInBook(&ProjectTree->Pairs, i);
string Filepath = Wrap0(This->Position.Filename);
switch(This->Key) switch(This->Key)
{ {
case IDENT_DEFAULT_MEDIUM: case IDENT_DEFAULT_MEDIUM:
@ -3290,7 +3298,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
{ P->Theme = ResolveString(C, E, ProjectTree, This, FALSE); { P->Theme = ResolveString(C, E, ProjectTree, This, FALSE);
if(P->Theme.Length > MAX_THEME_LENGTH) if(P->Theme.Length > MAX_THEME_LENGTH)
{ {
ConfigErrorSizing(This->Position.Filename, This->Position.LineNumber, This->Key, ConfigErrorSizing(&Filepath, This->Position.LineNumber, This->Key,
&P->Theme, MAX_THEME_LENGTH); &P->Theme, MAX_THEME_LENGTH);
PushError(E, S_ERROR, 0, This->Key); PushError(E, S_ERROR, 0, This->Key);
} }
@ -3300,7 +3308,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
P->Title = ResolveString(C, E, ProjectTree, This, FALSE); P->Title = ResolveString(C, E, ProjectTree, This, FALSE);
if(P->Title.Length > MAX_PROJECT_NAME_LENGTH) if(P->Title.Length > MAX_PROJECT_NAME_LENGTH)
{ {
ConfigErrorSizing(This->Position.Filename, This->Position.LineNumber, This->Key, ConfigErrorSizing(&Filepath, This->Position.LineNumber, This->Key,
&P->Title, MAX_PROJECT_NAME_LENGTH); &P->Title, MAX_PROJECT_NAME_LENGTH);
PushError(E, S_ERROR, 0, This->Key); PushError(E, S_ERROR, 0, This->Key);
} }
@ -3317,7 +3325,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
P->BaseDir = StripSlashes(ResolveString(C, E, ProjectTree, This, TRUE), P_ABS); P->BaseDir = StripSlashes(ResolveString(C, E, ProjectTree, This, TRUE), P_ABS);
if(P->BaseDir.Length > MAX_BASE_DIR_LENGTH) if(P->BaseDir.Length > MAX_BASE_DIR_LENGTH)
{ {
ConfigErrorSizing(This->Position.Filename, This->Position.LineNumber, This->Key, ConfigErrorSizing(&Filepath, This->Position.LineNumber, This->Key,
&P->BaseDir, MAX_BASE_DIR_LENGTH); &P->BaseDir, MAX_BASE_DIR_LENGTH);
PushError(E, S_ERROR, 0, This->Key); PushError(E, S_ERROR, 0, This->Key);
} }
@ -3327,7 +3335,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
P->BaseURL = ResolveString(C, E, ProjectTree, This, FALSE); P->BaseURL = ResolveString(C, E, ProjectTree, This, FALSE);
if(P->BaseURL.Length > MAX_BASE_URL_LENGTH) if(P->BaseURL.Length > MAX_BASE_URL_LENGTH)
{ {
ConfigErrorSizing(This->Position.Filename, This->Position.LineNumber, This->Key, ConfigErrorSizing(&Filepath, This->Position.LineNumber, This->Key,
&P->BaseURL, MAX_BASE_URL_LENGTH); &P->BaseURL, MAX_BASE_URL_LENGTH);
PushError(E, S_ERROR, 0, This->Key); PushError(E, S_ERROR, 0, This->Key);
} }
@ -3337,7 +3345,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
P->PlayerLocation = StripSlashes(ResolveString(C, E, ProjectTree, This, FALSE), P_REL); P->PlayerLocation = StripSlashes(ResolveString(C, E, ProjectTree, This, FALSE), P_REL);
if(P->PlayerLocation.Length > MAX_RELATIVE_PAGE_LOCATION_LENGTH) if(P->PlayerLocation.Length > MAX_RELATIVE_PAGE_LOCATION_LENGTH)
{ {
ConfigErrorSizing(This->Position.Filename, This->Position.LineNumber, This->Key, ConfigErrorSizing(&Filepath, This->Position.LineNumber, This->Key,
&P->PlayerLocation, MAX_RELATIVE_PAGE_LOCATION_LENGTH); &P->PlayerLocation, MAX_RELATIVE_PAGE_LOCATION_LENGTH);
PushError(E, S_ERROR, 0, This->Key); PushError(E, S_ERROR, 0, This->Key);
} }
@ -3347,7 +3355,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *P, sc
P->SearchLocation = StripSlashes(ResolveString(C, E, ProjectTree, This, FALSE), P_REL); P->SearchLocation = StripSlashes(ResolveString(C, E, ProjectTree, This, FALSE), P_REL);
if(P->SearchLocation.Length > MAX_RELATIVE_PAGE_LOCATION_LENGTH) if(P->SearchLocation.Length > MAX_RELATIVE_PAGE_LOCATION_LENGTH)
{ {
ConfigErrorSizing(This->Position.Filename, This->Position.LineNumber, This->Key, ConfigErrorSizing(&Filepath, This->Position.LineNumber, This->Key,
&P->SearchLocation, MAX_RELATIVE_PAGE_LOCATION_LENGTH); &P->SearchLocation, MAX_RELATIVE_PAGE_LOCATION_LENGTH);
PushError(E, S_ERROR, 0, This->Key); PushError(E, S_ERROR, 0, This->Key);
} }
@ -4374,18 +4382,18 @@ config_verifiers
InitVerifiers(void) InitVerifiers(void)
{ {
config_verifiers Result = {}; config_verifiers Result = {};
InitBook(&Result.VariantStrings, sizeof(variant_string), 8, MBT_VARIANT_STRING); Result.VariantStrings = InitBook(MBT_VARIANT_STRING, 8);
Result.HMMLDirs.ID0 = IDENT_HMML_DIR; Result.HMMLDirs.ID0 = IDENT_HMML_DIR;
InitBook(&Result.HMMLDirs.Associations, sizeof(config_string_association), 8, MBT_CONFIG_STRING_ASSOCIATION); Result.HMMLDirs.Associations = InitBook(MBT_CONFIG_STRING_ASSOCIATION, 8);
Result.BaseDirAndSearchLocation.ID0 = IDENT_BASE_DIR; Result.BaseDirAndSearchLocation.ID0 = IDENT_BASE_DIR;
Result.BaseDirAndSearchLocation.ID1 = IDENT_SEARCH_LOCATION; Result.BaseDirAndSearchLocation.ID1 = IDENT_SEARCH_LOCATION;
InitBook(&Result.BaseDirAndSearchLocation.Associations, sizeof(config_string_association), 8, MBT_CONFIG_STRING_ASSOCIATION); Result.BaseDirAndSearchLocation.Associations = InitBook(MBT_CONFIG_STRING_ASSOCIATION, 8);
Result.BaseDirAndPlayerLocation.ID0 = IDENT_BASE_DIR; Result.BaseDirAndPlayerLocation.ID0 = IDENT_BASE_DIR;
Result.BaseDirAndPlayerLocation.ID1 = IDENT_PLAYER_LOCATION; Result.BaseDirAndPlayerLocation.ID1 = IDENT_PLAYER_LOCATION;
InitBook(&Result.BaseDirAndPlayerLocation.Associations, sizeof(config_string_association), 8, MBT_CONFIG_STRING_ASSOCIATION); Result.BaseDirAndPlayerLocation.Associations = InitBook(MBT_CONFIG_STRING_ASSOCIATION, 8);
return Result; return Result;
} }
@ -4394,19 +4402,20 @@ ResolveVariables(scope_tree *S)
{ {
Assert(LOG_COUNT == ArrayCount(LogLevelStrings)); Assert(LOG_COUNT == ArrayCount(LogLevelStrings));
config *Result = calloc(1, sizeof(config)); config *Result = calloc(1, sizeof(config));
InitBook(&Result->ResolvedVariables, 1, Kilobytes(1), MBT_STRING); Result->ResolvedVariables = InitBookOfStrings(Kilobytes(1));
InitBook(&Result->Person, sizeof(person), 8, MBT_PERSON); Result->Person = InitBook(MBT_PERSON, 8);
InitBook(&Result->Project, sizeof(project), 8, MBT_PROJECT); Result->Project = InitBook(MBT_PROJECT, 8);
resolution_errors Errors = {}; resolution_errors Errors = {};
InitBook(&Errors.Warnings, sizeof(resolution_error), 16, MBT_RESOLUTION_ERROR); Errors.Warnings = InitBook(MBT_RESOLUTION_ERROR, 16);
InitBook(&Errors.Errors, sizeof(resolution_error), 16, MBT_RESOLUTION_ERROR); Errors.Errors = InitBook(MBT_RESOLUTION_ERROR, 16);
config_verifiers Verifiers = InitVerifiers(); config_verifiers Verifiers = InitVerifiers();
for(int i = 0; i < S->Pairs.ItemCount; ++i) for(int i = 0; i < S->Pairs.ItemCount; ++i)
{ {
config_pair *Pair = GetPlaceInBook(&S->Pairs, i); config_pair *Pair = GetPlaceInBook(&S->Pairs, i);
string Filepath = Wrap0(Pair->Position.Filename);
switch(Pair->Key) switch(Pair->Key)
{ {
case IDENT_DB_LOCATION: case IDENT_DB_LOCATION:
@ -4416,7 +4425,7 @@ ResolveVariables(scope_tree *S)
Result->GlobalSearchDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); Result->GlobalSearchDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS);
if(Result->GlobalSearchDir.Length > MAX_BASE_DIR_LENGTH) if(Result->GlobalSearchDir.Length > MAX_BASE_DIR_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->GlobalSearchDir, MAX_BASE_DIR_LENGTH); &Result->GlobalSearchDir, MAX_BASE_DIR_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4426,7 +4435,7 @@ ResolveVariables(scope_tree *S)
Result->GlobalSearchURL = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); Result->GlobalSearchURL = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS);
if(Result->GlobalSearchURL.Length > MAX_BASE_URL_LENGTH) if(Result->GlobalSearchURL.Length > MAX_BASE_URL_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->GlobalSearchURL, MAX_BASE_URL_LENGTH); &Result->GlobalSearchURL, MAX_BASE_URL_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4440,7 +4449,7 @@ ResolveVariables(scope_tree *S)
Result->GlobalTheme = ResolveString(Result, &Errors, S, Pair, FALSE); Result->GlobalTheme = ResolveString(Result, &Errors, S, Pair, FALSE);
if(Result->GlobalTheme.Length > MAX_THEME_LENGTH) if(Result->GlobalTheme.Length > MAX_THEME_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->GlobalTheme, MAX_THEME_LENGTH); &Result->GlobalTheme, MAX_THEME_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4450,7 +4459,7 @@ ResolveVariables(scope_tree *S)
Result->AssetsRootDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); Result->AssetsRootDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS);
if(Result->AssetsRootDir.Length > MAX_ROOT_DIR_LENGTH) if(Result->AssetsRootDir.Length > MAX_ROOT_DIR_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->AssetsRootDir, MAX_ROOT_DIR_LENGTH); &Result->AssetsRootDir, MAX_ROOT_DIR_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4460,7 +4469,7 @@ ResolveVariables(scope_tree *S)
Result->AssetsRootURL = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS); Result->AssetsRootURL = StripSlashes(ResolveString(Result, &Errors, S, Pair, TRUE), P_ABS);
if(Result->AssetsRootURL.Length > MAX_ROOT_URL_LENGTH) if(Result->AssetsRootURL.Length > MAX_ROOT_URL_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->AssetsRootURL, MAX_ROOT_URL_LENGTH); &Result->AssetsRootURL, MAX_ROOT_URL_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4470,7 +4479,7 @@ ResolveVariables(scope_tree *S)
Result->CSSDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL); Result->CSSDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL);
if(Result->CSSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) if(Result->CSSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->CSSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); &Result->CSSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4480,7 +4489,7 @@ ResolveVariables(scope_tree *S)
Result->ImagesDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL); Result->ImagesDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL);
if(Result->ImagesDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) if(Result->ImagesDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->ImagesDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); &Result->ImagesDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4490,7 +4499,7 @@ ResolveVariables(scope_tree *S)
Result->JSDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL); Result->JSDir = StripSlashes(ResolveString(Result, &Errors, S, Pair, FALSE), P_REL);
if(Result->JSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH) if(Result->JSDir.Length > MAX_RELATIVE_ASSET_LOCATION_LENGTH)
{ {
ConfigErrorSizing(Pair->Position.Filename, Pair->Position.LineNumber, Pair->Key, ConfigErrorSizing(&Filepath, Pair->Position.LineNumber, Pair->Key,
&Result->JSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH); &Result->JSDir, MAX_RELATIVE_ASSET_LOCATION_LENGTH);
PushError(&Errors, S_ERROR, 0, Pair->Key); PushError(&Errors, S_ERROR, 0, Pair->Key);
} }
@ -4517,6 +4526,17 @@ ResolveVariables(scope_tree *S)
} }
} }
for(int i = 0; i < S->BoolPairs.ItemCount; ++i)
{
config_bool_pair *BoolPair = GetPlaceInBook(&S->BoolPairs, i);
switch(BoolPair->Key)
{
case IDENT_SUPPRESS_PROMPTS:
{ Result->SuppressingPrompts = BoolPair->Value; } break;
default: break;
}
}
for(int i = 0; i < S->Trees.ItemCount; ++i) for(int i = 0; i < S->Trees.ItemCount; ++i)
{ {
scope_tree *Tree = GetPlaceInBook(&S->Trees, i); scope_tree *Tree = GetPlaceInBook(&S->Trees, i);