diff --git a/cinera/cinera.c b/cinera/cinera.c index a9e20e2..9718b87 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -23,7 +23,7 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 7, - .Patch = 6 + .Patch = 7 }; #include // NOTE(matt): varargs @@ -251,6 +251,7 @@ typedef enum RC_ERROR_QUOTE, RC_ERROR_SEEK, RC_FOUND, + RC_INIT, RC_INVALID_IDENTIFIER, RC_INVALID_REFERENCE, RC_INVALID_TEMPLATE, @@ -321,6 +322,7 @@ char *BufferIDStrings[] = "BID_MENU_BUFFERS_FILTER_TOPICS", "BID_MENU_BUFFERS_QUOTE", "BID_MENU_BUFFERS_REFERENCE", + "BID_NAVIGATION", "BID_NEXT_PLAYER_URL", "BID_PLAYER_BUFFERS_MAIN", "BID_PLAYER_BUFFERS_MENUS", @@ -389,6 +391,7 @@ typedef enum BID_MENU_BUFFERS_FILTER_TOPICS, BID_MENU_BUFFERS_QUOTE, BID_MENU_BUFFERS_REFERENCE, + BID_NAVIGATION, BID_NEXT_PLAYER_URL, BID_PLAYER_BUFFERS_MAIN, BID_PLAYER_BUFFERS_MENUS, @@ -417,6 +420,13 @@ typedef struct uint32_t IndentLevel; } buffer; +typedef struct +{ + buffer Buffer; + char *Path; + FILE *Handle; +} file; + typedef struct { char *Base; @@ -450,8 +460,17 @@ typedef struct memory_pen_location typedef enum { MBT_NONE, + MBT_ASSET, + MBT_MEDIUM, + MBT_NAVIGATION_BUFFER, + MBT_PERSON, + MBT_PROJECT, MBT_STRING, + MBT_SUPPORT, + MBT_TAG_OFFSET, + MBT_TOKEN, + MBT_TOKENS, } memory_book_type; typedef struct @@ -459,10 +478,12 @@ typedef struct int64_t PageCount; uint64_t PageSize; uint64_t DataWidthInBytes; + uint64_t ItemCount; memory_page *Pages; memory_pen_location *Pen; memory_book_type Type; } memory_book; +#define _memory_book(type) memory_book void InitBook(memory_book *M, uint64_t DataWidthInBytes, uint64_t ItemsPerPage, memory_book_type Type) @@ -700,8 +721,16 @@ PrintBook(memory_book *M) PrintPage(&M->Pages[i]); } } break; - case MBT_ASSET: Assert(0); break; case MBT_NONE: Assert(0); break; + case MBT_ASSET: Assert(0); break; + case MBT_MEDIUM: Assert(0); break; + case MBT_NAVIGATION_BUFFER: Assert(0); break; + case MBT_PERSON: Assert(0); break; + case MBT_PROJECT: 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; } } @@ -972,6 +1001,51 @@ ExtendString0(char **Dest, string Src) } } +file +InitFile(string *Directory, string *Filename, extension_id Extension) +{ + file Result = {}; + if(Directory) + { + ExtendString0(&Result.Path, *Directory); + ExtendString0(&Result.Path, Wrap0("/")); + } + + ExtendString0(&Result.Path, *Filename); + + if(Extension != EXT_NULL) + { + ExtendString0(&Result.Path, ExtensionStrings[Extension]); + } + return Result; +} + +rc +ReadFileIntoBuffer(file *F) +{ + rc Result = RC_ERROR_FILE; + if(F->Path) + { + if((F->Handle = fopen(F->Path, "r"))) + { + fseek(F->Handle, 0, SEEK_END); + F->Buffer.Size = ftell(F->Handle); + F->Buffer.Location = malloc(F->Buffer.Size); + F->Buffer.Ptr = F->Buffer.Location; + fseek(F->Handle, 0, SEEK_SET); + fread(F->Buffer.Location, F->Buffer.Size, 1, F->Handle); + fclose(F->Handle); + F->Handle = 0; + Result = RC_SUCCESS; + } + else + { + perror(F->Path); + } + } + return Result; +} + char *ColourStrings[] = { "\e[0m", @@ -1122,15 +1196,6 @@ char *TokenStrings[] = "Number", // Numeric }; -#define ArrayCount(A) sizeof(A)/sizeof(*(A)) - -typedef struct -{ - buffer Buffer; - char *Path; - FILE *Handle; -} file; - typedef enum { FID_NULL, @@ -1569,18 +1634,11 @@ typedef struct typedef struct { file File; - uint64_t Count; - token *Token; + _memory_book(token) Token; uint64_t CurrentIndex; uint64_t CurrentLine; } tokens; -typedef struct -{ - tokens *Tokens; - uint64_t Count; -} tokens_list; - char *ArtVariantStrings[] = { "light_normal", @@ -1726,16 +1784,17 @@ ConfigErrorInt(char *Filename, uint64_t LineNumber, severity Severity, char *Mes void ConfigErrorExpectation(tokens *T, token_type GreaterExpectation, token_type LesserExpectation) { - ConfigErrorFilenameAndLineNumber(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_ERROR); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + ConfigErrorFilenameAndLineNumber(T->File.Path, This->LineNumber, S_ERROR); fprintf(stderr, "Syntax error: Received "); - if(T->Token[T->CurrentIndex].Content.Base) + if(This->Content.Base) { - PrintStringC(CS_RED, T->Token[T->CurrentIndex].Content); + PrintStringC(CS_RED, This->Content); } else { - fprintf(stderr, "%s%ld%s", ColourStrings[CS_BLUE_BOLD], T->Token[T->CurrentIndex].int64_t, ColourStrings[CS_END]); + fprintf(stderr, "%s%ld%s", ColourStrings[CS_BLUE_BOLD], This->int64_t, ColourStrings[CS_END]); } fprintf(stderr, @@ -2395,12 +2454,6 @@ typedef enum BUILTIN_ASSETS_COUNT, } builtin_asset_id; -typedef struct -{ - int Count; - memory_book Asset; -} assets; - typedef enum { // Contents and Player Pages Mandatory @@ -2441,6 +2494,8 @@ typedef enum TAG_IMAGE, TAG_JS, TAG_NAV, + TAG_GLOBAL_NAV, + // TAG_PATHED_NAV, TAG_PROJECT, TAG_PROJECT_ID, TAG_PROJECT_PLAIN, @@ -2484,6 +2539,8 @@ char *TemplateTags[] = { "__CINERA_IMAGE__", "__CINERA_JS__", "__CINERA_NAV__", + "__CINERA_GLOBAL_NAV__", + //"__CINERA_PATHED_NAV__", "__CINERA_PROJECT__", "__CINERA_PROJECT_ID__", "__CINERA_PROJECT_PLAIN__", @@ -2509,16 +2566,31 @@ typedef enum NT_COUNT, } navigation_type; +typedef struct project project; // NOTE(matt): Forward declared. Consider reorganising the code? + +typedef struct +{ + project *ChildrenOf; + navigation_type Type; +} navigation_spec; + +typedef struct +{ + buffer Buffer; + navigation_spec Spec; +} navigation_buffer; + typedef struct { int Offset; + template_tag_code TagCode; asset *Asset; - navigation_type NavigationType; - enum8(template_tag_codes) TagCode; + navigation_buffer *Nav; } tag_offset; typedef enum { + TEMPLATE_NULL, TEMPLATE_GLOBAL_SEARCH, TEMPLATE_SEARCH, TEMPLATE_PLAYER, @@ -2530,8 +2602,8 @@ typedef struct int Validity; // NOTE(matt): Bitmask describing which page the template is valid for, i.e. contents and / or player page template_type Type; bool RequiresCineraJS; - uint64_t TagCount; - tag_offset *Tags; + _memory_book(tag_offset) Tags; + _memory_book(navigation_buffer) NavBuffer; } template_metadata; typedef struct @@ -2540,11 +2612,24 @@ typedef struct template_metadata Metadata; } template; +void +FreeTemplateNavBuffers(template *T) +{ + for(int i = 0; i < T->Metadata.NavBuffer.ItemCount; ++i) + { + navigation_buffer *This = GetPlaceInBook(&T->Metadata.NavBuffer, i); + FreeBuffer(&This->Buffer); + } +} + void ClearTemplateMetadata(template *Template) { - Template->Metadata.TagCount = 0; Template->Metadata.Validity = 0; + Template->Metadata.Type = TEMPLATE_NULL; + Template->Metadata.RequiresCineraJS = FALSE; + FreeTemplateNavBuffers(Template); + FreeBook(&Template->Metadata.NavBuffer); } void @@ -2567,8 +2652,7 @@ void FreeTemplate(template *Template) { FreeFile(&Template->File); - - FreeAndResetCount(Template->Metadata.Tags, Template->Metadata.TagCount); + FreeBook(&Template->Metadata.Tags); ClearTemplateMetadata(Template); } @@ -2684,14 +2768,12 @@ typedef struct #define AFD 1 #define AFE 0 +// NOTE(matt): Globals config *Config; project *CurrentProject; - -// NOTE(matt): Globals mode Mode; arena MemoryArena; -//config *Config; -assets Assets; +_memory_book(asset) Assets; int inotifyInstance; watch_handles WatchHandles; database DB; @@ -3262,9 +3344,9 @@ OffsetLandmarks(buffer *Dest, buffer *Src, page_type PageType) { if(Config->QueryString.Length > 0) { - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *Asset = GetPlaceInBook(&Assets.Asset, i); + asset *Asset = GetPlaceInBook(&Assets, i); if(PageType == PAGE_PLAYER) { for(int LandmarkIndex = 0; LandmarkIndex < Asset->PlayerLandmarkCount; ++LandmarkIndex) @@ -3603,14 +3685,14 @@ GetDirectoryPath(char *Filepath) } void -PushTemplateTag(template *Template, int Offset, enum8(template_tag_types) TagType, asset *Asset, navigation_type NavigationType) +PushTemplateTag(template *Template, int Offset, template_tag_code TagCode, asset *Asset, navigation_buffer *NavBuffer) { - Template->Metadata.Tags = Fit(Template->Metadata.Tags, sizeof(*Template->Metadata.Tags), Template->Metadata.TagCount, 16, FALSE); - Template->Metadata.Tags[Template->Metadata.TagCount].Offset = Offset; - Template->Metadata.Tags[Template->Metadata.TagCount].TagCode = TagType; - Template->Metadata.Tags[Template->Metadata.TagCount].Asset = Asset; - Template->Metadata.Tags[Template->Metadata.TagCount].NavigationType = NavigationType; - ++Template->Metadata.TagCount; + tag_offset *This = GetPlaceInBook(&Template->Metadata.Tags, Template->Metadata.Tags.ItemCount); + This->Offset = Offset; + This->TagCode = TagCode; + This->Asset = Asset; + This->Nav = NavBuffer; + ++Template->Metadata.Tags.ItemCount; } void @@ -3632,9 +3714,11 @@ InitTemplate(template *Template, string Location, template_type Type) Template->File = InitFile(Type == TEMPLATE_BESPOKE ? &CurrentProject->HMMLDir : &CurrentProject->TemplatesDir, &Location, EXT_NULL); } } - printf("%sPacking%s template: %s\n", ColourStrings[CS_ONGOING], ColourStrings[CS_END], Template->File.Path); + fprintf(stderr, "%sPacking%s template: %s\n", ColourStrings[CS_ONGOING], ColourStrings[CS_END], Template->File.Path); ReadFileIntoBuffer(&Template->File); ClearTemplateMetadata(Template); + InitBook(&Template->Metadata.Tags, sizeof(tag_offset), 16, MBT_TAG_OFFSET); + InitBook(&Template->Metadata.NavBuffer, sizeof(navigation_buffer), 4, MBT_NAVIGATION_BUFFER); } int @@ -4588,30 +4672,30 @@ ConstructHTMLIndexFilePath(db_header_project *P, string *PageLocation, string *E return Result; } -void +rc ReadSearchPageIntoBuffer(db_header_project *P, file *File) { string SearchLocationL = Wrap0i(P->SearchLocation, sizeof(P->SearchLocation)); File->Path = ConstructHTMLIndexFilePath(P, &SearchLocationL, 0); - ReadFileIntoBuffer(File); + return ReadFileIntoBuffer(File); } -void +rc ReadGlobalSearchPageIntoBuffer(file *File) { db_block_projects *ProjectsBlock = DB.Metadata.Signposts.ProjectsBlock.Ptr ? DB.Metadata.Signposts.ProjectsBlock.Ptr : LocateBlock(B_PROJ); string SearchLocationL = Wrap0i(ProjectsBlock->GlobalSearchDir, sizeof(ProjectsBlock->GlobalSearchDir)); File->Path = ConstructHTMLIndexFilePath(0, &SearchLocationL, 0); - ReadFileIntoBuffer(File); + return ReadFileIntoBuffer(File); } -void +rc ReadPlayerPageIntoBuffer(db_header_project *P, file *File, db_entry *Entry) { string EntryOutput = Wrap0i(Entry->OutputLocation, sizeof(Entry->OutputLocation)); string PlayerLocationL = Wrap0i(P->PlayerLocation, sizeof(P->PlayerLocation)); File->Path = ConstructHTMLIndexFilePath(P, &PlayerLocationL, &EntryOutput); - ReadFileIntoBuffer(File); + return ReadFileIntoBuffer(File); } rc @@ -4628,12 +4712,13 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum) db_header_project *P = LocateProject(Landmark->Project); file HTML = {}; + rc FileReadRC = RC_INIT; if(Landmark->EntryIndex >= 0) { db_entry *Entry = LocateEntry(Landmark->Project, Landmark->EntryIndex); if(Entry) { - ReadPlayerPageIntoBuffer(P, &HTML, Entry); + FileReadRC = ReadPlayerPageIntoBuffer(P, &HTML, Entry); } else { @@ -4652,11 +4737,11 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum) { if(P) { - ReadSearchPageIntoBuffer(P, &HTML); + FileReadRC = ReadSearchPageIntoBuffer(P, &HTML); } else { - ReadGlobalSearchPageIntoBuffer(&HTML); + FileReadRC = ReadGlobalSearchPageIntoBuffer(&HTML); } } break; default: @@ -4669,11 +4754,14 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum) } } - landmark_range Range = {}; - Range.First = RunningLandmarkIndex; - Range.Length = Asset->LandmarkCount - Range.First; - int Length = GetIndexRangeLength(Asset, Range, RunningLandmarkIndex); - SnipeChecksumAndCloseFile(&HTML, Asset, Length, Checksum, &RunningLandmarkIndex); + if(FileReadRC == RC_SUCCESS) + { + landmark_range Range = {}; + Range.First = RunningLandmarkIndex; + Range.Length = Asset->LandmarkCount - Range.First; + int Length = GetIndexRangeLength(Asset, Range, RunningLandmarkIndex); + SnipeChecksumAndCloseFile(&HTML, Asset, Length, Checksum, &RunningLandmarkIndex); + } } return Result; @@ -4862,11 +4950,11 @@ WriteFilenameThenTargetPathIntoBook(memory_book *M, string Path, watch_type Type if(IsSymlink(OriginalPath0)) { - fprintf(stderr, "%s\n", OriginalPath0); + //fprintf(stderr, "%s\n", OriginalPath0); int PathLength = readlink(OriginalPath0, ResolvedSymlinkPath, 4096); FullPath = Wrap0i(ResolvedSymlinkPath, PathLength); - PrintString(FullPath); - fprintf(stderr, "\n"); + //PrintString(FullPath); + //fprintf(stderr, "\n"); } else { @@ -5305,9 +5393,9 @@ PushAssetLandmark(buffer *Dest, asset *Asset, int PageType, bool GrowableBuffer) void ResetAssetLandmarks(void) { - for(int AssetIndex = 0; AssetIndex < Assets.Count; ++AssetIndex) + for(int AssetIndex = 0; AssetIndex < Assets.ItemCount; ++AssetIndex) { - asset *A = GetPlaceInBook(&Assets.Asset, AssetIndex); + asset *A = GetPlaceInBook(&Assets, AssetIndex); FreeAndResetCount(A->Player, A->PlayerLandmarkCount); FreeAndResetCount(A->Search, A->SearchLandmarkCount); A->OffsetLandmarks = FALSE; @@ -5400,20 +5488,21 @@ ComputeSpriteData(asset *A) asset * PlaceAsset(string Filename, asset_type Type, uint64_t Variants, bool Associated, int Position) { - asset *This = GetPlaceInBook(&Assets.Asset, Position); + asset *This = GetPlaceInBook(&Assets, Position); This->Type = Type; This->Variants = Variants; This->Associated = Associated; ClearCopyString(This->Filename, sizeof(This->Filename), "%.*s", (int)Filename.Length, Filename.Base); This->FilenameAt = FinalPathComponentPosition(Filename); - if(Position == Assets.Count && !This->Known) { ++Assets.Count; } + if(Position == Assets.ItemCount && !This->Known) { ++Assets.ItemCount; } file File = {}; File.Path = ConstructAssetPath(&File, Filename, Type); ReadFileIntoBuffer(&File); if(File.Buffer.Location) { + // TODO(matt): Print out the asset that we've hashed? This->Hash = StringToFletcher32(File.Buffer.Location, File.Buffer.Size); if(This->Type == ASSET_IMG) { @@ -5436,9 +5525,9 @@ asset * PushAsset(string Filename, asset_type Type, uint64_t Variants, bool Associated) { int i; - for(i = 0; i < Assets.Count; ++i) + for(i = 0; i < Assets.ItemCount; ++i) { - asset *Asset = GetPlaceInBook(&Assets.Asset, i); + asset *Asset = GetPlaceInBook(&Assets, i); if(!StringsDifferLv0(Filename, Asset->Filename) && Type == Asset->Type) { break; @@ -5448,16 +5537,15 @@ PushAsset(string Filename, asset_type Type, uint64_t Variants, bool Associated) } void -FreeAssets(assets *A) +FreeAssets(memory_book *A) { - for(int i = 0; i < A->Count; ++i) + for(int i = 0; i < A->ItemCount; ++i) { - asset *Asset = GetPlaceInBook(&Assets.Asset, i); + asset *Asset = GetPlaceInBook(&Assets, i); FreeAndResetCount(Asset->Search, Asset->SearchLandmarkCount); FreeAndResetCount(Asset->Player, Asset->PlayerLandmarkCount); } - FreeBook(&A->Asset); - A->Count = 0; + FreeBook(A); } void @@ -5473,7 +5561,7 @@ InitBuiltinAssets(void) printf( " %s└───────┴────┴─── Don't worry about this one. We'll generate it if needed%s\n", ColourStrings[CS_COMMENT], ColourStrings[CS_END]); } } - Assets.Count = BUILTIN_ASSETS_COUNT; + Assets.ItemCount = BUILTIN_ASSETS_COUNT; // TODO(matt): Think deeply about how and when we push these support icon assets on #if 0 @@ -5488,7 +5576,7 @@ InitBuiltinAssets(void) void InitAssets(void) { - InitBook(&Assets.Asset, sizeof(asset), 16, MBT_ASSET); + InitBook(&Assets, sizeof(asset), 16, MBT_ASSET); InitBuiltinAssets(); db_block_assets *AssetsBlock = LocateBlock(B_ASET); if(AssetsBlock) @@ -5665,23 +5753,26 @@ SortAndAbbreviateSpeakers(speakers *Speakers) person * GetPersonFromConfig(string Person) { - for(int i = 0; i < Config->PersonCount; ++i) + person *Result = 0; + for(int i = 0; i < Config->Person.ItemCount; ++i) { - if(!StringsDifferCaseInsensitive(Config->Person[i].ID, Person)) + person *This = GetPlaceInBook(&Config->Person, i); + if(!StringsDifferCaseInsensitive(This->ID, Person)) { - return &Config->Person[i]; + Result = This; + break; } } - return 0; + return Result; } asset * GetAsset(string Filename, asset_type AssetType) { asset *Result = 0; - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *This = GetPlaceInBook(&Assets.Asset, i); + asset *This = GetPlaceInBook(&Assets, i); if(StringsMatch(Filename, Wrap0i(This->Filename, sizeof(This->Filename))) && AssetType == This->Type) { @@ -5695,12 +5786,12 @@ GetAsset(string Filename, asset_type AssetType) void PushSupportIconAssets() { - for(int i = 0; i < Config->PersonCount; ++i) + for(int i = 0; i < Config->Person.ItemCount; ++i) { - person *Person = Config->Person + i; - for(int j = 0; j < Person->SupportCount; ++j) + person *Person = GetPlaceInBook(&Config->Person, i); + for(int j = 0; j < Person->Support.ItemCount; ++j) { - support *Support = Person->Support + j; + support *Support = GetPlaceInBook(&Person->Support, j); if(Support->IconType == IT_GRAPHICAL) { asset *IconAsset = GetAsset(Support->Icon, ASSET_IMG); @@ -5854,14 +5945,15 @@ PushProjectAssets(project *P) P->IconAsset = SyncAssetAssociation(P->Icon, P->IconVariants, P->Index, AI_PROJECT_ICON); } - for(int i = 0; i < P->MediumCount; ++i) + for(int i = 0; i < P->Medium.ItemCount; ++i) { - PushMediumIconAsset(P->Medium + i); + medium *This = GetPlaceInBook(&P->Medium, i); + PushMediumIconAsset(This); } - for(int i = 0; i < P->ChildCount; ++i) + for(int i = 0; i < P->Child.ItemCount; ++i) { - PushProjectAssets(&P->Child[i]); + PushProjectAssets(GetPlaceInBook(&P->Child, i)); } FreeString(&Theme); } @@ -5876,9 +5968,9 @@ PushThemeAssets() // storing the Theme by index rather than a string } FreeString(&GlobalTheme); - for(int i = 0; i < Config->ProjectCount; ++i) + for(int i = 0; i < Config->Project.ItemCount; ++i) { - PushProjectAssets(&Config->Project[i]); + PushProjectAssets(GetPlaceInBook(&Config->Project, i)); } } @@ -6061,9 +6153,9 @@ PushCredentials(buffer *CreditsMenu, speakers *Speakers, person *Actor, role Rol // TODO(matt): Handle multiple support platforms! // AFD - if(Actor->Support) + if(Actor->Support.ItemCount > 0) { - support *Support = Actor->Support; + support *Support = GetPlaceInBook(&Actor->Support, 0); CopyStringToBuffer(CreditsMenu, " ", (int)Support->URL.Length, Support->URL.Base); @@ -6085,8 +6177,10 @@ FreeCredentials(speakers *S) void WaitForInput() { +#if 0 fprintf(stderr, "Press Enter to continue...\n"); getchar(); +#endif } void @@ -6849,7 +6943,7 @@ GenerateTopicColours(neighbourhood *N, string Topic) #endif FreeBuffer(&Topics.Buffer); - asset *Asset = GetPlaceInBook(&Assets.Asset, ASSET_CSS_TOPICS); + asset *Asset = GetPlaceInBook(&Assets, ASSET_CSS_TOPICS); if(Asset->Known) { // NOTE(matt): We may index this out directly because InitBuiltinAssets() places it in its own known slot @@ -7409,7 +7503,7 @@ AtHTMLCommentCloser(buffer *B) } asset * -ParseAssetString(template *Template, enum8(template_tag_codes) TagIndex, rc *ReturnCode) +ParseAssetString(template *Template, template_tag_code TagIndex, rc *ReturnCode) { asset *Result = 0; buffer *B = &Template->File.Buffer; @@ -7456,6 +7550,7 @@ ParseAssetString(template *Template, enum8(template_tag_codes) TagIndex, rc *Ret case TAG_CSS: AssetType = ASSET_CSS; break; case TAG_IMAGE: AssetType = ASSET_IMG; break; case TAG_JS: AssetType = ASSET_JS; break; + default: break; } string FinalAssetString = StripPWDIndicators(StripSlashes(AssetString, P_REL)); @@ -7496,16 +7591,66 @@ ParseAssetString(template *Template, enum8(template_tag_codes) TagIndex, rc *Ret return Result; } -navigation_type -ParseNavigationTag(template *Template, template_tag_code TagIndex) +navigation_buffer * +GetNavBufferFromTemplate(template *Template, navigation_spec Spec) +{ + navigation_buffer *Result = 0; + for(int i = 0; i < Template->Metadata.NavBuffer.ItemCount; ++i) + { + navigation_buffer *This = GetPlaceInBook(&Template->Metadata.NavBuffer, i); + if(Spec.Type == This->Spec.Type && Spec.ChildrenOf == This->Spec.ChildrenOf) + { + Result = This; + break; + } + } + return Result; +} + +navigation_buffer * +PushNavBufferUniquely(template *Template, navigation_spec Spec) +{ + navigation_buffer *Result = GetNavBufferFromTemplate(Template, Spec); + if(!Result) + { + Result = GetPlaceInBook(&Template->Metadata.NavBuffer, Template->Metadata.NavBuffer.ItemCount); + Result->Spec = Spec; + Result->Buffer.ID = BID_NAVIGATION; + ++Template->Metadata.NavBuffer.ItemCount; + } + return Result; +} + +navigation_buffer * +ParseNavigationTag(template *Template, template_tag_code TagCode, project *Project) { - navigation_type Result = NT_NULL; buffer *B = &Template->File.Buffer; - B->Ptr += StringLength(TemplateTags[TagIndex]); + B->Ptr += StringLength(TemplateTags[TagCode]); ConsumeWhitespace(B); + + navigation_spec Spec = {}; + Spec.Type = NT_NULL; + + // TODO(matt): This is temporary, until we have __CINERA_PATHED_NAV__ + // Once we do, we'll be parsing the ChildrenOf out of the file and doing GetProjectByLineage() + if(!Project || TagCode == TAG_GLOBAL_NAV) + { + Spec.ChildrenOf = 0; + } + else if(TagCode == TAG_NAV) + { + // TODO(matt): With __CINERA_PATHED_NAV__ make sure we handle nonexistent project lineages + project *P = Project; + while(P->Parent) + { + P = P->Parent; + } + Spec.ChildrenOf = P; + } + if(AtHTMLCommentCloser(B)) { - Result = NT_PLAIN; + Spec.Type = NT_PLAIN; } else { @@ -7517,12 +7662,12 @@ ParseNavigationTag(template *Template, template_tag_code TagIndex) { if(!StringsDifferLv0(NavigationString, NavigationTypes[NavigationType])) { - Result = NavigationType; + Spec.Type = NavigationType; break; } } - if(Result == NT_NULL) + if(Spec.Type == NT_NULL) { fprintf(stderr, "\n" "┌─ "); @@ -7559,11 +7704,18 @@ ParseNavigationTag(template *Template, template_tag_code TagIndex) } } + navigation_buffer *Result = 0; + + if(Spec.Type != NT_NULL) + { + Result = PushNavBufferUniquely(Template, Spec); + } + return Result; } int -PackTemplate(template *Template, string Location, template_type Type) +PackTemplate(template *Template, string Location, template_type Type, project *Project) { // TODO(matt): Record line numbers and contextual information: // @@ -7596,7 +7748,7 @@ NextTagSearch: Template->File.Buffer.Ptr += StringLength("!--"); while(Template->File.Buffer.Ptr - Template->File.Buffer.Location < Template->File.Buffer.Size && StringsDifferT("-->", Template->File.Buffer.Ptr, 0)) { - for(int TagIndex = 0; TagIndex < TEMPLATE_TAG_COUNT; ++TagIndex) + for(template_tag_code TagIndex = 0; TagIndex < TEMPLATE_TAG_COUNT; ++TagIndex) { if(!(StringsDifferT(TemplateTags[TagIndex], Template->File.Buffer.Ptr, 0))) { @@ -7613,7 +7765,7 @@ NextTagSearch: */ asset *Asset = 0; - navigation_type NavigationType = NT_NULL; + navigation_buffer *NavBuffer = 0; switch(TagIndex) { @@ -7660,14 +7812,15 @@ NextTagSearch: } } goto RecordTag; case TAG_NAV: + case TAG_GLOBAL_NAV: { - NavigationType = ParseNavigationTag(Template, TagIndex); - if(NavigationType == NT_NULL) + NavBuffer = ParseNavigationTag(Template, TagIndex, Project); + if(!NavBuffer) { HaveErrors = TRUE; HaveNavParsingErrors = TRUE; } - else if(NavigationType == NT_DROPDOWN) + else if(NavBuffer->Spec.Type == NT_DROPDOWN) { Template->Metadata.RequiresCineraJS = TRUE; } @@ -7687,7 +7840,7 @@ NextTagSearch: RecordTag: { int Offset = CommentStart - Previous; - PushTemplateTag(Template, Offset, TagIndex, Asset, NavigationType); + PushTemplateTag(Template, Offset, TagIndex, Asset, NavBuffer); DepartComment(&Template->File.Buffer); Previous = Template->File.Buffer.Ptr; goto NextTagSearch; @@ -7809,7 +7962,7 @@ MediumExists(string Medium) } fprintf(stderr, "Specified default medium \"%.*s\" not available. Valid media are:\n", (int)Medium.Length, Medium.Base); - for(int i = 0; i < CurrentProject->MediumCount; ++i) + for(int i = 0; i < CurrentProject->Medium.ItemCount; ++i) { typography Typography = { @@ -7824,7 +7977,8 @@ MediumExists(string Medium) .Delimiter = ": ", .Separator = "•", }; - PrintMedium(&Typography, &CurrentProject->Medium[i], ": ", 2, TRUE); + 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" @@ -8799,7 +8953,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF { if(HMML.metadata.template) { - switch(PackTemplate(BespokeTemplate, Wrap0(HMML.metadata.template), TEMPLATE_BESPOKE)) + switch(PackTemplate(BespokeTemplate, Wrap0(HMML.metadata.template), TEMPLATE_BESPOKE, CurrentProject)) { case RC_ARENA_FULL: case RC_INVALID_TEMPLATE: // Invalid template @@ -9904,7 +10058,7 @@ AppendedIdentifier: CopyStringToBuffer(&CollationBuffers->IncludesPlayer, "\">"); - if(BespokeTemplate->Metadata.TagCount > 0) + if(BespokeTemplate->Metadata.Tags.ItemCount > 0) { if(BespokeTemplate->Metadata.RequiresCineraJS) { @@ -9997,13 +10151,238 @@ AppendedIdentifier: return RC_SUCCESS; } +typedef struct +{ + char *String; + bool SelfClosing; +} html_element; + +html_element HTMLElements[] = +{ + { "a", FALSE }, + { "div", FALSE }, + { "img", TRUE }, + { "input", TRUE }, + { "label", FALSE }, + { "li", FALSE }, + { "nav", FALSE }, + { "script", FALSE }, + { "span", FALSE }, + { "ul", FALSE }, +}; + +typedef enum +{ + NODE_A, + NODE_DIV, + NODE_IMG, + NODE_INPUT, + NODE_LABEL, + NODE_LI, + NODE_NAV, + NODE_SCRIPT, + NODE_SPAN, + NODE_UL, +} html_element_id; + +void +OpenNode(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) +{ + AppendStringToBuffer(B, Wrap0("<")); + AppendStringToBuffer(B, Wrap0(HTMLElements[Element].String)); + if(ID) + { + AppendStringToBuffer(B, Wrap0(" ")); + AppendStringToBuffer(B, Wrap0("id=\"")); + AppendStringToBuffer(B, Wrap0(ID)); + AppendStringToBuffer(B, Wrap0("\"")); + } + if(!HTMLElements[Element].SelfClosing) + { + ++*IndentationLevel; + } +} + +void +OpenNodeC(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) +{ + AppendStringToBuffer(B, Wrap0("<")); + AppendStringToBuffer(B, Wrap0(HTMLElements[Element].String)); + if(ID) + { + AppendStringToBuffer(B, Wrap0(" ")); + AppendStringToBuffer(B, Wrap0("id=\"")); + AppendStringToBuffer(B, Wrap0(ID)); + AppendStringToBuffer(B, Wrap0("\"")); + } + AppendStringToBuffer(B, Wrap0(">")); + if(!HTMLElements[Element].SelfClosing) + { + ++*IndentationLevel; + } +} + +void +OpenNodeNewLine(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) +{ + AppendStringToBuffer(B, Wrap0("\n")); + IndentBuffer(B, *IndentationLevel); + OpenNode(B, IndentationLevel, Element, ID); +} + +void +OpenNodeCNewLine(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) +{ + AppendStringToBuffer(B, Wrap0("\n")); + IndentBuffer(B, *IndentationLevel); + OpenNodeC(B, IndentationLevel, Element, ID); +} + +void +CloseNode(buffer *B, uint32_t *IndentationLevel, html_element_id Element) +{ + --*IndentationLevel; + AppendStringToBuffer(B, Wrap0("")); +} + +void +CloseNodeNewLine(buffer *B, uint32_t *IndentationLevel, html_element_id Element) +{ + AppendStringToBuffer(B, Wrap0("\n")); + --*IndentationLevel; + IndentBuffer(B, *IndentationLevel); + AppendStringToBuffer(B, Wrap0("")); +} + +void +GenerateNavigationRecursively(project *Current, project *Target, navigation_buffer *NavBuffer, uint32_t *IndentationLevel) +{ + buffer *B = &NavBuffer->Buffer; + if(Target == Current) + { + OpenNodeNewLine(B, IndentationLevel, NODE_LI, 0); + AppendStringToBuffer(B, Wrap0(" class=\"current\">")); + } + else + { + OpenNodeCNewLine(B, IndentationLevel, NODE_LI, 0); + } + + OpenNode(B, IndentationLevel, NODE_A, 0); + AppendStringToBuffer(B, Wrap0(" href=\"")); + + buffer URL; + ClaimBuffer(&URL, BID_URL_SEARCH, MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1); + ConstructSearchURL(&URL, Current); + AppendBuffer(B, &URL); + DeclaimBuffer(&URL); + + AppendStringToBuffer(B, Wrap0("\">")); + AppendStringToBuffer(B, Current->HTMLTitle.Length ? Current->HTMLTitle : Current->Title); + CloseNode(B, IndentationLevel, NODE_A); + + if(Current->Child.ItemCount > 0) + { + OpenNodeCNewLine(B, IndentationLevel, NODE_UL, 0); + } + + for(int i = 0; i < Current->Child.ItemCount; ++i) + { + GenerateNavigationRecursively(GetPlaceInBook(&Current->Child, i), Target, NavBuffer, IndentationLevel); + } + + if(Current->Child.ItemCount > 0) + { + CloseNodeNewLine(B, IndentationLevel, NODE_UL); + CloseNodeNewLine(B, IndentationLevel, NODE_LI); + } + else + { + CloseNode(B, IndentationLevel, NODE_LI); + } +} + +void +GenerateNavigation(config *C, project *Target, navigation_buffer *NavBuffer) +{ + uint32_t IndentationLevel = 0; + uint32_t DropdownIndent = 0; + buffer *B = &NavBuffer->Buffer; + string Theme = C ? C->GlobalTheme : Target->Theme; + switch(NavBuffer->Spec.Type) + { + case NT_DROPDOWN: + { + //IndentationLevel = 0; + OpenNode(B, &IndentationLevel, NODE_NAV, 0); + AppendStringToBuffer(B, Wrap0(" class=\"cineraNavDropdown ")); + AppendStringToBuffer(B, Theme); + AppendStringToBuffer(B, Wrap0("\">")); + OpenNodeNewLine(B, &IndentationLevel, NODE_NAV, 0); + AppendStringToBuffer(B, Wrap0(" class=\"cineraNavTitle\">")); + AppendStringToBuffer(B, Target ? Target->HTMLTitle.Length ? Target->HTMLTitle : Target->Title : Wrap0("Indexed Episode Guide")); + CloseNode(B, &IndentationLevel, NODE_NAV); + OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0); + AppendStringToBuffer(B, Wrap0(" class=\"cineraPositioner\">")); + DropdownIndent = IndentationLevel; + } // NOTE(matt): Intentional fall-through + case NT_HORIZONTAL: + { + //IndentationLevel = 0; + OpenNode(B, &IndentationLevel, NODE_UL, 0); + AppendStringToBuffer(B, Wrap0(" class=\"cineraNavHorizontal ")); + AppendStringToBuffer(B, Theme); + AppendStringToBuffer(B, Wrap0("\">")); + } break; + case NT_PLAIN: + { + //IndentationLevel = 0; + OpenNode(B, &IndentationLevel, NODE_UL, 0); + AppendStringToBuffer(B, Wrap0(" class=\"cineraNavPlain ")); + AppendStringToBuffer(B, Theme); + AppendStringToBuffer(B, Wrap0("\">")); + } break; + case NT_NULL: + case NT_COUNT: break; + }; + + //IndentationLevel = 1; + if(NavBuffer->Spec.ChildrenOf) + { + project *Parent = NavBuffer->Spec.ChildrenOf; + for(int i = 0; i < Parent->Child.ItemCount; ++i) + { + GenerateNavigationRecursively(GetPlaceInBook(&Parent->Child, i), Target, NavBuffer, &IndentationLevel); + } + } + else + { + for(int i = 0; i < Config->Project.ItemCount; ++i) + { + GenerateNavigationRecursively(GetPlaceInBook(&Config->Project, i), Target, NavBuffer, &IndentationLevel); + } + } + + CloseNodeNewLine(B, &IndentationLevel, NODE_UL); + if(NavBuffer->Spec.Type == NT_DROPDOWN) + { + + CloseNodeNewLine(B, &DropdownIndent, NODE_DIV); + CloseNodeNewLine(B, &DropdownIndent, NODE_NAV); + } +} + int -BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, page_type PageType, unsigned int *PlayerOffset) +BuffersToHTML(project *Project, buffers *CollationBuffers, template *Template, char *OutputPath, page_type PageType, unsigned int *PlayerOffset) { MEM_TEST_INITIAL(); #if DEBUG printf("\n\n --- Buffer Collation ---\n" - " %s\n\n\n", OutputPath ? OutputPath : CurrentProject->OutLocation); + " %s\n\n\n", OutputPath ? OutputPath : Project->OutLocation); #endif #if DEBUG_MEM @@ -10015,7 +10394,7 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, p } else { - fprintf(MemLog, "%.*s", (int)CurrentProject->PlayerLocation.Length, CurrentProject->PlayerLocation.Base); + fprintf(MemLog, "%.*s", (int)Project->PlayerLocation.Length, Project->PlayerLocation.Base); } fprintf(MemLog, ")\n"); fclose(MemLog); @@ -10028,7 +10407,7 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, p if(Template->File.Buffer.Location) { #if AFD - if((Template->Metadata.Validity & PageType))// || CurrentProject->Mode & MODE_FORCEINTEGRATION) + if((Template->Metadata.Validity & PageType))// || Project->Mode & MODE_FORCEINTEGRATION) { buffer Master; Master.Size = Template->File.Buffer.Size + (Kilobytes(512)); @@ -10051,10 +10430,11 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, p Master.Ptr = Master.Location; Template->File.Buffer.Ptr = Template->File.Buffer.Location; - for(int i = 0; i < Template->Metadata.TagCount; ++i) + for(int i = 0; i < Template->Metadata.Tags.ItemCount; ++i) { int j = 0; - while(Template->Metadata.Tags[i].Offset > j) + tag_offset *Tag = GetPlaceInBook(&Template->Metadata.Tags, i); + while(Tag->Offset > j) { *Master.Ptr++ = *Template->File.Buffer.Ptr++; ++j; @@ -10062,17 +10442,17 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, p // TODO(matt): Make this whole template stuff context-aware, so it can determine whether or not to HTML-encode // or sanitise punctuation for CSS-safety - switch(Template->Metadata.Tags[i].TagCode) + switch(Tag->TagCode) { case TAG_PROJECT: { - if(CurrentProject->HTMLTitle.Length > 0) { CopyStringToBufferNoFormat(&Master, CurrentProject->HTMLTitle); } // NOTE(matt): Not HTML-safe - else { CopyStringToBufferHTMLSafe(&Master, CurrentProject->Title); } + if(Project->HTMLTitle.Length > 0) { CopyStringToBufferNoFormat(&Master, Project->HTMLTitle); } // NOTE(matt): Not HTML-safe + else { CopyStringToBufferHTMLSafe(&Master, Project->Title); } } break; - case TAG_PROJECT_ID: CopyStringToBufferNoFormat(&Master, CurrentProject->ID); break; // NOTE(matt): Not HTML-safe - case TAG_PROJECT_PLAIN: CopyStringToBufferHTMLSafe(&Master, CurrentProject->Title); break; + case TAG_PROJECT_ID: CopyStringToBufferNoFormat(&Master, Project->ID); break; // NOTE(matt): Not HTML-safe + case TAG_PROJECT_PLAIN: CopyStringToBufferHTMLSafe(&Master, Project->Title); break; case TAG_SEARCH_URL: CopyStringToBufferNoFormat(&Master, Wrap0i(CollationBuffers->URLSearch, sizeof(CollationBuffers->URLSearch))); break; // NOTE(matt): Not HTML-safe - case TAG_THEME: CopyStringToBufferNoFormat(&Master, CurrentProject->Theme); break; // NOTE(matt): Not HTML-safe + case TAG_THEME: CopyStringToBufferNoFormat(&Master, Project->Theme); break; // NOTE(matt): Not HTML-safe case TAG_TITLE: CopyStringToBufferHTMLSafe(&Master, Wrap0i(CollationBuffers->Title, sizeof(CollationBuffers->Title))); break; case TAG_URL: if(PageType == PAGE_PLAYER) @@ -10106,86 +10486,52 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, p case TAG_ASSET: { buffer URL; - ConstructResolvedAssetURL(&URL, Template->Metadata.Tags[i].Asset, PageType); + ConstructResolvedAssetURL(&URL, Tag->Asset, PageType); CopyStringToBuffer(&Master, "%s", URL.Location); DeclaimBuffer(&URL); - PushAssetLandmark(&Master, Template->Metadata.Tags[i].Asset, PageType, 0); + PushAssetLandmark(&Master, Tag->Asset, PageType, 0); } break; case TAG_CSS: { buffer URL; - ConstructResolvedAssetURL(&URL, Template->Metadata.Tags[i].Asset, PageType); + ConstructResolvedAssetURL(&URL, Tag->Asset, PageType); CopyStringToBuffer(&Master, "Metadata.Tags[i].Asset, PageType, 0); + PushAssetLandmark(&Master, Tag->Asset, PageType, 0); CopyStringToBuffer(&Master, "\">"); } break; case TAG_IMAGE: { buffer URL; - ConstructResolvedAssetURL(&URL, Template->Metadata.Tags[i].Asset, PageType); + ConstructResolvedAssetURL(&URL, Tag->Asset, PageType); CopyStringToBuffer(&Master, "%s", URL.Location); DeclaimBuffer(&URL); - PushAssetLandmark(&Master, Template->Metadata.Tags[i].Asset, PageType, 0); + PushAssetLandmark(&Master, Tag->Asset, PageType, 0); } break; case TAG_JS: { buffer URL; - ConstructResolvedAssetURL(&URL, Template->Metadata.Tags[i].Asset, PageType); + ConstructResolvedAssetURL(&URL, Tag->Asset, PageType); CopyStringToBuffer(&Master, ""); } break; case TAG_NAV: + case TAG_GLOBAL_NAV: { - buffer *NavDropdownPre; - buffer *NavHorizontalPre; - buffer *NavPlainPre; - buffer *NavGeneric; - buffer *NavDropdownPost; - if(Template->Metadata.Type == TEMPLATE_GLOBAL_SEARCH) + if(!Tag->Nav->Buffer.Location) { - NavDropdownPre = &Config->NavDropdownPre; - NavHorizontalPre = &Config->NavHorizontalPre; - NavPlainPre = &Config->NavPlainPre; - NavGeneric = &Config->NavGeneric; - NavDropdownPost = &Config->NavDropdownPost; - } - else - { - NavDropdownPre = &CurrentProject->NavDropdownPre; - NavHorizontalPre = &CurrentProject->NavHorizontalPre; - NavPlainPre = &CurrentProject->NavPlainPre; - NavGeneric = &CurrentProject->NavGeneric; - NavDropdownPost = &CurrentProject->NavDropdownPost; + GenerateNavigation(0, Project, Tag->Nav); } - switch(Template->Metadata.Tags[i].NavigationType) - { - case NT_DROPDOWN: - { - CopyLandmarkedBuffer(&Master, NavDropdownPre, 0, PageType); - } // NOTE(matt): Intentional fall-through - case NT_HORIZONTAL: - { - CopyLandmarkedBuffer(&Master, NavHorizontalPre, 0, PageType); - } break; - case NT_PLAIN: - { - CopyLandmarkedBuffer(&Master, NavPlainPre, 0, PageType); - } break; - default: break; - } - CopyLandmarkedBuffer(&Master, NavGeneric, 0, PageType); - if(Template->Metadata.Tags[i].NavigationType == NT_DROPDOWN) - { - CopyLandmarkedBuffer(&Master, NavDropdownPost, 0, PageType); - } + // TODO(matt): If we add project icons to the nav - and, frankly, we will want project art at some + // point - we'll need to correctly offset its landmarks here + CopyLandmarkedBuffer(&Master, &Tag->Nav->Buffer, 0, PageType); } case TAG_CUSTOM0: CopyStringToBufferNoFormat(&Master, Wrap0i(CollationBuffers->Custom0, sizeof(CollationBuffers->Custom0))); break; case TAG_CUSTOM1: CopyStringToBufferNoFormat(&Master, Wrap0i(CollationBuffers->Custom1, sizeof(CollationBuffers->Custom1))); break; @@ -10203,6 +10549,7 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, p case TAG_CUSTOM13: CopyStringToBufferNoFormat(&Master, Wrap0i(CollationBuffers->Custom13, sizeof(CollationBuffers->Custom13))); break; case TAG_CUSTOM14: CopyStringToBufferNoFormat(&Master, Wrap0i(CollationBuffers->Custom14, sizeof(CollationBuffers->Custom14))); break; case TAG_CUSTOM15: CopyStringToBufferNoFormat(&Master, Wrap0i(CollationBuffers->Custom15, sizeof(CollationBuffers->Custom15))); break; + case TEMPLATE_TAG_COUNT: break; } DepartComment(&Template->File.Buffer); @@ -11158,9 +11505,9 @@ void UpdateLandmarksForNeighbourhood(neighbourhood *N, edit_type_id EditType); void AddLandmarks(neighbourhood *N, project *P, edit_type_id EditType) { - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *Asset = GetPlaceInBook(&Assets.Asset, i); + asset *Asset = GetPlaceInBook(&Assets, i); Asset->Known = FALSE; } @@ -11177,9 +11524,9 @@ AddLandmarks(neighbourhood *N, project *P, edit_type_id EditType) DB.Metadata.File.Buffer.Ptr += sizeof(*Asset); int RunningIndex = 0; - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *AssetInMemory = GetPlaceInBook(&Assets.Asset, i); + asset *AssetInMemory = GetPlaceInBook(&Assets, i); // TODO(matt): Exhaustively test BinarySearchForMetadataLandmark() and figure out why ProcessPrevLandmarks() / // ProcessNextLandmarks() are apparently failing to write out all the existing landmarks if(!StringsDiffer(Wrap0i(Asset->Filename, sizeof(Asset->Filename)), Wrap0i(AssetInMemory->Filename, sizeof(AssetInMemory->Filename))) && Asset->Type == AssetInMemory->Type) @@ -11246,9 +11593,9 @@ AddLandmarks(neighbourhood *N, project *P, edit_type_id EditType) UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts); bool NewAsset = FALSE; - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *This = GetPlaceInBook(&Assets.Asset, i); + asset *This = GetPlaceInBook(&Assets, i); if(!This->Known && This->PlayerLandmarkCount > 0) { UpdateAssetInDB(This); @@ -11467,9 +11814,9 @@ UpdateLandmarksForSearch(neighbourhood *N, db_project_index ProjectIndex) { if(Config->QueryString.Length > 0) { - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *This = GetPlaceInBook(&Assets.Asset, i); + asset *This = GetPlaceInBook(&Assets, i); This->Known = FALSE; } @@ -11483,9 +11830,9 @@ UpdateLandmarksForSearch(neighbourhood *N, db_project_index ProjectIndex) db_landmark *FirstLandmark = LocateFirstLandmark(Asset); uint64_t ExistingLandmarkCount = Asset->LandmarkCount; - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *This = GetPlaceInBook(&Assets.Asset, i); + asset *This = GetPlaceInBook(&Assets, i); if(!StringsDiffer0(Asset->Filename, This->Filename) && Asset->Type == This->Type) { This->Known = TRUE; @@ -11527,9 +11874,9 @@ UpdateLandmarksForSearch(neighbourhood *N, db_project_index ProjectIndex) VerifyLandmarks(N); bool NewAsset = FALSE; - for(int InternalAssetIndex = 0; InternalAssetIndex < Assets.Count; ++InternalAssetIndex) + for(int InternalAssetIndex = 0; InternalAssetIndex < Assets.ItemCount; ++InternalAssetIndex) { - asset *This = GetPlaceInBook(&Assets.Asset, InternalAssetIndex); + asset *This = GetPlaceInBook(&Assets, InternalAssetIndex); if(!This->Known && This->SearchLandmarkCount > 0) { NewAsset = TRUE; @@ -12004,113 +12351,6 @@ DeleteFromDB(neighbourhood *N, string BaseFilename) return Entry ? RC_SUCCESS : RC_NOOP; } -typedef struct -{ - char *String; - bool SelfClosing; -} html_element; - -html_element HTMLElements[] = -{ - { "a", FALSE }, - { "div", FALSE }, - { "img", TRUE }, - { "input", TRUE }, - { "label", FALSE }, - { "li", FALSE }, - { "nav", FALSE }, - { "script", FALSE }, - { "span", FALSE }, - { "ul", FALSE }, -}; - -typedef enum -{ - NODE_A, - NODE_DIV, - NODE_IMG, - NODE_INPUT, - NODE_LABEL, - NODE_LI, - NODE_NAV, - NODE_SCRIPT, - NODE_SPAN, - NODE_UL, -} html_element_id; - -void -OpenNode(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) -{ - AppendStringToBuffer(B, Wrap0("<")); - AppendStringToBuffer(B, Wrap0(HTMLElements[Element].String)); - if(ID) - { - AppendStringToBuffer(B, Wrap0(" ")); - AppendStringToBuffer(B, Wrap0("id=\"")); - AppendStringToBuffer(B, Wrap0(ID)); - AppendStringToBuffer(B, Wrap0("\"")); - } - if(!HTMLElements[Element].SelfClosing) - { - ++*IndentationLevel; - } -} - -void -OpenNodeC(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) -{ - AppendStringToBuffer(B, Wrap0("<")); - AppendStringToBuffer(B, Wrap0(HTMLElements[Element].String)); - if(ID) - { - AppendStringToBuffer(B, Wrap0(" ")); - AppendStringToBuffer(B, Wrap0("id=\"")); - AppendStringToBuffer(B, Wrap0(ID)); - AppendStringToBuffer(B, Wrap0("\"")); - } - AppendStringToBuffer(B, Wrap0(">")); - if(!HTMLElements[Element].SelfClosing) - { - ++*IndentationLevel; - } -} - -void -OpenNodeNewLine(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) -{ - AppendStringToBuffer(B, Wrap0("\n")); - IndentBuffer(B, *IndentationLevel); - OpenNode(B, IndentationLevel, Element, ID); -} - -void -OpenNodeCNewLine(buffer *B, uint32_t *IndentationLevel, html_element_id Element, char *ID) -{ - AppendStringToBuffer(B, Wrap0("\n")); - IndentBuffer(B, *IndentationLevel); - OpenNodeC(B, IndentationLevel, Element, ID); -} - -void -CloseNode(buffer *B, uint32_t *IndentationLevel, html_element_id Element) -{ - --*IndentationLevel; - AppendStringToBuffer(B, Wrap0("")); -} - -void -CloseNodeNewLine(buffer *B, uint32_t *IndentationLevel, html_element_id Element) -{ - AppendStringToBuffer(B, Wrap0("\n")); - --*IndentationLevel; - IndentBuffer(B, *IndentationLevel); - AppendStringToBuffer(B, Wrap0("")); -} - string TrimString(string S, uint32_t CharsFromStart, uint32_t CharsFromEnd) @@ -12143,7 +12383,7 @@ GenerateFilterOfProjectAndChildren(buffer *Filter, db_header_project *StoredP, p db_header_project *StoredChild = LocateFirstChildProject(StoredP); for(int ChildIndex = 0; ChildIndex < StoredP->ChildCount; ++ChildIndex) { - project *Child = P->Child + ChildIndex; + project *Child = GetPlaceInBook(&P->Child, ChildIndex); GenerateFilterOfProjectAndChildren(Filter, StoredChild, Child, SearchRequired, FALSE, RequiresCineraJS); StoredChild = SkipProjectAndChildren(StoredChild); } @@ -12239,7 +12479,7 @@ GenerateIndexOfProjectAndChildren(buffer *Index, db_header_project *StoredP, pro db_header_project *StoredChild = LocateFirstChildProject(StoredP); for(int ChildIndex = 0; ChildIndex < StoredP->ChildCount; ++ChildIndex) { - project *Child = &P->Child[ChildIndex]; + project *Child = GetPlaceInBook(&P->Child, ChildIndex); GenerateIndexOfProjectAndChildren(Index, StoredChild, Child, SearchRequired, FALSE, RequiresCineraJS); StoredChild = SkipProjectAndChildren(StoredChild); } @@ -12308,6 +12548,7 @@ AtLeastNProjectsHavePublicEntries(uint8_t N) return FALSE; } +// TODO(matt): Replace with a memory_book typedef struct { string *S; @@ -12564,7 +12805,7 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P StoredP = LocateFirstChildProjectOfBlock(ProjectsBlock); for(int i = 0; i < ProjectsBlock->Count; ++i) { - project *Child = &Config->Project[i]; + project *Child = GetPlaceInBook(&Config->Project, i); if(FilterRequired) { GenerateFilterOfProjectAndChildren(&Filter, StoredP, Child, &SearchRequired, FALSE, &RequiresCineraJS); @@ -12689,9 +12930,10 @@ GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *Player MEM_TEST_MID("GeneratePlayerPage3"); bool SearchInTemplate = FALSE; - for(int TagIndex = 0; TagIndex < PlayerTemplate->Metadata.TagCount; ++TagIndex) + for(int TagIndex = 0; TagIndex < PlayerTemplate->Metadata.Tags.ItemCount; ++TagIndex) { - if(PlayerTemplate->Metadata.Tags[TagIndex].TagCode == TAG_SEARCH) + tag_offset *Tag = GetPlaceInBook(&PlayerTemplate->Metadata.Tags, TagIndex); + if(Tag->TagCode == TAG_SEARCH) { SearchInTemplate = TRUE; // TODO(matt): Fully determine whether UpdateNeighbourhoodPointers() must happen here @@ -12702,7 +12944,7 @@ GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *Player } MEM_TEST_MID("GeneratePlayerPage4"); - BuffersToHTML(CollationBuffers, PlayerTemplate, PlayerPath, PAGE_PLAYER, &N->This->LinkOffsets.PrevStart); + BuffersToHTML(CurrentProject, CollationBuffers, PlayerTemplate, PlayerPath, PAGE_PLAYER, &N->This->LinkOffsets.PrevStart); MEM_TEST_MID("GeneratePlayerPage5"); Free(PlayerPath); // NOTE(matt): A previous InsertNeighbourLink() call will have done SnipeEntryIntoMetadataBuffer(), but we must do it here now @@ -12746,7 +12988,7 @@ GenerateSearchPage(neighbourhood *N, buffers *CollationBuffers, db_header_projec { case RC_SUCCESS: { - BuffersToHTML(CollationBuffers, &P->SearchTemplate, SearchPath, PAGE_SEARCH, 0); + BuffersToHTML(P, CollationBuffers, &P->SearchTemplate, SearchPath, PAGE_SEARCH, 0); UpdateLandmarksForSearch(N, P->Index); break; } @@ -12788,7 +13030,7 @@ GenerateGlobalSearchPage(neighbourhood *N, buffers *CollationBuffers) { case RC_SUCCESS: { - BuffersToHTML(CollationBuffers, &Config->SearchTemplate, SearchPath, PAGE_SEARCH, 0); + BuffersToHTML(0, CollationBuffers, &Config->SearchTemplate, SearchPath, PAGE_SEARCH, 0); UpdateLandmarksForSearch(N, GLOBAL_SEARCH_PAGE_INDEX); break; } @@ -12899,6 +13141,12 @@ SetCurrentProject(project *P, neighbourhood *N) { FreeFile(&DB.File); + if(CurrentProject) + { + FreeTemplateNavBuffers(&CurrentProject->SearchTemplate); + FreeTemplateNavBuffers(&CurrentProject->PlayerTemplate); + } + CurrentProject = P; InitNeighbourhood(N); @@ -12942,18 +13190,18 @@ RecheckPrivacyRecursively(project *P, neighbourhood *N, buffers *CollationBuffer } - for(int i = 0; i < P->ChildCount; ++i) + for(int i = 0; i < P->Child.ItemCount; ++i) { - RecheckPrivacyRecursively(&P->Child[i], N, CollationBuffers, BespokeTemplate); + RecheckPrivacyRecursively(GetPlaceInBook(&P->Child, i), N, CollationBuffers, BespokeTemplate); } } void RecheckPrivacy(neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate) { - for(int i = 0; i < Config->ProjectCount; ++i) + for(int i = 0; i < Config->Project.ItemCount; ++i) { - RecheckPrivacyRecursively(&Config->Project[i], N, CollationBuffers, BespokeTemplate); + RecheckPrivacyRecursively(GetPlaceInBook(&Config->Project, i), N, CollationBuffers, BespokeTemplate); } LastPrivacyCheck = time(0); } @@ -12961,9 +13209,9 @@ RecheckPrivacy(neighbourhood *N, buffers *CollationBuffers, template *BespokeTem void UpdateDeferredAssetChecksums(void) { - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *This = GetPlaceInBook(&Assets.Asset, i); + asset *This = GetPlaceInBook(&Assets, i); if(This->DeferredUpdate) { UpdateAssetInDB(This); @@ -13647,15 +13895,15 @@ InitProjectInDBRecursively(project_generations *G, project *P) Project.ArtIndex = SAI_UNSET; Project.IconIndex = SAI_UNSET; Project.EntryCount = 0; - Project.ChildCount = P->ChildCount; + Project.ChildCount = P->Child.ItemCount; fwrite(&Project, sizeof(Project), 1, DB.Metadata.File.Handle); AccumulateFileEditSize(&DB.Metadata, sizeof(Project)); IncrementCurrentGeneration(G); - for(int i = 0; i < P->ChildCount; ++i) + for(int i = 0; i < P->Child.ItemCount; ++i) { - InitProjectInDBRecursively(G, &P->Child[i]); + InitProjectInDBRecursively(G, GetPlaceInBook(&P->Child, i)); } DecrementCurrentGeneration(G); } @@ -14155,10 +14403,10 @@ SyncProjects_TopLevel(project_generations *G, project *C, db_block_projects **SP db_header_project *SGrandChild = LocateFirstChildProject(*SChild); - for(int ci = 0; ci < C->ChildCount; ++ci) + for(int ci = 0; ci < C->Child.ItemCount; ++ci) { bool Located = FALSE; - project *CChild = &C->Child[ci]; + project *CChild = GetPlaceInBook(&C->Child, ci); if(ci < (*SChild)->ChildCount) { if(ConfiguredAndStoredProjectIDsMatch(CChild, SGrandChild)) @@ -14181,7 +14429,7 @@ SyncProjects_TopLevel(project_generations *G, project *C, db_block_projects **SP SGrandChild = SkipProjectAndChildren(SGrandChild); } - uint64_t DeletionCount = (*SChild)->ChildCount - C->ChildCount; + uint64_t DeletionCount = (*SChild)->ChildCount - C->Child.ItemCount; for(int DeletionIndex = 0; DeletionIndex < DeletionCount; ++DeletionIndex) { DeleteProject(SChild, &SGrandChild, G); @@ -14209,10 +14457,10 @@ SyncProjects(project_generations *G, project *C, db_header_project **SParent, db db_header_project *SGrandChild = LocateFirstChildProject(*SChild); - for(int ci = 0; ci < C->ChildCount; ++ci) + for(int ci = 0; ci < C->Child.ItemCount; ++ci) { bool Located = FALSE; - project *CChild = &C->Child[ci]; + project *CChild = GetPlaceInBook(&C->Child, ci); if(ci < (*SChild)->ChildCount) { if(ConfiguredAndStoredProjectIDsMatch(CChild, SGrandChild)) @@ -14235,7 +14483,7 @@ SyncProjects(project_generations *G, project *C, db_header_project **SParent, db SGrandChild = SkipProjectAndChildren(SGrandChild); } - uint64_t DeletionCount = (*SChild)->ChildCount - C->ChildCount; + uint64_t DeletionCount = (*SChild)->ChildCount - C->Child.ItemCount; for(int DeletionIndex = 0; DeletionIndex < DeletionCount; ++DeletionIndex) { DeleteProject(SChild, &SGrandChild, G); @@ -14268,10 +14516,10 @@ SyncDB(config *C) db_block_projects *SParent = DB.Metadata.Signposts.ProjectsBlock.Ptr; db_header_project *SChild = LocateFirstChildProjectOfBlock(SParent); - for(uint64_t ci = 0; ci < C->ProjectCount; ++ci) + for(uint64_t ci = 0; ci < C->Project.ItemCount; ++ci) { bool Located = FALSE; - project *CChild = &C->Project[ci]; + project *CChild = GetPlaceInBook(&C->Project, ci); if(ci < SParent->Count) { if(ConfiguredAndStoredProjectIDsMatch(CChild, SChild)) @@ -14294,7 +14542,7 @@ SyncDB(config *C) SChild = SkipProjectAndChildren(SChild); } - uint64_t DeletionCount = SParent->Count - C->ProjectCount; + uint64_t DeletionCount = SParent->Count - C->Project.ItemCount; for(int DeletionIndex = 0; DeletionIndex < DeletionCount; ++DeletionIndex) { DeleteProject_TopLevel(&SParent, &SChild, &Accumulator); @@ -14305,7 +14553,7 @@ SyncDB(config *C) //PrintConfig(C); - PrintGenerations(&Accumulator, FALSE); + //PrintGenerations(&Accumulator, FALSE); FreeGenerations(&Accumulator); //_exit(0); } @@ -14390,220 +14638,25 @@ ProjectIndexIs(db_project_index I, uint64_t Generation, uint64_t Index) } void -GenerateGlobalNavigationRecursively(config *C, project *P, uint32_t *IndentationLevel) +PackProjectTemplates(project *P, neighbourhood *N, bool *Titled) { - OpenNodeCNewLine(&C->NavGeneric, IndentationLevel, NODE_LI, 0); - OpenNode(&C->NavGeneric, IndentationLevel, NODE_A, 0); - AppendStringToBuffer(&C->NavGeneric, Wrap0(" href=\"")); - - buffer URL; - ClaimBuffer(&URL, BID_URL_SEARCH, MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1); - ConstructSearchURL(&URL, P); - AppendBuffer(&C->NavGeneric, &URL); - DeclaimBuffer(&URL); - - AppendStringToBuffer(&C->NavGeneric, Wrap0("\">")); - AppendStringToBuffer(&C->NavGeneric, P->HTMLTitle.Length ? P->HTMLTitle: P->Title); - CloseNode(&C->NavGeneric, IndentationLevel, NODE_A); - - if(P->ChildCount > 0) + for(int i = 0; i < P->Child.ItemCount; ++i) { - OpenNodeCNewLine(&C->NavGeneric, IndentationLevel, NODE_UL, 0); - } - - for(int i = 0; i < P->ChildCount; ++i) - { - project *Child = &P->Child[i]; - GenerateGlobalNavigationRecursively(C, Child, IndentationLevel); - } - - if(P->ChildCount > 0) - { - CloseNodeNewLine(&C->NavGeneric, IndentationLevel, NODE_UL); - CloseNodeNewLine(&C->NavGeneric, IndentationLevel, NODE_LI); - } - else - { - CloseNode(&C->NavGeneric, IndentationLevel, NODE_LI); - } -} - -void -GenerateGlobalNavigationBars(config *C) -{ - // NavGeneric; - // NavDropdownPre; - // NavDropdownPost; - // NavHorizontalPre; - // NavPlainPre; - - uint32_t IndentationLevel = 0; - OpenNode(&C->NavDropdownPre, &IndentationLevel, NODE_NAV, 0); - AppendStringToBuffer(&C->NavDropdownPre, Wrap0(" class=\"cineraNavDropdown ")); - AppendStringToBuffer(&C->NavDropdownPre, C->GlobalTheme); - AppendStringToBuffer(&C->NavDropdownPre, Wrap0("\">")); - OpenNodeNewLine(&C->NavDropdownPre, &IndentationLevel, NODE_NAV, 0); - AppendStringToBuffer(&C->NavDropdownPre, Wrap0(" class=\"cineraNavTitle\">")); - AppendStringToBuffer(&C->NavDropdownPre, Wrap0("Indexed Episode Guides")); - CloseNode(&C->NavDropdownPre, &IndentationLevel, NODE_NAV); - OpenNodeNewLine(&C->NavDropdownPre, &IndentationLevel, NODE_DIV, 0); - AppendStringToBuffer(&C->NavDropdownPre, Wrap0(" class=\"cineraPositioner\">")); - - CloseNodeNewLine(&C->NavDropdownPost, &IndentationLevel, NODE_DIV); - CloseNodeNewLine(&C->NavDropdownPost, &IndentationLevel, NODE_NAV); - - IndentationLevel = 0; - OpenNode(&C->NavHorizontalPre, &IndentationLevel, NODE_UL, 0); - AppendStringToBuffer(&C->NavHorizontalPre, Wrap0(" class=\"cineraNavHorizontal ")); - AppendStringToBuffer(&C->NavHorizontalPre, C->GlobalTheme); - AppendStringToBuffer(&C->NavHorizontalPre, Wrap0("\">")); - - IndentationLevel = 0; - OpenNode(&C->NavPlainPre, &IndentationLevel, NODE_UL, 0); - AppendStringToBuffer(&C->NavPlainPre, Wrap0(" class=\"cineraNavPlain ")); - AppendStringToBuffer(&C->NavPlainPre, C->GlobalTheme); - AppendStringToBuffer(&C->NavPlainPre, Wrap0("\">")); - - IndentationLevel = 1; - - for(int i = 0; i < C->ProjectCount; ++i) - { - project *P = &C->Project[i]; - GenerateGlobalNavigationRecursively(C, P, &IndentationLevel); - } - - CloseNodeNewLine(&C->NavGeneric, &IndentationLevel, NODE_UL); -} - -void -GenerateNavigationRecursively(project *TargetP, project *P, uint32_t *IndentationLevel) -{ - if(TargetP == P) - { - OpenNodeNewLine(&TargetP->NavGeneric, IndentationLevel, NODE_LI, 0); - AppendStringToBuffer(&TargetP->NavGeneric, Wrap0(" class=\"current\">")); - } - else - { - OpenNodeCNewLine(&TargetP->NavGeneric, IndentationLevel, NODE_LI, 0); - } - OpenNode(&TargetP->NavGeneric, IndentationLevel, NODE_A, 0); - AppendStringToBuffer(&TargetP->NavGeneric, Wrap0(" href=\"")); - - buffer URL; - ClaimBuffer(&URL, BID_URL_SEARCH, MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1); - ConstructSearchURL(&URL, P); - AppendBuffer(&TargetP->NavGeneric, &URL); - DeclaimBuffer(&URL); - - AppendStringToBuffer(&TargetP->NavGeneric, Wrap0("\">")); - AppendStringToBuffer(&TargetP->NavGeneric, P->HTMLTitle.Length ? P->HTMLTitle : P->Title); - CloseNode(&TargetP->NavGeneric, IndentationLevel, NODE_A); - - if(P->ChildCount > 0) - { - OpenNodeCNewLine(&TargetP->NavGeneric, IndentationLevel, NODE_UL, 0); - } - - for(int i = 0; i < P->ChildCount; ++i) - { - project *Child = &P->Child[i]; - GenerateNavigationRecursively(TargetP, Child, IndentationLevel); - } - - if(P->ChildCount > 0) - { - CloseNodeNewLine(&TargetP->NavGeneric, IndentationLevel, NODE_UL); - CloseNodeNewLine(&TargetP->NavGeneric, IndentationLevel, NODE_LI); - } - else - { - CloseNode(&TargetP->NavGeneric, IndentationLevel, NODE_LI); - } -} - -void -GenerateNavigationBars(project *P) -{ - // NavGeneric; - // NavDropdownPre; - // NavDropdownPost; - // NavHorizontalPre; - // NavPlainPre; - - uint32_t IndentationLevel = 0; - OpenNode(&P->NavDropdownPre, &IndentationLevel, NODE_NAV, 0); - AppendStringToBuffer(&P->NavDropdownPre, Wrap0(" class=\"cineraNavDropdown ")); - AppendStringToBuffer(&P->NavDropdownPre, P->Theme); - AppendStringToBuffer(&P->NavDropdownPre, Wrap0("\">")); - OpenNodeNewLine(&P->NavDropdownPre, &IndentationLevel, NODE_NAV, 0); - AppendStringToBuffer(&P->NavDropdownPre, Wrap0(" class=\"cineraNavTitle\">")); - AppendStringToBuffer(&P->NavDropdownPre, P->HTMLTitle.Length ? P->HTMLTitle : P->Title); - CloseNode(&P->NavDropdownPre, &IndentationLevel, NODE_NAV); - OpenNodeNewLine(&P->NavDropdownPre, &IndentationLevel, NODE_DIV, 0); - AppendStringToBuffer(&P->NavDropdownPre, Wrap0(" class=\"cineraPositioner\">")); - - CloseNodeNewLine(&P->NavDropdownPost, &IndentationLevel, NODE_DIV); - CloseNodeNewLine(&P->NavDropdownPost, &IndentationLevel, NODE_NAV); - - IndentationLevel = 0; - OpenNode(&P->NavHorizontalPre, &IndentationLevel, NODE_UL, 0); - AppendStringToBuffer(&P->NavHorizontalPre, Wrap0(" class=\"cineraNavHorizontal ")); - AppendStringToBuffer(&P->NavHorizontalPre, P->Theme); - AppendStringToBuffer(&P->NavHorizontalPre, Wrap0("\">")); - - IndentationLevel = 0; - OpenNode(&P->NavPlainPre, &IndentationLevel, NODE_UL, 0); - AppendStringToBuffer(&P->NavPlainPre, Wrap0(" class=\"cineraNavPlain ")); - AppendStringToBuffer(&P->NavPlainPre, P->Theme); - AppendStringToBuffer(&P->NavPlainPre, Wrap0("\">")); - - IndentationLevel = 1; - - project *Parent = P; - while(Parent->Parent) - { - Parent = Parent->Parent; - } - - // TODO(matt): Should this be calling GenerateNavigationRecursively() on the Parent? - for(int i = 0; i < Parent->ChildCount; ++i) - { - project *Child = &Parent->Child[i]; - GenerateNavigationRecursively(P, Child, &IndentationLevel); - } - - CloseNodeNewLine(&P->NavGeneric, &IndentationLevel, NODE_UL); -} - -void -SyncProject(project *P, neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate) -{ - for(int i = 0; i < P->ChildCount; ++i) - { - SyncProject(&P->Child[i], N, CollationBuffers, BespokeTemplate); + PackProjectTemplates(GetPlaceInBook(&P->Child, i), N, Titled); } SetCurrentProject(P, N); - fprintf(stderr, "\n" - "┌─ "); - PrintLineage(P->Lineage, FALSE); - fprintf(stderr, " ─╼"); - - bool Titled = FALSE; - bool TitledTemplates = FALSE; // TODO(matt): We need to figure out a way to stay awake beyond the detection of an invalid template if(CurrentProject->PlayerTemplatePath.Length > 0) { - if(!TitledTemplates) + if(!Titled) { fprintf(stderr, "\n" - "%s─── Packing templates ───╼\n", Titled ? "╾" : "└"); - TitledTemplates = TRUE; - Titled = TRUE; + "╾─ Packing templates ─╼\n"); + *Titled = TRUE; } - switch(PackTemplate(&CurrentProject->PlayerTemplate, CurrentProject->PlayerTemplatePath, TEMPLATE_PLAYER)) + switch(PackTemplate(&CurrentProject->PlayerTemplate, CurrentProject->PlayerTemplatePath, TEMPLATE_PLAYER, CurrentProject)) { case RC_ERROR_FILE: // Could not load template case RC_ERROR_MEMORY: // Could not allocate memory for template @@ -14616,17 +14669,15 @@ SyncProject(project *P, neighbourhood *N, buffers *CollationBuffers, template *B } } - // TODO(matt): We need to figure out a way to stay awake beyond the detection of an invalid template if(CurrentProject->SearchTemplatePath.Length > 0) { - if(!TitledTemplates) + if(!*Titled) { fprintf(stderr, "\n" - "%s─── Packing templates ───╼\n", Titled ? "╾" : "└"); - TitledTemplates = TRUE; - Titled = TRUE; + "╾─ Packing templates ─╼\n"); + *Titled = TRUE; } - switch(PackTemplate(&CurrentProject->SearchTemplate, CurrentProject->SearchTemplatePath, TEMPLATE_SEARCH)) + switch(PackTemplate(&CurrentProject->SearchTemplate, CurrentProject->SearchTemplatePath, TEMPLATE_SEARCH, CurrentProject)) { case RC_ERROR_MEMORY: // Could not allocate memory for template case RC_ERROR_FILE: // Could not load template @@ -14638,11 +14689,65 @@ SyncProject(project *P, neighbourhood *N, buffers *CollationBuffers, template *B break; } } +} - GenerateNavigationBars(P); +void +PackTemplates(neighbourhood *N) +{ + bool Titled = FALSE; + if(Config->GlobalSearchTemplatePath.Length > 0) + { + if(!Titled) + { + fprintf(stderr, "\n" + "╾─ Packing templates ─╼\n"); + Titled = TRUE; + } + fprintf(stderr, "\n"); + switch(PackTemplate(&Config->SearchTemplate, Config->GlobalSearchTemplatePath, TEMPLATE_GLOBAL_SEARCH, 0)) + { + case RC_ERROR_MEMORY: // Could not allocate memory for template + case RC_ERROR_FILE: // Could not load template + // TODO(matt): Urgently decide how we handle the case in which we've been given an invalid template + free(MemoryArena.Location); + _exit(0); + case RC_INVALID_TEMPLATE: // Invalid template + case RC_SUCCESS: + break; + } + } + + for(int i = 0; i < Config->Project.ItemCount; ++i) + { + PackProjectTemplates(GetPlaceInBook(&Config->Project, i), N, &Titled); + } +} + +void +SyncProject(project *P, neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate, bool *Titled) +{ + for(int i = 0; i < P->Child.ItemCount; ++i) + { + SyncProject(GetPlaceInBook(&P->Child, i), N, CollationBuffers, BespokeTemplate, Titled); + } + + SetCurrentProject(P, N); + if(!*Titled) + { + fprintf(stderr, "\n" + "┌─ Synchronising with Input Directories ─╼\n" + "└─── "); + *Titled = TRUE; + } + else + { + fprintf(stderr, "\n" + "╾─── "); + } + + PrintLineage(P->Lineage, FALSE); + fprintf(stderr, " ───╼\n"); - fprintf(stderr, "\n" - "%s─── Synchronising with Input Directories ───╼\n", Titled ? "╾" : "└"); SyncDBWithInput(N, CollationBuffers, BespokeTemplate); PushWatchHandle(P->HMMLDir, EXT_HMML, WT_HMML, P, 0); @@ -14716,34 +14821,19 @@ InitAll(neighbourhood *Neighbourhood, buffers *CollationBuffers, template *Bespo // //// - if(Config->GlobalSearchTemplatePath.Length > 0) - { - fprintf(stderr, "\n"); - switch(PackTemplate(&Config->SearchTemplate, Config->GlobalSearchTemplatePath, TEMPLATE_GLOBAL_SEARCH)) - { - case RC_ERROR_MEMORY: // Could not allocate memory for template - case RC_ERROR_FILE: // Could not load template - // TODO(matt): Urgently decide how we handle the case in which we've been given an invalid template - free(MemoryArena.Location); - _exit(0); - case RC_INVALID_TEMPLATE: // Invalid template - case RC_SUCCESS: - break; - } - } + PackTemplates(Neighbourhood); - GenerateGlobalNavigationBars(Config); - - for(int i = 0; i < Config->ProjectCount; ++i) + bool TitledSync = FALSE; + for(int i = 0; i < Config->Project.ItemCount; ++i) { - SyncProject(&Config->Project[i], Neighbourhood, CollationBuffers, BespokeTemplate); + SyncProject(GetPlaceInBook(&Config->Project, i), Neighbourhood, CollationBuffers, BespokeTemplate, &TitledSync); } SyncGlobalPagesWithInput(Neighbourhood, CollationBuffers); - for(int i = 0; i < Assets.Count; ++i) + for(int i = 0; i < Assets.ItemCount; ++i) { - asset *This = GetPlaceInBook(&Assets.Asset, i); + asset *This = GetPlaceInBook(&Assets, i); UpdateAssetInDB(This); } DeleteStaleAssets(); @@ -14830,7 +14920,7 @@ GetWatchFileForEvent(struct inotify_event *Event) } void -ParseAndEitherPrintConfigOrInitAll(string ConfigPath, tokens_list *TokensList, neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate) +ParseAndEitherPrintConfigOrInitAll(string ConfigPath, memory_book *TokensList, neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate) { Config = ParseConfig(ConfigPath, TokensList); if(Config) @@ -14847,7 +14937,7 @@ ParseAndEitherPrintConfigOrInitAll(string ConfigPath, tokens_list *TokensList, n } int -MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate, string ConfigPath, tokens_list *TokensList) +MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate, string ConfigPath, memory_book *TokensList) { buffer Events = {}; if(ClaimBuffer(&Events, BID_INOTIFY_EVENTS, Kilobytes(4)) == RC_ARENA_FULL) { return RC_ARENA_FULL; }; @@ -15053,7 +15143,8 @@ main(int ArgC, char **Args) CollationBuffers.Search.ID = BID_COLLATION_BUFFERS_SEARCH; // NOTE(matt): Allocated by SearchToBuffer() - tokens_list TokensList = {}; + memory_book TokensList = {}; + InitBook(&TokensList, sizeof(tokens), 8, MBT_TOKENS); template BespokeTemplate = {}; neighbourhood Neighbourhood = {}; diff --git a/cinera/cinera_config.c b/cinera/cinera_config.c index 1cb105c..d42454d 100644 --- a/cinera/cinera_config.c +++ b/cinera/cinera_config.c @@ -285,48 +285,6 @@ MakeString0_(char *Filename, int LineNumber, char *Format, int ArgCount, ...) return Result; } -file -InitFile(string *Directory, string *Filename, extension_id Extension) -{ - file Result = {}; - if(Directory) - { - ExtendString0(&Result.Path, *Directory); - ExtendString0(&Result.Path, Wrap0("/")); - } - - ExtendString0(&Result.Path, *Filename); - - if(Extension != EXT_NULL) - { - ExtendString0(&Result.Path, ExtensionStrings[Extension]); - } - return Result; -} - -void -ReadFileIntoBuffer(file *F) -{ - if(F->Path) - { - if((F->Handle = fopen(F->Path, "r"))) - { - fseek(F->Handle, 0, SEEK_END); - F->Buffer.Size = ftell(F->Handle); - F->Buffer.Location = malloc(F->Buffer.Size); - F->Buffer.Ptr = F->Buffer.Location; - fseek(F->Handle, 0, SEEK_SET); - fread(F->Buffer.Location, F->Buffer.Size, 1, F->Handle); - fclose(F->Handle); - F->Handle = 0; - } - else - { - perror(F->Path); - } - } -} - void PushToken(tokens *Set, token *Token) { @@ -334,19 +292,19 @@ PushToken(tokens *Set, token *Token) //PrintFunctionName("PushToken()"); if(!(Token->Type == TOKEN_NULL || Token->Type == TOKEN_COMMENT || Token->Type == TOKEN_NEWLINE)) { - Set->Token = Fit(Set->Token, sizeof(*Set->Token), Set->Count, 16, TRUE); - Set->Token[Set->Count].Type = Token->Type; - Set->Token[Set->Count].LineNumber = Set->CurrentLine; + token *This = GetPlaceInBook(&Set->Token, Set->Token.ItemCount); + This->Type = Token->Type; + This->LineNumber = Set->CurrentLine; if(Token->Type == TOKEN_NUMBER) { - Set->Token[Set->Count].int64_t = StringToInt(Token->Content); + This->int64_t = StringToInt(Token->Content); } else { - Set->Token[Set->Count].Content = Token->Content; + This->Content = Token->Content; } - ++Set->Count; + ++Set->Token.ItemCount; } } @@ -376,32 +334,35 @@ void PrintTokens(tokens *T) { //PrintFunctionName("PrintTokens()"); - for(int i = 0; i < T->Count; ++i) + for(int i = 0; i < T->Token.ItemCount; ++i) { - PrintToken(&T->Token[i], i); + token *This = GetPlaceInBook(&T->Token, i); + PrintToken(This, i); } } tokens * -PushTokens(tokens_list *S) +PushTokens(memory_book *TokensList) { - S->Tokens = Fit(S->Tokens, sizeof(*S->Tokens), S->Count, 4, TRUE); - S->Tokens[S->Count].CurrentLine = 1; - ++S->Count; - return &S->Tokens[S->Count - 1]; + tokens *This = GetPlaceInBook(TokensList, TokensList->ItemCount); + InitBook(&This->Token, sizeof(token), 16, MBT_TOKEN); + This->CurrentLine = 1; + ++TokensList->ItemCount; + return This; } void -FreeTokensList(tokens_list *T) +FreeTokensList(memory_book *TokensList) { - for(int i = 0; i < T->Count; ++i) + for(int i = 0; i < TokensList->ItemCount; ++i) { - T->Tokens[i].CurrentIndex = 0; - T->Tokens[i].CurrentLine = 0; - FreeAndResetCount(T->Tokens[i].Token, T->Tokens[i].Count); - FreeFile(&T->Tokens[i].File); + tokens *This = GetPlaceInBook(TokensList, i); + This->CurrentIndex = 0; + This->CurrentLine = 0; + FreeBook(&This->Token); + FreeFile(&This->File); } - T->Count = 0; + TokensList->ItemCount = 0; } void @@ -523,8 +484,7 @@ typedef struct string ID; string Name; string Homepage; - support *Support; - uint8_t SupportCount; + _memory_book(support) Support; } person; typedef struct project @@ -565,36 +525,23 @@ typedef struct project bool IgnorePrivacy; person *Owner; - person **Indexer; - person **Guest; - person **CoHost; + _memory_book(person) Indexer; + _memory_book(person) Guest; + _memory_book(person) CoHost; - medium *Medium; // Multiple - medium *DefaultMedium; // Pointer to Medium + _memory_book(medium) Medium; + medium *DefaultMedium; - struct project *Child; // Multiple - struct project *Parent; // Pointer to single parent + _memory_book(project) Child; + + struct project *Parent; genre Genre; numbering_scheme NumberingScheme; - uint8_t IndexerCount; - uint8_t GuestCount; - uint8_t CoHostCount; - - uint8_t MediumCount; - - uint8_t ChildCount; - db_project_index Index; template PlayerTemplate; template SearchTemplate; - - buffer NavDropdownPre; - buffer NavHorizontalPre; - buffer NavPlainPre; - buffer NavGeneric; - buffer NavDropdownPost; } project; typedef struct @@ -609,12 +556,6 @@ typedef struct string GlobalTheme; template SearchTemplate; - buffer NavDropdownPre; - buffer NavHorizontalPre; - buffer NavPlainPre; - buffer NavGeneric; - buffer NavDropdownPost; - string AssetsRootDir; string AssetsRootURL; string CSSDir; @@ -626,10 +567,8 @@ typedef struct time_t PrivacyCheckInterval; uint8_t LogLevel; - person *Person; - project *Project; - uint8_t ProjectCount; - uint8_t PersonCount; + _memory_book(person) Person; + _memory_book(project) Project; memory_book ResolvedVariables; } config; @@ -637,7 +576,7 @@ char *ExpandPath(string Path, string *RelativeToFile); // NOTE(matt): Forward de void PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *Project, asset *Asset); // NOTE(matt): Forward declared. Consider reorganising the code? tokens * -Tokenise(tokens_list *TokensList, string Path) +Tokenise(memory_book *TokensList, string Path) { tokens *Result = 0; char *Path0 = MakeString0("l", &Path); @@ -646,6 +585,7 @@ Tokenise(tokens_list *TokensList, string Path) if((Handle = fopen(Path0, "r"))) { fclose(Handle); + Result = PushTokens(TokensList); Result->File = InitFile(0, &Path, EXT_NULL); ReadFileIntoBuffer(&Result->File); @@ -820,10 +760,11 @@ bool TokenEquals(tokens *T, char *String) { int i = 0; - for(; i < T->Token[T->CurrentIndex].Content.Length && *String && T->Token[T->CurrentIndex].Content.Base[i] == String[i]; ++i) + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + for(; i < This->Content.Length && *String && This->Content.Base[i] == String[i]; ++i) { } - if(i == T->Token[T->CurrentIndex].Content.Length && !String[i]) + if(i == This->Content.Length && !String[i]) { return TRUE; } @@ -833,7 +774,8 @@ TokenEquals(tokens *T, char *String) bool TokenIs(tokens *T, token_type Type) { - return(T->Token[T->CurrentIndex].Type == Type); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + return(This->Type == Type); } bool @@ -841,12 +783,13 @@ ExpectToken(tokens *T, token_type Type, token *Dest) { bool Result = FALSE; - if(T->Token[T->CurrentIndex].Type == Type) + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + if(This->Type == Type) { Result = TRUE; if(Dest) { - *Dest = T->Token[T->CurrentIndex]; + *Dest = *This; } } else @@ -1255,20 +1198,23 @@ SetTypeSpec(scope_tree *Type, config_type_specs *TypeSpecs) config_type_field * CurrentFieldIsInSpec(config_type_spec *Spec, tokens *T) { - + config_type_field *Result = 0; if(Spec) { for(int i = 0; i < Spec->FieldCount; ++i) { - if(!StringsDifferLv0(T->Token[T->CurrentIndex].Content, ConfigIdentifiers[Spec->Field[i].ID].String)) + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + if(!StringsDifferLv0(This->Content, ConfigIdentifiers[Spec->Field[i].ID].String)) { - return &Spec->Field[i]; + Result = &Spec->Field[i]; + break; } } } - return 0; + return Result; } +// TODO(matt): Replace with a memory_book typedef struct { uint64_t Count; @@ -1319,7 +1265,8 @@ void PrintCurrentToken(colour_code C, tokens *T) { Colourise(C); - PrintToken(&T->Token[T->CurrentIndex], T->CurrentIndex); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + PrintToken(This, T->CurrentIndex); Colourise(CS_END); } @@ -1999,7 +1946,7 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec else if(TokenIs(T, TOKEN_OPEN_BRACE)) { ++T->CurrentIndex; - for(; T->CurrentIndex < T->Count;) + for(; T->CurrentIndex < T->Token.ItemCount;) { if(TokenIs(T, TOKEN_IDENTIFIER)) { @@ -2008,7 +1955,8 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec if(Rules->Scheme == CRT_DENY) { FreeRules(Rules); - ConfigError(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_WARNING, "Mixture of allow and deny identifiers in \"include\" scope", 0); + 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; } Rules->Scheme = CRT_ALLOW; @@ -2018,14 +1966,16 @@ ParseIncludeRules(config_type_specs *TypeSpecs, config_type_spec *ParentTypeSpec if(Rules->Scheme == CRT_ALLOW) { FreeRules(Rules); - ConfigError(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_WARNING, "Mixture of allow and deny identifiers in \"include\" scope", 0); + 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; } Rules->Scheme = CRT_DENY; } else { - ConfigError(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_WARNING, "Invalid identifier in \"include\" scope: ", &T->Token[T->CurrentIndex].Content); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Invalid identifier in \"include\" scope: ", &This->Content); fprintf(stderr, " Valid identifiers:\n" " allow\n" @@ -2134,10 +2084,10 @@ SetDefaults(scope_tree *Root, config_type_specs *TypeSpecs) } scope_tree * -ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_specs *TypeSpecs, config_include_rules *Rules) +ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, config_type_specs *TypeSpecs, config_include_rules *Rules) { scope_tree *Parent = Tree; - for(T->CurrentIndex = 0; T->CurrentIndex < T->Count;) + for(T->CurrentIndex = 0; T->CurrentIndex < T->Token.ItemCount;) { if(TokenIs(T, TOKEN_IDENTIFIER)) { @@ -2148,7 +2098,8 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp { if(Field->IsSetLocally && Field->Singleton) { - ConfigError(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_WARNING, "Field already set: ", &T->Token[T->CurrentIndex].Content); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + ConfigError(T->File.Path, 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 // right here @@ -2163,7 +2114,8 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp { case FT_BARE: { - token Value = T->Token[T->CurrentIndex]; + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + token Value = *This; Pair.Position.LineNumber = Value.LineNumber; ++T->CurrentIndex; @@ -2363,11 +2315,12 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp string IncludePathL = Wrap0(IncludePath); tokens *I = 0; - for(int i = 0; i < TokensList->Count; ++i) + for(int i = 0; i < TokensList->ItemCount; ++i) { - if(!StringsDifferLv0(Value.Content, TokensList->Tokens[i].File.Path)) + tokens *This = GetPlaceInBook(TokensList, i); + if(!StringsDifferLv0(Value.Content, This->File.Path)) { - I = TokensList->Tokens + i; + I = This; I->CurrentIndex = 0; I->CurrentLine = 0; } @@ -2387,7 +2340,8 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp } else { - ConfigFileIncludeError(T->File.Path, T->Token[IncludePathTokenIndex].LineNumber, Wrap0(IncludePath)); + token *This = GetPlaceInBook(&T->Token, IncludePathTokenIndex); + ConfigFileIncludeError(T->File.Path, This->LineNumber, Wrap0(IncludePath)); } Free(IncludePath); } break; @@ -2406,11 +2360,14 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp } else { + // TODO(matt): Here is probably where we must fix deduplication of support scopes scope_tree *Search = 0; + bool SelfContained = FALSE; if(Field->ID == IDENT_SUPPORT) { scope_tree *ParentP = Parent; Search = GetScope(ParentP, &Pair, Field->Singleton); + if(Search) { SelfContained = TRUE; } while(!Search && ParentP->Parent) { ParentP = ParentP->Parent; @@ -2425,7 +2382,7 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp if(Search) { - if(Field->ID == IDENT_SUPPORT) + if(Field->ID == IDENT_SUPPORT && !SelfContained) { Parent = CopyScope(TypeSpecs, Parent, Search); } @@ -2471,13 +2428,15 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp } else { - ConfigError(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_WARNING, "Field not allowed: ", &T->Token[T->CurrentIndex].Content); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Field not allowed: ", &This->Content); DepartAssignment(T); } } else { - ConfigError(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_WARNING, "Invalid field: ", &T->Token[T->CurrentIndex].Content); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + ConfigError(T->File.Path, This->LineNumber, S_WARNING, "Invalid field: ", &This->Content); if(!DepartAssignment(T)) { FreeScopeTree(Tree); @@ -2489,7 +2448,8 @@ ScopeTokens(scope_tree *Tree, tokens_list *TokensList, tokens *T, config_type_sp { if(!Parent->Parent) { - ConfigError(T->File.Path, T->Token[T->CurrentIndex].LineNumber, S_ERROR, "Syntax error: Unpaired closing brace", 0); + token *This = GetPlaceInBook(&T->Token, T->CurrentIndex); + ConfigError(T->File.Path, This->LineNumber, S_ERROR, "Syntax error: Unpaired closing brace", 0); FreeScopeTree(Tree); return 0; } @@ -2617,11 +2577,12 @@ ResolveEnvironmentVariable(memory_book *M, string Variable) person * GetPerson(config *C, resolution_errors *E, config_pair *PersonID) { - for(int i = 0; i < C->PersonCount; ++i) + for(int i = 0; i < C->Person.ItemCount; ++i) { - if(!StringsDifferCaseInsensitive(C->Person[i].ID, PersonID->Value)) + person *Person = GetPlaceInBook(&C->Person, i); + if(!StringsDifferCaseInsensitive(Person->ID, PersonID->Value)) { - return &C->Person[i]; + return Person; } } @@ -2908,22 +2869,19 @@ string StripSlashes(string Path, path_relativity Relativity) { string Result = Path; - if(Path.Length > 0) + if(Relativity == P_REL) { - if(Relativity == P_REL) - { - while(*Result.Base == '/') - { - ++Result.Base; - --Result.Length; - } - } - - while(Result.Base[Result.Length - 1] == '/') + while(Result.Length > 0 && *Result.Base == '/') { + ++Result.Base; --Result.Length; } } + + while(Result.Length > 0 && Result.Base[Result.Length - 1] == '/') + { + --Result.Length; + } return Result; } @@ -2961,24 +2919,6 @@ PushVariantUniquely(resolution_errors *E, variant_strings *VS, string Path, uint if(StringsMatch(This->Path, Path)) { FoundPath = TRUE; -/* -Incoming Variants: 4 -List: - 16 - 2 - -Incoming Variants: 4 -List: - 16 - 2 - 4 - -Incoming Variants: 2 -List: - 16 - 2 - 4 -*/ bool FoundVariantsMatch = FALSE; for(int VariantsIndex = 0; VariantsIndex < This->VariantsCount; ++VariantsIndex) { @@ -3013,16 +2953,10 @@ List: } } -typedef struct -{ - project *Alloc; - project *Project; -} project_and_alloc; - typedef struct { string String; - project_and_alloc *Projects; + project **Projects; uint64_t ProjectCount; } config_string_association; @@ -3043,9 +2977,7 @@ 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? - P->Medium = Fit(P->Medium, sizeof(*P->Medium), P->MediumCount, 8, TRUE); - - medium *Medium = P->Medium + P->MediumCount; + medium *Medium = GetPlaceInBook(&P->Medium, P->Medium.ItemCount); Medium->ID = ResolveString(C, E, MediumTree, &MediumTree->ID, FALSE); for(int i = 0; i < MediumTree->PairCount; ++i) { @@ -3112,16 +3044,16 @@ PushMedium(config *C, resolution_errors *E, config_verifiers *V, project *P, sco } } - ++P->MediumCount; + ++P->Medium.ItemCount; } medium * GetMediumFromProject(project *P, string ID) { medium *Result = 0; - for(int i = 0; i < P->MediumCount; ++i) + for(int i = 0; i < P->Medium.ItemCount; ++i) { - medium *This = P->Medium + i; + medium *This = GetPlaceInBook(&P->Medium, i); if(StringsMatch(ID, This->ID)) { Result = This; @@ -3134,8 +3066,7 @@ GetMediumFromProject(project *P, string ID) void PushSupport(config *C, resolution_errors *E, config_verifiers *V, person *P, scope_tree *SupportTree) { - P->Support = Fit(P->Support, sizeof(*P->Support), P->SupportCount, 2, TRUE); - support *Support = P->Support + P->SupportCount; + support *Support = GetPlaceInBook(&P->Support, P->Support.ItemCount); Support->ID = ResolveString(C, E, SupportTree, &SupportTree->ID, FALSE); for(int i = 0; i < SupportTree->PairCount; ++i) { @@ -3190,7 +3121,7 @@ PushSupport(config *C, resolution_errors *E, config_verifiers *V, person *P, sco } } - ++P->SupportCount; + ++P->Support.ItemCount; } void @@ -3198,26 +3129,27 @@ PushPersonOntoConfig(config *C, resolution_errors *E, config_verifiers *V, scope { //PrintFunctionName("PushPersonOntoConfig()"); //PrintScopeTree(PersonTree); - C->Person = Fit(C->Person, sizeof(*C->Person), C->PersonCount, 8, TRUE); - C->Person[C->PersonCount].ID = ResolveString(C, E, PersonTree, &PersonTree->ID, FALSE); + person *This = GetPlaceInBook(&C->Person, C->Person.ItemCount); + This->ID = ResolveString(C, E, PersonTree, &PersonTree->ID, FALSE); for(int i = 0; i < PersonTree->PairCount; ++i) { if(PersonTree->Pairs[i].Key == IDENT_NAME) { - C->Person[C->PersonCount].Name = ResolveString(C, E, PersonTree, &PersonTree->Pairs[i], FALSE); + This->Name = ResolveString(C, E, PersonTree, &PersonTree->Pairs[i], FALSE); } else if(PersonTree->Pairs[i].Key == IDENT_HOMEPAGE) { - C->Person[C->PersonCount].Homepage = ResolveString(C, E, PersonTree, &PersonTree->Pairs[i], FALSE); + This->Homepage = ResolveString(C, E, PersonTree, &PersonTree->Pairs[i], FALSE); } } + InitBook(&This->Support, sizeof(support), 2, MBT_SUPPORT); for(int i = 0; i < PersonTree->TreeCount; ++i) { - PushSupport(C, E, V, &C->Person[C->PersonCount], &PersonTree->Trees[i]); + PushSupport(C, E, V, This, &PersonTree->Trees[i]); } - ++C->PersonCount; + ++C->Person.ItemCount; } void @@ -3230,21 +3162,21 @@ PushPersonOntoProject(config *C, resolution_errors *E, project *P, config_pair * { case IDENT_INDEXER: { - P->Indexer = Fit(P->Indexer, sizeof(*P->Indexer), P->IndexerCount, 4, FALSE); - P->Indexer[P->IndexerCount] = Person; - ++P->IndexerCount; + person **Indexer = GetPlaceInBook(&P->Indexer, P->Indexer.ItemCount); + *Indexer = Person; + ++P->Indexer.ItemCount; } break; case IDENT_COHOST: { - P->CoHost = Fit(P->CoHost, sizeof(*P->CoHost), P->CoHostCount, 4, FALSE); - P->CoHost[P->CoHostCount] = Person; - ++P->CoHostCount; + person **CoHost = GetPlaceInBook(&P->CoHost, P->CoHost.ItemCount); + *CoHost = Person; + ++P->CoHost.ItemCount; } break; case IDENT_GUEST: { - P->Guest = Fit(P->Guest, sizeof(*P->Guest), P->GuestCount, 4, FALSE); - P->Guest[P->GuestCount] = Person; - ++P->GuestCount; + person **Guest = GetPlaceInBook(&P->Guest, P->Guest.ItemCount); + *Guest = Person; + ++P->Guest.ItemCount; } break; default:; } @@ -3254,25 +3186,24 @@ PushPersonOntoProject(config *C, resolution_errors *E, project *P, config_pair * void PushProjectOntoProject(config *C, resolution_errors *E, config_verifiers *Verifiers, project *Parent, scope_tree *ProjectTree); void -AddProjectToAssociation(config_string_association *A, project *Alloc, project *P) +AddProjectToAssociation(config_string_association *A, project *P) { A->Projects = Fit(A->Projects, sizeof(*A->Projects), A->ProjectCount, 4, TRUE); - A->Projects[A->ProjectCount].Alloc = Alloc; - A->Projects[A->ProjectCount].Project = P; + A->Projects[A->ProjectCount] = P; ++A->ProjectCount; } void -PushHMMLDirAssociation(config_string_associations *HMMLDirs, string *S, project *Alloc, project *P) +PushHMMLDirAssociation(config_string_associations *HMMLDirs, string *S, project *P) { HMMLDirs->Associations = Fit(HMMLDirs->Associations, sizeof(*HMMLDirs->Associations), HMMLDirs->Count, 8, TRUE); HMMLDirs->Associations[HMMLDirs->Count].String = *S; - AddProjectToAssociation(&HMMLDirs->Associations[HMMLDirs->Count], Alloc, P); + AddProjectToAssociation(&HMMLDirs->Associations[HMMLDirs->Count], P); ++HMMLDirs->Count; } void -SetUniqueHMMLDir(config *C, resolution_errors *E, config_string_associations *HMMLDirs, project *Alloc, project *P, scope_tree *ProjectTree, config_pair *HMMLDir) +SetUniqueHMMLDir(config *C, resolution_errors *E, config_string_associations *HMMLDirs, project *P, scope_tree *ProjectTree, config_pair *HMMLDir) { string Result = StripSlashes(ResolveString(C, E, ProjectTree, HMMLDir, TRUE), P_ABS); bool Clashed = FALSE; @@ -3280,7 +3211,7 @@ SetUniqueHMMLDir(config *C, resolution_errors *E, config_string_associations *HM { if(StringsMatch(HMMLDirs->Associations[i].String, Result)) { - AddProjectToAssociation(&HMMLDirs->Associations[i], Alloc, P); + AddProjectToAssociation(&HMMLDirs->Associations[i], P); PushError(E, S_ERROR, &HMMLDir->Position, IDENT_HMML_DIR); Clashed = TRUE; break; @@ -3289,14 +3220,20 @@ SetUniqueHMMLDir(config *C, resolution_errors *E, config_string_associations *HM if(!Clashed) { - PushHMMLDirAssociation(HMMLDirs, &Result, Alloc, P); + PushHMMLDirAssociation(HMMLDirs, &Result, P); } P->HMMLDir = Result; } void -PushProject(config *C, resolution_errors *E, config_verifiers *V, project *Alloc, 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); + 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); + config_string_associations *HMMLDirs = &V->HMMLDirs; P->ID = ResolveString(C, E, ProjectTree, &ProjectTree->ID, FALSE); if(P->ID.Length > MAX_PROJECT_ID_LENGTH) @@ -3324,7 +3261,7 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *Alloc case IDENT_DEFAULT_MEDIUM: { P->DefaultMedium = GetMediumFromProject(P, This->Value); } break; case IDENT_HMML_DIR: - { SetUniqueHMMLDir(C, E, HMMLDirs, Alloc, P, ProjectTree, This); } break; + { SetUniqueHMMLDir(C, E, HMMLDirs, P, ProjectTree, This); } break; case IDENT_INDEXER: case IDENT_COHOST: case IDENT_GUEST: @@ -3502,121 +3439,63 @@ PushProject(config *C, resolution_errors *E, config_verifiers *V, project *Alloc C->RespectingPrivacy |= !P->IgnorePrivacy; } -void -OffsetAssociationProjectPointers(config_string_associations *HMMLDirs, project *Alloc, int64_t Diff) -{ - for(int i = 0; i < HMMLDirs->Count; ++i) - { - config_string_association *A = HMMLDirs->Associations + i; - for(int j = 0; j < A->ProjectCount; ++j) - { - if(A->Projects[j].Alloc == Alloc) - { - A->Projects[j].Alloc += Diff; - A->Projects[j].Project += Diff; - } - } - } -} - -void -OffsetProjectPointers_TopLevel(config_string_associations *HMMLDirs, config *Parent, project *Alloc, int64_t Diff) -{ - OffsetAssociationProjectPointers(HMMLDirs, Alloc, Diff); - for(int i = 0; i < Parent->ProjectCount; ++i) - { - project *Child = Parent->Project + i; - for(int j = 0; j < Child->ChildCount; ++j) - { - project *Grandchild = Child->Child + j; - Grandchild->Parent += Diff; - } - } -} - -void -OffsetProjectPointers(config_string_associations *HMMLDirs, project *Parent, project *Alloc, int64_t Diff) -{ - OffsetAssociationProjectPointers(HMMLDirs, Alloc, Diff); - for(int i = 0; i < Parent->ChildCount; ++i) - { - project *Child = Parent->Child + i; - for(int j = 0; j < Child->ChildCount; ++j) - { - project *Grandchild = Child->Child + j; - Grandchild->Parent += Diff; - } - } -} - void PushProjectOntoProject(config *C, resolution_errors *E, config_verifiers *Verifiers, project *Parent, scope_tree *ProjectTree) { - config_string_associations *HMMLDirs = &Verifiers->HMMLDirs; - project *Current = Parent->Child; - Parent->Child = Fit(Parent->Child, sizeof(*Parent->Child), Parent->ChildCount, 8, TRUE); - int64_t Diff = Parent->Child - Current; - if(Diff) - { - OffsetProjectPointers(HMMLDirs, Parent, Current, Diff); - } + project *P = GetPlaceInBook(&Parent->Child, Parent->Child.ItemCount); - project *P = Parent->Child + Parent->ChildCount; - - PushProject(C, E, Verifiers, Parent->Child, P, ProjectTree); + PushProject(C, E, Verifiers, P, ProjectTree); P->Parent = Parent; - ++Parent->ChildCount; + ++Parent->Child.ItemCount; } project * GetProjectFromProject(project *Parent, string ID) { + project *Result = 0; if(Parent) { - for(int i = 0; i < Parent->ChildCount; ++i) + for(int i = 0; i < Parent->Child.ItemCount; ++i) { - if(StringsMatch(Parent->Child[i].ID, ID)) + project *This = GetPlaceInBook(&Parent->Child, i); + if(StringsMatch(This->ID, ID)) { - return &Parent->Child[i]; + Result = This; + break; } } } - return 0; + return Result; } void PushProjectOntoConfig(config *C, resolution_errors *E, config_verifiers *Verifiers, scope_tree *ProjectTree) { - config_string_associations *HMMLDirs = &Verifiers->HMMLDirs; - project *Current = C->Project; - C->Project = Fit(C->Project, sizeof(*C->Project), C->ProjectCount, 8, TRUE); - int64_t Diff = C->Project - Current; - if(Diff) - { - OffsetProjectPointers_TopLevel(HMMLDirs, C, Current, Diff); - } - project *P = C->Project + C->ProjectCount; + project *P = GetPlaceInBook(&C->Project, C->Project.ItemCount); - PushProject(C, E, Verifiers, C->Project, P, ProjectTree); + PushProject(C, E, Verifiers, P, ProjectTree); - ++C->ProjectCount; + ++C->Project.ItemCount; } project * GetProjectFromConfig(config *C, string ID) { + project *Result = 0; if(C) { - for(int i = 0; i < C->ProjectCount; ++i) + for(int i = 0; i < C->Project.ItemCount; ++i) { - if(StringsMatch(C->Project[i].ID, ID)) + project *This = GetPlaceInBook(&C->Project, i); + if(StringsMatch(This->ID, ID)) { - return &C->Project[i]; + Result = This; + break; } } } - return 0; + return Result; } void @@ -3634,7 +3513,7 @@ PrintAssociationClashes(config_string_associations *A) fprintf(stderr, "\n"); for(int j = 0; j < Association->ProjectCount; ++j) { - project *P = Association->Projects[j].Project; + project *P = Association->Projects[j]; fprintf(stderr, " "); PrintStringC(CS_CYAN, P->Lineage); fprintf(stderr, "\n"); @@ -3735,6 +3614,8 @@ 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.ID = IDENT_HMML_DIR; @@ -4161,10 +4042,10 @@ GetRowsRequiredForPersonInfo(typography *T, person *P) if(P->Name.Length > 0) { ++RowsRequired; } if(P->Homepage.Length > 0) { ++RowsRequired; } - for(int i = 0; i < P->SupportCount; ++i) + for(int i = 0; i < P->Support.ItemCount; ++i) { ++RowsRequired; - support *This = P->Support + i; + support *This = GetPlaceInBook(&P->Support, i); if(This->URL.Length > 0) { ++RowsRequired; } if(This->Icon.Length > 0) { ++RowsRequired; } if(This->IconNormal.Length > 0) { ++RowsRequired; } @@ -4179,7 +4060,7 @@ GetRowsRequiredForPersonInfo(typography *T, person *P) void PrintPerson(person *P, config_identifier_id Role, typography *Typography) { - bool HaveInfo = P->Name.Length > 0 || P->Homepage.Length > 0 || P->SupportCount > 0; + bool HaveInfo = P->Name.Length > 0 || P->Homepage.Length > 0 || P->Support.ItemCount > 0; fprintf(stderr, "\n" "%s%s%s%s%s ", HaveInfo ? Typography->UpperLeftCorner : Typography->UpperLeft, Typography->Horizontal, Typography->Horizontal, Typography->Horizontal, Typography->UpperRight); @@ -4204,9 +4085,10 @@ PrintPerson(person *P, config_identifier_id Role, typography *Typography) --RowsRequired; } - for(int i = 0; i < P->SupportCount; ++i) + for(int i = 0; i < P->Support.ItemCount; ++i) { - PrintSupport(&P->Support[i], Typography, IndentationLevel, &RowsRequired); + support *This = GetPlaceInBook(&P->Support, i); + PrintSupport(This, Typography, IndentationLevel, &RowsRequired); } } @@ -4269,16 +4151,17 @@ PrintMedia(project *P, typography *T, uint8_t Generation, int AvailableColumns) fprintf(stderr, "%s", T->Margin); //AvailableColumns -= Generation + 1; int RunningAvailableColumns = AvailableColumns; - int ColumnsRequired = GetColumnsRequiredForMedium(&P->Medium[0], T); + medium *This = GetPlaceInBook(&P->Medium, 0); + int ColumnsRequired = GetColumnsRequiredForMedium(This, T); if(ColumnsRequired <= RunningAvailableColumns) { - PrintMedium(T, &P->Medium[0], T->Delimiter, IndentationLevel, FALSE); + PrintMedium(T, This, T->Delimiter, IndentationLevel, FALSE); } RunningAvailableColumns -= ColumnsRequired; int StringLengthOfSpacePlusSeparator = 2; - for(int i = 1; i < P->MediumCount; ++i) + for(int i = 1; i < P->Medium.ItemCount; ++i) { - medium *This = P->Medium + i; + This = GetPlaceInBook(&P->Medium, i); ColumnsRequired = GetColumnsRequiredForMedium(This, T); if(RunningAvailableColumns >= StringLengthOfSpacePlusSeparator) { @@ -4394,7 +4277,7 @@ PrintProject(project *P, typography *T, int Ancestors, int IndentationLevel, int int CharactersInMargin = 1; int AvailableColumns = TerminalColumns - (Generation + CharactersInMargin); - if(P->MediumCount > 0) + if(P->Medium.ItemCount > 0) { PrintMedia(P, T, Generation, AvailableColumns); } @@ -4444,23 +4327,33 @@ PrintProject(project *P, typography *T, int Ancestors, int IndentationLevel, int TypesetPair(T, Generation, IDENT_OWNER, P->Owner->ID, AvailableColumns); } - for(int i = 0; i < P->IndexerCount; ++i) - { TypesetPair(T, Generation, IDENT_INDEXER, P->Indexer[i]->ID, AvailableColumns); } - for(int i = 0; i < P->CoHostCount; ++i) - { TypesetPair(T, Generation, IDENT_COHOST, P->CoHost[i]->ID, AvailableColumns); } - for(int i = 0; i < P->GuestCount; ++i) - { TypesetPair(T, Generation, IDENT_GUEST, P->Guest[i]->ID, AvailableColumns); } + for(int i = 0; i < P->Indexer.ItemCount; ++i) + { + person **Indexer = GetPlaceInBook(&P->Indexer, i); + TypesetPair(T, Generation, IDENT_INDEXER, (*Indexer)->ID, AvailableColumns); + } + for(int i = 0; i < P->CoHost.ItemCount; ++i) + { + person **CoHost = GetPlaceInBook(&P->CoHost, i); + TypesetPair(T, Generation, IDENT_COHOST, (*CoHost)->ID, AvailableColumns); + } + for(int i = 0; i < P->Guest.ItemCount; ++i) + { + person **Guest = GetPlaceInBook(&P->Guest, i); + TypesetPair(T, Generation, IDENT_GUEST, (*Guest)->ID, AvailableColumns); + } - if(P->ChildCount) + if(P->Child.ItemCount) { CarriageReturn(T, Generation); CarriageReturn(T, Generation); fprintf(stderr, "%s", T->Margin); PrintTitle("Children", AvailableColumns); ++Ancestors; - for(int i = 0; i < P->ChildCount; ++i) + for(int i = 0; i < P->Child.ItemCount; ++i) { - PrintProject(&P->Child[i], T, Ancestors, IndentationLevel, TerminalColumns); + project *This = GetPlaceInBook(&P->Child, i); + PrintProject(This, T, Ancestors, IndentationLevel, TerminalColumns); } --Ancestors; } @@ -4528,47 +4421,36 @@ PrintConfig(config *C, bool ShouldClearTerminal) fprintf(stderr, "\n"); PrintTitle("People", TermCols); - for(int i = 0; i < C->PersonCount; ++i) + for(int i = 0; i < C->Person.ItemCount; ++i) { - PrintPerson(&C->Person[i], IDENT_NULL, &Typography); + person *This = GetPlaceInBook(&C->Person, i); + PrintPerson(This, IDENT_NULL, &Typography); } fprintf(stderr, "\n"); PrintTitle("Projects", TermCols); - for(int i = 0; i < C->ProjectCount; ++i) + for(int i = 0; i < C->Project.ItemCount; ++i) { - PrintProject(&C->Project[i], &Typography, 0, IndentationLevel, TermCols); + PrintProject(GetPlaceInBook(&C->Project, i), &Typography, 0, IndentationLevel, TermCols); } } } -void -FreePerson(person *P) -{ - FreeAndResetCount(P->Support, P->SupportCount); -} - void FreeProject(project *P) { - FreeAndResetCount(P->Medium, P->MediumCount); + FreeBook(&P->Medium); - FreeAndResetCount(P->Indexer, P->IndexerCount); - FreeAndResetCount(P->Guest, P->GuestCount); - FreeAndResetCount(P->CoHost, P->CoHostCount); - for(int i = 0; i < P->ChildCount; ++i) + FreeBook(&P->Indexer); + FreeBook(&P->Guest); + FreeBook(&P->CoHost); + for(int i = 0; i < P->Child.ItemCount; ++i) { - FreeProject(&P->Child[i]); + FreeProject(GetPlaceInBook(&P->Child, i)); } - FreeAndResetCount(P->Child, P->ChildCount); + FreeBook(&P->Child); FreeTemplate(&P->SearchTemplate); FreeTemplate(&P->PlayerTemplate); - - FreeBuffer(&P->NavGeneric); - FreeBuffer(&P->NavDropdownPre); - FreeBuffer(&P->NavDropdownPost); - FreeBuffer(&P->NavHorizontalPre); - FreeBuffer(&P->NavPlainPre); } void @@ -4576,31 +4458,26 @@ FreeConfig(config *C) { if(C) { - for(int i = 0; i < C->PersonCount; ++i) + for(int i = 0; i < C->Person.ItemCount; ++i) { - FreePerson(&C->Person[i]); + person *Person = GetPlaceInBook(&C->Person, i); + FreeBook(&Person->Support); } - FreeAndResetCount(C->Person, C->PersonCount); - for(int i = 0; i < C->ProjectCount; ++i) + FreeBook(&C->Person); + for(int i = 0; i < C->Project.ItemCount; ++i) { - FreeProject(&C->Project[i]); + FreeProject(GetPlaceInBook(&C->Project, i)); } - FreeAndResetCount(C->Project, C->ProjectCount); + FreeBook(&C->Project); FreeBook(&C->ResolvedVariables); FreeTemplate(&C->SearchTemplate); - FreeBuffer(&C->NavGeneric); - FreeBuffer(&C->NavDropdownPre); - FreeBuffer(&C->NavDropdownPost); - FreeBuffer(&C->NavHorizontalPre); - FreeBuffer(&C->NavPlainPre); - Free(C); } } config * -ParseConfig(string Path, tokens_list *TokensList) +ParseConfig(string Path, memory_book *TokensList) { //PrintFunctionName("ParseConfig()"); config_type_specs TypeSpecs = InitTypeSpecs(); @@ -4609,10 +4486,10 @@ ParseConfig(string Path, tokens_list *TokensList) #if 0 MEM_LOOP_PRE_FREE("Tokenise") - FreeTokensList(&TokensList); + FreeTokensList(TokensList); //FreeAndResetCount(WatchHandles.Handle, WatchHandles.Count); MEM_LOOP_PRE_WORK() - T = Tokenise(&TokensList, Path); + T = Tokenise(TokensList, Path); MEM_LOOP_POST("Tokenise") #endif @@ -4628,13 +4505,13 @@ ParseConfig(string Path, tokens_list *TokensList) #if 0 MEM_LOOP_PRE_FREE("ScopeTree") FreeScopeTree(ScopeTree); - FreeTokensList(&TokensList); + FreeTokensList(TokensList); MEM_LOOP_PRE_WORK() - T = Tokenise(&TokensList, Path); + T = Tokenise(TokensList, Path); ScopeTree = calloc(1, sizeof(scope_tree)); SetTypeSpec(ScopeTree, &TypeSpecs); SetDefaults(ScopeTree, &TypeSpecs); - ScopeTree = ScopeTokens(ScopeTree, &TokensList, T, &TypeSpecs, 0); + ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0); MEM_LOOP_POST("ScopeTree") #endif //