From 6e1f6a4faa1674da1f5c88fc169aecf14794d758 Mon Sep 17 00:00:00 2001 From: Matt Mascarenhas Date: Fri, 18 Aug 2017 23:46:58 +0100 Subject: [PATCH] hmml_to_html.c: Complete credits [#4] Support multiple co-hosts, guests and annotators --- hmml_to_html/cinera.css | 8 +- hmml_to_html/hmml_to_html.c | 496 ++++++++++++++++++++---------------- 2 files changed, 282 insertions(+), 222 deletions(-) diff --git a/hmml_to_html/cinera.css b/hmml_to_html/cinera.css index 8342f20..b0fe468 100644 --- a/hmml_to_html/cinera.css +++ b/hmml_to_html/cinera.css @@ -171,12 +171,16 @@ flex-direction: column; } +.title > .menu > .credits_container .credit { + cursor: default; +} + .title > .menu > .credits_container .credit .person { + flex-grow: 1; text-decoration: none; } .title > .menu > .credits_container .credit .support { - flex-grow: 1; text-align: right; padding: 16px; } @@ -409,6 +413,7 @@ /* CUSTOM PAGE STYLE */ +/* body { background-color: #000; font-family: sans-serif; @@ -416,6 +421,7 @@ body { margin: 0; padding: 0; } +*/ /* Open menu: ▾ ▾ diff --git a/hmml_to_html/hmml_to_html.c b/hmml_to_html/hmml_to_html.c index 9499289..d1d79b1 100644 --- a/hmml_to_html/hmml_to_html.c +++ b/hmml_to_html/hmml_to_html.c @@ -73,7 +73,16 @@ typedef struct } category_info; // TODO(matt): Parse this stuff out of a config file -char *Credentials[ ][5] = +typedef struct +{ + char *Username; + char *CreditedName; + char *HomepageURL; + char *SupportIcon; + char *SupportURL; +} credential_info; + +credential_info Credentials[] = { { "Miblo", "Matt Mascarenhas", "http://miblodelcarpio.co.uk", "cinera_icon_patreon.png", "https://patreon.com/miblo"}, { "miotatsu", "Mio Iwakura", "http://riscy.tv/", "cinera_icon_patreon.png", "https://patreon.com/miotatsu"}, @@ -81,6 +90,31 @@ char *Credentials[ ][5] = { "cmuratori", "Casey Muratori", "https://handmadehero.org", "cinera_icon_patreon.png", "https://patreon.com/cmuratori"}, { "fierydrake", "Mike Tunnicliffe", "", "", ""}, { "abnercoimbre", "Abner Coimbre", "https://handmade.network/m/abnercoimbre", "cinera_icon_patreon.png", "https://patreon.com/handmade_dev"}, + { "/y_lee", "Yunsup Lee", "https://www.linkedin.com/in/yunsup-lee-385b692b/", "", ""}, + { "/a_waterman", "Andrew Waterman", "https://www.linkedin.com/in/andrew-waterman-76805788", "", ""}, + { "debiatan", "Miguel Lechón", "http://blog.debiatan.net/", "", ""}, +}; + +typedef struct +{ + char *Medium; + char *Icon; + char *WrittenName; +} category_medium; + +category_medium CategoryMedium[] = +{ + // medium icon written name + { "afk", "…" , "Away from Keyboard"}, // TODO(matt): Filter this out by default + { "authored", "🗪", "Chat Comment"}, // TODO(matt): Conditionally handle Chat vs Guest Comments + { "blackboard", "🖌", "Blackboard"}, + { "experience", "🍷", "Experience"}, + { "owl", "🦉", "Owl of Shame"}, + { "programming", "🖮", "Programming"}, // TODO(matt): Potentially make this configurable per project + { "rant", "💢", "Rant"}, + { "research", "📖", "Research"}, + { "run", "🏃", "In-Game"}, // TODO(matt): Potentially make this configurable per project + { "trivia", "🎲", "Trivia"}, }; #define EDITION EDITION_SINGLE @@ -205,6 +239,19 @@ CopyStringNoFormat(char *Dest, char *String) return Length; } +int +CopyStringNoFormatT(char *Dest, char *String, char Terminator) +{ + int Length = 0; + while(*String != Terminator) + { + *Dest++ = *String++; + ++Length; + } + *Dest = '\0'; + return Length; +} + int StringLength(char *String) { @@ -423,118 +470,157 @@ SanitisePunctuation(char *String) return String; } -int -BuildCredits(buffer *CreditsMenu, buffer *HostInfo, buffer *AnnotatorInfo, bool *HasCreditsMenu, char *ImagesDir, char *Host, char *Annotator) +enum { - // TODO(matt): Handle co-hosts and guests - bool FoundHost = FALSE; - bool FoundAnnotator = FALSE; + CreditsError_NoHost = 1 << 0, + CreditsError_NoAnnotator = 1 << 1, + CreditsError_NoCredentials = 1 << 2 +} CreditsErrorCodes; +int +SearchCredentials(buffer *CreditsMenu, bool *HasCreditsMenu, char *ImagesDir, char *Person, char* Role) +{ + bool Found = FALSE; for(int CredentialIndex = 0; CredentialIndex < ArrayCount(Credentials); ++CredentialIndex) { - if(!StringsDiffer(Host, Credentials[CredentialIndex][0])) + if(!StringsDiffer(Person, Credentials[CredentialIndex].Username)) { - FoundHost = TRUE; // TODO(matt): Check if this is actually necessary... - CopyStringToBuffer(HostInfo, - " \n"); - if(*Credentials[CredentialIndex][2]) + Found = TRUE; + if(*HasCreditsMenu == FALSE) { - CopyStringToBuffer(HostInfo, - " \n" - "
Host
\n" - "
%s
\n" - "
\n", - Credentials[CredentialIndex][2], - Credentials[CredentialIndex][1]); - } - else - { - CopyStringToBuffer(HostInfo, - "
\n" - "
Host
\n" - "
%s
\n" - "
\n", - Credentials[CredentialIndex][1]); - } - - if(*Credentials[CredentialIndex][4] && *Credentials[CredentialIndex][3]) - { - CopyStringToBuffer(HostInfo, - " \n", - Credentials[CredentialIndex][4], - ImagesDir, - Credentials[CredentialIndex][3]); - } - - CopyStringToBuffer(HostInfo, - "
\n"); - } - - if(!StringsDiffer(Annotator, Credentials[CredentialIndex][0])) - { - FoundAnnotator = TRUE; // TODO(matt): Check if this is actually necessary... - CopyStringToBuffer(AnnotatorInfo, - " \n"); - if(*Credentials[CredentialIndex][2]) - { - CopyStringToBuffer(AnnotatorInfo, - " \n" - "
Annotator
\n" - "
%s
\n" - "
\n", - Credentials[CredentialIndex][2], - Credentials[CredentialIndex][1]); - } - else - { - CopyStringToBuffer(AnnotatorInfo, - "
\n" - "
Annotator
\n" - "
%s
\n" - "
\n", - Credentials[CredentialIndex][1]); - } - - if(*Credentials[CredentialIndex][4] && *Credentials[CredentialIndex][3]) - { - CopyStringToBuffer(AnnotatorInfo, - " \n", - Credentials[CredentialIndex][4], - ImagesDir, - Credentials[CredentialIndex][3]); - } - - CopyStringToBuffer(AnnotatorInfo, - "
\n"); - } - } - - if(FoundHost || FoundAnnotator) - { - CopyStringToBuffer(CreditsMenu, + CopyStringToBuffer(CreditsMenu, "
\n" "
\n" " Credits\n" "
\n"); - if(FoundHost) - { - CopyBuffer(CreditsMenu, HostInfo); + *HasCreditsMenu = TRUE; + } + + CopyStringToBuffer(CreditsMenu, + " \n"); + if(*Credentials[CredentialIndex].HomepageURL) + { + CopyStringToBuffer(CreditsMenu, + " \n" + "
%s
\n" + "
%s
\n" + "
\n", + Credentials[CredentialIndex].HomepageURL, + Role, + Credentials[CredentialIndex].CreditedName); + } + else + { + CopyStringToBuffer(CreditsMenu, + "
\n" + "
%s
\n" + "
%s
\n" + "
\n", + Role, + Credentials[CredentialIndex].CreditedName); + } + + if(*Credentials[CredentialIndex].SupportIcon && *Credentials[CredentialIndex].SupportURL) + { + CopyStringToBuffer(CreditsMenu, + " \n", + Credentials[CredentialIndex].SupportURL, + ImagesDir, + Credentials[CredentialIndex].SupportIcon); + } + + CopyStringToBuffer(CreditsMenu, + "
\n"); } - if(FoundAnnotator) + } + return Found ? 0 : CreditsError_NoCredentials; +} + +int +BuildCredits(buffer *CreditsMenu, bool *HasCreditsMenu, char *ImagesDir, HMML_VideoMetaData Metadata) + // TODO(matt): Make this take the Credentials, once we are parsing them from a config +{ + if(Metadata.member) + { + if(SearchCredentials(CreditsMenu, HasCreditsMenu, ImagesDir, Metadata.member, "Host")) { - CopyBuffer(CreditsMenu, AnnotatorInfo); + printf("No credentials for %s. Please contact matt@handmadedev.org with their:\n" + " Full name\n" + " Homepage URL (optional)\n" + " Financial support info, e.g. Patreon URL (optional)\n", Metadata.member); } - CopyStringToBuffer(CreditsMenu, - "
\n" - "
\n"); } else { - return 1; + if(*HasCreditsMenu == TRUE) + { + CopyStringToBuffer(CreditsMenu, + " \n" + " \n"); + } + return CreditsError_NoHost; + } + + if(Metadata.co_host_count > 0) + { + for(int i = 0; i < Metadata.co_host_count; ++i) + { + if(SearchCredentials(CreditsMenu, HasCreditsMenu, ImagesDir, Metadata.co_hosts[i], "Co-host")) + { + printf("No credentials for %s. Please contact matt@handmadedev.org with their:\n" + " Full name\n" + " Homepage URL (optional)\n" + " Financial support info, e.g. Patreon URL (optional)\n", Metadata.co_hosts[i]); + } + } + } + + if(Metadata.guest_count > 0) + { + for(int i = 0; i < Metadata.guest_count; ++i) + { + if(SearchCredentials(CreditsMenu, HasCreditsMenu, ImagesDir, Metadata.guests[i], "Guest")) + { + printf("No credentials for %s. Please contact matt@handmadedev.org with their:\n" + " Full name\n" + " Homepage URL (optional)\n" + " Financial support info, e.g. Patreon URL (optional)\n", Metadata.guests[i]); + } + } + } + + if(Metadata.annotator_count > 0) + { + for(int i = 0; i < Metadata.annotator_count; ++i) + { + if(SearchCredentials(CreditsMenu, HasCreditsMenu, ImagesDir, Metadata.annotators[i], "Annotator")) + { + printf("No credentials for %s. Please contact matt@handmadedev.org with their:\n" + " Full name\n" + " Homepage URL (optional)\n" + " Financial support info, e.g. Patreon URL (optional)\n", Metadata.annotators[i]); + } + } + } + else + { + if(*HasCreditsMenu == TRUE) + { + CopyStringToBuffer(CreditsMenu, + " \n" + " \n"); + } + return CreditsError_NoAnnotator; + } + + if(*HasCreditsMenu == TRUE) + { + CopyStringToBuffer(CreditsMenu, + " \n" + " \n"); } - *HasCreditsMenu = TRUE; return 0; } @@ -643,21 +729,6 @@ BuildReference(ref_info *ReferencesArray, int RefIdentifier, int UniqueRefs, HMM return 0; } -char *CategoryMedium[][3] = -{ - // medium icon written name - { "afk", "…" , "Away from Keyboard"}, // TODO(matt): Filter this out by default - { "authored", "🗪", "Chat Comment"}, // TODO(matt): Conditionally handle Chat vs Guest Comments - { "blackboard", "🖌", "Blackboard"}, - { "experience", "🍷", "Experience"}, - { "owl", "🦉", "Owl of Shame"}, - { "programming", "🖮", "Programming"}, // TODO(matt): Potentially make this configurable per project - { "rant", "💢", "Rant"}, - { "research", "📖", "Research"}, - { "run", "🏃", "In-Game"}, // TODO(matt): Potentially make this configurable per project - { "trivia", "🎲", "Trivia"}, -}; - void BuildFilter(category_info *TopicsArray, int *UniqueTopics, category_info *MediaArray, int *UniqueMedia, char *Marker) { @@ -666,7 +737,7 @@ BuildFilter(category_info *TopicsArray, int *UniqueTopics, category_info *MediaA int i = 0; for(i = 0; i < ArrayCount(CategoryMedium); ++i) { - if(!StringsDiffer(CategoryMedium[i][0], Marker)) + if(!StringsDiffer(CategoryMedium[i].Medium, Marker)) { IsMedium = TRUE; break; @@ -679,11 +750,11 @@ BuildFilter(category_info *TopicsArray, int *UniqueTopics, category_info *MediaA int j = 0; for(j = 0; j < *UniqueMedia; ++j) { - if(!StringsDiffer(CategoryMedium[i][0], MediaArray[j].Marker)) + if(!StringsDiffer(CategoryMedium[i].Medium, MediaArray[j].Marker)) { return; } - if((Offset = StringsDiffer(CategoryMedium[i][2], MediaArray[j].WrittenText)) < 0) + if((Offset = StringsDiffer(CategoryMedium[i].WrittenName, MediaArray[j].WrittenText)) < 0) { int k; for(k = *UniqueMedia; k > j; --k) @@ -692,16 +763,16 @@ BuildFilter(category_info *TopicsArray, int *UniqueTopics, category_info *MediaA CopyString(MediaArray[k].WrittenText, MediaArray[k-1].WrittenText); } - CopyString(MediaArray[k].Marker, CategoryMedium[i][0]); - CopyString(MediaArray[k].WrittenText, CategoryMedium[i][2]); + CopyString(MediaArray[k].Marker, CategoryMedium[i].Medium); + CopyString(MediaArray[k].WrittenText, CategoryMedium[i].WrittenName); break; } } if(j == *UniqueMedia) { - CopyString(MediaArray[j].Marker, CategoryMedium[i][0]); - CopyString(MediaArray[j].WrittenText, CategoryMedium[i][2]); + CopyString(MediaArray[j].Marker, CategoryMedium[i].Medium); + CopyString(MediaArray[j].WrittenText, CategoryMedium[i].WrittenName); } ++*UniqueMedia; @@ -748,7 +819,7 @@ BuildCategories(buffer *AnnotationClass, buffer *Category, int *MarkerIndex, boo // The code in the "annotation loop" would then have to write both the head and tail of the category stuff for(int i = 0; i < ArrayCount(CategoryMedium); ++i) { - if(!StringsDiffer(CategoryMedium[i][0], Marker)) + if(!StringsDiffer(CategoryMedium[i].Medium, Marker)) { CopyStringToBuffer(AnnotationClass, " %s", SanitisePunctuation(Marker)); *HasMedium = TRUE; @@ -812,70 +883,6 @@ StringToInt(char *String) return Result; } -size_t -CurlIntoBuffer(char *InPtr, size_t CharLength, size_t Chars, char **OutputPtr) -{ - int Length = CharLength * Chars; - int i; - for(i = 0; InPtr[i] && i < Length; ++i) - { - *((*OutputPtr)++) = InPtr[i]; - } - **OutputPtr = '\0'; - return Length; -}; - -int -SearchQuotes(buffer QuoteStaging, int CacheSize, quote_info *Info, int ID) -{ - QuoteStaging.Ptr = QuoteStaging.Location; - while(QuoteStaging.Ptr - QuoteStaging.Location < CacheSize) - { - char InID[4] = { 0 }; - char InTime[16] = { 0 }; - char *OutPtr = InID; - while(*QuoteStaging.Ptr != ',') - { - *OutPtr++ = *QuoteStaging.Ptr++; - } - *OutPtr = '\0'; - - if(StringToInt(InID) == ID) - { - QuoteStaging.Ptr += 1; - OutPtr = InTime; - while(*QuoteStaging.Ptr != ',') - { - *OutPtr++ = *QuoteStaging.Ptr++; - } - *OutPtr = '\0'; - - long int Time = StringToInt(InTime); - strftime(Info->Date, 32, "%d %B, %Y", gmtime(&Time)); - - QuoteStaging.Ptr += 1; - OutPtr = Info->Text; - while(*QuoteStaging.Ptr != '\n') - { - *OutPtr++ = *QuoteStaging.Ptr++; - } - *OutPtr = '\0'; - - FreeBuffer(&QuoteStaging); - return 0; - } - else - { - while(*QuoteStaging.Ptr != '\n') - { - ++QuoteStaging.Ptr; - } - ++QuoteStaging.Ptr; - } - } - return 1; -} - int MakeDir(char *Path) { @@ -907,6 +914,19 @@ MakeDir(char *Path) return 0; } +size_t +CurlIntoBuffer(char *InPtr, size_t CharLength, size_t Chars, char **OutputPtr) +{ + int Length = CharLength * Chars; + int i; + for(i = 0; InPtr[i] && i < Length; ++i) + { + *((*OutputPtr)++) = InPtr[i]; + } + **OutputPtr = '\0'; + return Length; +}; + void CurlQuotes(buffer *QuoteStaging, char *QuotesURL) { @@ -924,6 +944,56 @@ CurlQuotes(buffer *QuoteStaging, char *QuotesURL) } } +int +SearchQuotes(buffer QuoteStaging, int CacheSize, quote_info *Info, int ID) +{ + QuoteStaging.Ptr = QuoteStaging.Location; + while(QuoteStaging.Ptr - QuoteStaging.Location < CacheSize) + { + char InID[4] = { 0 }; + char InTime[16] = { 0 }; + char *OutPtr = InID; + QuoteStaging.Ptr += CopyStringNoFormatT(OutPtr, QuoteStaging.Ptr, ','); + + if(StringToInt(InID) == ID) + { + QuoteStaging.Ptr += 1; + OutPtr = InTime; + QuoteStaging.Ptr += CopyStringNoFormatT(OutPtr, QuoteStaging.Ptr, ','); + + long int Time = StringToInt(InTime); + char DayString[3]; + strftime(DayString, 3, "%d", gmtime(&Time)); + int Day = StringToInt(DayString); + + char DaySuffix[3]; if(DayString[1] == '1' && Day != 11) { CopyString(DaySuffix, "st"); } + else if(DayString[1] == '2' && Day != 12) { CopyString(DaySuffix, "nd"); } + else if(DayString[1] == '3' && Day != 13) { CopyString(DaySuffix, "rd"); } + else { CopyString(DaySuffix, "th"); } + + char MonthYear[32]; + strftime(MonthYear, 32, "%B, %Y", gmtime(&Time)); + CopyString(Info->Date, "%d%s %s", Day, DaySuffix, MonthYear); + + QuoteStaging.Ptr += 1; + OutPtr = Info->Text; + QuoteStaging.Ptr += CopyStringNoFormatT(OutPtr, QuoteStaging.Ptr, '\n'); + + FreeBuffer(&QuoteStaging); + return 0; + } + else + { + while(*QuoteStaging.Ptr != '\n') + { + ++QuoteStaging.Ptr; + } + ++QuoteStaging.Ptr; + } + } + return 1; +} + int BuildQuote(quote_info *Info, char *Speaker, int ID, char *CacheDir) { @@ -963,7 +1033,7 @@ BuildQuote(quote_info *Info, char *Speaker, int ID, char *CacheDir) QuoteStaging.Size = Kilobytes(256); if(!(QuoteStaging.Location = malloc(QuoteStaging.Size))) { - perror("malloc"); + perror("BuildQuote"); } QuoteStaging.Ptr = QuoteStaging.Location; @@ -1016,7 +1086,7 @@ GenerateTopicColours(buffer *Colour, char *Topic, char *TopicsDir) { for(int i = 0; i < ArrayCount(CategoryMedium); ++i) { - if(!StringsDiffer(Topic, CategoryMedium[i][0])) + if(!StringsDiffer(Topic, CategoryMedium[i].Medium)) { return; } @@ -1482,7 +1552,7 @@ main(int ArgC, char **Args) bool ValidDefaultMedium = FALSE; for(int i = 0; i < ArrayCount(CategoryMedium); ++i) { - if(!StringsDiffer(DefaultMedium, CategoryMedium[i][0])) + if(!StringsDiffer(DefaultMedium, CategoryMedium[i].Medium)) { ValidDefaultMedium = TRUE; break; @@ -1493,7 +1563,7 @@ main(int ArgC, char **Args) fprintf(stderr, "Specified default medium \"%s\" not available. Valid media are:\n", DefaultMedium); for(int i = 0; i < ArrayCount(CategoryMedium); ++i) { - fprintf(stderr, " %s\n", CategoryMedium[i][0]); + fprintf(stderr, " %s\n", CategoryMedium[i].Medium); } fprintf(stderr, "To have \"%s\" added to the list, contact matt@handmadedev.org\n", DefaultMedium); return 1; @@ -1714,6 +1784,7 @@ main(int ArgC, char **Args) // FilterMenu // FilterTopics // FilterMedia + // CreditsMenu // Player // Colour // Annotation @@ -1735,8 +1806,6 @@ main(int ArgC, char **Args) buffer FilterTopics; buffer FilterMedia; buffer CreditsMenu; - buffer HostInfo; - buffer AnnotatorInfo; buffer Player; buffer Colour; @@ -1803,8 +1872,6 @@ main(int ArgC, char **Args) ClaimBuffer(&MemoryArena, &ClaimedMemory, &FilterTopics, "FilterTopics", Kilobytes(8)); ClaimBuffer(&MemoryArena, &ClaimedMemory, &FilterMedia, "FilterMedia", Kilobytes(8)); ClaimBuffer(&MemoryArena, &ClaimedMemory, &CreditsMenu, "CreditsMenu", Kilobytes(8)); - ClaimBuffer(&MemoryArena, &ClaimedMemory, &HostInfo, "HostInfo", Kilobytes(1)); - ClaimBuffer(&MemoryArena, &ClaimedMemory, &AnnotatorInfo, "AnnotatorInfo", Kilobytes(1)); ClaimBuffer(&MemoryArena, &ClaimedMemory, &Player, "Player", Kilobytes(256)); ClaimBuffer(&MemoryArena, &ClaimedMemory, &Colour, "Colour", 32); @@ -1840,18 +1907,22 @@ main(int ArgC, char **Args) "
\n" "
\n", HMML.metadata.id, HMML.metadata.project); - // TODO(matt): Handle multiple annotators - if(HMML.metadata.annotator_count > 0) + int CreditsErrorCode = BuildCredits(&CreditsMenu, &HasCreditsMenu, ImagesDir, HMML.metadata); + if(CreditsErrorCode) { - BuildCredits(&CreditsMenu, &HostInfo, &AnnotatorInfo, &HasCreditsMenu, ImagesDir, HMML.metadata.member, HMML.metadata.annotators[0]); - } - else - { - fprintf(stderr, "%s: Missing annotator in [video] node\n", Args[FileIndex]); - hmml_free(&HMML); - free(MemoryArena.Location); - free(Template.Location); - return 1; + switch(CreditsErrorCode) + { + case CreditsError_NoHost: + fprintf(stderr, "%s: Missing \"member\" in the [video] node. Skipping...\n", Args[FileIndex]); +goto Cleanup; + break; + case CreditsError_NoAnnotator: + fprintf(stderr, "%s: Missing \"annotator\" in the [video] node. Skipping...\n", Args[FileIndex]); +goto Cleanup; + break; + default: + break; + } } #if DEBUG @@ -2216,20 +2287,6 @@ main(int ArgC, char **Args) free(Template.Location); return 1; } - if(BuildQuote(&QuoteInfo, - Speaker, - Anno->quote.id, - CacheDir) == 2) - { - fprintf(stderr, "%s:%d: Failed to create quote cache at %s/quotes/%s for Quote #%s %d.\n" - "Proceeding anyway, without a cache!\n", - Args[FileIndex], - Anno->line, - CacheDir, - Speaker, - Speaker, - Anno->quote.id); - } CopyStringToBuffer(&QuoteMenu, " \n" @@ -2478,7 +2535,7 @@ main(int ArgC, char **Args) int j; for(j = 0; j < ArrayCount(CategoryMedium); ++j) { - if(!StringsDiffer(MediaArray[i].Marker, CategoryMedium[j][0])) + if(!StringsDiffer(MediaArray[i].Marker, CategoryMedium[j].Medium)) { break; } @@ -2489,8 +2546,8 @@ main(int ArgC, char **Args) " %s%s\n" "
\n", MediaArray[i].Marker, - CategoryMedium[j][1], - CategoryMedium[j][2] + CategoryMedium[j].Icon, + CategoryMedium[j].WrittenName ); } @@ -3158,8 +3215,6 @@ main(int ArgC, char **Args) // Annotation // Colour // Player - // AnnotatorInfo - // HostInfo // CreditsMenu // FilterMedia // FilterTopics @@ -3170,14 +3225,13 @@ main(int ArgC, char **Args) // Includes // Master +Cleanup: DeclaimBuffer(&FilterState, &ClaimedMemory); DeclaimBuffer(&Script, &ClaimedMemory); DeclaimBuffer(&Annotation, &ClaimedMemory); DeclaimBuffer(&Colour, &ClaimedMemory); DeclaimBuffer(&Player, &ClaimedMemory); - DeclaimBuffer(&AnnotatorInfo, &ClaimedMemory); - DeclaimBuffer(&HostInfo, &ClaimedMemory); DeclaimBuffer(&CreditsMenu, &ClaimedMemory); DeclaimBuffer(&FilterMedia, &ClaimedMemory); DeclaimBuffer(&FilterTopics, &ClaimedMemory);