diff --git a/README.md b/README.md
index 50e5b9b..1e46538 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,11 @@ deployment
## Cinera
+### Install the dependencies
+
+1. flex (for hmmlib)
+2. curl (for cinera)
+
### Download, and prepare the parser
1. `git clone git@gitssh.handmade.network:Annotation-Pushers/Annotation-System.git`
@@ -13,10 +18,6 @@ deployment
Note: For each parser update, remember to make and copy it into place.
-### Install the dependency
-
-1. curl
-
### Build
1. `$SHELL cinera.c`
@@ -57,56 +58,75 @@ By default all directories - input and output - are set to the current working
directory. Typical operation will involve setting these flags:
-d Project Input Directory, the directory where the .hmml files reside
- -r Root Directory, path shallower than or equal to the CSS, Images and JS
- directories
- -R Root URL, corresponding to the Root Directory (optional if the Output
- Base Directory resides in the Root Directory)
+ -r Asset Root Directory, path shallower than or equal to the CSS, Images and
+ JS directories
+ -R Asset Root URL, corresponding to the Root Directory
-c CSS Directory, relative to Root
-i Images Directory, relative to Root
-j JS Directory, relative to Root
-b Output Base Directory, location of the table of contents / search page
-B Output Base URL, corresponding to the Output Base Directory
-t Template Directory
- -x Index Template Location, relative to Template Directory
+ -x Search Template Location, relative to Template Directory
-y Player Template Location, relative to Template Directory
#### Templates
-*Index Template*
-- `` _the necessary `.css` and `.js` files_
-- `` _the table of contents, and search functionality_
+*Search Template*
+- `` _to put inside your own `
`_
+- `` _the table of contents and search functionality_
*Player Template*
-- `` _the necessary `.css` and `.js` files, and
- charset setting_
-- `` _ _the menu bar that typically appears above the
- player in my samples_
-- `` _the player_
-- `` _the filter state objects and `.js` file, which
- must come after both the MENUS and PLAYER tags_
+- `` _to put inside your own ``_
+- ``
+- ``
+- `` _must come after `` and ``_
*Optional tags available for use in your Player Template*
-- `` _the day / episode name, intended to be used
- inside your own `` element, but may be used wherever and as many times
- as you want on your page_
-- `` _the unique identifer of the video as provided
- by the VoD platform_
+- ``
+- ``
-*Other available tags*
-- `` _the full name of the project_
-- `` _the ID of the project_
-- `` _the theme of the project_
-- `` _the URL where we have derived the page will be
- publically accessibly, only really usable if BaseURL is set (-B)_
+*Other tags available for use in either template*
+- Asset tags:
+ - ``
+ General purpose tag that outputs the URL of the specified asset
+ relative to the Asset Root URL (-R)
+ - ``
+ General purpose tag that outputs the URL of the specified asset
+ relative to the Images Directory (-i)
+ - ``
+ Convenience tag that outputs a node
+ for the specified asset relative to the CSS Directory (-c), for
+ use inside your block
+ - ``
+ Convenience tag that outputs a ",
- URLPrefix.Location);
+ "\n"
+ " IncludesPlayer, ASSET_CSS_CINERA, PAGE_PLAYER);
+
+ ConstructResolvedAssetURL(&URL, ASSET_CSS_THEME, PAGE_PLAYER);
+ CopyStringToBuffer(&CollationBuffers->IncludesPlayer,
+ "\">\n"
+ " IncludesPlayer, ASSET_CSS_THEME, PAGE_PLAYER);
+
+ ConstructResolvedAssetURL(&URL, ASSET_CSS_TOPICS, PAGE_PLAYER);
+ CopyStringToBuffer(&CollationBuffers->IncludesPlayer,
+ "\">\n"
+ " IncludesPlayer, ASSET_CSS_TOPICS, PAGE_PLAYER);
+
+ CopyStringToBuffer(&CollationBuffers->IncludesPlayer,
+ "\">\n");
+
+ ConstructResolvedAssetURL(&URL, ASSET_JS_PLAYER_PRE, PAGE_PLAYER);
+ CopyStringToBuffer(&CollationBuffers->IncludesPlayer,
+ " ");
+
+ ConstructResolvedAssetURL(&URL, ASSET_JS_PLAYER_POST, PAGE_PLAYER);
+ CopyStringToBuffer(&CollationBuffers->ScriptPlayer,
+ "",
- URLPrefix.Location);
- DeclaimBuffer(&URLPrefix);
+ "\">");
// NOTE(matt): Tree structure of "global" buffer dependencies
// CreditsMenu
@@ -4413,7 +5847,7 @@ AppendedIdentifier:
else
{
LogError(LOG_ERROR, "%s:%d: %s", Filename, HMML.error.line, HMML.error.message);
- fprintf(stderr, "\e[1;31mSkipping\e[0m %s:%d: %s\n", Filename, HMML.error.line, HMML.error.message);
+ fprintf(stderr, "%sSkipping%s %s:%d: %s\n", ColourStrings[CS_ERROR], ColourStrings[CS_END], Filename, HMML.error.line, HMML.error.message);
hmml_free(&HMML);
return RC_ERROR_HMML;
}
@@ -4509,35 +5943,39 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
}
else
{
- CopyStringToBufferNoFormat(&Output, CollationBuffers->URLIndex);
+ CopyStringToBufferNoFormat(&Output, CollationBuffers->URLSearch);
}
break;
case TAG_VIDEO_ID:
CopyStringToBufferNoFormat(&Output, CollationBuffers->VideoID);
break;
- case TAG_INDEX:
+ case TAG_SEARCH:
if(Config.Edition == EDITION_SINGLE)
{
- fprintf(stderr, "Template contains a tag\n"
- "Skipping just this tag, because an index cannot be generated for inclusion in a\n"
+ fprintf(stderr, "Template contains a tag\n"
+ "Skipping just this tag, because a search cannot be generated for inclusion in a\n"
"bespoke template in Single Edition\n");
}
else
{
- CopyBuffer(&Output, &CollationBuffers->Index);
+ OffsetLandmarks(&Output, ASSET_JS_SEARCH, PAGE_SEARCH);
+ CopyBuffer(&Output, &CollationBuffers->Search);
}
break;
case TAG_INCLUDES:
if(PageType == PAGE_PLAYER)
{
+ OffsetLandmarksIncludes(&Output, PageType);
CopyBuffer(&Output, &CollationBuffers->IncludesPlayer);
}
else
{
- CopyBuffer(&Output, &CollationBuffers->IncludesIndex);
+ OffsetLandmarksIncludes(&Output, PageType);
+ CopyBuffer(&Output, &CollationBuffers->IncludesSearch);
}
break;
case TAG_MENUS:
+ OffsetLandmarksMenus(&Output);
CopyBuffer(&Output, &CollationBuffers->Menus);
break;
case TAG_PLAYER:
@@ -4545,8 +5983,47 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
CopyBuffer(&Output, &CollationBuffers->Player);
break;
case TAG_SCRIPT:
+ OffsetLandmarks(&Output, ASSET_JS_PLAYER_POST, PAGE_PLAYER);
CopyBuffer(&Output, &CollationBuffers->ScriptPlayer);
break;
+ case TAG_ASSET:
+ {
+ buffer URL;
+ ConstructResolvedAssetURL(&URL, Template->Metadata.Tag[i].AssetIndex, PageType);
+ CopyStringToBuffer(&Output, "%s", URL.Location);
+ DeclaimBuffer(&URL);
+ PushAssetLandmark(&Output, Template->Metadata.Tag[i].AssetIndex, PageType);
+ } break;
+ case TAG_CSS:
+ {
+ buffer URL;
+ ConstructResolvedAssetURL(&URL, Template->Metadata.Tag[i].AssetIndex, PageType);
+ CopyStringToBuffer(&Output,
+ " Metadata.Tag[i].AssetIndex, PageType);
+ CopyStringToBuffer(&Output, "\">");
+ } break;
+ case TAG_IMAGE:
+ {
+ buffer URL;
+ ConstructResolvedAssetURL(&URL, Template->Metadata.Tag[i].AssetIndex, PageType);
+ CopyStringToBuffer(&Output, "%s", URL.Location);
+ DeclaimBuffer(&URL);
+ PushAssetLandmark(&Output, Template->Metadata.Tag[i].AssetIndex, PageType);
+ } break;
+ case TAG_JS:
+ {
+ buffer URL;
+ ConstructResolvedAssetURL(&URL, Template->Metadata.Tag[i].AssetIndex, PageType);
+ CopyStringToBuffer(&Output,
+ "");
+ } break;
case TAG_CUSTOM0: CopyStringToBufferNoFormat(&Output, CollationBuffers->Custom0); break;
case TAG_CUSTOM1: CopyStringToBufferNoFormat(&Output, CollationBuffers->Custom1); break;
case TAG_CUSTOM2: CopyStringToBufferNoFormat(&Output, CollationBuffers->Custom2); break;
@@ -4616,7 +6093,8 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
" \n"
" ");
- CopyBuffer(&Master, PageType == PAGE_PLAYER ? &CollationBuffers->IncludesPlayer : &CollationBuffers->IncludesIndex);
+ OffsetLandmarksIncludes(&Master, PageType);
+ CopyBuffer(&Master, PageType == PAGE_PLAYER ? &CollationBuffers->IncludesPlayer : &CollationBuffers->IncludesSearch);
CopyStringToBuffer(&Master, "\n");
CopyStringToBuffer(&Master,
@@ -4627,6 +6105,8 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
{
CopyStringToBuffer(&Master, "\n"
" ");
+
+ OffsetLandmarksMenus(&Master);
CopyBuffer(&Master, &CollationBuffers->Menus);
CopyStringToBuffer(&Master, "\n"
" ");
@@ -4638,12 +6118,15 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
" ");
CopyStringToBuffer(&Master, "
\n"
" ");
+
+ OffsetLandmarks(&Master, ASSET_JS_PLAYER_POST, PAGE_PLAYER);
CopyBuffer(&Master, &CollationBuffers->ScriptPlayer);
CopyStringToBuffer(&Master, "\n");
}
else
{
- CopyBuffer(&Master, &CollationBuffers->Index);
+ OffsetLandmarks(&Master, ASSET_JS_SEARCH, PAGE_SEARCH);
+ CopyBuffer(&Master, &CollationBuffers->Search);
}
CopyStringToBuffer(&Master,
@@ -4665,21 +6148,22 @@ BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, i
}
int
-BinarySearchForMetadataEntry(index *Index, index_metadata **Entry, char *SearchTerm)
+BinarySearchForMetadataEntry(db_entry **Entry, char *SearchTerm)
{
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader);
int Lower = 0;
- index_metadata *LowerEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Lower);
+ db_entry *LowerEntry = (db_entry*)(DB.Metadata.Buffer.Ptr + sizeof(DB.Entry) * Lower);
if(StringsDiffer(SearchTerm, LowerEntry->BaseFilename) < 0 ) { return -1; }
- int Upper = Index->Header.EntryCount - 1;
+ int Upper = DB.EntriesHeader.Count - 1;
int Pivot = Upper - ((Upper - Lower) >> 1);
- index_metadata *UpperEntry;
- index_metadata *PivotEntry;
+ db_entry *UpperEntry;
+ db_entry *PivotEntry;
do {
- LowerEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Lower);
- PivotEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Pivot);
- UpperEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Upper);
+ LowerEntry = (db_entry*)(DB.Metadata.Buffer.Ptr + sizeof(DB.Entry) * Lower);
+ PivotEntry = (db_entry*)(DB.Metadata.Buffer.Ptr + sizeof(DB.Entry) * Pivot);
+ UpperEntry = (db_entry*)(DB.Metadata.Buffer.Ptr + sizeof(DB.Entry) * Upper);
if(!StringsDiffer(SearchTerm, LowerEntry->BaseFilename)) { *Entry = LowerEntry; return Lower; }
if(!StringsDiffer(SearchTerm, PivotEntry->BaseFilename)) { *Entry = PivotEntry; return Pivot; }
@@ -4693,34 +6177,33 @@ BinarySearchForMetadataEntry(index *Index, index_metadata **Entry, char *SearchT
}
int
-AccumulateIndexEntryInsertionOffset(index *Index, int EntryIndex)
+AccumulateDBEntryInsertionOffset(int EntryIndex)
{
int Result = 0;
- index_metadata *AccEntry = { 0 };
- if(EntryIndex < Index->Header.EntryCount >> 1)
+ db_entry *AccEntry = { 0 };
+ if(EntryIndex < DB.EntriesHeader.Count >> 1)
{
- //printf("\u200B"); // NOTE(matt): Don't ask...
for(; EntryIndex > 0; --EntryIndex)
{
- AccEntry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * (EntryIndex - 1));
+ AccEntry = (db_entry*)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * (EntryIndex - 1));
Result += AccEntry->Size;
}
Result += StringLength("---\n");
}
else
{
- for(; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
+ for(; EntryIndex < DB.EntriesHeader.Count; ++EntryIndex)
{
- AccEntry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
+ AccEntry = (db_entry*)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex);
Result += AccEntry->Size;
}
- Result = Index->File.FileSize - Result;
+ Result = DB.File.FileSize - Result;
}
return Result;
}
void
-ClearEntry(index_metadata *Entry)
+ClearEntry(db_entry *Entry)
{
Entry->LinkOffsets.PrevStart = 0;
Entry->LinkOffsets.NextStart = 0;
@@ -4731,105 +6214,133 @@ ClearEntry(index_metadata *Entry)
Clear(Entry->Title, sizeof(Entry->Title));
}
-enum
+void
+InitNeighbourhood(neighbourhood *N)
{
- EDIT_DELETION,
- EDIT_ADDITION,
- EDIT_REINSERTION
-} index_edits;
+ N->PrevIndex = -1;
+ N->PreDeletionThisIndex = N->ThisIndex = 0;
+ N->NextIndex = -1;
+
+ N->PreLinkPrevOffsetTotal = N->PreLinkThisOffsetTotal = N->PreLinkNextOffsetTotal = 0;
+ N->PrevOffsetModifier = N->ThisOffsetModifier = N->NextOffsetModifier = 0;
+ N->FormerIsFirst = N->LatterIsFinal = FALSE;
+ N->DeletedEntryWasFirst = N->DeletedEntryWasFinal = FALSE;
+
+ N->Prev.LinkOffsets.PrevStart = N->Prev.LinkOffsets.PrevEnd = N->Prev.LinkOffsets.NextStart = N->Prev.LinkOffsets.NextEnd = 0;
+ N->This.LinkOffsets.PrevStart = N->This.LinkOffsets.PrevEnd = N->This.LinkOffsets.NextStart = N->This.LinkOffsets.NextEnd = 0;
+ N->Next.LinkOffsets.PrevStart = N->Next.LinkOffsets.PrevEnd = N->Next.LinkOffsets.NextStart = N->Next.LinkOffsets.NextEnd = 0;
+
+ N->Prev.Size = N->This.Size = N->Next.Size = 0;
+
+ Clear(N->Prev.BaseFilename, sizeof(N->Prev.BaseFilename));
+ Clear(N->This.BaseFilename, sizeof(N->This.BaseFilename));
+ Clear(N->Next.BaseFilename, sizeof(N->Next.BaseFilename));
+
+ Clear(N->Prev.Title, sizeof(N->Prev.Title));
+ Clear(N->This.Title, sizeof(N->This.Title));
+ Clear(N->Next.Title, sizeof(N->Next.Title));
+}
+
+#define PrintNeighbourhood(N) PrintNeighbourhood_(N, __LINE__)
+void
+PrintNeighbourhood_(neighbourhood *N, int Line)
+{
+ printf( "\n"
+ " Neighbourhood (line %d):\n", Line);
+
+ if(N->PrevIndex >= 0)
+ {
+ printf(
+ " Prev [%d]: %s: %6d %6d %6d %6d\n",
+ N->PrevIndex, N->Prev.BaseFilename,
+ N->Prev.LinkOffsets.PrevStart,
+ N->Prev.LinkOffsets.PrevEnd,
+ N->Prev.LinkOffsets.NextStart,
+ N->Prev.LinkOffsets.NextEnd);
+ }
+
+ if(N->ThisIndex >= 0)
+ {
+ printf(
+ " This [%d (pre-deletion %d)]: %s: %6d %6d %6d %6d\n",
+ N->ThisIndex, N->PreDeletionThisIndex, N->This.BaseFilename,
+ N->This.LinkOffsets.PrevStart,
+ N->This.LinkOffsets.PrevEnd,
+ N->This.LinkOffsets.NextStart,
+ N->This.LinkOffsets.NextEnd);
+ }
+
+ if(N->NextIndex >= 0)
+ {
+ printf(
+ " Next [%d]: %s: %6d %6d %6d %6d\n",
+ N->NextIndex, N->Next.BaseFilename,
+ N->Next.LinkOffsets.PrevStart,
+ N->Next.LinkOffsets.PrevEnd,
+ N->Next.LinkOffsets.NextStart,
+ N->Next.LinkOffsets.NextEnd);
+ }
+
+ printf(
+ " OffsetModifiers: Prev %6d • This %6d • Next %6d\n"
+ " PreLinkOffsetTotals: Prev %6d • This %6d • Next %6d\n"
+ " DeletedEntryWasFirst: %s\n"
+ " DeletedEntryWasFinal: %s\n"
+ " FormerIsFirst: %s\n"
+ " LatterIsFinal: %s\n"
+ "\n",
+ N->PrevOffsetModifier, N->ThisOffsetModifier, N->NextOffsetModifier,
+ N->PreLinkPrevOffsetTotal, N->PreLinkThisOffsetTotal, N->PreLinkNextOffsetTotal,
+ N->DeletedEntryWasFirst ? "yes" : "no", N->DeletedEntryWasFinal ? "yes" : "no",
+ N->FormerIsFirst ? "yes" : "no", N->LatterIsFinal ? "yes" : "no");
+}
void
-GetNeighbourhood(index *Index, neighbourhood *N, int IndexEditType, bool *ThisIsPrev)
+SetNeighbour(db_entry *Dest, db_entry *Src)
{
- index_metadata Entry = { };
+ Dest->Size = Src->Size;
+ Dest->LinkOffsets.PrevStart = Src->LinkOffsets.PrevStart;
+ Dest->LinkOffsets.PrevEnd = Src->LinkOffsets.PrevEnd;
+ Dest->LinkOffsets.NextStart = Src->LinkOffsets.NextStart;
+ Dest->LinkOffsets.NextEnd = Src->LinkOffsets.NextEnd;
+ CopyString(Dest->BaseFilename, sizeof(Dest->BaseFilename), "%s", Src->BaseFilename);
+ CopyString(Dest->Title, sizeof(Dest->Title), "%s", Src->Title);
+}
+
+void
+GetNeighbourhoodForAddition(neighbourhood *N, enum8(edit_types) EditType)
+{
+ db_entry Entry = { };
+
int EntryIndex;
- int IncomingIndex = N->ThisIndex;
- if(IndexEditType == EDIT_DELETION)
- {
- bool FoundThis = FALSE;
- for(EntryIndex = IncomingIndex + 1; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
- {
- Entry = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
- if(Entry.Size > 0)
- {
- FoundThis = TRUE;
- break;
- }
- }
-
- if(!FoundThis)
- {
- for(EntryIndex = IncomingIndex - 1; EntryIndex >= 0; --EntryIndex)
- {
- Entry = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
- if(Entry.Size > 0)
- {
- FoundThis = TRUE;
- *ThisIsPrev = TRUE;
- break;
- }
- }
- }
-
- if(FoundThis)
- {
- N->ThisIndex = EntryIndex;
- N->This.Size = Entry.Size;
- N->This.LinkOffsets.PrevStart = Entry.LinkOffsets.PrevStart;
- N->This.LinkOffsets.PrevEnd = Entry.LinkOffsets.PrevEnd;
- N->This.LinkOffsets.NextStart = Entry.LinkOffsets.NextStart;
- N->This.LinkOffsets.NextEnd = Entry.LinkOffsets.NextEnd;
- CopyString(N->This.BaseFilename, sizeof(N->This.BaseFilename), "%s", Entry.BaseFilename);
- CopyString(N->This.Title, sizeof(N->This.Title), "%s", Entry.Title);
- }
- else
- {
- return; // NOTE(matt): We were evidently the last public entry, until now
- }
- }
-
- N->PrevIsFirst = TRUE;
- N->NextIsFinal = TRUE;
-
- if(IndexEditType == EDIT_DELETION && *ThisIsPrev == FALSE)
- {
- EntryIndex = IncomingIndex - 1;
- }
- else
- {
- EntryIndex = N->ThisIndex - 1;
- }
bool FoundPrev = FALSE;
+ bool FoundNext = FALSE;
+
+ N->FormerIsFirst = TRUE;
+ EntryIndex = N->ThisIndex - 1;
+
for(; EntryIndex >= 0; --EntryIndex)
{
- Entry = *(index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
+ Entry = *(db_entry*)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex);
if(Entry.Size > 0)
{
if(!FoundPrev)
{
N->PrevIndex = EntryIndex;
- N->Prev.Size = Entry.Size;
- N->Prev.LinkOffsets.PrevStart = Entry.LinkOffsets.PrevStart;
- N->Prev.LinkOffsets.PrevEnd = Entry.LinkOffsets.PrevEnd;
- N->Prev.LinkOffsets.NextStart = Entry.LinkOffsets.NextStart;
- N->Prev.LinkOffsets.NextEnd = Entry.LinkOffsets.NextEnd;
- CopyString(N->Prev.BaseFilename, sizeof(N->Prev.BaseFilename), "%s", Entry.BaseFilename);
- CopyString(N->Prev.Title, sizeof(N->Prev.Title), "%s", Entry.Title);
+ SetNeighbour(&N->Prev, &Entry);
FoundPrev = TRUE;
}
else
{
- N->PrevIsFirst = FALSE;
+ N->FormerIsFirst = FALSE;
break;
}
}
}
- switch(IndexEditType)
+ switch(EditType)
{
- case EDIT_DELETION:
- if(*ThisIsPrev == TRUE) { EntryIndex = Index->Header.EntryCount; break; } // NOTE(matt): No need to enter the loop, else fallthrough
case EDIT_REINSERTION:
EntryIndex = N->ThisIndex + 1;
break;
@@ -4837,142 +6348,149 @@ GetNeighbourhood(index *Index, neighbourhood *N, int IndexEditType, bool *ThisIs
EntryIndex = N->ThisIndex;
break;
}
- bool FoundNext = FALSE;
- for(; EntryIndex < Index->Header.EntryCount;
+
+ N->LatterIsFinal = TRUE;
+ for(; EntryIndex < DB.EntriesHeader.Count;
++EntryIndex)
{
- Entry = *(index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
+ Entry = *(db_entry*)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex);
if(Entry.Size > 0)
{
if(!FoundNext)
{
N->NextIndex = EntryIndex;
- N->Next.Size = Entry.Size;
- N->Next.LinkOffsets.PrevStart = Entry.LinkOffsets.PrevStart;
- N->Next.LinkOffsets.PrevEnd = Entry.LinkOffsets.PrevEnd;
- N->Next.LinkOffsets.NextStart = Entry.LinkOffsets.NextStart;
- N->Next.LinkOffsets.NextEnd = Entry.LinkOffsets.NextEnd;
- CopyString(N->Next.BaseFilename, sizeof(N->Next.BaseFilename), "%s", Entry.BaseFilename);
- CopyString(N->Next.Title, sizeof(N->Next.Title), "%s", Entry.Title);
+ SetNeighbour(&N->Next, &Entry);
FoundNext = TRUE;
}
else
{
- N->NextIsFinal = FALSE;
+ N->LatterIsFinal = FALSE;
break;
}
}
}
- switch(IndexEditType)
+ if(EditType == EDIT_ADDITION && FoundNext)
{
- case EDIT_REINSERTION:
- break;
- case EDIT_DELETION:
- if(*ThisIsPrev == FALSE) { --N->ThisIndex; }
- if(FoundNext) { --N->NextIndex; }
- break;
- case EDIT_ADDITION:
- if(FoundNext) { ++N->NextIndex; }
- break;
+ ++N->NextIndex;
}
}
-int
-InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename, bool RecheckingPrivacy)
+void
+GetNeighbourhoodForDeletion(neighbourhood *N)
{
- int IndexEntryInsertionStart = -1;
- int IndexEntryInsertionEnd = -1;
- Index->Header.EntryCount = 0;
- ClearEntry(&Index->Entry);
- bool Reinserting = FALSE;
+ db_entry Entry = { };
+ Entry = *(db_entry *)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * N->ThisIndex);
+ N->PreDeletionThisIndex = N->ThisIndex;
+ SetNeighbour(&N->This, &Entry);
- index_metadata *Entry = { 0 };
- if(Index->Metadata.FileSize > 0 && Index->File.FileSize > 0)
+ int EntryIndex;
+
+ N->DeletedEntryWasFirst = TRUE;
+ N->FormerIsFirst = TRUE;
+ bool FoundPrev = FALSE;
+ for(EntryIndex = N->PreDeletionThisIndex - 1; EntryIndex >= 0; --EntryIndex)
{
- // TODO(matt): Index validation?
- // Maybe at least if(!StringsDiffer(..., "name: \"");
- // and check that we won't crash through the end of the file when skipping to the next entry
+ Entry = *(db_entry *)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex);
+ if(Entry.Size > 0)
+ {
+ if(!FoundPrev)
+ {
+ FoundPrev = TRUE;
+ N->DeletedEntryWasFirst = FALSE;
- Index->Header = *(index_header *)Index->Metadata.Buffer.Location;
- Index->Header.CurrentDBVersion = CINERA_DB_VERSION;
- Index->Header.CurrentAppVersion = CINERA_APP_VERSION;
- Index->Header.CurrentHMMLVersion.Major = hmml_version.Major;
- Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
- Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
+ N->PrevIndex = EntryIndex;
+ SetNeighbour(&N->Prev, &Entry);
+ }
+ else
+ {
+ N->FormerIsFirst = FALSE;
+ break;
+ }
+ }
+ }
- *(index_header *)Index->Metadata.Buffer.Location = Index->Header;
- Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header);
- Index->File.Buffer.Ptr = Index->File.Buffer.Location + StringLength("---\n");
+ N->DeletedEntryWasFinal = TRUE;
+ N->LatterIsFinal = TRUE;
+ bool FoundNext = FALSE;
+ for(EntryIndex = N->PreDeletionThisIndex + 1; EntryIndex < DB.EntriesHeader.Count; ++EntryIndex)
+ {
+ Entry = *(db_entry *)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex);
+ if(Entry.Size > 0)
+ {
+ if(!FoundNext)
+ {
+ FoundNext = TRUE;
+ N->DeletedEntryWasFinal = FALSE;
- N->ThisIndex = BinarySearchForMetadataEntry(Index, &Entry, BaseFilename);
+ N->NextIndex = EntryIndex - 1;
+ SetNeighbour(&N->Next, &Entry);
+ }
+ else
+ {
+ N->LatterIsFinal = FALSE;
+ break;
+ }
+ }
+ }
+}
+
+void
+GetNeighbourhood(neighbourhood *N, enum8(edit_types) EditType)
+{
+ if(EditType == EDIT_DELETION)
+ {
+ GetNeighbourhoodForDeletion(N);
+ }
+ else
+ {
+ GetNeighbourhoodForAddition(N, EditType);
+ }
+}
+
+void
+SnipeEntryIntoMetadataBuffer(db_entry *Entry, int EntryIndex)
+{
+ *(db_entry *)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex) = *Entry;
+}
+
+int
+InsertIntoDB(neighbourhood *N, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename, bool RecheckingPrivacy, bool *Reinserting)
+{
+ enum8(edit_types) EditType = EDIT_APPEND;
+ int EntryInsertionStart = StringLength("---\n");
+ int EntryInsertionEnd;
+
+ if(DB.EntriesHeader.Count > 0)
+ {
+ db_entry *Entry = { 0 };
+ N->ThisIndex = BinarySearchForMetadataEntry(&Entry, BaseFilename);
if(Entry)
{
// Reinsert
- Reinserting = TRUE;
- N->This.Size = Entry->Size;
- N->This.LinkOffsets.PrevStart = Entry->LinkOffsets.PrevStart;
- N->This.LinkOffsets.PrevEnd = Entry->LinkOffsets.PrevEnd;
- N->This.LinkOffsets.NextStart = Entry->LinkOffsets.NextStart;
- N->This.LinkOffsets.NextEnd = Entry->LinkOffsets.NextEnd;
-
- IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, N->ThisIndex);
- IndexEntryInsertionEnd = IndexEntryInsertionStart + Entry->Size;
+ *Reinserting = TRUE;
+ EntryInsertionStart = AccumulateDBEntryInsertionOffset(N->ThisIndex);
+ EntryInsertionEnd = EntryInsertionStart + Entry->Size;
+ EditType = EDIT_REINSERTION;
}
else
{
if(N->ThisIndex == -1) { ++N->ThisIndex; } // NOTE(matt): BinarySearchForMetadataEntry returns -1 if search term precedes the set
- Entry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex);
+ Entry = (db_entry*)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * N->ThisIndex);
if(StringsDiffer(BaseFilename, Entry->BaseFilename) < 0)
{
// Insert
- IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, N->ThisIndex);
-
+ EditType = EDIT_INSERTION;
}
else
{
// Append
++N->ThisIndex;
+ EditType = EDIT_APPEND;
}
+ EntryInsertionStart = AccumulateDBEntryInsertionOffset(N->ThisIndex);
}
- GetNeighbourhood(Index, N, Reinserting ? EDIT_REINSERTION : EDIT_ADDITION, 0);
- }
- else
- {
- // NOTE(matt): Initialising new index_header
- Index->Header.InitialDBVersion = Index->Header.CurrentDBVersion = CINERA_DB_VERSION;
- Index->Header.InitialAppVersion = Index->Header.CurrentAppVersion = CINERA_APP_VERSION;
- Index->Header.InitialHMMLVersion.Major = Index->Header.CurrentHMMLVersion.Major = hmml_version.Major;
- Index->Header.InitialHMMLVersion.Minor = Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
- Index->Header.InitialHMMLVersion.Patch = Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
-
- CopyStringNoFormat(Index->Header.ProjectID, sizeof(Index->Header.ProjectID), Config.ProjectID);
-
- for(int ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
- {
- if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID, Config.ProjectID))
- {
- CopyStringNoFormat(Index->Header.ProjectName, sizeof(Index->Header.ProjectName), ProjectInfo[ProjectIndex].FullName);
- break;
- }
- }
-
- CopyStringNoFormat(Index->Header.BaseURL, sizeof(Index->Header.BaseURL), Config.BaseURL);
- CopyStringNoFormat(Index->Header.IndexLocation, sizeof(Index->Header.IndexLocation), Config.IndexLocation);
- CopyStringNoFormat(Index->Header.PlayerLocation, sizeof(Index->Header.PlayerLocation), Config.PlayerLocation);
- CopyStringNoFormat(Index->Header.PlayerURLPrefix, sizeof(Index->Header.PlayerURLPrefix), Config.PlayerURLPrefix);
-
- DIR *OutputDirectoryHandle;
- if(!(OutputDirectoryHandle = opendir(Config.BaseDir)))
- {
- if(MakeDir(Config.BaseDir) == RC_ERROR_DIRECTORY)
- {
- LogError(LOG_ERROR, "Unable to create directory %s: %s", Config.BaseDir, strerror(errno));
- fprintf(stderr, "Unable to create directory %s: %s\n", Config.BaseDir, strerror(errno));
- return RC_ERROR_DIRECTORY;
- };
- }
- closedir(OutputDirectoryHandle);
+ GetNeighbourhood(N, *Reinserting ? EDIT_REINSERTION : EDIT_ADDITION);
}
char InputFile[StringLength(BaseFilename) + StringLength(".hmml") + 1];
@@ -4997,105 +6515,82 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ
}
ClearCopyStringNoFormat(N->This.BaseFilename, sizeof(N->This.BaseFilename), BaseFilename);
- if(N->This.Size > 0) { ClearCopyStringNoFormat(N->This.Title, sizeof(N->This.Title), CollationBuffers->Title); }
+ if(!VideoIsPrivate) { ClearCopyStringNoFormat(N->This.Title, sizeof(N->This.Title), CollationBuffers->Title); }
- if(Reinserting)
+ if(EditType == EDIT_REINSERTION)
{
- // Reinsert
+ // NOTE(matt): To save opening the DB.Metadata file, we defer sniping N->This in until InsertNeighbourLink()
if(!VideoIsPrivate)
{
- if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { return RC_ERROR_FILE; }
- fwrite(Index->File.Buffer.Location, IndexEntryInsertionStart, 1, Index->File.Handle);
- fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
- fwrite(Index->File.Buffer.Location + IndexEntryInsertionEnd, Index->File.FileSize - IndexEntryInsertionEnd, 1, Index->File.Handle);
- fclose(Index->File.Handle);
+ if(!(DB.File.Handle = fopen(DB.File.Path, "w"))) { return RC_ERROR_FILE; }
+ fwrite(DB.File.Buffer.Location, EntryInsertionStart, 1, DB.File.Handle);
+ fwrite(CollationBuffers->SearchEntry.Location, N->This.Size, 1, DB.File.Handle);
+ fwrite(DB.File.Buffer.Location + EntryInsertionEnd, DB.File.FileSize - EntryInsertionEnd, 1, DB.File.Handle);
+ fclose(DB.File.Handle);
- if(N->This.Size == IndexEntryInsertionEnd - IndexEntryInsertionStart)
+ if(N->This.Size == EntryInsertionEnd - EntryInsertionStart)
{
- Index->File.Buffer.Ptr = Index->File.Buffer.Location + IndexEntryInsertionStart;
- CopyBufferSized(&Index->File.Buffer, &CollationBuffers->Search, N->This.Size);
+ DB.File.Buffer.Ptr = DB.File.Buffer.Location + EntryInsertionStart;
+ CopyBufferSized(&DB.File.Buffer, &CollationBuffers->SearchEntry, N->This.Size);
}
else
{
- FreeBuffer(&Index->File.Buffer);
- ReadFileIntoBuffer(&Index->File, 0);
+ FreeBuffer(&DB.File.Buffer);
+ ReadFileIntoBuffer(&DB.File, 0);
}
- LogError(LOG_NOTICE, "Reinserted %s - %s", BaseFilename, CollationBuffers->Title);
- fprintf(stderr, "\e[1;33mReinserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title);
- }
- else if(!RecheckingPrivacy)
- {
- LogError(LOG_NOTICE, "Privately Reinserted %s", BaseFilename);
- fprintf(stderr, "\e[0;34mPrivately Reinserted\e[0m %s\n", BaseFilename);
}
}
else
{
- ++Index->Header.EntryCount;
+ int ExistingEntryCount = DB.EntriesHeader.Count;
+ ++DB.EntriesHeader.Count;
- if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { return RC_ERROR_FILE; }
- fwrite(&Index->Header, sizeof(index_header), 1, Index->Metadata.Handle);
+ if(!(DB.Metadata.Handle = fopen(DB.Metadata.Path, "w"))) { return RC_ERROR_FILE; }
+ fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.Handle);
+ fwrite(&DB.EntriesHeader, sizeof(DB.EntriesHeader), 1, DB.Metadata.Handle);
- if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { return RC_ERROR_FILE; }
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader);
+ fwrite(DB.Metadata.Buffer.Ptr,
+ sizeof(DB.Entry),
+ N->ThisIndex,
+ DB.Metadata.Handle);
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Entry) * N->ThisIndex;
- if(IndexEntryInsertionStart >= 0)
- {
- // Insert new
- fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), sizeof(index_metadata) * N->ThisIndex, 1, Index->Metadata.Handle);
- fwrite(&N->This, sizeof(index_metadata), 1, Index->Metadata.Handle);
- fwrite(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex,
- Index->Metadata.FileSize - sizeof(index_header) - sizeof(index_metadata) * N->ThisIndex,
- 1, Index->Metadata.Handle);
+ fwrite(&N->This, sizeof(DB.Entry), 1, DB.Metadata.Handle);
- fwrite(Index->File.Buffer.Location, IndexEntryInsertionStart, 1, Index->File.Handle);
- fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
- fwrite(Index->File.Buffer.Location + IndexEntryInsertionStart, Index->File.FileSize - IndexEntryInsertionStart, 1, Index->File.Handle);
+ fwrite(DB.Metadata.Buffer.Ptr,
+ sizeof(DB.Entry),
+ ExistingEntryCount - N->ThisIndex,
+ DB.Metadata.Handle);
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Entry) * (ExistingEntryCount - N->ThisIndex);
- if(!VideoIsPrivate)
- {
- LogError(LOG_NOTICE, "Inserted %s - %s", BaseFilename, CollationBuffers->Title);
- fprintf(stderr, "\e[1;32mInserted\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title);
- }
- else if(!RecheckingPrivacy)
- {
- LogError(LOG_NOTICE, "Privately Inserted %s", BaseFilename);
- fprintf(stderr, "\e[0;34mPrivately Inserted\e[0m %s\n", BaseFilename);
- }
- }
- else
- {
- // Append new
- if(Index->Metadata.FileSize > 0)
- {
- fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), Index->Metadata.FileSize - sizeof(index_header), 1, Index->Metadata.Handle);
- fwrite(Index->File.Buffer.Location, Index->File.FileSize, 1, Index->File.Handle);
- }
- else
- {
- fprintf(Index->File.Handle, "---\n");
- }
- fwrite(&N->This, sizeof(index_metadata), 1, Index->Metadata.Handle);
- fwrite(CollationBuffers->Search.Location, N->This.Size, 1, Index->File.Handle);
+ fwrite(DB.Metadata.Buffer.Ptr,
+ DB.Metadata.FileSize - (DB.Metadata.Buffer.Ptr - DB.Metadata.Buffer.Location),
+ 1,
+ DB.Metadata.Handle);
- if(!VideoIsPrivate)
- {
- LogError(LOG_NOTICE, "Appended %s - %s", BaseFilename, CollationBuffers->Title);
- fprintf(stderr, "\e[1;32mAppended\e[0m %s - %s\n", BaseFilename, CollationBuffers->Title);
- }
- else if(!RecheckingPrivacy)
- {
- LogError(LOG_NOTICE, "Privately Appended %s", BaseFilename);
- fprintf(stderr, "\e[0;34mPrivately Appended\e[0m %s\n", BaseFilename);
- }
- }
+ CycleFile(&DB.Metadata);
- fclose(Index->Metadata.Handle);
- FreeBuffer(&Index->Metadata.Buffer);
- ReadFileIntoBuffer(&Index->Metadata, 0);
- fclose(Index->File.Handle);
- FreeBuffer(&Index->File.Buffer);
- ReadFileIntoBuffer(&Index->File, 0);
+ if(!(DB.File.Handle = fopen(DB.File.Path, "w"))) { return RC_ERROR_FILE; }
+ fwrite(DB.File.Buffer.Location,
+ DB.File.FileSize - (DB.File.FileSize - EntryInsertionStart),
+ 1, DB.File.Handle);
+ fwrite(CollationBuffers->SearchEntry.Location, N->This.Size, 1, DB.File.Handle);
+ fwrite(DB.File.Buffer.Location + EntryInsertionStart, DB.File.FileSize - EntryInsertionStart, 1, DB.File.Handle);
+
+ CycleFile(&DB.File);
+ }
+
+ if(!VideoIsPrivate)
+ {
+ LogError(LOG_NOTICE, "%s %s - %s", EditTypes[EditType].Name, BaseFilename, CollationBuffers->Title);
+ fprintf(stderr, "%s%s%s %s - %s\n", ColourStrings[EditTypes[EditType].Colour], EditTypes[EditType].Name, ColourStrings[CS_END], BaseFilename, CollationBuffers->Title);
+ }
+ else if(!RecheckingPrivacy)
+ {
+ LogError(LOG_NOTICE, "Privately %s %s", EditTypes[EditType].Name, BaseFilename);
+ fprintf(stderr, "%sPrivately %s%s %s\n", ColourStrings[CS_PRIVATE], EditTypes[EditType].Name, ColourStrings[CS_END], BaseFilename);
}
// TODO(matt): Remove VideoIsPrivate in favour of generating a player page in a random location
@@ -5103,36 +6598,357 @@ InsertIntoIndex(index *Index, neighbourhood *N, buffers *CollationBuffers, templ
}
void
-ConstructDirectoryPath(buffer *DirectoryPath, int PageType, char *PageLocation, char *BaseFilename)
+WritePastAssetsHeader(void)
{
- RewindBuffer(DirectoryPath);
- CopyStringToBuffer(DirectoryPath, "%s", Config.BaseDir);
- switch(PageType)
+ DB.Metadata.Handle = fopen(DB.Metadata.Path, "w");
+ fwrite(DB.Metadata.Buffer.Location,
+ sizeof(DB.Header)
+ + sizeof(DB.EntriesHeader)
+ + sizeof(DB.Entry) * DB.EntriesHeader.Count
+ + sizeof(DB.AssetsHeader),
+ 1,
+ DB.Metadata.Handle);
+
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location
+ + sizeof(DB.Header)
+ + sizeof(DB.EntriesHeader)
+ + sizeof(DB.Entry) * DB.EntriesHeader.Count;
+
+ DB.AssetsHeader = *(db_header_assets *)DB.Metadata.Buffer.Ptr;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.AssetsHeader);
+}
+
+void
+PrintLandmarks(void *FirstLandmark, int LandmarkCount)
+{
+ printf("PrintLandmarks()\n");
+ for(int i = 0; i < LandmarkCount; ++i)
{
- case PAGE_INDEX:
- if(StringsDiffer(PageLocation, ""))
+ db_landmark Landmark = *(db_landmark *)(FirstLandmark + sizeof(Landmark) * i);
+ printf(" %4d %d\n", Landmark.EntryIndex, Landmark.Position);
+ }
+}
+
+void
+ProcessPrevLandmarks(neighbourhood *N, void *FirstLandmark, int ExistingLandmarkCount, landmark_range *CurrentTarget, bool OffsetLandmarks, int *RunningIndex)
+{
+ if(N->PrevIndex >= 0)
+ {
+ landmark_range FormerTarget = BinarySearchForMetadataLandmark(FirstLandmark, N->PrevIndex, ExistingLandmarkCount);
+ fwrite(FirstLandmark, sizeof(db_landmark), FormerTarget.First, DB.Metadata.Handle);
+ *RunningIndex += FormerTarget.First;
+
+ for(int j = 0; j < FormerTarget.Length; ++j, ++*RunningIndex)
+ {
+ db_landmark Landmark = *(db_landmark *)(FirstLandmark + sizeof(Landmark) * *RunningIndex);
+ if(!OffsetLandmarks && Landmark.Position >= N->PreLinkPrevOffsetTotal)
{
- CopyStringToBuffer(DirectoryPath, "/%s", PageLocation);
+ Landmark.Position += N->PrevOffsetModifier;
}
- break;
- case PAGE_PLAYER:
- if(StringsDiffer(PageLocation, ""))
+ fwrite(&Landmark, sizeof(Landmark), 1, DB.Metadata.Handle);
+ }
+ }
+ else
+ {
+ fwrite(FirstLandmark + sizeof(db_landmark) * *RunningIndex, sizeof(db_landmark), CurrentTarget->First, DB.Metadata.Handle);
+ *RunningIndex += CurrentTarget->First;
+ }
+}
+
+void
+ProcessNextLandmarks(neighbourhood *N, void *FirstLandmark, int ExistingLandmarkCount, bool OffsetLandmarks, int *RunningIndex, enum8(edit_types) EditType)
+{
+ if(N->NextIndex >= 0 && *RunningIndex < ExistingLandmarkCount)
+ {
+ db_landmark Landmark = *(db_landmark *)(FirstLandmark + sizeof(Landmark) * *RunningIndex);
+ landmark_range LatterTarget = BinarySearchForMetadataLandmark(FirstLandmark, Landmark.EntryIndex, ExistingLandmarkCount);
+
+ for(int j = 0; j < LatterTarget.Length; ++j, ++*RunningIndex)
+ {
+ Landmark = *(db_landmark *)(FirstLandmark + sizeof(Landmark) * *RunningIndex);
+ if(!OffsetLandmarks && Landmark.Position >= N->PreLinkNextOffsetTotal)
{
- CopyStringToBuffer(DirectoryPath, "/%s", PageLocation);
+ Landmark.Position += N->NextOffsetModifier;
}
- if(BaseFilename)
+ switch(EditType)
{
- if(StringsDiffer(Config.PlayerURLPrefix, ""))
+ case EDIT_DELETION: --Landmark.EntryIndex; break;
+ case EDIT_ADDITION: ++Landmark.EntryIndex; break;
+ }
+ fwrite(&Landmark, sizeof(Landmark), 1, DB.Metadata.Handle);
+ }
+
+ for(; *RunningIndex < ExistingLandmarkCount; ++*RunningIndex)
+ {
+ Landmark = *(db_landmark *)(FirstLandmark + sizeof(Landmark) * *RunningIndex);
+ switch(EditType)
+ {
+ case EDIT_DELETION: --Landmark.EntryIndex; break;
+ case EDIT_ADDITION: ++Landmark.EntryIndex; break;
+ }
+ fwrite(&Landmark, sizeof(Landmark), 1, DB.Metadata.Handle);
+ }
+ }
+}
+
+void
+DeleteStaleAssets(void)
+{
+ LocateAssetsBlock();
+ char *AssetsHeaderLocation = DB.Metadata.Buffer.Ptr;
+ DB.AssetsHeader = *(db_header_assets *)AssetsHeaderLocation;
+ int AssetDeletionCount = 0;
+ int AssetDeletionLocations[DB.AssetsHeader.Count];
+ DB.Metadata.Buffer.Ptr += sizeof(DB.AssetsHeader);
+ for(int AssetIndex = 0; AssetIndex < DB.AssetsHeader.Count; ++AssetIndex)
+ {
+ DB.Asset = *(db_asset*)DB.Metadata.Buffer.Ptr;
+ if(DB.Asset.LandmarkCount == 0)
+ {
+ AssetDeletionLocations[AssetDeletionCount] = DB.Metadata.Buffer.Ptr - DB.Metadata.Buffer.Location;
+ ++AssetDeletionCount;
+ --DB.AssetsHeader.Count;
+ }
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Asset) + sizeof(DB.Landmark) * DB.Asset.LandmarkCount;
+ }
+
+ if(AssetDeletionCount > 0)
+ {
+ DB.Metadata.Handle = fopen(DB.Metadata.Path, "w");
+ fwrite(DB.Metadata.Buffer.Location, AssetsHeaderLocation - DB.Metadata.Buffer.Location, 1, DB.Metadata.Handle);
+ fwrite(&DB.AssetsHeader, sizeof(DB.AssetsHeader), 1, DB.Metadata.Handle);
+
+ int WrittenBytes = (AssetsHeaderLocation - DB.Metadata.Buffer.Location) + sizeof(DB.AssetsHeader);
+
+ for(int DeletionIndex = 0; DeletionIndex < AssetDeletionCount; ++DeletionIndex)
+ {
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location + AssetDeletionLocations[DeletionIndex];
+ fwrite(DB.Metadata.Buffer.Location + WrittenBytes,
+ (DB.Metadata.Buffer.Ptr - DB.Metadata.Buffer.Location) - WrittenBytes,
+ 1,
+ DB.Metadata.Handle);
+ WrittenBytes += (DB.Metadata.Buffer.Ptr - DB.Metadata.Buffer.Location) - WrittenBytes + sizeof(DB.Asset);
+ }
+ fwrite(DB.Metadata.Buffer.Location + WrittenBytes, DB.Metadata.FileSize - WrittenBytes, 1, DB.Metadata.Handle);
+ CycleFile(&DB.Metadata);
+ }
+}
+
+void
+DeleteStaleLandmarks(void)
+{
+ WritePastAssetsHeader();
+ for(int AssetIndex = 0; AssetIndex < DB.AssetsHeader.Count; ++AssetIndex)
+ {
+ DB.Asset = *(db_asset *)DB.Metadata.Buffer.Ptr;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Asset) + sizeof(DB.Landmark) * DB.Asset.LandmarkCount;
+ DB.Asset.LandmarkCount = 0;
+ fwrite(&DB.Asset, sizeof(DB.Asset), 1, DB.Metadata.Handle);
+ }
+ CycleFile(&DB.Metadata);
+}
+
+void
+DeleteLandmarks(neighbourhood *N)
+{
+ for(int AssetIndex = 0; AssetIndex < DB.AssetsHeader.Count; ++AssetIndex)
+ {
+ DB.Asset = *(db_asset *)DB.Metadata.Buffer.Ptr;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Asset);
+ db_landmark *FirstLandmark = (db_landmark *)DB.Metadata.Buffer.Ptr;
+ int ExistingLandmarkCount = DB.Asset.LandmarkCount;
+ int RunningIndex = 0;
+
+ landmark_range DeletionTarget = BinarySearchForMetadataLandmark(FirstLandmark, N->PreDeletionThisIndex, ExistingLandmarkCount);
+ DB.Asset.LandmarkCount -= DeletionTarget.Length;
+ fwrite(&DB.Asset, sizeof(DB.Asset), 1, DB.Metadata.Handle);
+
+ ProcessPrevLandmarks(N, FirstLandmark, ExistingLandmarkCount, &DeletionTarget, Assets.Asset[AssetIndex].OffsetLandmarks, &RunningIndex);
+
+ RunningIndex += DeletionTarget.Length;
+
+ ProcessNextLandmarks(N, FirstLandmark, ExistingLandmarkCount, Assets.Asset[AssetIndex].OffsetLandmarks, &RunningIndex, EDIT_DELETION);
+ DB.Metadata.Buffer.Ptr += sizeof(db_landmark) * ExistingLandmarkCount;
+ }
+ CycleFile(&DB.Metadata);
+}
+
+void UpdateLandmarksForNeighbourhood(neighbourhood *N, enum8(edit_types) EditType);
+
+void
+AddLandmarks(neighbourhood *N, enum8(edit_types) EditType)
+{
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ Assets.Asset[i].Known = FALSE;
+ }
+
+ for(int StoredAssetIndex = 0; StoredAssetIndex < DB.AssetsHeader.Count; ++StoredAssetIndex)
+ {
+ DB.Asset = *(db_asset *)DB.Metadata.Buffer.Ptr;
+ int ExistingLandmarkCount = DB.Asset.LandmarkCount;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Asset);
+ void *FirstLandmark;
+ if(ExistingLandmarkCount > 0)
+ {
+ FirstLandmark = DB.Metadata.Buffer.Ptr;
+ }
+ int RunningIndex = 0;
+
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ if(!StringsDiffer(DB.Asset.Filename, Assets.Asset[i].Filename) && DB.Asset.Type == Assets.Asset[i].Type)
+ {
+ Assets.Asset[i].Known = TRUE;
+ DB.Asset.LandmarkCount += Assets.Asset[i].PlayerLandmarkCount;
+ landmark_range ThisTarget;
+ if(ExistingLandmarkCount > 0)
{
- char *Ptr = BaseFilename + StringLength(Config.ProjectID);
- CopyStringToBuffer(DirectoryPath, "/%s%s", Config.PlayerURLPrefix, Ptr);
+ ThisTarget = BinarySearchForMetadataLandmark(FirstLandmark, N->ThisIndex, ExistingLandmarkCount);
+
+ if(EditType == EDIT_REINSERTION) { DB.Asset.LandmarkCount -= ThisTarget.Length; }
}
- else
+
+ fwrite(&DB.Asset, sizeof(DB.Asset), 1, DB.Metadata.Handle);
+
+ if(ExistingLandmarkCount > 0)
{
- CopyStringToBuffer(DirectoryPath, "/%s", BaseFilename);
+ ProcessPrevLandmarks(N, FirstLandmark, ExistingLandmarkCount, &ThisTarget, Assets.Asset[i].OffsetLandmarks, &RunningIndex);
+ }
+
+ for(int j = 0; j < Assets.Asset[i].PlayerLandmarkCount; ++j)
+ {
+ db_landmark Landmark;
+ Landmark.EntryIndex = N->ThisIndex;
+ Landmark.Position = Assets.Asset[i].PlayerLandmark[j];
+ fwrite(&Landmark, sizeof(Landmark), 1, DB.Metadata.Handle);
+ }
+
+ if(ExistingLandmarkCount > 0)
+ {
+ if(EditType == EDIT_REINSERTION) { RunningIndex += ThisTarget.Length; }
+
+ ProcessNextLandmarks(N, FirstLandmark, ExistingLandmarkCount, Assets.Asset[i].OffsetLandmarks, &RunningIndex, EditType);
+ }
+ Assets.Asset[i].OffsetLandmarks = TRUE;
+ break;
+ }
+ }
+ DB.Metadata.Buffer.Ptr += sizeof(db_landmark) * ExistingLandmarkCount;
+ }
+ CycleFile(&DB.Metadata);
+
+ bool NewAsset = FALSE;
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ if(!Assets.Asset[i].Known && Assets.Asset[i].PlayerLandmarkCount > 0)
+ {
+ UpdateAssetInDB(i);
+ NewAsset = TRUE;
+ }
+ }
+ if(NewAsset) {
+ UpdateLandmarksForNeighbourhood(N, EDIT_REINSERTION); // NOTE(matt): EDIT_REINSERTION this time because all existing
+ // assets will have been updated in the first pass
+ }
+}
+
+void
+UpdateLandmarksForNeighbourhood(neighbourhood *N, enum8(edit_types) EditType)
+{
+ if(!(Config.Mode & MODE_NOREVVEDRESOURCE))
+ {
+ WritePastAssetsHeader();
+ switch(EditType)
+ {
+ case EDIT_DELETION: DeleteLandmarks(N); break;
+ case EDIT_ADDITION: case EDIT_REINSERTION: { AddLandmarks(N, EditType); break; }
+ }
+ }
+}
+
+void
+DeleteLandmarksForSearch(void)
+{
+ if(!(Config.Mode & MODE_NOREVVEDRESOURCE))
+ {
+ WritePastAssetsHeader();
+ for(int AssetIndex = 0; AssetIndex < DB.AssetsHeader.Count; ++AssetIndex)
+ {
+ DB.Asset = *(db_asset *)DB.Metadata.Buffer.Ptr;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Asset);
+ db_landmark *FirstLandmark = (db_landmark *)DB.Metadata.Buffer.Ptr;
+ int ExistingLandmarkCount = DB.Asset.LandmarkCount;
+
+ landmark_range DeletionTarget = BinarySearchForMetadataLandmark(FirstLandmark, PAGE_TYPE_SEARCH, ExistingLandmarkCount);
+ DB.Asset.LandmarkCount -= DeletionTarget.Length;
+ fwrite(&DB.Asset, sizeof(DB.Asset), 1, DB.Metadata.Handle);
+
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Landmark) * DeletionTarget.Length;
+ fwrite(DB.Metadata.Buffer.Ptr, sizeof(DB.Landmark), ExistingLandmarkCount - DeletionTarget.Length, DB.Metadata.Handle);
+
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Landmark) * ExistingLandmarkCount - DeletionTarget.Length;
+ }
+ CycleFile(&DB.Metadata);
+ }
+}
+
+void
+UpdateLandmarksForSearch(void)
+{
+ if(!(Config.Mode & MODE_NOREVVEDRESOURCE))
+ {
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ Assets.Asset[i].Known = FALSE;
+ }
+
+ WritePastAssetsHeader();
+ for(int AssetIndex = 0; AssetIndex < DB.AssetsHeader.Count; ++AssetIndex)
+ {
+ DB.Asset = *(db_asset *)DB.Metadata.Buffer.Ptr;
+ int ExistingLandmarkCount = DB.Asset.LandmarkCount;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Asset);
+ void *FirstLandmark = DB.Metadata.Buffer.Ptr;
+
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ if(!StringsDiffer(DB.Asset.Filename, Assets.Asset[i].Filename) && DB.Asset.Type == Assets.Asset[i].Type)
+ {
+ Assets.Asset[i].Known = TRUE;
+
+ landmark_range Target = BinarySearchForMetadataLandmark(FirstLandmark, PAGE_TYPE_SEARCH, DB.Asset.LandmarkCount);
+
+ DB.Asset.LandmarkCount += Assets.Asset[i].SearchLandmarkCount - Target.Length;
+
+ fwrite(&DB.Asset, sizeof(DB.Asset), 1, DB.Metadata.Handle);
+
+ for(int j = 0; j < Assets.Asset[i].SearchLandmarkCount; ++j)
+ {
+ DB.Landmark.EntryIndex = PAGE_TYPE_SEARCH;
+ DB.Landmark.Position = Assets.Asset[i].SearchLandmark[j];
+ fwrite(&DB.Landmark, sizeof(DB.Landmark), 1, DB.Metadata.Handle);
+ }
+
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Landmark) * (Target.First + Target.Length);
+ fwrite(DB.Metadata.Buffer.Ptr, sizeof(DB.Landmark), ExistingLandmarkCount - (Target.First + Target.Length), DB.Metadata.Handle);
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Landmark) * (ExistingLandmarkCount - (Target.First + Target.Length));
+ break;
}
}
- break;
+ }
+ CycleFile(&DB.Metadata);
+
+ bool NewAsset = FALSE;
+ for(int InternalAssetIndex = 0; InternalAssetIndex < Assets.Count; ++InternalAssetIndex)
+ {
+ if(!Assets.Asset[InternalAssetIndex].Known && Assets.Asset[InternalAssetIndex].SearchLandmarkCount > 0)
+ {
+ NewAsset = TRUE;
+ UpdateAssetInDB(InternalAssetIndex);
+ }
+ }
+ if(NewAsset) { UpdateLandmarksForSearch(); }
}
}
@@ -5144,19 +6960,20 @@ enum
enum
{
- LINK_PREV,
- LINK_NEXT
+ LINK_FORWARDS,
+ LINK_BACKWARDS
} link_directions;
int
-InsertNeighbourLink(file_buffer *FromFile, index_metadata *From, index_metadata *To, int LinkDirection, char *ProjectName, bool FromHasOneNeighbour)
+InsertNeighbourLink(db_entry *From, int FromIndex, db_entry *To, enum8(link_directions) LinkDirection, bool FromHasOneNeighbour)
{
- if(ReadFileIntoBuffer(FromFile, 0) == RC_SUCCESS)
+ file_buffer HTML;
+ if(ReadPlayerPageIntoBuffer(&HTML, From) == RC_SUCCESS)
{
- if(!(FromFile->Handle = fopen(FromFile->Path, "w"))) { FreeBuffer(&FromFile->Buffer); return RC_ERROR_FILE; };
+ if(!(HTML.Handle = fopen(HTML.Path, "w"))) { FreeBuffer(&HTML.Buffer); return RC_ERROR_FILE; };
buffer Link;
- ClaimBuffer(&Link, "Link", 4096);
+ ClaimBuffer(&Link, "Link", Kilobytes(4));
buffer ToPlayerURL;
if(To)
@@ -5165,13 +6982,13 @@ InsertNeighbourLink(file_buffer *FromFile, index_metadata *From, index_metadata
ConstructPlayerURL(&ToPlayerURL, To->BaseFilename);
}
+ int NewPrevEnd = 0;
+ int NewNextEnd = 0;
switch(LinkDirection)
{
- case LINK_PREV:
+ case LINK_BACKWARDS:
{
- int NewPrevEnd = 0;
- int NewNextEnd = 0;
- fwrite(FromFile->Buffer.Location, From->LinkOffsets.PrevStart, 1, FromFile->Handle);
+ fwrite(HTML.Buffer.Location, From->LinkOffsets.PrevStart, 1, HTML.Handle);
if(To)
{
CopyStringToBuffer(&Link,
@@ -5182,52 +6999,50 @@ InsertNeighbourLink(file_buffer *FromFile, index_metadata *From, index_metadata
else
{
CopyStringToBuffer(&Link,
- " \n", ProjectName);
+ " \n", DB.EntriesHeader.ProjectName);
}
NewPrevEnd = Link.Ptr - Link.Location;
- fwrite(Link.Location, (Link.Ptr - Link.Location), 1, FromFile->Handle);
+ fwrite(Link.Location, (Link.Ptr - Link.Location), 1, HTML.Handle);
if(FromHasOneNeighbour)
{
- fwrite(FromFile->Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd, From->LinkOffsets.NextStart, 1, FromFile->Handle);
+ fwrite(HTML.Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd, From->LinkOffsets.NextStart, 1, HTML.Handle);
RewindBuffer(&Link);
CopyStringToBuffer(&Link,
- " •
You have arrived at the (current) end of %s
•
\n", ProjectName);
+ " •
You have arrived at the (current) end of %s
•
\n", DB.EntriesHeader.ProjectName);
NewNextEnd = Link.Ptr - Link.Location;
- fwrite(Link.Location, NewNextEnd, 1, FromFile->Handle);
- fwrite(FromFile->Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd,
- FromFile->FileSize - (From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd),
+ fwrite(Link.Location, NewNextEnd, 1, HTML.Handle);
+ fwrite(HTML.Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd,
+ HTML.FileSize - (From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd),
1,
- FromFile->Handle);
+ HTML.Handle);
}
else
{
- fwrite(FromFile->Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd,
- FromFile->FileSize - (From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd),
+ fwrite(HTML.Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd,
+ HTML.FileSize - (From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd),
1,
- FromFile->Handle);
+ HTML.Handle);
}
From->LinkOffsets.PrevEnd = NewPrevEnd;
if(FromHasOneNeighbour) { From->LinkOffsets.NextEnd = NewNextEnd; }
} break;
- case LINK_NEXT:
+ case LINK_FORWARDS:
{
- int NewPrevEnd = 0;
- int NewNextEnd = 0;
if(FromHasOneNeighbour)
{
- fwrite(FromFile->Buffer.Location, From->LinkOffsets.PrevStart, 1, FromFile->Handle);
+ fwrite(HTML.Buffer.Location, From->LinkOffsets.PrevStart, 1, HTML.Handle);
CopyStringToBuffer(&Link,
- " \n", ProjectName);
+ " \n", DB.EntriesHeader.ProjectName);
NewPrevEnd = Link.Ptr - Link.Location;
- fwrite(Link.Location, NewPrevEnd, 1, FromFile->Handle);
+ fwrite(Link.Location, NewPrevEnd, 1, HTML.Handle);
RewindBuffer(&Link);
- fwrite(FromFile->Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd,
- From->LinkOffsets.NextStart, 1, FromFile->Handle);
+ fwrite(HTML.Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd,
+ From->LinkOffsets.NextStart, 1, HTML.Handle);
}
else
{
- fwrite(FromFile->Buffer.Location, From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart, 1, FromFile->Handle);
+ fwrite(HTML.Buffer.Location, From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart, 1, HTML.Handle);
}
if(To)
@@ -5240,15 +7055,15 @@ InsertNeighbourLink(file_buffer *FromFile, index_metadata *From, index_metadata
else
{
CopyStringToBuffer(&Link,
- " •
You have arrived at the (current) end of %s
•
\n", ProjectName);
+ " •
You have arrived at the (current) end of %s
•
\n", DB.EntriesHeader.ProjectName);
}
NewNextEnd = Link.Ptr - Link.Location;
- fwrite(Link.Location, (Link.Ptr - Link.Location), 1, FromFile->Handle);
+ fwrite(Link.Location, (Link.Ptr - Link.Location), 1, HTML.Handle);
- fwrite(FromFile->Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd,
- FromFile->FileSize - (From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd),
+ fwrite(HTML.Buffer.Location + From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd,
+ HTML.FileSize - (From->LinkOffsets.PrevStart + From->LinkOffsets.PrevEnd + From->LinkOffsets.NextStart + From->LinkOffsets.NextEnd),
1,
- FromFile->Handle);
+ HTML.Handle);
if(FromHasOneNeighbour) { From->LinkOffsets.PrevEnd = NewPrevEnd; }
From->LinkOffsets.NextEnd = NewNextEnd;
@@ -5257,8 +7072,9 @@ InsertNeighbourLink(file_buffer *FromFile, index_metadata *From, index_metadata
if(To) { DeclaimBuffer(&ToPlayerURL); }
DeclaimBuffer(&Link);
- fclose(FromFile->Handle);
- FreeBuffer(&FromFile->Buffer);
+ fclose(HTML.Handle);
+ FreeBuffer(&HTML.Buffer);
+ SnipeEntryIntoMetadataBuffer(From, FromIndex);
return RC_SUCCESS;
}
else
@@ -5268,131 +7084,253 @@ InsertNeighbourLink(file_buffer *FromFile, index_metadata *From, index_metadata
}
int
-DeleteNeighbourLinks(file_buffer *File, index_metadata *Metadata)
+DeleteNeighbourLinks(neighbourhood *N)
{
- if(ReadFileIntoBuffer(File, 0) == RC_SUCCESS)
+ db_entry *Entry;
+ int EntryIndex;
+ if(N->PrevIndex >= 0)
{
- if(!(File->Handle = fopen(File->Path, "w"))) { FreeBuffer(&File->Buffer); return RC_ERROR_FILE; };
+ Entry = &N->Prev;
+ EntryIndex = N->PrevIndex;
- fwrite(File->Buffer.Location, Metadata->LinkOffsets.PrevStart, 1, File->Handle);
- fwrite(File->Buffer.Location + Metadata->LinkOffsets.PrevStart + Metadata->LinkOffsets.PrevEnd, Metadata->LinkOffsets.NextStart, 1, File->Handle);
- fwrite(File->Buffer.Location + Metadata->LinkOffsets.PrevStart + Metadata->LinkOffsets.PrevEnd + Metadata->LinkOffsets.NextStart + Metadata->LinkOffsets.NextEnd,
- File->FileSize - (Metadata->LinkOffsets.PrevStart + Metadata->LinkOffsets.PrevEnd + Metadata->LinkOffsets.NextStart + Metadata->LinkOffsets.NextEnd),
- 1,
- File->Handle);
- fclose(File->Handle);
- Metadata->LinkOffsets.PrevEnd = 0;
- Metadata->LinkOffsets.NextEnd = 0;
- FreeBuffer(&File->Buffer);
- return RC_SUCCESS;
- }
- else { return RC_ERROR_FILE; }
-}
-
-int
-LinkNeighbours(index *Index, neighbourhood *N, char *BaseFilename, int LinkType)
-{
- if(N->PrevIndex == -1 && N->NextIndex == -1)
- {
- buffer LonePlayerPagePath;
- ClaimBuffer(&LonePlayerPagePath, "LonePlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
- ConstructDirectoryPath(&LonePlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->This.BaseFilename);
- CopyStringToBuffer(&LonePlayerPagePath, "/index.html");
-
- file_buffer LonePlayerPage;
- CopyStringNoFormat(LonePlayerPage.Path, sizeof(LonePlayerPage.Path), LonePlayerPagePath.Location);
-
- DeleteNeighbourLinks(&LonePlayerPage, &N->This);
- DeclaimBuffer(&LonePlayerPagePath);
+ N->PreLinkPrevOffsetTotal = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd;
}
else
{
+ Entry = &N->Next;
+ EntryIndex = N->NextIndex;
+
+ N->PreLinkNextOffsetTotal = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd;
+ }
+
+ file_buffer HTML;
+ if(ReadPlayerPageIntoBuffer(&HTML, Entry) == RC_SUCCESS)
+ {
+ if(!(HTML.Handle = fopen(HTML.Path, "w"))) { FreeBuffer(&HTML.Buffer); return RC_ERROR_FILE; };
+
+ fwrite(HTML.Buffer.Location, Entry->LinkOffsets.PrevStart, 1, HTML.Handle);
+ fwrite(HTML.Buffer.Location + Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd, Entry->LinkOffsets.NextStart, 1, HTML.Handle);
+ fwrite(HTML.Buffer.Location + Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd + Entry->LinkOffsets.NextStart + Entry->LinkOffsets.NextEnd,
+ HTML.FileSize - (Entry->LinkOffsets.PrevStart + Entry->LinkOffsets.PrevEnd + Entry->LinkOffsets.NextStart + Entry->LinkOffsets.NextEnd),
+ 1,
+ HTML.Handle);
+ fclose(HTML.Handle);
+ Entry->LinkOffsets.PrevEnd = 0;
+ Entry->LinkOffsets.NextEnd = 0;
if(N->PrevIndex >= 0)
{
- buffer PreviousPlayerPagePath;
- ClaimBuffer(&PreviousPlayerPagePath, "PreviousPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
- ConstructDirectoryPath(&PreviousPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->Prev.BaseFilename);
- CopyStringToBuffer(&PreviousPlayerPagePath, "/index.html");
-
- file_buffer PreviousPlayerPage;
- CopyStringNoFormat(PreviousPlayerPage.Path, sizeof(PreviousPlayerPage.Path), PreviousPlayerPagePath.Location);
-
- switch(LinkType)
- {
- case LINK_EXCLUDE:
- {
- buffer ThisPlayerPagePath;
- ClaimBuffer(&ThisPlayerPagePath, "ThisPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
- ConstructDirectoryPath(&ThisPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->This.BaseFilename);
- CopyStringToBuffer(&ThisPlayerPagePath, "/index.html");
-
- file_buffer ThisPlayerPage;
- CopyStringNoFormat(ThisPlayerPage.Path, sizeof(ThisPlayerPage.Path), ThisPlayerPagePath.Location);
-
- InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Prev, LINK_PREV, Index->Header.ProjectName, N->NextIndex == -1 ? TRUE : FALSE);
-
- DeclaimBuffer(&ThisPlayerPagePath);
- }
- case LINK_INCLUDE:
- {
- InsertNeighbourLink(&PreviousPlayerPage, &N->Prev, &N->This, LINK_NEXT, Index->Header.ProjectName, N->PrevIsFirst);
- *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->PrevIndex) = N->Prev;
- }
- }
-
- DeclaimBuffer(&PreviousPlayerPagePath);
+ N->PrevOffsetModifier = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd
+ - N->PreLinkPrevOffsetTotal;
}
-
- if(N->NextIndex >= 0)
+ else
{
- buffer NextPlayerPagePath;
- ClaimBuffer(&NextPlayerPagePath, "NextPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
- ConstructDirectoryPath(&NextPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->Next.BaseFilename);
- CopyStringToBuffer(&NextPlayerPagePath, "/index.html");
-
- file_buffer NextPlayerPage;
- CopyStringNoFormat(NextPlayerPage.Path, sizeof(NextPlayerPage.Path), NextPlayerPagePath.Location);
-
- switch(LinkType)
- {
- case LINK_EXCLUDE:
- {
- buffer ThisPlayerPagePath;
- ClaimBuffer(&ThisPlayerPagePath, "ThisPlayerPagePath", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
- ConstructDirectoryPath(&ThisPlayerPagePath, PAGE_PLAYER, Config.PlayerLocation, N->This.BaseFilename);
- CopyStringToBuffer(&ThisPlayerPagePath, "/index.html");
-
- file_buffer ThisPlayerPage;
- CopyStringNoFormat(ThisPlayerPage.Path, sizeof(ThisPlayerPage.Path), ThisPlayerPagePath.Location);
-
- InsertNeighbourLink(&ThisPlayerPage, &N->This, &N->Next, LINK_NEXT, Index->Header.ProjectName, N->PrevIndex == -1 ? TRUE : FALSE);
-
- DeclaimBuffer(&ThisPlayerPagePath);
- }
- case LINK_INCLUDE:
- {
- InsertNeighbourLink(&NextPlayerPage, &N->Next, &N->This, LINK_PREV, Index->Header.ProjectName, N->NextIsFinal);
- *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->NextIndex) = N->Next;
- }
- }
-
- DeclaimBuffer(&NextPlayerPagePath);
+ N->NextOffsetModifier = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd
+ - N->PreLinkNextOffsetTotal;
}
+ FreeBuffer(&HTML.Buffer);
+ SnipeEntryIntoMetadataBuffer(Entry, EntryIndex);
}
+
return RC_SUCCESS;
}
void
-DeleteIndexPageFromFilesystem() // NOTE(matt): Do we need to handle relocating, like the PlayerPage function?
+LinkToNewEntry(neighbourhood *N)
{
- buffer IndexDirectory;
- ClaimBuffer(&IndexDirectory, "IndexDirectory", 1024);
- ConstructDirectoryPath(&IndexDirectory, PAGE_INDEX, Config.IndexLocation, "");
- char IndexPagePath[1024];
- CopyString(IndexPagePath, sizeof(IndexPagePath), "%s/index.html", IndexDirectory.Location);
- remove(IndexPagePath);
- remove(IndexDirectory.Location);
- DeclaimBuffer(&IndexDirectory);
+ N->PreLinkThisOffsetTotal = N->This.LinkOffsets.PrevEnd
+ + N->This.LinkOffsets.NextStart
+ + N->This.LinkOffsets.NextEnd;
+
+ if(N->PrevIndex >= 0)
+ {
+ N->PreLinkPrevOffsetTotal = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd;
+
+ InsertNeighbourLink(&N->Prev, N->PrevIndex, &N->This, LINK_FORWARDS, N->FormerIsFirst);
+
+ N->PrevOffsetModifier = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd
+ - N->PreLinkPrevOffsetTotal;
+ }
+
+ if(N->NextIndex >= 0)
+ {
+ N->PreLinkNextOffsetTotal = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd;
+
+ InsertNeighbourLink(&N->Next, N->NextIndex, &N->This, LINK_BACKWARDS, N->LatterIsFinal);
+
+ N->NextOffsetModifier = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd
+ - N->PreLinkNextOffsetTotal;
+ }
+}
+
+void
+MarkNextAsFirst(neighbourhood *N)
+{
+ file_buffer HTML;
+ ReadPlayerPageIntoBuffer(&HTML, &N->Next);
+
+ buffer Link;
+ ClaimBuffer(&Link, "Link", Kilobytes(4));
+
+ HTML.Handle = fopen(HTML.Path, "w");
+
+ fwrite(HTML.Buffer.Location, N->Next.LinkOffsets.PrevStart, 1, HTML.Handle);
+
+ CopyStringToBuffer(&Link,
+ " \n", DB.EntriesHeader.ProjectName);
+
+ fwrite(Link.Location, (Link.Ptr - Link.Location), 1, HTML.Handle);
+
+ fwrite(HTML.Buffer.Location + N->Next.LinkOffsets.PrevStart + N->Next.LinkOffsets.PrevEnd,
+ HTML.FileSize - (N->Next.LinkOffsets.PrevStart + N->Next.LinkOffsets.PrevEnd),
+ 1,
+ HTML.Handle);
+
+ N->Next.LinkOffsets.PrevEnd = Link.Ptr - Link.Location;
+
+ DeclaimBuffer(&Link);
+ fclose(HTML.Handle);
+ FreeBuffer(&HTML.Buffer);
+
+ SnipeEntryIntoMetadataBuffer(&N->Next, N->NextIndex);
+}
+
+void
+MarkPrevAsFinal(neighbourhood *N)
+{
+ file_buffer File;
+ ReadPlayerPageIntoBuffer(&File, &N->Prev);
+
+ File.Handle = fopen(File.Path, "w");
+ buffer Link;
+ ClaimBuffer(&Link, "Link", Kilobytes(4));
+
+
+ fwrite(File.Buffer.Location, N->Prev.LinkOffsets.PrevStart + N->Prev.LinkOffsets.PrevEnd + N->Prev.LinkOffsets.NextStart, 1, File.Handle);
+
+ CopyStringToBuffer(&Link,
+ " •
You have arrived at the (current) end of %s
•
\n", DB.EntriesHeader.ProjectName);
+
+ fwrite(Link.Location, (Link.Ptr - Link.Location), 1, File.Handle);
+
+ fwrite(File.Buffer.Location + N->Prev.LinkOffsets.PrevStart + N->Prev.LinkOffsets.PrevEnd + N->Prev.LinkOffsets.NextStart + N->Prev.LinkOffsets.NextEnd,
+ File.FileSize - (N->Prev.LinkOffsets.PrevStart + N->Prev.LinkOffsets.PrevEnd + N->Prev.LinkOffsets.NextStart + N->Prev.LinkOffsets.NextEnd),
+ 1,
+ File.Handle);
+
+ N->Prev.LinkOffsets.NextEnd = Link.Ptr - Link.Location;
+
+ DeclaimBuffer(&Link);
+ fclose(File.Handle);
+ FreeBuffer(&File.Buffer);
+
+ SnipeEntryIntoMetadataBuffer(&N->Prev, N->PrevIndex);
+}
+
+void
+LinkOverDeletedEntry(neighbourhood *N)
+{
+ if(DB.EntriesHeader.Count == 1)
+ {
+ DeleteNeighbourLinks(N);
+ }
+ else
+ {
+ if(N->DeletedEntryWasFirst)
+ {
+ N->PreLinkNextOffsetTotal = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd;
+
+ MarkNextAsFirst(N);
+
+ N->NextOffsetModifier = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd
+ - N->PreLinkNextOffsetTotal;
+ return;
+ }
+ else if(N->DeletedEntryWasFinal)
+ {
+ N->PreLinkPrevOffsetTotal = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd;
+
+ MarkPrevAsFinal(N);
+
+ N->PrevOffsetModifier = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd
+ - N->PreLinkPrevOffsetTotal;
+ return;
+ }
+ else
+ {
+ // Assert(N->PrevIndex >= 0 && N->NextIndex >= 0)
+ N->PreLinkPrevOffsetTotal = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd;
+
+
+ N->PreLinkNextOffsetTotal = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd;
+ }
+
+ InsertNeighbourLink(&N->Prev, N->PrevIndex, &N->Next, LINK_FORWARDS, N->FormerIsFirst);
+ InsertNeighbourLink(&N->Next, N->NextIndex, &N->Prev, LINK_BACKWARDS, N->LatterIsFinal);
+
+ N->PrevOffsetModifier = N->Prev.LinkOffsets.PrevEnd
+ + N->Prev.LinkOffsets.NextStart
+ + N->Prev.LinkOffsets.NextEnd
+ - N->PreLinkPrevOffsetTotal;
+
+ N->NextOffsetModifier = N->Next.LinkOffsets.PrevEnd
+ + N->Next.LinkOffsets.NextStart
+ + N->Next.LinkOffsets.NextEnd
+ - N->PreLinkNextOffsetTotal;
+ }
+}
+
+void
+LinkNeighbours(neighbourhood *N, enum8(link_types) LinkType)
+{
+ if(LinkType == LINK_INCLUDE)
+ {
+ LinkToNewEntry(N);
+ }
+ else
+ {
+ LinkOverDeletedEntry(N);
+ }
+}
+
+void
+DeleteSearchPageFromFilesystem() // NOTE(matt): Do we need to handle relocating, like the PlayerPage function?
+{
+ buffer SearchDirectory;
+ ClaimBuffer(&SearchDirectory, "SearchDirectory", MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + 10);
+ ConstructDirectoryPath(&SearchDirectory, PAGE_SEARCH, Config.SearchLocation, "");
+ char SearchPagePath[1024];
+ CopyString(SearchPagePath, sizeof(SearchPagePath), "%s/index.html", SearchDirectory.Location);
+ remove(SearchPagePath);
+ remove(SearchDirectory.Location);
+ DeclaimBuffer(&SearchDirectory);
}
int
@@ -5400,7 +7338,7 @@ DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Re
{
// NOTE(matt): Once we have the notion of an output filename format, we'll need to use that here
buffer OutputDirectoryPath;
- ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024);
+ ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
ConstructDirectoryPath(&OutputDirectoryPath, PAGE_PLAYER, PlayerLocation, BaseFilename);
DIR *PlayerDir;
@@ -5419,14 +7357,14 @@ DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Re
if((remove(OutputDirectoryPath.Location) == -1))
{
LogError(LOG_NOTICE, "Mostly deleted %s. Unable to remove directory %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno));
- fprintf(stderr, "\e[1;30mMostly deleted\e[0m %s. \e[1;31mUnable to remove directory\e[0m %s: %s", BaseFilename, OutputDirectoryPath.Location, strerror(errno));
+ fprintf(stderr, "%sMostly deleted%s %s. %sUnable to remove directory%s %s: %s", ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END], BaseFilename, ColourStrings[CS_ERROR], ColourStrings[CS_END], OutputDirectoryPath.Location, strerror(errno));
}
else
{
if(!Relocating)
{
LogError(LOG_INFORMATIONAL, "Deleted %s", BaseFilename);
- fprintf(stderr, "\e[1;30mDeleted\e[0m %s\n", BaseFilename);
+ fprintf(stderr, "%sDeleted%s %s\n", ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END], BaseFilename);
}
}
@@ -5436,56 +7374,51 @@ DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Re
}
int
-DeleteFromIndex(index *Index, neighbourhood *N, char *BaseFilename)
+DeleteFromDB(neighbourhood *N, char *BaseFilename)
{
// TODO(matt): LogError()
- Index->Header = *(index_header *)Index->Metadata.Buffer.Location;
- Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header);
+ DB.Header = *(db_header *)DB.Metadata.Buffer.Location;
+ DB.EntriesHeader = *(db_header_entries *)(DB.Metadata.Buffer.Location + sizeof(DB.Header));
- index_metadata *Entry = { 0 };
- int EntryIndex = BinarySearchForMetadataEntry(Index, &Entry, BaseFilename);
+ db_entry *Entry = { 0 };
+ int EntryIndex = BinarySearchForMetadataEntry(&Entry, BaseFilename);
if(Entry)
{
- int DeleteFileFrom = AccumulateIndexEntryInsertionOffset(Index, EntryIndex);
+ int DeleteFileFrom = AccumulateDBEntryInsertionOffset(EntryIndex);
int DeleteFileTo = DeleteFileFrom + Entry->Size;
- bool ThisIsPrev = FALSE;
N->ThisIndex = EntryIndex;
- GetNeighbourhood(Index, N, EDIT_DELETION, &ThisIsPrev);
- --Index->Header.EntryCount;
+ GetNeighbourhood(N, EDIT_DELETION);
+ --DB.EntriesHeader.Count;
- if(Index->Header.EntryCount == 0)
+ if(DB.EntriesHeader.Count == 0)
{
- DeleteIndexPageFromFilesystem();
+ // TODO(matt): Handle this differently, allowing 0 entries but > 0 assets?
+ DeleteSearchPageFromFilesystem();
- remove(Index->Metadata.Path);
- Index->Metadata.FileSize = 0;
- FreeBuffer(&Index->Metadata.Buffer);
+ remove(DB.Metadata.Path);
+ DB.Metadata.FileSize = 0;
+ FreeBuffer(&DB.Metadata.Buffer);
- remove(Index->File.Path);
- Index->File.FileSize = 0;
- FreeBuffer(&Index->File.Buffer);
+ remove(DB.File.Path);
+ DB.File.FileSize = 0;
+ FreeBuffer(&DB.File.Buffer);
}
else
{
- if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; }
- if(!(Index->File.Handle = fopen(Index->File.Path, "w"))) { FreeBuffer(&Index->File.Buffer); return RC_ERROR_FILE; }
+ if(!(DB.Metadata.Handle = fopen(DB.Metadata.Path, "w"))) { FreeBuffer(&DB.Metadata.Buffer); return RC_ERROR_FILE; }
+ if(!(DB.File.Handle = fopen(DB.File.Path, "w"))) { FreeBuffer(&DB.File.Buffer); return RC_ERROR_FILE; }
- fwrite(&Index->Header, sizeof(Index->Header), 1, Index->Metadata.Handle);
- fwrite(Index->Metadata.Buffer.Location + sizeof(index_header), sizeof(index_metadata) * EntryIndex, 1, Index->Metadata.Handle);
- fwrite(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * (EntryIndex + 1),
- Index->Metadata.FileSize - sizeof(index_header) - sizeof(index_metadata) * (EntryIndex + 1),
- 1, Index->Metadata.Handle);
- fclose(Index->Metadata.Handle);
+ fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.Handle);
+ fwrite(&DB.EntriesHeader, sizeof(DB.EntriesHeader), 1, DB.Metadata.Handle);
+ fwrite(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader), sizeof(DB.Entry) * EntryIndex, 1, DB.Metadata.Handle);
+ fwrite(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * (EntryIndex + 1),
+ DB.Metadata.FileSize - sizeof(DB.Header) - sizeof(DB.EntriesHeader) - sizeof(DB.Entry) * (EntryIndex + 1),
+ 1, DB.Metadata.Handle);
+ CycleFile(&DB.Metadata);
- FreeBuffer(&Index->Metadata.Buffer);
- ReadFileIntoBuffer(&Index->Metadata, 0);
-
- fwrite(Index->File.Buffer.Location, DeleteFileFrom, 1, Index->File.Handle);
- fwrite(Index->File.Buffer.Location + DeleteFileTo, Index->File.FileSize - DeleteFileTo, 1, Index->File.Handle);
- fclose(Index->File.Handle);
-
- FreeBuffer(&Index->File.Buffer);
- ReadFileIntoBuffer(&Index->File, 0);
+ fwrite(DB.File.Buffer.Location, DeleteFileFrom, 1, DB.File.Handle);
+ fwrite(DB.File.Buffer.Location + DeleteFileTo, DB.File.FileSize - DeleteFileTo, 1, DB.File.Handle);
+ CycleFile(&DB.File);
}
}
@@ -5493,185 +7426,193 @@ DeleteFromIndex(index *Index, neighbourhood *N, char *BaseFilename)
}
int
-IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy malloc's CollationBuffers->Index
+SearchToBuffer(buffers *CollationBuffers) // NOTE(matt): This guy malloc's CollationBuffers->Search
{
- if(Index->Metadata.FileSize > 0)
+ if(DB.Metadata.Buffer.Location)
{
- Index->Header = *(index_header*)Index->Metadata.Buffer.Location;
-
- int ProjectIndex;
- for(ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
+ DB.Header = *(db_header *)DB.Metadata.Buffer.Location;
+ DB.EntriesHeader = *(db_header_entries *)(DB.Metadata.Buffer.Location + sizeof(DB.Header));
+ if(DB.EntriesHeader.Count > 0)
{
- if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID, Config.ProjectID))
+ RewindBuffer(&CollationBuffers->IncludesSearch);
+
+ buffer URL;
+ ConstructResolvedAssetURL(&URL, ASSET_CSS_CINERA, PAGE_SEARCH);
+ CopyStringToBuffer(&CollationBuffers->IncludesSearch,
+ " \n"
+ " \n"
+ "\n"
+ " IncludesSearch, ASSET_CSS_CINERA, PAGE_SEARCH);
+
+ ConstructResolvedAssetURL(&URL, ASSET_CSS_THEME, PAGE_SEARCH);
+ CopyStringToBuffer(&CollationBuffers->IncludesSearch,
+ "\">\n"
+ " IncludesSearch, ASSET_CSS_THEME, PAGE_SEARCH);
+
+ ConstructResolvedAssetURL(&URL, ASSET_CSS_TOPICS, PAGE_SEARCH);
+ CopyStringToBuffer(&CollationBuffers->IncludesSearch,
+ "\">\n"
+ " IncludesSearch, ASSET_CSS_TOPICS, PAGE_SEARCH);
+
+ CopyStringToBuffer(&CollationBuffers->IncludesSearch,
+ "\">\n");
+
+ int ProjectIndex;
+ for(ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
{
- break;
- }
- }
-
- char *Theme = StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID;
- int Allowance = StringLength(Theme) * 2 + StringLength(Config.ProjectID) + StringLength(Config.BaseURL) + StringLength(Config.PlayerLocation);
- char queryContainer[678 + Allowance]; // NOTE(matt): Update the size if changing the string
- CopyString(queryContainer, sizeof(queryContainer),
- "\n"
- "
Query: \n"
- "
\n"
- "
\n"
- " Found: 0 episodes, 0 markers, 0h 0m 0s total.
\n"
- "
\n"
- "\n"
- " \n"
- "
Sort: Old to New ⏶
\n"
- "
\n",
- Theme,
- Config.Mode & MODE_SINGLETAB ? 1 : 0,
- Theme,
- Config.ProjectID,
- Config.BaseURL,
- Config.PlayerLocation);
-
- buffer URLPrefix;
- ClaimBuffer(&URLPrefix, "URLPrefix", 1024);
- ConstructURLPrefix(&URLPrefix, INCLUDE_JS, PAGE_INDEX);
- char Script[107 + StringLength(URLPrefix.Location)]; // NOTE(matt): Update the size if changing the string
- CopyString(Script, sizeof(Script),
- "
\n"
- "
\n"
- " \n",
- URLPrefix.Location);
- DeclaimBuffer(&URLPrefix);
-
- buffer PlayerURL;
- ClaimBuffer(&PlayerURL, "PlayerURL", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH);
- ConstructPlayerURL(&PlayerURL, "");
- char *ProjectUnit = 0;
- if(StringsDiffer(ProjectInfo[ProjectIndex].Unit, ""))
- {
- ProjectUnit = ProjectInfo[ProjectIndex].Unit;
- }
- char Number[16];
- index_metadata *This;
- char Text[(ProjectUnit ? StringLength(ProjectUnit) : 0) + sizeof(Number) + sizeof(This->Title) + 3];
-
- int EntryLength = StringLength(PlayerURL.Location) + sizeof(Text) + 82;
- CollationBuffers->Index.Size = StringLength(queryContainer) + (Index->Header.EntryCount * EntryLength) + StringLength(Script);
-
- if(!(CollationBuffers->Index.Location = malloc(CollationBuffers->Index.Size))) { return RC_ERROR_MEMORY; }
-
- CollationBuffers->Index.ID = "Index";
- CollationBuffers->Index.Ptr = CollationBuffers->Index.Location;
-
- CopyStringToBuffer(&CollationBuffers->Index, "%s", queryContainer);
-
- int ProjectIDLength = StringLength(Config.ProjectID);
- bool IndexRequired = FALSE;
-
- Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + sizeof(Index->Header);
- for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata))
- {
- This = (index_metadata *)Index->Metadata.Buffer.Ptr;
- if(This->Size > 0)
- {
- IndexRequired = TRUE;
- CopyString(Number, sizeof(Number), "%s", This->BaseFilename + ProjectIDLength);
- if(ProjectInfo[ProjectIndex].NumberingScheme == NS_LINEAR)
+ if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID, Config.ProjectID))
{
- for(int i = 0; Number[i]; ++i)
+ break;
+ }
+ }
+
+ char *Theme = StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID;
+ int Allowance = StringLength(Theme) * 2 + StringLength(Config.ProjectID) + StringLength(Config.BaseURL) + StringLength(Config.PlayerLocation);
+ char queryContainer[678 + Allowance]; // NOTE(matt): Update the size if changing the string
+ CopyString(queryContainer, sizeof(queryContainer),
+ "\n"
+ "
Query: \n"
+ "
\n"
+ "
\n"
+ " Found: 0 episodes, 0 markers, 0h 0m 0s total.
\n"
+ "
\n"
+ "\n"
+ " \n"
+ "
Sort: Old to New ⏶
\n"
+ "
\n",
+ Theme,
+ Config.Mode & MODE_SINGLETAB ? 1 : 0,
+ Theme,
+ Config.ProjectID,
+ Config.BaseURL,
+ Config.PlayerLocation);
+
+ ConstructResolvedAssetURL(&URL, ASSET_JS_SEARCH, PAGE_SEARCH);
+ buffer Script;
+ ClaimBuffer(&Script, "Script", (117 + URL.Ptr - URL.Location) * 2); // NOTE(matt): Update the size if changing the string
+ CopyStringToBuffer(&Script,
+ "
\n"
+ "
\n"
+ " ");
+
+ buffer PlayerURL;
+ ClaimBuffer(&PlayerURL, "PlayerURL", MAX_BASE_URL_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH);
+ ConstructPlayerURL(&PlayerURL, "");
+ char *ProjectUnit = 0;
+ if(StringsDiffer(ProjectInfo[ProjectIndex].Unit, ""))
+ {
+ ProjectUnit = ProjectInfo[ProjectIndex].Unit;
+ }
+ char Number[16];
+ db_entry *This;
+ char Text[(ProjectUnit ? StringLength(ProjectUnit) : 0) + sizeof(Number) + sizeof(This->Title) + 3];
+
+ int EntryLength = StringLength(PlayerURL.Location) + sizeof(Text) + 82;
+ CollationBuffers->Search.Size = StringLength(queryContainer) + (DB.EntriesHeader.Count * EntryLength) + Script.Ptr - Script.Location;
+
+ if(!(CollationBuffers->Search.Location = malloc(CollationBuffers->Search.Size))) { return RC_ERROR_MEMORY; }
+
+ CollationBuffers->Search.ID = "Search";
+ CollationBuffers->Search.Ptr = CollationBuffers->Search.Location;
+
+ CopyStringToBuffer(&CollationBuffers->Search, "%s", queryContainer);
+
+ int ProjectIDLength = StringLength(Config.ProjectID);
+ bool SearchRequired = FALSE;
+
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader);
+ for(int EntryIndex = 0; EntryIndex < DB.EntriesHeader.Count; ++EntryIndex, DB.Metadata.Buffer.Ptr += sizeof(DB.Entry))
+ {
+ This = (db_entry *)DB.Metadata.Buffer.Ptr;
+ if(This->Size > 0)
+ {
+ SearchRequired = TRUE;
+ CopyString(Number, sizeof(Number), "%s", This->BaseFilename + ProjectIDLength);
+ if(ProjectInfo[ProjectIndex].NumberingScheme == NS_LINEAR)
{
- if(Number[i] == '_')
+ for(int i = 0; Number[i]; ++i)
{
- Number[i] = '.';
+ if(Number[i] == '_')
+ {
+ Number[i] = '.';
+ }
}
}
- }
- ConstructPlayerURL(&PlayerURL, This->BaseFilename);
+ ConstructPlayerURL(&PlayerURL, This->BaseFilename);
- if(ProjectUnit)
- {
- CopyStringToBuffer(&CollationBuffers->Index,
- " \n"
- "
", PlayerURL.Location);
+ if(ProjectUnit)
+ {
+ CopyStringToBuffer(&CollationBuffers->Search,
+ " \n"
+ "
", PlayerURL.Location);
- CopyString(Text, sizeof(Text), "%s %s: %s",
- ProjectUnit, // TODO(matt): Do we need to special-case the various numbering schemes?
- Number,
- This->Title);
+ CopyString(Text, sizeof(Text), "%s %s: %s",
+ ProjectUnit, // TODO(matt): Do we need to special-case the various numbering schemes?
+ Number,
+ This->Title);
- CopyStringToBufferHTMLSafe(&CollationBuffers->Index, Text);
+ CopyStringToBufferHTMLSafe(&CollationBuffers->Search, Text);
- CopyStringToBuffer(&CollationBuffers->Index,
- " \n"
- "
\n");
- }
- else
- {
- CopyStringToBuffer(&CollationBuffers->Index,
- " \n");
+ }
+ else
+ {
+ CopyStringToBuffer(&CollationBuffers->Search,
+ " \n");
+ CopyStringToBufferHTMLSafe(&CollationBuffers->Search, This->Title);
+ CopyStringToBuffer(&CollationBuffers->Search,
+ " \n"
+ "
\n");
+ }
}
}
- }
- DeclaimBuffer(&PlayerURL);
+ OffsetLandmarks(&CollationBuffers->Search, ASSET_JS_SEARCH, PAGE_SEARCH);
+ CopyBuffer(&CollationBuffers->Search, &Script);
- CopyStringToBuffer(&CollationBuffers->Index, "%s", Script);
+ DeclaimBuffer(&PlayerURL);
+ DeclaimBuffer(&Script);
+ DeclaimBuffer(&URL);
- if(!IndexRequired) { return RC_NOOP; }
- else { return RC_SUCCESS; }
- }
- else
- {
- return RC_ERROR_FILE;
- }
-}
-
-char *
-StripTrailingSlash(char *String) // NOTE(matt): For absolute paths
-{
- int Length = StringLength(String);
- while(Length > 0 && String[Length - 1] == '/')
- {
- String[Length - 1] = '\0';
- --Length;
- }
- return String;
-}
-
-char *
-StripSurroundingSlashes(char *String) // NOTE(matt): For relative paths
-{
- int Length = StringLength(String);
- if(Length > 0)
- {
- while((String[0]) == '/')
- {
- ++String;
- --Length;
- }
- while(String[Length - 1] == '/')
- {
- String[Length - 1] = '\0';
- --Length;
+ if(!SearchRequired) { return RC_NOOP; }
+ else { return RC_SUCCESS; }
}
}
- return String;
+ return RC_NOOP;
}
int
-GeneratePlayerPage(index *Index, neighbourhood *N, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename)
+GeneratePlayerPage(neighbourhood *N, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename, bool Reinserting)
{
buffer OutputDirectoryPath;
- ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024);
+ ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
ConstructDirectoryPath(&OutputDirectoryPath, PAGE_PLAYER, Config.PlayerLocation, BaseFilename);
DIR *OutputDirectoryHandle;
@@ -5690,38 +7631,36 @@ GeneratePlayerPage(index *Index, neighbourhood *N, buffers *CollationBuffers, te
CopyString(PlayerPagePath, sizeof(PlayerPagePath), "%s/index.html", OutputDirectoryPath.Location);
DeclaimBuffer(&OutputDirectoryPath);
- bool IndexInTemplate = FALSE;
+ bool SearchInTemplate = FALSE;
for(int TagIndex = 0; TagIndex < PlayerTemplate->Metadata.TagCount; ++TagIndex)
{
- if(PlayerTemplate->Metadata.Tag[TagIndex].TagCode == TAG_INDEX)
+ if(PlayerTemplate->Metadata.Tag[TagIndex].TagCode == TAG_SEARCH)
{
- IndexInTemplate = TRUE;
- IndexToBuffer(Index, CollationBuffers);
+ SearchInTemplate = TRUE;
+ SearchToBuffer(CollationBuffers);
break;
}
}
BuffersToHTML(CollationBuffers, PlayerTemplate, PlayerPagePath, PAGE_PLAYER, &N->This.LinkOffsets.PrevStart);
+ // NOTE(matt): A previous InsertNeighbourLink() call will have done SnipeEntryIntoMetadataBuffer(), but we must do it here now
+ // that PrevStart has been adjusted by BuffersToHTML()
+ SnipeEntryIntoMetadataBuffer(&N->This, N->ThisIndex);
+ UpdateLandmarksForNeighbourhood(N, Reinserting ? EDIT_REINSERTION : EDIT_ADDITION);
- *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * N->ThisIndex) = N->This;
-
- Index->Metadata.Handle = fopen(Index->Metadata.Path, "w");
- fwrite(Index->Metadata.Buffer.Location, Index->Metadata.Buffer.Size, 1, Index->Metadata.Handle);
- fclose(Index->Metadata.Handle);
-
- if(IndexInTemplate)
+ if(SearchInTemplate)
{
- FreeBuffer(&CollationBuffers->Index);
+ FreeBuffer(&CollationBuffers->Search);
}
return RC_SUCCESS;
}
int
-GenerateIndexPage(index *Index, buffers *CollationBuffers, template *IndexTemplate)
+GenerateSearchPage(buffers *CollationBuffers, template *SearchTemplate)
{
buffer OutputDirectoryPath;
- ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024);
- ConstructDirectoryPath(&OutputDirectoryPath, PAGE_INDEX, Config.IndexLocation, 0);
+ ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + 10);
+ ConstructDirectoryPath(&OutputDirectoryPath, PAGE_SEARCH, Config.SearchLocation, 0);
DIR *OutputDirectoryHandle;
if(!(OutputDirectoryHandle = opendir(OutputDirectoryPath.Location))) // TODO(matt): open()
@@ -5735,55 +7674,56 @@ GenerateIndexPage(index *Index, buffers *CollationBuffers, template *IndexTempla
}
closedir(OutputDirectoryHandle);
- char IndexPagePath[1024];
- CopyString(IndexPagePath, sizeof(IndexPagePath), "%s/index.html", OutputDirectoryPath.Location);
+ char SearchPagePath[1024];
+ CopyString(SearchPagePath, sizeof(SearchPagePath), "%s/index.html", OutputDirectoryPath.Location);
DeclaimBuffer(&OutputDirectoryPath);
- switch(IndexToBuffer(Index, CollationBuffers))
+ switch(SearchToBuffer(CollationBuffers))
{
case RC_SUCCESS:
{
- BuffersToHTML(CollationBuffers, IndexTemplate, IndexPagePath, PAGE_INDEX, 0);
+ BuffersToHTML(CollationBuffers, SearchTemplate, SearchPagePath, PAGE_SEARCH, 0);
+ UpdateLandmarksForSearch();
break;
}
case RC_NOOP:
{
- DeleteIndexPageFromFilesystem();
+ DeleteSearchPageFromFilesystem();
+ DeleteLandmarksForSearch();
break;
}
}
- FreeBuffer(&CollationBuffers->Index);
+ FreeBuffer(&CollationBuffers->Search);
return RC_SUCCESS;
}
int
-DeleteEntry(index *Index, neighbourhood *Neighbourhood, char *BaseFilename)
+DeleteEntry(neighbourhood *Neighbourhood, char *BaseFilename)
{
- if(DeleteFromIndex(Index, Neighbourhood, BaseFilename) == RC_SUCCESS)
+ if(DeleteFromDB(Neighbourhood, BaseFilename) == RC_SUCCESS)
{
- if(Neighbourhood->This.Size > 0)
- {
- LinkNeighbours(Index, Neighbourhood, BaseFilename, LINK_EXCLUDE);
- }
+ LinkNeighbours(Neighbourhood, LINK_EXCLUDE);
DeletePlayerPageFromFilesystem(BaseFilename, Config.PlayerLocation, FALSE);
+ UpdateLandmarksForNeighbourhood(Neighbourhood, EDIT_DELETION);
return RC_SUCCESS;
}
return RC_NOOP;
}
int
-InsertEntry(index *Index, neighbourhood *Neighbourhood, buffers *CollationBuffers, template *PlayerTemplate, template *BespokeTemplate, char *BaseFilename, bool RecheckingPrivacy)
+InsertEntry(neighbourhood *Neighbourhood, buffers *CollationBuffers, template *PlayerTemplate, template *BespokeTemplate, char *BaseFilename, bool RecheckingPrivacy)
{
- if(InsertIntoIndex(Index, Neighbourhood, CollationBuffers, &BespokeTemplate, BaseFilename, RecheckingPrivacy) == RC_SUCCESS)
+ bool Reinserting = FALSE;
+ if(InsertIntoDB(Neighbourhood, CollationBuffers, &BespokeTemplate, BaseFilename, RecheckingPrivacy, &Reinserting) == RC_SUCCESS)
{
- LinkNeighbours(Index, Neighbourhood, BaseFilename, LINK_INCLUDE);
+ LinkNeighbours(Neighbourhood, LINK_INCLUDE);
if(StringsDiffer(BespokeTemplate->Metadata.Filename, ""))
{
- GeneratePlayerPage(Index, Neighbourhood, CollationBuffers, BespokeTemplate, BaseFilename);
+ GeneratePlayerPage(Neighbourhood, CollationBuffers, BespokeTemplate, BaseFilename, Reinserting);
DeclaimTemplate(BespokeTemplate);
}
else
{
- GeneratePlayerPage(Index, Neighbourhood, CollationBuffers, PlayerTemplate, BaseFilename);
+ GeneratePlayerPage(Neighbourhood, CollationBuffers, PlayerTemplate, BaseFilename, Reinserting);
}
return RC_SUCCESS;
}
@@ -5791,18 +7731,19 @@ InsertEntry(index *Index, neighbourhood *Neighbourhood, buffers *CollationBuffer
}
int
-RecheckPrivacy(index *Index, buffers *CollationBuffers, template *IndexTemplate, template *PlayerTemplate, template *BespokeTemplate)
+RecheckPrivacy(buffers *CollationBuffers, template *SearchTemplate, template *PlayerTemplate, template *BespokeTemplate)
{
- if(Index->Metadata.FileSize > 0)
+ if(DB.Metadata.FileSize > 0)
{
- Index->Header = *(index_header*)Index->Metadata.Buffer.Location;
- index_metadata Entry = { };
+ DB.Header = *(db_header *)DB.Metadata.Buffer.Location;
+ DB.EntriesHeader = *(db_header_entries *)(DB.Metadata.Buffer.Location + sizeof(DB.Header));
+ db_entry Entry = { };
int PrivateEntryIndex = 0;
- index_metadata PrivateEntries[Index->Header.EntryCount];
+ db_entry PrivateEntries[DB.EntriesHeader.Count];
bool Inserted = FALSE;
- for(int IndexEntry = 0; IndexEntry < Index->Header.EntryCount; ++IndexEntry)
+ for(int IndexEntry = 0; IndexEntry < DB.EntriesHeader.Count; ++IndexEntry)
{
- Entry = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * IndexEntry);
+ Entry = *(db_entry *)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * IndexEntry);
if(Entry.Size == 0)
{
PrivateEntries[PrivateEntryIndex] = Entry;
@@ -5813,15 +7754,15 @@ RecheckPrivacy(index *Index, buffers *CollationBuffers, template *IndexTemplate,
for(int i = 0; i < PrivateEntryIndex; ++i)
{
neighbourhood Neighbourhood = { };
- Neighbourhood.PrevIndex = -1;
- Neighbourhood.ThisIndex = -1;
- Neighbourhood.NextIndex = -1;
- Inserted = (InsertEntry(Index, &Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, PrivateEntries[i].BaseFilename, TRUE) == RC_SUCCESS);
+ InitNeighbourhood(&Neighbourhood);
+ ResetAssetLandmarks();
+ Inserted = (InsertEntry(&Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, PrivateEntries[i].BaseFilename, TRUE) == RC_SUCCESS);
}
if(Inserted)
{
- GenerateIndexPage(Index, CollationBuffers, IndexTemplate);
+ GenerateSearchPage(CollationBuffers, SearchTemplate);
+ DeleteStaleAssets();
}
LastPrivacyCheck = time(0);
@@ -5829,74 +7770,275 @@ RecheckPrivacy(index *Index, buffers *CollationBuffers, template *IndexTemplate,
return RC_SUCCESS;
}
-int
-MonitorDirectory(index *Index, buffers *CollationBuffers, template *IndexTemplate, template *PlayerTemplate, template *BespokeTemplate, int inotifyInstance, int WatchDescriptor)
+#define DEBUG_LANDMARKS 0
+#if DEBUG_LANDMARKS
+void
+VerifyLandmarks(void)
{
+ printf("\n"
+ "VerifyLandmarks()\n");
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location;
+ DB.Header = *(db_header *)DB.Metadata.Buffer.Ptr;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Header);
+ DB.EntriesHeader = *(db_header_entries *)DB.Metadata.Buffer.Ptr;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.EntriesHeader);
+ char *FirstEntry = DB.Metadata.Buffer.Ptr;
-#if DEBUG_MEM
- FILE *MemLog = fopen("/home/matt/cinera_mem", "a+");
- fprintf(MemLog, "\nCalled MonitorDirectory()\n");
- fclose(MemLog);
-#endif
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Entry) * DB.EntriesHeader.Count;
+ DB.AssetsHeader = *(db_header_assets *)DB.Metadata.Buffer.Ptr;
+ DB.Metadata.Buffer.Ptr += sizeof(DB.AssetsHeader);
+ char *FirstAsset = DB.Metadata.Buffer.Ptr;
- buffer Events;
- if(ClaimBuffer(&Events, "inotify Events", Kilobytes(4)) == RC_ARENA_FULL) { return RC_ARENA_FULL; };
+ buffer OutputDirectoryPath;
+ ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1 + 10);
- struct inotify_event *Event;
- int BytesRead = read(inotifyInstance, Events.Location, Events.Size); // TODO(matt): Handle error EINVAL
- if(inotifyInstance < 0) { perror("MonitorDirectory()"); }
+ bool UniversalSuccess = TRUE;
- struct inotify_event *FinalFileEvents[1024];
- int FinalFileEventsCount = 0;
-
- // TODO(matt): Test this with longer update intervals, and combinations of events...
- for(Events.Ptr = Events.Location;
- Events.Ptr < Events.Location + BytesRead && Events.Ptr - Events.Location < Events.Size;
- Events.Ptr += sizeof(struct inotify_event) + Event->len)
+ // Search
{
- Event = (struct inotify_event *)Events.Ptr;
- char *Ptr = Event->name;
- Ptr += (StringLength(Event->name) - StringLength(".hmml"));
- if(!(StringsDiffer(Ptr, ".hmml")))
+ file_buffer HTML;
+ ReadSearchPageIntoBuffer(&HTML);
+ char *Cursor = FirstAsset;
+ for(int j = 0; j < DB.AssetsHeader.Count; ++j)
{
- *Ptr = '\0';
- bool FoundEvent = FALSE;
- int FinalFileEventsIndex;
- for(FinalFileEventsIndex = 0; FinalFileEventsIndex < FinalFileEventsCount; ++FinalFileEventsIndex)
+ DB.Asset = *(db_asset *)Cursor;
+ Cursor += sizeof(DB.Asset);
+ landmark_range Target = BinarySearchForMetadataLandmark(Cursor, PAGE_TYPE_SEARCH, DB.Asset.LandmarkCount);
+ for(int k = 0; k < Target.Length; ++k)
{
- if(!StringsDiffer(FinalFileEvents[FinalFileEventsIndex]->name, Event->name))
+ DB.Landmark = *(db_landmark *)(Cursor + sizeof(db_landmark) * (Target.First + k));
+ bool Found = FALSE;
+ for(int l = 0; l < Assets.Count; ++l)
{
- FinalFileEvents[FinalFileEventsIndex] = Event;
- FoundEvent = TRUE;
+ // TODO(matt): StringToInt (base16)
+ char HashString[9];
+ sprintf(HashString, "%08x", Assets.Asset[l].Hash);
+
+ if(HTML.Buffer.Size >= DB.Landmark.Position + 8 && !StringsDifferT(HashString, HTML.Buffer.Location + DB.Landmark.Position, 0))
+ {
+ Found = TRUE;
+ break;
+ }
+ }
+ if(!Found)
+ {
+ printf("Failure!!!\n");
+ printf(" %s\n", HTML.Path);
+ printf(" %.*s [at byte %d] is not a known asset hash\n", 8, HTML.Buffer.Location + DB.Landmark.Position, DB.Landmark.Position);
+ UniversalSuccess = FALSE;
}
}
- if(!FoundEvent) { FinalFileEvents[FinalFileEventsIndex] = Event; ++FinalFileEventsCount; }
+ Cursor += sizeof(DB.Landmark) * DB.Asset.LandmarkCount;
}
+ FreeBuffer(&HTML.Buffer);
}
- bool Deleted = FALSE;
- bool Inserted = FALSE;
- for(int FinalFileEventsIndex = 0; FinalFileEventsIndex < FinalFileEventsCount; ++FinalFileEventsIndex)
+ for(int i = 0; i < DB.EntriesHeader.Count; ++i)
{
- neighbourhood Neighbourhood = { };
- Neighbourhood.PrevIndex = -1;
- Neighbourhood.ThisIndex = -1;
- Neighbourhood.NextIndex = -1;
-
- // TODO(matt): Maybe handle IN_ALL_EVENTS
- if(FinalFileEvents[FinalFileEventsIndex]->mask & IN_DELETE || FinalFileEvents[FinalFileEventsIndex]->mask & IN_MOVED_FROM)
+ DB.Entry = *(db_entry *)(FirstEntry + sizeof(DB.Entry) * i);
+ ConstructDirectoryPath(&OutputDirectoryPath, PAGE_PLAYER, Config.PlayerLocation, DB.Entry.BaseFilename);
+ file_buffer HTML;
+ CopyString(HTML.Path, sizeof(HTML.Path), "%s/index.html", OutputDirectoryPath.Location);
+ if(ReadFileIntoBuffer(&HTML, 0) == RC_SUCCESS)
{
- Deleted |= (DeleteEntry(Index, &Neighbourhood, FinalFileEvents[FinalFileEventsIndex]->name) == RC_SUCCESS);
+ char *Cursor = FirstAsset;
+ for(int j = 0; j < DB.AssetsHeader.Count; ++j)
+ {
+ DB.Asset = *(db_asset *)Cursor;
+ Cursor += sizeof(DB.Asset);
+ landmark_range Target = BinarySearchForMetadataLandmark(Cursor, i, DB.Asset.LandmarkCount);
+ for(int k = 0; k < Target.Length; ++k)
+ {
+ DB.Landmark = *(db_landmark *)(Cursor + sizeof(db_landmark) * (Target.First + k));
+ bool Found = FALSE;
+ for(int l = 0; l < Assets.Count; ++l)
+ {
+ // TODO(matt): StringToInt (base16)
+ char HashString[9];
+ sprintf(HashString, "%08x", Assets.Asset[l].Hash);
+
+ if((HTML.Buffer.Size >= DB.Landmark.Position + 8) && !StringsDifferT(HashString, HTML.Buffer.Location + DB.Landmark.Position, 0))
+ {
+ Found = TRUE;
+ break;
+ }
+ }
+ if(!Found)
+ {
+ printf("%sFailure ↓%s\n", ColourStrings[CS_ERROR], ColourStrings[CS_END]);
+ printf(" %s\n", HTML.Path);
+ printf(" %.*s [at byte %d] is not a known asset hash\n", 8, HTML.Buffer.Location + DB.Landmark.Position, DB.Landmark.Position);
+ UniversalSuccess = FALSE;
+ }
+ }
+ Cursor += sizeof(DB.Landmark) * DB.Asset.LandmarkCount;
+ }
+ FreeBuffer(&HTML.Buffer);
}
else
{
- Inserted |= (InsertEntry(Index, &Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, FinalFileEvents[FinalFileEventsIndex]->name, 0) == RC_SUCCESS);
+ printf("%sFailed to open%s %s\n", ColourStrings[CS_ERROR], ColourStrings[CS_END], HTML.Path);
+ }
+ }
+ Assert(UniversalSuccess);
+ printf("Success! All landmarks correspond to asset hashes\n");
+ DeclaimBuffer(&OutputDirectoryPath);
+}
+#endif
+
+void
+UpdateDeferredAssetChecksums(void)
+{
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ if(Assets.Asset[i].DeferredUpdate)
+ {
+ UpdateAssetInDB(i);
+ }
+ }
+}
+
+#define DEBUG_EVENTS 0
+#if DEBUG_EVENTS
+void
+PrintEvent(struct inotify_event *Event, int EventIndex)
+{
+
+ printf("\nEvent[%d]\n"
+ " wd: %d\n"
+ " mask: %d\n",
+ EventIndex,
+ Event->wd,
+ Event->mask);
+
+ if(Event->mask & IN_ACCESS) { printf(" IN_ACCESS\n"); }
+ if(Event->mask & IN_ATTRIB) { printf(" IN_ATTRIB\n"); }
+ if(Event->mask & IN_CLOSE_WRITE) { printf(" IN_CLOSE_WRITE\n"); }
+ if(Event->mask & IN_CLOSE_NOWRITE) { printf(" IN_CLOSE_NOWRITE\n"); }
+ if(Event->mask & IN_CREATE) { printf(" IN_CREATE\n"); }
+ if(Event->mask & IN_DELETE) { printf(" IN_DELETE\n"); }
+ if(Event->mask & IN_DELETE_SELF) { printf(" IN_DELETE_SELF\n"); }
+ if(Event->mask & IN_MODIFY) { printf(" IN_MODIFY\n"); }
+ if(Event->mask & IN_MOVE_SELF) { printf(" IN_MOVE_SELF\n"); }
+ if(Event->mask & IN_MOVED_FROM) { printf(" IN_MOVED_FROM\n"); }
+ if(Event->mask & IN_MOVED_TO) { printf(" IN_MOVED_TO\n"); }
+ if(Event->mask & IN_OPEN) { printf(" IN_OPEN\n"); }
+ if(Event->mask & IN_MOVE) { printf(" IN_MOVE\n"); }
+ if(Event->mask & IN_CLOSE) { printf(" IN_CLOSE\n"); }
+ if(Event->mask & IN_DONT_FOLLOW) { printf(" IN_DONT_FOLLOW\n"); }
+ if(Event->mask & IN_EXCL_UNLINK) { printf(" IN_EXCL_UNLINK\n"); }
+ if(Event->mask & IN_MASK_ADD) { printf(" IN_MASK_ADD\n"); }
+ if(Event->mask & IN_ONESHOT) { printf(" IN_ONESHOT\n"); }
+ if(Event->mask & IN_ONLYDIR) { printf(" IN_ONLYDIR\n"); }
+ if(Event->mask & IN_IGNORED) { printf(" IN_IGNORED\n"); }
+ if(Event->mask & IN_ISDIR) { printf(" IN_ISDIR\n"); }
+ if(Event->mask & IN_Q_OVERFLOW) { printf(" IN_Q_OVERFLOW\n"); }
+ if(Event->mask & IN_UNMOUNT) { printf(" IN_UNMOUNT\n"); }
+
+ printf( " cookie: %d\n"
+ " len: %d\n"
+ " name: %s\n",
+ Event->cookie,
+ Event->len,
+ Event->name);
+}
+#endif
+
+int
+MonitorFilesystem(buffers *CollationBuffers, template *SearchTemplate, template *PlayerTemplate, template *BespokeTemplate)
+{
+ buffer Events;
+ if(ClaimBuffer(&Events, "inotify Events", Kilobytes(4)) == RC_ARENA_FULL) { return RC_ARENA_FULL; };
+ Clear(Events.Location, Events.Size);
+
+ struct inotify_event *Event;
+ int BytesRead = read(inotifyInstance, Events.Location, Events.Size); // TODO(matt): Handle error EINVAL
+ if(inotifyInstance < 0) { perror("MonitorFilesystem()"); }
+
+ // TODO(matt): Test this with longer update intervals, and combinations of events...
+#if DEBUG_EVENTS
+ int i = 0;
+#endif
+ bool Deleted = FALSE;
+ bool Inserted = FALSE;
+ bool UpdatedAsset = FALSE;
+
+ for(Events.Ptr = Events.Location;
+ Events.Ptr - Events.Location < BytesRead && Events.Ptr - Events.Location < Events.Size;
+ Events.Ptr += sizeof(struct inotify_event) + Event->len
+#if DEBUG_EVENTS
+ , ++i
+#endif
+ )
+ {
+ Event = (struct inotify_event *)Events.Ptr;
+
+#if DEBUG_EVENTS
+ PrintEvent(Event, i);
+#endif
+ //PrintWatchHandles();
+
+ for(int WatchHandleIndex = 0; WatchHandleIndex < WatchHandles.Count; ++WatchHandleIndex)
+ {
+ if(Event->wd == WatchHandles.Handle[WatchHandleIndex].Descriptor)
+ {
+ switch(WatchHandles.Handle[WatchHandleIndex].Type)
+ {
+ case WT_HMML:
+ {
+ char *Ptr = Event->name;
+ Ptr += (StringLength(Event->name) - StringLength(".hmml"));
+ if(!(StringsDiffer(Ptr, ".hmml")))
+ {
+ *Ptr = '\0';
+
+ neighbourhood Neighbourhood = { };
+ InitNeighbourhood(&Neighbourhood);
+ ResetAssetLandmarks();
+
+ if(Event->mask & IN_DELETE)
+ {
+ Deleted |= (DeleteEntry(&Neighbourhood, Event->name) == RC_SUCCESS);
+ }
+ else if(Event->mask & IN_CLOSE_WRITE)
+ {
+ Inserted |= (InsertEntry(&Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, Event->name, 0) == RC_SUCCESS);
+ }
+ }
+ } break;
+ case WT_ASSET:
+ {
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ if(!StringsDiffer(Event->name, Assets.Asset[i].Filename + Assets.Asset[i].FilenameAt))
+ {
+ UpdateAsset(i, 0);
+ UpdatedAsset = TRUE;
+ break;
+ }
+ }
+ } break;
+ }
+ break;
+ }
}
}
if(Deleted || Inserted)
{
- GenerateIndexPage(Index, CollationBuffers, IndexTemplate);
+ UpdateDeferredAssetChecksums();
+ GenerateSearchPage(CollationBuffers, SearchTemplate);
+ DeleteStaleAssets();
+#if DEBUG_LANDMARKS
+ VerifyLandmarks();
+#endif
+ }
+
+ if(UpdatedAsset)
+ {
+#if DEBUG_LANDMARKS
+ VerifyLandmarks();
+#endif
}
DeclaimBuffer(&Events);
@@ -5909,13 +8051,13 @@ RemoveDirectory(char *Path)
if((remove(Path) == -1))
{
LogError(LOG_NOTICE, "Unable to remove directory %s: %s", Path, strerror(errno));
- fprintf(stderr, "\e[1;30mUnable to remove directory\e[0m %s: %s\n", Path, strerror(errno));
+ fprintf(stderr, "%sUnable to remove directory%s %s: %s\n", ColourStrings[CS_WARNING], ColourStrings[CS_END], Path, strerror(errno));
return RC_ERROR_DIRECTORY;
}
else
{
LogError(LOG_INFORMATIONAL, "Deleted %s", Path);
- //fprintf(stderr, "\e[1;30mDeleted\e[0m %s\n", Path);
+ //fprintf(stderr, "%sDeleted%s %s\n", ColourStrings[CS_DELETION], ColourStrings[CS_END], Path);
return RC_SUCCESS;
}
}
@@ -5938,143 +8080,173 @@ RemoveDirectoryRecursively(char *Path)
}
int
-UpgradeDB(index *Index)
+UpgradeDB(int OriginalDBVersion)
{
- // DBVersion 1
- typedef struct { unsigned int DBVersion; version AppVersion; version HMMLVersion; unsigned int EntryCount; } index_header1;
- typedef struct { int Size; char BaseFilename[32]; } index_metadata1;
- typedef struct { file_buffer File; file_buffer Metadata; index_header1 Header; index_metadata1 Entry; } index1;
- //
-
- // DBVersion 2
- typedef struct { unsigned int DBVersion; version AppVersion; version HMMLVersion; unsigned int EntryCount; char IndexLocation[32]; char PlayerLocation[32]; } index_header2;
- typedef struct { int Size; char BaseFilename[32]; } index_metadata2;
- typedef struct { file_buffer File; file_buffer Metadata; index_header2 Header; index_metadata2 Entry; } index2;
- //
-
// NOTE(matt): For each new DB version, we must declare and initialise one instance of each preceding version, only cast the
- // incoming Index to the type of the OriginalDBVersion, and move into the final case all operations on that incoming Index
+ // incoming DB to the type of the OriginalDBVersion, and move into the final case all operations on that incoming DB
bool OnlyHeaderChanged = TRUE;
int OriginalHeaderSize = 0;
- index1 Index1 = { };
- index2 Index2 = { };
+ database1 DB1 = { };
+ database2 DB2 = { };
+ database3 DB3 = { };
- int OriginalDBVersion = Index->Header.CurrentDBVersion;
switch(OriginalDBVersion)
{
case 1:
{
- OriginalHeaderSize = sizeof(index_header1);
- Index1.Header = *(index_header1 *)Index->Metadata.Buffer.Ptr;
+ OriginalHeaderSize = sizeof(db_header1);
+ DB1.Header = *(db_header1 *)DB.Metadata.Buffer.Location;
- Index2.Header.DBVersion = CINERA_DB_VERSION;
- Index2.Header.AppVersion = CINERA_APP_VERSION;
- Index2.Header.HMMLVersion.Major = hmml_version.Major;
- Index2.Header.HMMLVersion.Minor = hmml_version.Minor;
- Index2.Header.HMMLVersion.Patch = hmml_version.Patch;
- Index2.Header.EntryCount = Index1.Header.EntryCount;
+ DB2.Header.DBVersion = CINERA_DB_VERSION;
+ DB2.Header.AppVersion = CINERA_APP_VERSION;
+ DB2.Header.HMMLVersion.Major = hmml_version.Major;
+ DB2.Header.HMMLVersion.Minor = hmml_version.Minor;
+ DB2.Header.HMMLVersion.Patch = hmml_version.Patch;
+ DB2.Header.EntryCount = DB1.Header.EntryCount;
- Clear(Index2.Header.IndexLocation, sizeof(Index2.Header.IndexLocation));
- Clear(Index2.Header.PlayerLocation, sizeof(Index2.Header.PlayerLocation));
+ Clear(DB2.Header.SearchLocation, sizeof(DB2.Header.SearchLocation));
+ Clear(DB2.Header.PlayerLocation, sizeof(DB2.Header.PlayerLocation));
}
case 2:
{
if(OriginalDBVersion == 2)
{
- OriginalHeaderSize = sizeof(index_header2);
- Index2.Header = *(index_header2 *)Index->Metadata.Buffer.Ptr;
+ OriginalHeaderSize = sizeof(db_header2);
+ DB2.Header = *(db_header2 *)DB.Metadata.Buffer.Location;
+
+ DB.Header.InitialDBVersion = DB2.Header.DBVersion;
+ DB.Header.InitialAppVersion = DB2.Header.AppVersion;
+ DB.Header.InitialHMMLVersion.Major = DB2.Header.HMMLVersion.Major;
+ DB.Header.InitialHMMLVersion.Minor = DB2.Header.HMMLVersion.Minor;
+ DB.Header.InitialHMMLVersion.Patch = DB2.Header.HMMLVersion.Patch;
+
}
- Index->Header.InitialDBVersion = Index2.Header.DBVersion;
- Index->Header.InitialAppVersion = Index2.Header.AppVersion;
- Index->Header.InitialHMMLVersion.Major = Index2.Header.HMMLVersion.Major;
- Index->Header.InitialHMMLVersion.Minor = Index2.Header.HMMLVersion.Minor;
- Index->Header.InitialHMMLVersion.Patch = Index2.Header.HMMLVersion.Patch;
+ DB.EntriesHeader.Count = DB2.Header.EntryCount;
- Index->Header.CurrentDBVersion = CINERA_DB_VERSION;
- Index->Header.CurrentAppVersion = CINERA_APP_VERSION;
- Index->Header.CurrentHMMLVersion.Major = hmml_version.Major;
- Index->Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
- Index->Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
+ ClearCopyStringNoFormat(DB.EntriesHeader.ProjectID, sizeof(DB.EntriesHeader.ProjectID), Config.ProjectID);
- Index->Header.EntryCount = Index2.Header.EntryCount;
-
- ClearCopyStringNoFormat(Index->Header.ProjectID, sizeof(Index->Header.ProjectID), Config.ProjectID);
-
- Clear(Index->Header.ProjectName, sizeof(Index->Header.ProjectName));
+ Clear(DB.EntriesHeader.ProjectName, sizeof(DB.EntriesHeader.ProjectName));
for(int ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
{
if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID, Config.ProjectID))
{
- CopyString(Index->Header.ProjectName, sizeof(Index->Header.ProjectName), "%s", ProjectInfo[ProjectIndex].FullName);
+ CopyString(DB.EntriesHeader.ProjectName, sizeof(DB.EntriesHeader.ProjectName), "%s", ProjectInfo[ProjectIndex].FullName);
break;
}
}
- ClearCopyStringNoFormat(Index->Header.BaseURL, sizeof(Index->Header.BaseURL), Config.BaseURL);
- ClearCopyStringNoFormat(Index->Header.IndexLocation, sizeof(Index->Header.IndexLocation), Index2.Header.IndexLocation);
- ClearCopyStringNoFormat(Index->Header.PlayerLocation, sizeof(Index->Header.PlayerLocation), Index2.Header.PlayerLocation);
- ClearCopyStringNoFormat(Index->Header.PlayerURLPrefix, sizeof(Index->Header.PlayerURLPrefix), Config.PlayerURLPrefix);
+ ClearCopyStringNoFormat(DB.EntriesHeader.BaseURL, sizeof(DB.EntriesHeader.BaseURL), Config.BaseURL);
+ ClearCopyStringNoFormat(DB.EntriesHeader.SearchLocation, sizeof(DB.EntriesHeader.SearchLocation), DB2.Header.SearchLocation);
+ ClearCopyStringNoFormat(DB.EntriesHeader.PlayerLocation, sizeof(DB.EntriesHeader.PlayerLocation), DB2.Header.PlayerLocation);
+ ClearCopyStringNoFormat(DB.EntriesHeader.PlayerURLPrefix, sizeof(DB.EntriesHeader.PlayerURLPrefix), Config.PlayerURLPrefix);
OnlyHeaderChanged = FALSE;
- if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; }
- fwrite(&Index->Header, sizeof(Index->Header), 1, Index->Metadata.Handle);
+ if(!(DB.Metadata.Handle = fopen(DB.Metadata.Path, "w"))) { FreeBuffer(&DB.Metadata.Buffer); return RC_ERROR_FILE; }
+ fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.Handle);
- Index->Metadata.Buffer.Ptr = Index->Metadata.Buffer.Location + OriginalHeaderSize;
- Index->File.Buffer.Ptr += StringLength("---\n");
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location + OriginalHeaderSize;
+ DB.File.Buffer.Ptr += StringLength("---\n");
- for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
+ for(int EntryIndex = 0; EntryIndex < DB.EntriesHeader.Count; ++EntryIndex)
{
- // NOTE(matt): We can use either index_metadata1 or 2 here because they are the same
- index_metadata2 This = *(index_metadata2 *)Index->Metadata.Buffer.Ptr;
+ // NOTE(matt): We can use either db_entry1 or 2 here because they are the same
+ db_entry2 This = *(db_entry2 *)DB.Metadata.Buffer.Ptr;
- Index->Entry.LinkOffsets.PrevStart = 0;
- Index->Entry.LinkOffsets.NextStart = 0;
- Index->Entry.LinkOffsets.PrevEnd = 0;
- Index->Entry.LinkOffsets.NextEnd = 0;
+ DB.Entry.LinkOffsets.PrevStart = 0;
+ DB.Entry.LinkOffsets.NextStart = 0;
+ DB.Entry.LinkOffsets.PrevEnd = 0;
+ DB.Entry.LinkOffsets.NextEnd = 0;
- Index->Entry.Size = This.Size;
+ DB.Entry.Size = This.Size;
- ClearCopyStringNoFormat(Index->Entry.BaseFilename, sizeof(Index->Entry.BaseFilename), This.BaseFilename);
+ ClearCopyStringNoFormat(DB.Entry.BaseFilename, sizeof(DB.Entry.BaseFilename), This.BaseFilename);
- char *IndexEntryStart = Index->File.Buffer.Ptr;
- SeekBufferForString(&Index->File.Buffer, "title: \"", C_SEEK_FORWARDS, C_SEEK_AFTER);
- Clear(Index->Entry.Title, sizeof(Index->Entry.Title));
- CopyStringNoFormatT(Index->Entry.Title, sizeof(Index->Entry.Title), Index->File.Buffer.Ptr, '\n');
- Index->Entry.Title[StringLength(Index->Entry.Title) - 1] = '\0';
+ char *EntryStart = DB.File.Buffer.Ptr;
+ SeekBufferForString(&DB.File.Buffer, "title: \"", C_SEEK_FORWARDS, C_SEEK_AFTER);
+ Clear(DB.Entry.Title, sizeof(DB.Entry.Title));
+ CopyStringNoFormatT(DB.Entry.Title, sizeof(DB.Entry.Title), DB.File.Buffer.Ptr, '\n');
+ DB.Entry.Title[StringLength(DB.Entry.Title) - 1] = '\0';
- fwrite(&Index->Entry, sizeof(Index->Entry), 1, Index->Metadata.Handle);
+ fwrite(&DB.Entry, sizeof(DB.Entry), 1, DB.Metadata.Handle);
- Index->Metadata.Buffer.Ptr += sizeof(This);
- IndexEntryStart += This.Size;
- Index->File.Buffer.Ptr = IndexEntryStart;
+ DB.Metadata.Buffer.Ptr += sizeof(This);
+ EntryStart += This.Size;
+ DB.File.Buffer.Ptr = EntryStart;
}
- fclose(Index->Metadata.Handle);
- FreeBuffer(&Index->Metadata.Buffer);
- if(ReadFileIntoBuffer(&Index->Metadata, 0) == RC_ERROR_FILE)
- {
- return RC_ERROR_FILE;
- }
+ CycleFile(&DB.Metadata);
}
+ case 3:
+ {
+ OriginalHeaderSize = sizeof(db_header3);
+ DB3.Header = *(db_header3 *)DB.Metadata.Buffer.Location;
+ DB.Header.HexSignature = FOURCC("CNRA");
+
+ DB.Header.CurrentDBVersion = CINERA_DB_VERSION;
+ DB.Header.CurrentAppVersion = CINERA_APP_VERSION;
+ DB.Header.CurrentHMMLVersion.Major = hmml_version.Major;
+ DB.Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
+ DB.Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
+
+ DB.Header.InitialDBVersion = DB3.Header.InitialDBVersion;
+ DB.Header.InitialAppVersion = DB3.Header.InitialAppVersion;
+ DB.Header.InitialHMMLVersion.Major = DB3.Header.InitialHMMLVersion.Major;
+ DB.Header.InitialHMMLVersion.Minor = DB3.Header.InitialHMMLVersion.Minor;
+ DB.Header.InitialHMMLVersion.Patch = DB3.Header.InitialHMMLVersion.Patch;
+ DB.Header.BlockCount = 0;
+
+ // TODO(matt): Consider allowing zero NTRY or ASET blocks in a future version
+ DB.EntriesHeader.BlockID = FOURCC("NTRY");
+ DB.EntriesHeader.Count = DB3.Header.EntryCount;
+ ClearCopyStringNoFormat(DB.EntriesHeader.ProjectID, sizeof(DB.EntriesHeader.ProjectID), DB3.Header.ProjectID);
+ ClearCopyStringNoFormat(DB.EntriesHeader.ProjectName, sizeof(DB.EntriesHeader.ProjectName), DB3.Header.ProjectName);
+ ClearCopyStringNoFormat(DB.EntriesHeader.BaseURL, sizeof(DB.EntriesHeader.BaseURL), DB3.Header.BaseURL);
+ ClearCopyStringNoFormat(DB.EntriesHeader.SearchLocation, sizeof(DB.EntriesHeader.SearchLocation), DB3.Header.SearchLocation);
+ ClearCopyStringNoFormat(DB.EntriesHeader.PlayerLocation, sizeof(DB.EntriesHeader.PlayerLocation), DB3.Header.PlayerLocation);
+ ClearCopyStringNoFormat(DB.EntriesHeader.PlayerURLPrefix, sizeof(DB.EntriesHeader.PlayerURLPrefix), DB3.Header.PlayerURLPrefix);
+ ++DB.Header.BlockCount;
+
+ DB.AssetsHeader.BlockID = FOURCC("ASET");
+ DB.AssetsHeader.Count = 0;
+ ClearCopyStringNoFormat(DB.AssetsHeader.RootDir, sizeof(DB.AssetsHeader.RootDir), Config.RootDir);
+ ClearCopyStringNoFormat(DB.AssetsHeader.RootURL, sizeof(DB.AssetsHeader.RootURL), Config.RootURL);
+ ClearCopyStringNoFormat(DB.AssetsHeader.CSSDir, sizeof(DB.AssetsHeader.CSSDir), Config.CSSDir);
+ ClearCopyStringNoFormat(DB.AssetsHeader.ImagesDir, sizeof(DB.AssetsHeader.ImagesDir), Config.ImagesDir);
+ ClearCopyStringNoFormat(DB.AssetsHeader.JSDir, sizeof(DB.AssetsHeader.JSDir), Config.JSDir);
+ ++DB.Header.BlockCount;
+
+ OnlyHeaderChanged = FALSE;
+
+ if(!(DB.Metadata.Handle = fopen(DB.Metadata.Path, "w"))) { FreeBuffer(&DB.Metadata.Buffer); return RC_ERROR_FILE; }
+
+ fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.Handle);
+ fwrite(&DB.EntriesHeader, sizeof(DB.EntriesHeader), 1, DB.Metadata.Handle);
+ fwrite(DB.Metadata.Buffer.Location + OriginalHeaderSize,
+ sizeof(DB.Entry),
+ DB.EntriesHeader.Count,
+ DB.Metadata.Handle);
+
+ fwrite(&DB.AssetsHeader, sizeof(DB.AssetsHeader), 1, DB.Metadata.Handle);
+
+ CycleFile(&DB.Metadata);
+ }
+ // TODO(matt); DBVersion 4 is the first that uses HexSignatures
+ // We should try and deprecate earlier versions and just enforce a clean rebuild for invalid DB files
+ // Perhaps do this either the next time we have to bump the version, or when we scrap Single Edition
}
if(OnlyHeaderChanged)
{
- if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; }
- fwrite(&Index->Header, sizeof(Index->Header), 1, Index->Metadata.Handle);
- fwrite(Index->Metadata.Buffer.Location + OriginalHeaderSize, Index->Metadata.FileSize - OriginalHeaderSize, 1, Index->Metadata.Handle);
- fclose(Index->Metadata.Handle);
- FreeBuffer(&Index->Metadata.Buffer);
- if(ReadFileIntoBuffer(&Index->Metadata, 0) == RC_ERROR_FILE)
- {
- return RC_ERROR_FILE;
- }
+ if(!(DB.Metadata.Handle = fopen(DB.Metadata.Path, "w"))) { FreeBuffer(&DB.Metadata.Buffer); return RC_ERROR_FILE; }
+ fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.Handle);
+ fwrite(DB.Metadata.Buffer.Location + OriginalHeaderSize, DB.Metadata.FileSize - OriginalHeaderSize, 1, DB.Metadata.Handle);
+ CycleFile(&DB.Metadata);
}
- fprintf(stderr, "\n\e[1;32mUpgraded Cinera DB from %d to %d!\e[0m\n\n", OriginalDBVersion, Index->Header.CurrentDBVersion);
+ fprintf(stderr, "\n%sUpgraded Cinera DB from %d to %d!%s\n\n", ColourStrings[CS_SUCCESS], OriginalDBVersion, DB.Header.CurrentDBVersion, ColourStrings[CS_END]);
return RC_SUCCESS;
}
@@ -6082,7 +8254,7 @@ typedef struct
{
bool Present;
char ID[32];
-} index_entry; // Metadata, unless we actually want to bolster this?
+} entry_presence_id; // Metadata, unless we actually want to bolster this?
void
RemoveChildDirectories(buffer FullPath, char *ParentDirectory)
@@ -6101,101 +8273,83 @@ RemoveChildDirectories(buffer FullPath, char *ParentDirectory)
}
int
-DeleteDeadIndexEntries(index *Index)
+DeleteDeadDBEntries(void)
{
- // TODO(matt): More rigorously figure out who we should delete
- // Maybe compare the output directory and the input HMML names
- Index->Header = *(index_header *)Index->Metadata.Buffer.Location;
- if(Index->Header.CurrentDBVersion < CINERA_DB_VERSION)
- {
- if(CINERA_DB_VERSION == 4)
- {
- fprintf(stderr, "\n\e[1;31mHandle conversion from CINERA_DB_VERSION %d to %d!\e[0m\n\n", Index->Header.CurrentDBVersion, CINERA_DB_VERSION);
- exit(RC_ERROR_FATAL);
- }
- if(UpgradeDB(Index) == RC_ERROR_FILE) { return RC_NOOP; }
- }
- else if(Index->Header.CurrentDBVersion > CINERA_DB_VERSION)
- {
- fprintf(stderr, "\e[1;31mUnsupported DB Version (%d). Please upgrade Cinera\e[0m\n", Index->Header.CurrentDBVersion);
- exit(RC_ERROR_FATAL);
- }
-
bool NewPlayerLocation = FALSE;
- bool NewIndexLocation = FALSE;
- if(StringsDiffer(Index->Header.PlayerLocation, Config.PlayerLocation))
+ bool NewSearchLocation = FALSE;
+ if(StringsDiffer(DB.EntriesHeader.PlayerLocation, Config.PlayerLocation))
{
buffer OldPlayerDirectory;
- ClaimBuffer(&OldPlayerDirectory, "OldPlayerDirectory", 1024);
- ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, Index->Header.PlayerLocation, 0);
+ ClaimBuffer(&OldPlayerDirectory, "OldPlayerDirectory",
+ MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1);
+ ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, DB.EntriesHeader.PlayerLocation, 0);
buffer NewPlayerDirectory;
- ClaimBuffer(&NewPlayerDirectory, "NewPlayerDirectory", 1024);
+ ClaimBuffer(&NewPlayerDirectory, "NewPlayerDirectory",
+ MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1 + MAX_PLAYER_URL_PREFIX_LENGTH + MAX_BASE_FILENAME_LENGTH + 1);
ConstructDirectoryPath(&NewPlayerDirectory, PAGE_PLAYER, Config.PlayerLocation, 0);
- printf("\e[1;33mRelocating Player Page%s from %s to %s\e[0m\n",
- Index->Header.EntryCount > 1 ? "s" : "",
- OldPlayerDirectory.Location,
- NewPlayerDirectory.Location);
+ printf("%sRelocating Player Page%s from %s to %s%s\n",
+ ColourStrings[CS_REINSERTION], DB.EntriesHeader.Count > 1 ? "s" : "",
+ OldPlayerDirectory.Location, NewPlayerDirectory.Location, ColourStrings[CS_END]);
DeclaimBuffer(&NewPlayerDirectory);
- for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
+ for(int EntryIndex = 0; EntryIndex < DB.EntriesHeader.Count; ++EntryIndex)
{
- index_metadata This = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
- ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, Index->Header.PlayerLocation, This.BaseFilename);
- DeletePlayerPageFromFilesystem(This.BaseFilename, Index->Header.PlayerLocation, TRUE);
+ db_entry This = *(db_entry *)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex);
+ ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, DB.EntriesHeader.PlayerLocation, This.BaseFilename);
+ DeletePlayerPageFromFilesystem(This.BaseFilename, DB.EntriesHeader.PlayerLocation, TRUE);
}
- ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, Index->Header.PlayerLocation, 0);
+ ConstructDirectoryPath(&OldPlayerDirectory, PAGE_PLAYER, DB.EntriesHeader.PlayerLocation, 0);
- if(StringLength(Index->Header.PlayerLocation) > 0)
+ if(StringLength(DB.EntriesHeader.PlayerLocation) > 0)
{
RemoveChildDirectories(OldPlayerDirectory, Config.BaseDir);
}
DeclaimBuffer(&OldPlayerDirectory);
- ClearCopyStringNoFormat(Index->Header.PlayerLocation, sizeof(Index->Header.PlayerLocation), Config.PlayerLocation);
- *(index_header *)Index->Metadata.Buffer.Location = Index->Header;
+ ClearCopyStringNoFormat(DB.EntriesHeader.PlayerLocation, sizeof(DB.EntriesHeader.PlayerLocation), Config.PlayerLocation);
+ *(db_header *)DB.Metadata.Buffer.Location = DB.Header;
NewPlayerLocation = TRUE;
}
- if(StringsDiffer(Index->Header.IndexLocation, Config.IndexLocation))
+ if(StringsDiffer(DB.EntriesHeader.SearchLocation, Config.SearchLocation))
{
- buffer OldIndexDirectory;
- ClaimBuffer(&OldIndexDirectory, "OldIndexDirectory", 1024);
- ConstructDirectoryPath(&OldIndexDirectory, PAGE_INDEX, Index->Header.IndexLocation, 0);
- buffer NewIndexDirectory;
- ClaimBuffer(&NewIndexDirectory, "NewIndexDirectory", 1024);
- ConstructDirectoryPath(&NewIndexDirectory, PAGE_INDEX, Config.IndexLocation, 0);
- printf("\e[1;33mRelocating Index Page from %s to %s\e[0m\n",
- OldIndexDirectory.Location,
- NewIndexDirectory.Location);
- DeclaimBuffer(&NewIndexDirectory);
+ buffer OldSearchDirectory;
+ ClaimBuffer(&OldSearchDirectory, "OldSearchDirectory", MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1);
+ ConstructDirectoryPath(&OldSearchDirectory, PAGE_SEARCH, DB.EntriesHeader.SearchLocation, 0);
+ buffer NewSearchDirectory;
+ ClaimBuffer(&NewSearchDirectory, "NewSearchDirectory", MAX_BASE_DIR_LENGTH + 1 + MAX_RELATIVE_PAGE_LOCATION_LENGTH + 1);
+ ConstructDirectoryPath(&NewSearchDirectory, PAGE_SEARCH, Config.SearchLocation, 0);
+ printf("%sRelocating Search Page from %s to %s%s\n",
+ ColourStrings[CS_REINSERTION], OldSearchDirectory.Location, NewSearchDirectory.Location, ColourStrings[CS_END]);
+ DeclaimBuffer(&NewSearchDirectory);
- char IndexPagePath[2048] = { 0 };
- CopyString(IndexPagePath, sizeof(IndexPagePath), "%s/index.html", OldIndexDirectory.Location);
- remove(IndexPagePath);
- if(StringLength(Index->Header.IndexLocation) > 0)
+ char SearchPagePath[2048] = { 0 };
+ CopyString(SearchPagePath, sizeof(SearchPagePath), "%s/index.html", OldSearchDirectory.Location);
+ remove(SearchPagePath);
+ if(StringLength(DB.EntriesHeader.SearchLocation) > 0)
{
- RemoveChildDirectories(OldIndexDirectory, Config.BaseDir);
+ RemoveChildDirectories(OldSearchDirectory, Config.BaseDir);
}
- DeclaimBuffer(&OldIndexDirectory);
+ DeclaimBuffer(&OldSearchDirectory);
- ClearCopyStringNoFormat(Index->Header.IndexLocation, sizeof(Index->Header.IndexLocation), Config.IndexLocation);
- *(index_header *)Index->Metadata.Buffer.Location = Index->Header;
- NewIndexLocation = TRUE;
+ ClearCopyStringNoFormat(DB.EntriesHeader.SearchLocation, sizeof(DB.EntriesHeader.SearchLocation), Config.SearchLocation);
+ *(db_header *)DB.Metadata.Buffer.Location = DB.Header;
+ NewSearchLocation = TRUE;
}
- if(NewPlayerLocation || NewIndexLocation)
+ if(NewPlayerLocation || NewSearchLocation)
{
- if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; }
- fwrite(Index->Metadata.Buffer.Location, Index->Metadata.FileSize, 1, Index->Metadata.Handle);
- fclose(Index->Metadata.Handle);
+ if(!(DB.Metadata.Handle = fopen(DB.Metadata.Path, "w"))) { FreeBuffer(&DB.Metadata.Buffer); return RC_ERROR_FILE; }
+ fwrite(DB.Metadata.Buffer.Location, DB.Metadata.FileSize, 1, DB.Metadata.Handle);
+ CycleFile(&DB.Metadata);
}
- index_entry Entries[Index->Header.EntryCount];
+ entry_presence_id Entries[DB.EntriesHeader.Count];
- for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
+ for(int EntryIndex = 0; EntryIndex < DB.EntriesHeader.Count; ++EntryIndex)
{
- index_metadata This = *(index_metadata *)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
+ db_entry This = *(db_entry *)(DB.Metadata.Buffer.Location + sizeof(DB.Header) + sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * EntryIndex);
CopyStringNoFormat(Entries[EntryIndex].ID, sizeof(Entries[EntryIndex].ID), This.BaseFilename);
Entries[EntryIndex].Present = FALSE;
}
@@ -6218,7 +8372,7 @@ DeleteDeadIndexEntries(index *Index)
if(!(StringsDiffer(Ptr, ".hmml")))
{
*Ptr = '\0';
- for(int i = 0; i < Index->Header.EntryCount; ++i)
+ for(int i = 0; i < DB.EntriesHeader.Count; ++i)
{
if(!StringsDiffer(Entries[i].ID, ProjectFiles->d_name))
{
@@ -6231,16 +8385,15 @@ DeleteDeadIndexEntries(index *Index)
closedir(ProjectDirHandle);
bool Deleted = FALSE;
- for(int i = 0; i < Index->Header.EntryCount; ++i)
+ for(int i = 0; i < DB.EntriesHeader.Count; ++i)
{
if(Entries[i].Present == FALSE)
{
Deleted = TRUE;
neighbourhood Neighbourhood = { };
- Neighbourhood.PrevIndex = -1;
- Neighbourhood.ThisIndex = -1;
- Neighbourhood.NextIndex = -1;
- DeleteEntry(Index, &Neighbourhood, Entries[i].ID);
+ InitNeighbourhood(&Neighbourhood);
+ ResetAssetLandmarks();
+ DeleteEntry(&Neighbourhood, Entries[i].ID);
}
}
@@ -6248,10 +8401,15 @@ DeleteDeadIndexEntries(index *Index)
}
int
-SyncIndexWithInput(index *Index, buffers *CollationBuffers, template *IndexTemplate, template *PlayerTemplate, template *BespokeTemplate)
+SyncDBWithInput(buffers *CollationBuffers, template *SearchTemplate, template *PlayerTemplate, template *BespokeTemplate)
{
+ if(DB.Metadata.FileSize > 0 && Config.Mode & MODE_NOREVVEDRESOURCE)
+ {
+ DeleteStaleLandmarks();
+ }
+
bool Deleted = FALSE;
- Deleted = (Index->Metadata.FileSize > 0 && Index->File.FileSize > 0 && DeleteDeadIndexEntries(Index) == RC_SUCCESS);
+ Deleted = (DB.Metadata.FileSize > 0 && DB.File.FileSize > 0 && DeleteDeadDBEntries() == RC_SUCCESS);
DIR *ProjectDirHandle;
if(!(ProjectDirHandle = opendir(Config.ProjectDir)))
@@ -6272,16 +8430,21 @@ SyncIndexWithInput(index *Index, buffers *CollationBuffers, template *IndexTempl
{
*Ptr = '\0';
neighbourhood Neighbourhood = { };
- Neighbourhood.PrevIndex = -1;
- Neighbourhood.NextIndex = -1;
- Inserted |= (InsertEntry(Index, &Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, ProjectFiles->d_name, 0) == RC_SUCCESS);
+ InitNeighbourhood(&Neighbourhood);
+ ResetAssetLandmarks();
+ Inserted |= (InsertEntry(&Neighbourhood, CollationBuffers, PlayerTemplate, BespokeTemplate, ProjectFiles->d_name, 0) == RC_SUCCESS);
}
}
closedir(ProjectDirHandle);
+ UpdateDeferredAssetChecksums();
if(Deleted || Inserted)
{
- GenerateIndexPage(Index, CollationBuffers, IndexTemplate);
+ GenerateSearchPage(CollationBuffers, SearchTemplate);
+ DeleteStaleAssets();
+#if DEBUG_LANDMARKS
+ VerifyLandmarks();
+#endif
}
return RC_SUCCESS;
}
@@ -6300,6 +8463,193 @@ PrintVersions()
CurlVersion->version);
}
+int
+InitDB(void)
+{
+ DB.Metadata.Buffer.ID = "DBMetadata";
+ CopyString(DB.Metadata.Path, sizeof(DB.Metadata.Path), "%s/%s.metadata", Config.BaseDir, Config.ProjectID);
+ ReadFileIntoBuffer(&DB.Metadata, 0); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
+
+ DB.File.Buffer.ID = "DBFile";
+ CopyString(DB.File.Path, sizeof(DB.File.Path), "%s/%s.index", Config.BaseDir, Config.ProjectID);
+ ReadFileIntoBuffer(&DB.File, 0); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
+
+ if(DB.Metadata.Buffer.Location)
+ {
+ // TODO(matt): Handle this gracefully (it'll be an invalid file)
+ Assert(DB.Metadata.FileSize >= sizeof(DB.Header));
+ uint32_t OriginalDBVersion = 0;
+ uint32_t FirstInt = *(uint32_t *)DB.Metadata.Buffer.Location;
+ if(FirstInt != FOURCC("CNRA"))
+ {
+ // TODO(matt): More checking, somehow? Ideally this should be able to report "Invalid .metadata file" rather than
+ // trying to upgrade a file that isn't even valid
+ // TODO(matt): We should try and deprecate < CINERA_DB_VERSION 4 and enforce a clean rebuild for invalid DB files
+ // Perhaps do this either the next time we have to bump the version, or when we scrap Single Edition
+ OriginalDBVersion = FirstInt;
+ }
+ else
+ {
+ OriginalDBVersion = *(uint32_t *)(DB.Metadata.Buffer.Location + sizeof(DB.Header.HexSignature));
+ }
+
+ if(OriginalDBVersion < CINERA_DB_VERSION)
+ {
+ if(CINERA_DB_VERSION == 5)
+ {
+ fprintf(stderr, "\n%sHandle conversion from CINERA_DB_VERSION %d to %d!%s\n\n", ColourStrings[CS_ERROR], OriginalDBVersion, CINERA_DB_VERSION, ColourStrings[CS_END]);
+ exit(RC_ERROR_FATAL);
+ }
+ if(UpgradeDB(OriginalDBVersion) == RC_ERROR_FILE) { return RC_NOOP; }
+ }
+ else if(OriginalDBVersion > CINERA_DB_VERSION)
+ {
+ fprintf(stderr, "%sUnsupported DB Version (%d). Please upgrade Cinera%s\n", ColourStrings[CS_ERROR], OriginalDBVersion, ColourStrings[CS_END]);
+ exit(RC_ERROR_FATAL);
+ }
+
+ DB.Header = *(db_header *)DB.Metadata.Buffer.Location;
+ DB.Header.CurrentAppVersion = CINERA_APP_VERSION;
+ DB.Header.CurrentHMMLVersion.Major = hmml_version.Major;
+ DB.Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
+ DB.Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
+
+ DB.Metadata.Handle = fopen(DB.Metadata.Path, "w");
+ fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.Handle);
+
+ DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location + sizeof(DB.Header);
+
+ // NOTE(matt): In the future we may want to support multiple occurrences of a block type, at which point this code
+ // should continue to work
+ for(int BlockIndex = 0; BlockIndex < DB.Header.BlockCount; ++BlockIndex)
+ {
+ uint32_t BlockID = *(uint32_t *)DB.Metadata.Buffer.Ptr;
+ if(BlockID == FOURCC("NTRY"))
+ {
+ DB.EntriesHeader = *(db_header_entries *)DB.Metadata.Buffer.Ptr;
+ fwrite(DB.Metadata.Buffer.Ptr,
+ sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * DB.EntriesHeader.Count,
+ 1,
+ DB.Metadata.Handle);
+ DB.Metadata.Buffer.Ptr += sizeof(DB.EntriesHeader) + sizeof(DB.Entry) * DB.EntriesHeader.Count;
+ }
+ else if(BlockID == FOURCC("ASET"))
+ {
+ DB.AssetsHeader = *(db_header_assets *)DB.Metadata.Buffer.Ptr;
+ ClearCopyStringNoFormat(DB.AssetsHeader.RootDir, sizeof(DB.AssetsHeader.RootDir), Config.RootDir);
+ ClearCopyStringNoFormat(DB.AssetsHeader.RootURL, sizeof(DB.AssetsHeader.RootURL), Config.RootURL);
+ ClearCopyStringNoFormat(DB.AssetsHeader.CSSDir, sizeof(DB.AssetsHeader.CSSDir), Config.CSSDir);
+ ClearCopyStringNoFormat(DB.AssetsHeader.ImagesDir, sizeof(DB.AssetsHeader.ImagesDir), Config.ImagesDir);
+ ClearCopyStringNoFormat(DB.AssetsHeader.JSDir, sizeof(DB.AssetsHeader.JSDir), Config.JSDir);
+ fwrite(&DB.AssetsHeader, sizeof(DB.AssetsHeader), 1, DB.Metadata.Handle);
+ DB.Metadata.Buffer.Ptr += sizeof(DB.AssetsHeader);
+ for(int AssetIndex = 0; AssetIndex < DB.AssetsHeader.Count; ++AssetIndex)
+ {
+ DB.Asset = *(db_asset *)DB.Metadata.Buffer.Ptr;
+ fwrite(DB.Metadata.Buffer.Ptr,
+ sizeof(DB.Asset) + sizeof(DB.Landmark) * DB.Asset.LandmarkCount,
+ 1,
+ DB.Metadata.Handle);
+ DB.Metadata.Buffer.Ptr += sizeof(DB.Asset) + sizeof(DB.Landmark) * DB.Asset.LandmarkCount;
+ }
+ }
+ else
+ {
+ printf("%sMalformed metadata file%s: %s\n", ColourStrings[CS_ERROR], ColourStrings[CS_END], DB.Metadata.Path);
+ }
+ }
+
+ CycleFile(&DB.Metadata);
+ }
+ else
+ {
+ // NOTE(matt): Initialising new db_header
+ DB.Header.HexSignature = FOURCC("CNRA");
+ DB.Header.InitialDBVersion = DB.Header.CurrentDBVersion = CINERA_DB_VERSION;
+ DB.Header.InitialAppVersion = DB.Header.CurrentAppVersion = CINERA_APP_VERSION;
+ DB.Header.InitialHMMLVersion.Major = DB.Header.CurrentHMMLVersion.Major = hmml_version.Major;
+ DB.Header.InitialHMMLVersion.Minor = DB.Header.CurrentHMMLVersion.Minor = hmml_version.Minor;
+ DB.Header.InitialHMMLVersion.Patch = DB.Header.CurrentHMMLVersion.Patch = hmml_version.Patch;
+ DB.Header.BlockCount = 0;
+
+ CopyStringNoFormat(DB.EntriesHeader.ProjectID, sizeof(DB.EntriesHeader.ProjectID), Config.ProjectID);
+
+ for(int ProjectIndex = 0; ProjectIndex < ArrayCount(ProjectInfo); ++ProjectIndex)
+ {
+ if(!StringsDiffer(ProjectInfo[ProjectIndex].ProjectID, Config.ProjectID))
+ {
+ CopyStringNoFormat(DB.EntriesHeader.ProjectName, sizeof(DB.EntriesHeader.ProjectName), ProjectInfo[ProjectIndex].FullName);
+ break;
+ }
+ }
+
+ // TODO(matt): Consider allowing zero NTRY or ASET blocks in a future version
+ DB.EntriesHeader.BlockID = FOURCC("NTRY");
+ DB.EntriesHeader.Count = 0;
+ CopyStringNoFormat(DB.EntriesHeader.BaseURL, sizeof(DB.EntriesHeader.BaseURL), Config.BaseURL);
+ CopyStringNoFormat(DB.EntriesHeader.SearchLocation, sizeof(DB.EntriesHeader.SearchLocation), Config.SearchLocation);
+ CopyStringNoFormat(DB.EntriesHeader.PlayerLocation, sizeof(DB.EntriesHeader.PlayerLocation), Config.PlayerLocation);
+ CopyStringNoFormat(DB.EntriesHeader.PlayerURLPrefix, sizeof(DB.EntriesHeader.PlayerURLPrefix), Config.PlayerURLPrefix);
+ ++DB.Header.BlockCount;
+
+ DB.AssetsHeader.BlockID = FOURCC("ASET");
+ DB.AssetsHeader.Count = 0;
+ CopyStringNoFormat(DB.AssetsHeader.RootDir, sizeof(DB.AssetsHeader.RootDir), Config.RootDir);
+ CopyStringNoFormat(DB.AssetsHeader.RootURL, sizeof(DB.AssetsHeader.RootURL), Config.RootURL);
+ CopyStringNoFormat(DB.AssetsHeader.CSSDir, sizeof(DB.AssetsHeader.CSSDir), Config.CSSDir);
+ CopyStringNoFormat(DB.AssetsHeader.ImagesDir, sizeof(DB.AssetsHeader.ImagesDir), Config.ImagesDir);
+ CopyStringNoFormat(DB.AssetsHeader.JSDir, sizeof(DB.AssetsHeader.JSDir), Config.JSDir);
+ ++DB.Header.BlockCount;
+
+ DIR *OutputDirectoryHandle;
+ if(!(OutputDirectoryHandle = opendir(Config.BaseDir)))
+ {
+ if(MakeDir(Config.BaseDir) == RC_ERROR_DIRECTORY)
+ {
+ LogError(LOG_ERROR, "Unable to create directory %s: %s", Config.BaseDir, strerror(errno));
+ fprintf(stderr, "Unable to create directory %s: %s\n", Config.BaseDir, strerror(errno));
+ return RC_ERROR_DIRECTORY;
+ };
+ }
+ closedir(OutputDirectoryHandle);
+
+ DB.Metadata.Handle = fopen(DB.Metadata.Path, "w");
+ fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.Handle);
+ fwrite(&DB.EntriesHeader, sizeof(DB.EntriesHeader), 1, DB.Metadata.Handle);
+ fwrite(&DB.AssetsHeader, sizeof(DB.AssetsHeader), 1, DB.Metadata.Handle);
+ fclose(DB.Metadata.Handle);
+ ReadFileIntoBuffer(&DB.Metadata, 0);
+
+ DB.File.Handle = fopen(DB.File.Path, "w");
+ fprintf(DB.File.Handle, "---\n");
+ fclose(DB.File.Handle);
+ ReadFileIntoBuffer(&DB.File, 0);
+ }
+ return RC_SUCCESS;
+}
+
+void
+SetCacheDirectory(config *DefaultConfig)
+{
+ int Flags = WRDE_NOCMD | WRDE_UNDEF | WRDE_APPEND;
+ wordexp_t Expansions = {};
+ wordexp("$XDG_CACHE_HOME/cinera", &Expansions, Flags);
+ wordexp("$HOME/.cache/cinera", &Expansions, Flags);
+ if(Expansions.we_wordc > 0 ) { CopyString(DefaultConfig->CacheDir, sizeof(DefaultConfig->CacheDir), Expansions.we_wordv[0]); }
+ wordfree(&Expansions);
+}
+
+void
+InitMemoryArena(arena *Arena, int Size)
+{
+ Arena->Size = Size;
+ if(!(Arena->Location = calloc(1, Arena->Size)))
+ {
+ exit(RC_ERROR_MEMORY);
+ }
+ Arena->Ptr = Arena->Location;
+}
+
int
main(int ArgC, char **Args)
{
@@ -6310,12 +8660,13 @@ main(int ArgC, char **Args)
.CSSDir = "",
.ImagesDir = "",
.JSDir = "",
+ .QueryString = "r",
.TemplatesDir = ".",
- .TemplateIndexLocation = "",
+ .TemplateSearchLocation = "",
.TemplatePlayerLocation = "",
.BaseDir = ".",
.BaseURL = "",
- .IndexLocation = "",
+ .SearchLocation = "",
.PlayerLocation = "", // Should default to the ProjectID
.Edition = EDITION_SINGLE,
.LogLevel = LOG_EMERGENCY,
@@ -6330,14 +8681,7 @@ main(int ArgC, char **Args)
.PlayerURLPrefix = ""
};
- if(getenv("XDG_CACHE_HOME"))
- {
- CopyString(DefaultConfig.CacheDir, sizeof(DefaultConfig.CacheDir), "%s/cinera", getenv("XDG_CACHE_HOME"));
- }
- else
- {
- CopyString(DefaultConfig.CacheDir, sizeof(DefaultConfig.CacheDir), "%s/.cache/cinera", getenv("HOME"));
- }
+ SetCacheDirectory(&DefaultConfig);
Config = DefaultConfig;
@@ -6348,7 +8692,7 @@ main(int ArgC, char **Args)
}
char CommandLineArg;
- while((CommandLineArg = getopt(ArgC, Args, "1a:b:B:c:d:efghi:j:l:m:n:o:p:qr:R:s:t:u:vwx:y:")) != -1)
+ while((CommandLineArg = getopt(ArgC, Args, "1a:b:B:c:d:efghi:j:l:m:n:o:p:qQ:r:R:s:t:u:vwx:y:")) != -1)
{
switch(CommandLineArg)
{
@@ -6393,7 +8737,7 @@ main(int ArgC, char **Args)
Config.DefaultMedium = optarg;
break;
case 'n':
- Config.IndexLocation = StripSurroundingSlashes(optarg);
+ Config.SearchLocation = StripSurroundingSlashes(optarg);
break;
case 'o':
Config.OutLocation = optarg;
@@ -6405,6 +8749,13 @@ main(int ArgC, char **Args)
case 'q':
Config.Mode |= MODE_ONESHOT;
break;
+ case 'Q':
+ Config.QueryString = optarg;
+ if(!StringsDiffer(Config.QueryString, ""))
+ {
+ Config.Mode |= MODE_NOREVVEDRESOURCE;
+ }
+ break;
case 'r':
Config.RootDir = StripTrailingSlash(optarg);
break;
@@ -6427,7 +8778,7 @@ main(int ArgC, char **Args)
Config.Mode |= MODE_NOCACHE;
break;
case 'x':
- Config.TemplateIndexLocation = optarg;
+ Config.TemplateSearchLocation = optarg;
break;
case 'y':
Config.TemplatePlayerLocation = optarg;
@@ -6441,22 +8792,14 @@ main(int ArgC, char **Args)
if(Config.Mode & MODE_EXAMINE)
{
- index Index = { };
- Index.Metadata.Buffer.ID = "IndexMetadata";
// TODO(matt): Allow optionally passing a .metadata file as an argument?
- CopyString(Index.Metadata.Path, sizeof(Index.Metadata.Path), "%s/%s.metadata", Config.BaseDir, Config.ProjectID);
- ExamineIndex(&Index);
+ ExamineDB();
exit(RC_SUCCESS);
}
- // NOTE(matt): Init MemoryArena (it is global)
- MemoryArena.Size = Megabytes(4);
- if(!(MemoryArena.Location = calloc(MemoryArena.Size, 1)))
- {
- LogError(LOG_EMERGENCY, "%s: %s", Args[0], strerror(errno));
- return RC_RIP;
- }
- MemoryArena.Ptr = MemoryArena.Location;
+ // NOTE(matt): Init MemoryArenas (they are global)
+ InitMemoryArena(&MemoryArena, Megabytes(4));
+ InitMemoryArena(&TemplateArena, Kilobytes(16)); // TODO(matt): Consider some way of making this growable
#if DEBUG_MEM
FILE *MemLog = fopen("/home/matt/cinera_mem", "a+");
@@ -6475,8 +8818,8 @@ main(int ArgC, char **Args)
// Player
// ScriptPlayer
//
- // IncludesIndex
- // Index
+ // IncludesSearch
+ // Search
buffers CollationBuffers = {};
if(ClaimBuffer(&CollationBuffers.IncludesPlayer, "IncludesPlayer", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
@@ -6484,15 +8827,15 @@ main(int ArgC, char **Args)
if(ClaimBuffer(&CollationBuffers.Player, "Player", Kilobytes(256)) == RC_ARENA_FULL) { goto RIP; };
if(ClaimBuffer(&CollationBuffers.ScriptPlayer, "ScriptPlayer", Kilobytes(8)) == RC_ARENA_FULL) { goto RIP; };
- if(ClaimBuffer(&CollationBuffers.IncludesIndex, "IncludesIndex", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
- if(ClaimBuffer(&CollationBuffers.Search, "Search", Kilobytes(32)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.IncludesSearch, "IncludesSearch", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.SearchEntry, "Search", Kilobytes(32)) == RC_ARENA_FULL) { goto RIP; };
bool HaveConfigErrors = FALSE;
if(StringsDiffer(Config.ProjectID, ""))
{
if(StringLength(Config.ProjectID) > MAX_PROJECT_ID_LENGTH)
{
- fprintf(stderr, "\e[1;31mProjectID \"%s\" is too long (%d/%d characters)\e[0m\n", Config.ProjectID, StringLength(Config.ProjectID), MAX_PROJECT_ID_LENGTH);
+ fprintf(stderr, "%sProjectID \"%s\" is too long (%d/%d characters)%s\n", ColourStrings[CS_ERROR], Config.ProjectID, StringLength(Config.ProjectID), MAX_PROJECT_ID_LENGTH, ColourStrings[CS_END]);
HaveConfigErrors = TRUE;
}
@@ -6522,7 +8865,7 @@ main(int ArgC, char **Args)
{
if(StringLength(ProjectInfo[ProjectInfoIndex].AltURLPrefix) > MAX_PLAYER_URL_PREFIX_LENGTH)
{
- fprintf(stderr, "\e[1;31mPlayer URL Prefix \"%s\" is too long (%d/%d characters)\e[0m\n", ProjectInfo[ProjectInfoIndex].AltURLPrefix, StringLength(ProjectInfo[ProjectInfoIndex].AltURLPrefix), MAX_PLAYER_URL_PREFIX_LENGTH);
+ fprintf(stderr, "%sPlayer URL Prefix \"%s\" is too long (%d/%d characters)%s\n", ColourStrings[CS_ERROR], ProjectInfo[ProjectInfoIndex].AltURLPrefix, StringLength(ProjectInfo[ProjectInfoIndex].AltURLPrefix), MAX_PLAYER_URL_PREFIX_LENGTH, ColourStrings[CS_END]);
HaveConfigErrors = TRUE;
}
else
@@ -6533,7 +8876,7 @@ main(int ArgC, char **Args)
if(StringLength(ProjectInfo[ProjectInfoIndex].FullName) > MAX_PROJECT_NAME_LENGTH)
{
- fprintf(stderr, "\e[1;31mProject Name \"%s\" is too long (%d/%d characters)\e[0m\n", ProjectInfo[ProjectInfoIndex].FullName, StringLength(ProjectInfo[ProjectInfoIndex].FullName), MAX_PROJECT_NAME_LENGTH);
+ fprintf(stderr, "%sProject Name \"%s\" is too long (%d/%d characters)%s\n", ColourStrings[CS_ERROR], ProjectInfo[ProjectInfoIndex].FullName, StringLength(ProjectInfo[ProjectInfoIndex].FullName), MAX_PROJECT_NAME_LENGTH, ColourStrings[CS_END]);
HaveConfigErrors = TRUE;
}
@@ -6542,26 +8885,26 @@ main(int ArgC, char **Args)
}
if(!KnownProject)
{
- fprintf(stderr, "\e[1;31mMissing Project Info for %s\e[0m \e[1;30m(-p)\e[0m\n", Config.ProjectID);
+ fprintf(stderr, "%sMissing Project Info for %s%s %s(-p)%s\n", ColourStrings[CS_ERROR], Config.ProjectID, ColourStrings[CS_END], ColourStrings[CS_COMMENT], ColourStrings[CS_END]);
HaveConfigErrors = TRUE;
}
}
if(StringsDiffer(Config.BaseURL, "") && StringLength(Config.BaseURL) > MAX_BASE_URL_LENGTH)
{
- fprintf(stderr, "\e[1;31mBase URL \"%s\" is too long (%d/%d characters)\e[0m\n", Config.BaseURL, StringLength(Config.BaseURL), MAX_BASE_URL_LENGTH);
+ fprintf(stderr, "%sBase URL \"%s\" is too long (%d/%d characters)%s\n", ColourStrings[CS_ERROR], Config.BaseURL, StringLength(Config.BaseURL), MAX_BASE_URL_LENGTH, ColourStrings[CS_END]);
HaveConfigErrors = TRUE;
}
- if(StringsDiffer(Config.IndexLocation, "") && StringLength(Config.IndexLocation) > MAX_RELATIVE_PAGE_LOCATION_LENGTH)
+ if(StringsDiffer(Config.SearchLocation, "") && StringLength(Config.SearchLocation) > MAX_RELATIVE_PAGE_LOCATION_LENGTH)
{
- fprintf(stderr, "\e[1;31mRelative Index Page Location \"%s\" is too long (%d/%d characters)\e[0m\n", Config.IndexLocation, StringLength(Config.IndexLocation), MAX_RELATIVE_PAGE_LOCATION_LENGTH);
+ fprintf(stderr, "%sRelative Search Page Location \"%s\" is too long (%d/%d characters)%s\n", ColourStrings[CS_ERROR], Config.SearchLocation, StringLength(Config.SearchLocation), MAX_RELATIVE_PAGE_LOCATION_LENGTH, ColourStrings[CS_END]);
HaveConfigErrors = TRUE;
}
if(StringsDiffer(Config.PlayerLocation, "") && StringLength(Config.PlayerLocation) > MAX_RELATIVE_PAGE_LOCATION_LENGTH)
{
- fprintf(stderr, "\e[1;31mRelative Player Page Location \"%s\" is too long (%d/%d characters)\e[0m\n", Config.PlayerLocation, StringLength(Config.PlayerLocation), MAX_RELATIVE_PAGE_LOCATION_LENGTH);
+ fprintf(stderr, "%sRelative Player Page Location \"%s\" is too long (%d/%d characters)%s\n", ColourStrings[CS_ERROR], Config.PlayerLocation, StringLength(Config.PlayerLocation), MAX_RELATIVE_PAGE_LOCATION_LENGTH, ColourStrings[CS_END]);
HaveConfigErrors = TRUE;
}
@@ -6579,9 +8922,120 @@ main(int ArgC, char **Args)
// App is running all the time, and picking up changes to the config as we go
// If we find a new template, we first of all Init and Validate it
// In our case here, we just want to straight up Init our three possible templates
- // and Validate the Index and Player templates if their locations are set
+ // and Validate the Search and Player templates if their locations are set
- template *IndexTemplate; InitTemplate(&IndexTemplate);
+ if(Config.Edition == EDITION_PROJECT)
+ {
+#if DEBUG_MEM
+ FILE *MemLog = fopen("/home/matt/cinera_mem", "w+");
+ fprintf(MemLog, "Entered Project Edition\n");
+ fclose(MemLog);
+#endif
+
+ // TODO(matt): Also log these startup messages?
+ PrintVersions();
+ printf( "\n"
+ "Universal\n"
+ " Cache Directory: %s(XDG_CACHE_HOME)%s\t%s\n"
+ " Update Interval: %s(-u)%s\t\t%d second%s\n"
+ "\n"
+ " Assets Root\n"
+ " Directory: %s(-r)%s\t\t\t%s\n"
+ " URL: %s(-R)%s\t\t\t%s\n"
+ " Paths relative to root\n"
+ " CSS: %s(-c)%s\t\t\t%s\n"
+ " Images: %s(-i)%s\t\t\t%s\n"
+ " JS: %s(-j)%s\t\t\t%s\n"
+ " Revved resources query string: %s(-Q)%s\t%s\n"
+ "\n"
+ "Project\n"
+ " ID: %s(-p)%s\t\t\t\t%s\n"
+ " Default Medium: %s(-m)%s\t\t%s\n"
+ " Style / Theme: %s(-s)%s\t\t\t%s\n"
+ "\n"
+ "Input Paths\n"
+ " Annotations Directory: %s(-d)%s\t\t%s\n"
+ " Templates Directory: %s(-t)%s\t\t%s\n"
+ " Search Template: %s(-x)%s\t\t%s\n"
+ " Player Template: %s(-y)%s\t\t%s\n"
+ "\n"
+ "Output Paths\n"
+ " Base\n"
+ " Directory: %s(-b)%s\t\t\t%s\n"
+ " URL: %s(-B)%s\t\t\t%s\n"
+ " Paths relative to base\n"
+ " Search Page: %s(-n)%s\t\t%s\n"
+ /* NOTE(matt): Here, I think, is where we'll split into sub-projects (...really?...) */
+ " Player Page(s): %s(-a)%s\t\t%s\n"
+ " Player Page Prefix: %s(hardcoded)%s\t%s\n"
+ "\n"
+ "Modes\n"
+ " Single browser tab: %s(-1)%s\t\t%s\n"
+ " Force template integration: %s(-f)%s\t%s\n"
+ " Ignore video privacy status: %s(-g)%s\t%s\n"
+ " Quit after sync: %s(-q)%s\t\t%s\n"
+ " Force quote cache rebuild: %s(-w)%s\t%s\n"
+ "\n",
+
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.CacheDir,
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.UpdateInterval,
+ Config.UpdateInterval == 1 ? "" : "s",
+
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.RootDir,
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.RootURL, "") ? Config.RootURL : "[empty]",
+
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.CSSDir, "") ? Config.CSSDir : "(same as root)",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.ImagesDir, "") ? Config.ImagesDir : "(same as root)",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.JSDir, "") ? Config.JSDir : "(same as root)",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.Mode & MODE_NOREVVEDRESOURCE ? "[disabled]" : Config.QueryString,
+
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.ProjectID,
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.DefaultMedium,
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.Theme,
+
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.ProjectDir,
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.TemplatesDir,
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.TemplateSearchLocation, "") ? Config.TemplateSearchLocation : "[none set]",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.TemplatePlayerLocation, "") ? Config.TemplatePlayerLocation : "[none set]",
+
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.BaseDir,
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.BaseURL, "") ? Config.BaseURL : "[empty]",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.SearchLocation, "") ? Config.SearchLocation : "(same as base)",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.PlayerLocation, "") ? Config.PlayerLocation : "(directly descended from base)",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], StringsDiffer(Config.PlayerURLPrefix, "") ? Config.PlayerURLPrefix : Config.ProjectID,
+
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.Mode & MODE_SINGLETAB ? "on" : "off",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.Mode & MODE_FORCEINTEGRATION ? "on" : "off",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.Mode & MODE_NOPRIVACY ? "on" : "off",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.Mode & MODE_ONESHOT ? "on" : "off",
+ ColourStrings[CS_COMMENT], ColourStrings[CS_END], Config.Mode & MODE_NOCACHE ? "on" : "off");
+
+ if((StringsDiffer(Config.SearchLocation, "") || StringsDiffer(Config.PlayerLocation, ""))
+ && StringLength(Config.BaseURL) == 0)
+ {
+ printf("%sPlease set a Project Base URL (-B) so we can output the Search / Player pages to\n"
+ "locations other than the defaults%s\n",
+ ColourStrings[CS_ERROR], ColourStrings[CS_END]);
+ return(RC_SUCCESS);
+ }
+#if 0
+ for(int i = 0; i < Assets.Count; ++i)
+ {
+ printf("%08x - %s\n", Assets.Asset[i].Hash, Assets.Asset[i].Filename);
+ }
+#endif
+
+ InitDB();
+ inotifyInstance = inotify_init1(IN_NONBLOCK);
+
+ printf("┌╼ Hashing assets ╾┐\n");
+ // NOTE(matt): This had to happen before ValidateTemplate() because those guys may need to do PushAsset() and we must
+ // ensure that the builtin assets get placed correctly
+ InitAssets();
+ }
+
+ printf("┌╼ Packing templates ╾┐\n");
+ template *SearchTemplate; InitTemplate(&SearchTemplate);
template *PlayerTemplate; InitTemplate(&PlayerTemplate);
template *BespokeTemplate; InitTemplate(&BespokeTemplate);
@@ -6598,9 +9052,9 @@ main(int ArgC, char **Args)
}
}
- if(Config.Edition == EDITION_PROJECT && StringsDiffer(Config.TemplateIndexLocation, ""))
+ if(Config.Edition == EDITION_PROJECT && StringsDiffer(Config.TemplateSearchLocation, ""))
{
- switch(ValidateTemplate(&IndexTemplate, Config.TemplateIndexLocation, TEMPLATE_INDEX))
+ switch(ValidateTemplate(&SearchTemplate, Config.TemplateSearchLocation, TEMPLATE_SEARCH))
{
case RC_INVALID_TEMPLATE: // Invalid template
case RC_ERROR_MEMORY: // Could not allocate memory for template
@@ -6613,121 +9067,25 @@ main(int ArgC, char **Args)
if(Config.Edition == EDITION_PROJECT)
{
-
-#if DEBUG_MEM
- FILE *MemLog = fopen("/home/matt/cinera_mem", "w+");
- fprintf(MemLog, "Entered Project Edition\n");
- fclose(MemLog);
-#endif
-
- // TODO(matt): Also log these startup messages?
- PrintVersions();
- printf( "\n"
- "Universal\n"
- " Cache Directory: \e[1;30m(XDG_CACHE_HOME)\e[0m\t%s\n"
- "\n"
- " Root\n"
- " Directory: \e[1;30m(-r)\e[0m\t\t\t%s\n"
- " URL: \e[1;30m(-R)\e[0m\t\t\t%s\n"
- " Paths relative to root\n"
- " CSS: \e[1;30m(-c)\e[0m\t\t\t%s\n"
- " Images: \e[1;30m(-i)\e[0m\t\t\t%s\n"
- " JS: \e[1;30m(-j)\e[0m\t\t\t%s\n"
- "\n"
- "Project\n"
- " ID: \e[1;30m(-p)\e[0m\t\t\t\t%s\n"
- " Default Medium: \e[1;30m(-m)\e[0m\t\t%s\n"
- " Style / Theme: \e[1;30m(-s)\e[0m\t\t\t%s\n"
- "\n"
- "Input Paths\n"
- " Annotations Directory: \e[1;30m(-d)\e[0m\t\t%s\n"
- " Templates Directory: \e[1;30m(-t)\e[0m\t\t%s\n"
- " Index Template: \e[1;30m(-x)\e[0m\t\t%s\n"
- " Player Template: \e[1;30m(-y)\e[0m\t\t%s\n"
- "\n"
- "Output Paths\n"
- " Base\n"
- " Directory: \e[1;30m(-b)\e[0m\t\t\t%s\n"
- " URL: \e[1;30m(-B)\e[0m\t\t\t%s\n"
- " Paths relative to base\n"
- " Index Page: \e[1;30m(-n)\e[0m\t\t\t%s\n"
- /* NOTE(matt): Here, I think, is where we'll split into sub-projects (...really?...) */
- " Player Page(s): \e[1;30m(-a)\e[0m\t\t%s\n"
- " Player Page Prefix: \e[1;30m(hardcoded)\e[0m\t%s\n"
- "\n"
- "Modes\n"
- " Single browser tab: \e[1;30m(-1)\e[0m\t\t%s\n"
- " Force template integration: \e[1;30m(-f)\e[0m\t%s\n"
- " Ignore video privacy status: \e[1;30m(-g)\e[0m\t%s\n"
- " Quit after sync: \e[1;30m(-q)\e[0m\t\t%s\n"
- " Force quote cache rebuild: \e[1;30m(-w)\e[0m\t%s\n"
- "\n",
-
- Config.CacheDir,
-
- Config.RootDir,
- StringsDiffer(Config.RootURL, "") ? Config.RootURL : "[empty]",
-
- StringsDiffer(Config.CSSDir, "") ? Config.CSSDir : "(same as root)",
- StringsDiffer(Config.ImagesDir, "") ? Config.ImagesDir : "(same as root)",
- StringsDiffer(Config.JSDir, "") ? Config.JSDir : "(same as root)",
-
- Config.ProjectID,
- Config.DefaultMedium,
- Config.Theme,
-
- Config.ProjectDir,
- Config.TemplatesDir,
- StringsDiffer(Config.TemplateIndexLocation, "") ? Config.TemplateIndexLocation : "[none set]",
- StringsDiffer(Config.TemplatePlayerLocation, "") ? Config.TemplatePlayerLocation : "[none set]",
-
- Config.BaseDir,
- StringsDiffer(Config.BaseURL, "") ? Config.BaseURL : "[empty]",
- StringsDiffer(Config.IndexLocation, "") ? Config.IndexLocation : "(same as base)",
- StringsDiffer(Config.PlayerLocation, "") ? Config.PlayerLocation : "(directly descended from base)",
- StringsDiffer(Config.PlayerURLPrefix, "") ? Config.PlayerURLPrefix : Config.ProjectID,
-
- Config.Mode & MODE_SINGLETAB ? "on" : "off",
- Config.Mode & MODE_FORCEINTEGRATION ? "on" : "off",
- Config.Mode & MODE_NOPRIVACY ? "on" : "off",
- Config.Mode & MODE_ONESHOT ? "on" : "off",
- Config.Mode & MODE_NOCACHE ? "on" : "off");
-
- if((StringsDiffer(Config.IndexLocation, "") || StringsDiffer(Config.PlayerLocation, ""))
- && StringLength(Config.BaseURL) == 0)
- {
- printf("\e[1;33mPlease set a Project Base URL (-B) so we can output the Index / Player pages to\n"
- "locations other than the defaults\e[0m\n");
- return(RC_SUCCESS);
- }
-
- index Index = { };
-
- Index.Metadata.Buffer.ID = "IndexMetadata";
- CopyString(Index.Metadata.Path, sizeof(Index.Metadata.Path), "%s/%s.metadata", Config.BaseDir, Config.ProjectID);
- ReadFileIntoBuffer(&Index.Metadata, 0); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
-
- Index.File.Buffer.ID = "IndexFile";
- CopyString(Index.File.Path, sizeof(Index.File.Path), "%s/%s.index", Config.BaseDir, Config.ProjectID);
- ReadFileIntoBuffer(&Index.File, 0); // NOTE(matt): Could we actually catch errors (permissions?) here and bail?
-
- printf("┌╼ Synchronising with Annotations Directory ╾┐\n");
- SyncIndexWithInput(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate);
+ printf("\n┌╼ Synchronising with Annotations Directory ╾┐\n");
+ SyncDBWithInput(&CollationBuffers, SearchTemplate, PlayerTemplate, BespokeTemplate);
if(Config.Mode & MODE_ONESHOT)
{
goto RIP;
}
- printf("\n┌╼ Monitoring Annotations Directory for \e[1;32mnew\e[0m, \e[1;33medited\e[0m and \e[1;30mdeleted\e[0m .hmml files ╾┐\n");
- int inotifyInstance = inotify_init1(IN_NONBLOCK);
+ printf("\n┌╼ Monitoring Annotations Directory for %snew%s, %sedited%s and %sdeleted%s .hmml files ╾┐\n",
+ ColourStrings[EditTypes[EDIT_ADDITION].Colour], ColourStrings[CS_END],
+ ColourStrings[EditTypes[EDIT_REINSERTION].Colour], ColourStrings[CS_END],
+ ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END]);
// NOTE(matt): Do we want to also watch IN_DELETE_SELF events?
- int WatchDescriptor = inotify_add_watch(inotifyInstance, Config.ProjectDir, IN_CLOSE_WRITE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO);
+ PushHMMLWatchHandle();
- while(MonitorDirectory(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate, inotifyInstance, WatchDescriptor) != RC_ARENA_FULL)
+ while(MonitorFilesystem(&CollationBuffers, SearchTemplate, PlayerTemplate, BespokeTemplate) != RC_ARENA_FULL)
{
// TODO(matt): Refetch the quotes and rebuild player pages if needed
//
- // Every sixty mins, redownload the quotes and, I suppose, SyncIndexWithInput(). But here we still don't even know
+ // Every sixty mins, redownload the quotes and, I suppose, SyncDBWithInput(). But here we still don't even know
// who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe
// postpone this for now, but we will certainly need this to happen
//
@@ -6737,13 +9095,14 @@ main(int ArgC, char **Args)
//
if(!(Config.Mode & MODE_NOPRIVACY) && time(0) - LastPrivacyCheck > 60 * 60 * 4)
{
- RecheckPrivacy(&Index, &CollationBuffers, IndexTemplate, PlayerTemplate, BespokeTemplate);
+ RecheckPrivacy(&CollationBuffers, SearchTemplate, PlayerTemplate, BespokeTemplate);
}
sleep(Config.UpdateInterval);
}
}
else
{
+ // TODO(matt): Get rid of Single Edition once and for all, probably for v1.0.0
if(optind == ArgC)
{
fprintf(stderr, "%s: requires at least one input .hmml file\n", Args[0]);
@@ -6751,6 +9110,11 @@ main(int ArgC, char **Args)
goto RIP;
}
+ inotifyInstance = inotify_init1(IN_NONBLOCK);
+
+ printf("┌╼ Hashing assets ╾┐\n");
+ InitBuiltinAssets();
+
NextFile:
// TODO(matt): Just change the default output location so all these guys won't overwrite each other
for(int FileIndex = optind; FileIndex < ArgC; ++FileIndex)
@@ -6794,7 +9158,7 @@ NextFile:
goto RIP;
case RC_SUCCESS:
#if 0
- fprintf(stdout, "\e[1;32mWritten\e[0m %s\n", HasBespokeTemplate ? Config.OutIntegratedLocation : Config.OutLocation);
+ fprintf(stdout, "%sWritten%s %s\n", HasBespokeTemplate ? Config.OutIntegratedLocation : Config.OutLocation);
#endif
if(HasBespokeTemplate) { DeclaimTemplate(BespokeTemplate); }
break;
@@ -6807,13 +9171,13 @@ NextFile:
{
DeclaimTemplate(PlayerTemplate);
}
- if(Config.Edition == EDITION_PROJECT && StringsDiffer(IndexTemplate->Metadata.Filename, ""))
+ if(Config.Edition == EDITION_PROJECT && StringsDiffer(SearchTemplate->Metadata.Filename, ""))
{
- DeclaimTemplate(IndexTemplate);
+ DeclaimTemplate(SearchTemplate);
}
- DeclaimBuffer(&CollationBuffers.Search);
- DeclaimBuffer(&CollationBuffers.IncludesIndex);
+ DeclaimBuffer(&CollationBuffers.SearchEntry);
+ DeclaimBuffer(&CollationBuffers.IncludesSearch);
DeclaimBuffer(&CollationBuffers.ScriptPlayer);
DeclaimBuffer(&CollationBuffers.Player);