cinera.c: Binary search the .metadata
Also optimise out superfluous searches, and relieve IndexToBuffer() of the need to string-search the .index Rewrite the table of contents page after deleting an entry This commit also retains profiling, as a reminder to me how I used it, and the old linear search code. The timing blocks and the old code may be deleted in a future commit
This commit is contained in:
parent
ab598e37e6
commit
de2c632806
316
cinera/cinera.c
316
cinera/cinera.c
|
@ -14,20 +14,21 @@ typedef struct
|
|||
version CINERA_APP_VERSION = {
|
||||
.Major = 0,
|
||||
.Minor = 5,
|
||||
.Patch = 37
|
||||
.Patch = 38
|
||||
};
|
||||
|
||||
// TODO(matt): Copy in the DB 3 stuff from cinera_working.c
|
||||
#define CINERA_DB_VERSION 3
|
||||
|
||||
#define DEBUG 0
|
||||
#define DEBUG_MEM 0
|
||||
|
||||
typedef unsigned int bool;
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define DEBUG 0
|
||||
#define DEBUG_MEM 0
|
||||
#define BINARY_SEARCH 1
|
||||
bool PROFILING = 0;
|
||||
|
||||
#include <stdarg.h> // NOTE(matt): varargs
|
||||
#include <stdio.h> // NOTE(matt): printf, sprintf, vsprintf, fprintf, perror
|
||||
#include <stdlib.h> // NOTE(matt): calloc, malloc, free
|
||||
|
@ -44,6 +45,10 @@ typedef unsigned int bool;
|
|||
#include <sys/inotify.h> // NOTE(matt): inotify
|
||||
#include <unistd.h> // NOTE(matt): sleep()
|
||||
|
||||
clock_t TIMING_START;
|
||||
#define START_TIMING_BLOCK(...) if(PROFILING) { printf(__VA_ARGS__); TIMING_START = clock(); }
|
||||
#define END_TIMING_BLOCK() if(PROFILING) { printf("\e[1;34m%ld\e[0m\n", clock() - TIMING_START);}
|
||||
|
||||
#define Kilobytes(Bytes) Bytes << 10
|
||||
#define Megabytes(Bytes) Bytes << 20
|
||||
|
||||
|
@ -880,11 +885,17 @@ DeclaimBuffer(buffer *Buffer)
|
|||
MemoryArena.Ptr - MemoryArena.Location);
|
||||
#endif
|
||||
LogUsage(Buffer);
|
||||
if(PercentageUsed >= 80.0f)
|
||||
if(PercentageUsed >= 95.0f)
|
||||
{
|
||||
// TODO(matt): Implement either dynamically growing buffers, or phoning home to matt@handmadedev.org
|
||||
LogError(LOG_ERROR, "%s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed);
|
||||
fprintf(stderr, "Warning: %s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed);
|
||||
fprintf(stderr, "\e[1;31mWarning\e[0m: %s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed);
|
||||
}
|
||||
else if(PercentageUsed >= 80.0f)
|
||||
{
|
||||
// TODO(matt): Implement either dynamically growing buffers, or phoning home to matt@handmadedev.org
|
||||
LogError(LOG_ERROR, "%s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed);
|
||||
fprintf(stderr, "\e[0;33mWarning\e[0m: %s used %.2f%% of its allotted memory\n", Buffer->ID, PercentageUsed);
|
||||
}
|
||||
Buffer->Size = 0;
|
||||
}
|
||||
|
@ -2916,7 +2927,7 @@ HMMLToBuffers(buffers *CollationBuffers, template **BespokeTemplate, char *Filen
|
|||
if(ClaimBuffer(&AnnotationClass, "AnnotationClass", 256) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; };
|
||||
if(ClaimBuffer(&AnnotationData, "AnnotationData", 512) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; };
|
||||
if(ClaimBuffer(&Text, "Text", Kilobytes(4)) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; };
|
||||
if(ClaimBuffer(&CategoryIcons, "CategoryIcons", 512) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; };
|
||||
if(ClaimBuffer(&CategoryIcons, "CategoryIcons", Kilobytes(1)) == RC_ARENA_FULL) { hmml_free(&HMML); return RC_ARENA_FULL; };
|
||||
|
||||
CopyStringToBuffer(&AnnotationHeader,
|
||||
" <div data-timestamp=\"%d\"",
|
||||
|
@ -4373,7 +4384,61 @@ SeekBufferForString(buffer *Buffer, char *String,
|
|||
}
|
||||
|
||||
int
|
||||
InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename)
|
||||
BinarySearchForMetadataEntry(index *Index, index_metadata **Test, char *SearchTerm)
|
||||
{
|
||||
int Lower = 0;
|
||||
index_metadata *LowerEntry = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * Lower);
|
||||
if(StringsDiffer(SearchTerm, LowerEntry->BaseFilename) < 0 ) { return Lower; }
|
||||
|
||||
int Upper = Index->Header.EntryCount - 1;
|
||||
int Pivot = Upper - ((Upper - Lower) >> 1);
|
||||
index_metadata *UpperEntry;
|
||||
index_metadata *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);
|
||||
|
||||
if(!StringsDiffer(SearchTerm, LowerEntry->BaseFilename)) { *Test = LowerEntry; return Lower; }
|
||||
if(!StringsDiffer(SearchTerm, PivotEntry->BaseFilename)) { *Test = PivotEntry; return Pivot; }
|
||||
if(!StringsDiffer(SearchTerm, UpperEntry->BaseFilename)) { *Test = UpperEntry; return Upper; }
|
||||
|
||||
if((StringsDiffer(SearchTerm, PivotEntry->BaseFilename) < 0)) { Upper = Pivot; }
|
||||
else { Lower = Pivot; }
|
||||
Pivot = Upper - ((Upper - Lower) >> 1);
|
||||
} while(Upper > Pivot);
|
||||
return Upper;
|
||||
}
|
||||
|
||||
int
|
||||
AccumulateIndexEntryInsertionOffset(index *Index, int EntryIndex)
|
||||
{
|
||||
int Result = 0;
|
||||
index_metadata *AccEntry = { 0 };
|
||||
if(EntryIndex < Index->Header.EntryCount >> 1)
|
||||
{
|
||||
for(; EntryIndex > 0; --EntryIndex)
|
||||
{
|
||||
AccEntry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * (EntryIndex - 1));
|
||||
Result += AccEntry->Size;
|
||||
}
|
||||
Result += StringLength("---\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for(; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
|
||||
{
|
||||
AccEntry = (index_metadata*)(Index->Metadata.Buffer.Location + sizeof(index_header) + sizeof(index_metadata) * EntryIndex);
|
||||
Result += AccEntry->Size;
|
||||
}
|
||||
Result = Index->File.FileSize - Result;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
int
|
||||
InsertIntoIndex(index *Index, int *EntryIndex, buffers *CollationBuffers, template **BespokeTemplate, char *BaseFilename)
|
||||
{
|
||||
int IndexMetadataFileReadCode = ReadFileIntoBuffer(&Index->Metadata, 0);
|
||||
switch(IndexMetadataFileReadCode)
|
||||
|
@ -4399,12 +4464,11 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl
|
|||
int IndexEntryInsertionStart = -1;
|
||||
int IndexEntryInsertionEnd = -1;
|
||||
Index->Header.EntryCount = 0;
|
||||
char *IndexEntryStart;
|
||||
bool Found = FALSE;
|
||||
|
||||
int EntryIndex;
|
||||
neighbours Neighbours = { 0 };
|
||||
index_metadata *This, *Next;
|
||||
index_metadata *This = { 0 };
|
||||
index_metadata *Next = { 0 };
|
||||
if(IndexMetadataFileReadCode == RC_SUCCESS && IndexFileReadCode == RC_SUCCESS)
|
||||
{
|
||||
// TODO(matt): Index validation?
|
||||
|
@ -4421,15 +4485,70 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl
|
|||
|
||||
Index->Metadata.Buffer.Ptr += sizeof(Index->Header);
|
||||
Index->File.Buffer.Ptr += StringLength("---\n");
|
||||
IndexEntryStart = Index->File.Buffer.Ptr;
|
||||
|
||||
for(EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
|
||||
#if BINARY_SEARCH
|
||||
START_TIMING_BLOCK(" InsertIntoIndex(%s) BinarySearch: ", BaseFilename);
|
||||
index_metadata *Prev = { 0 };
|
||||
*EntryIndex = BinarySearchForMetadataEntry(Index, &This, BaseFilename);
|
||||
if(This)
|
||||
{
|
||||
// Reinsert
|
||||
Found = TRUE;
|
||||
MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * *EntryIndex;
|
||||
IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex);
|
||||
IndexEntryInsertionEnd = IndexEntryInsertionStart + This->Size;
|
||||
if(*EntryIndex > 0)
|
||||
{
|
||||
Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex - 1));
|
||||
Neighbours.Prev.BaseFilename = Prev->BaseFilename;
|
||||
Neighbours.Prev.Title = Prev->Title;
|
||||
}
|
||||
if(*EntryIndex < Index->Header.EntryCount - 1)
|
||||
{
|
||||
Next = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex + 1));
|
||||
Neighbours.Next.BaseFilename = Next->BaseFilename;
|
||||
Neighbours.Next.Title = Next->Title;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
This = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * *EntryIndex);
|
||||
if(StringsDiffer(BaseFilename, This->BaseFilename) < 0)
|
||||
{
|
||||
// Insert
|
||||
MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * *EntryIndex;
|
||||
IndexEntryInsertionStart = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex);
|
||||
if(*EntryIndex > 0)
|
||||
{
|
||||
Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (*EntryIndex - 1));
|
||||
Neighbours.Prev.BaseFilename = Prev->BaseFilename;
|
||||
Neighbours.Prev.Title = Prev->Title;
|
||||
}
|
||||
Neighbours.Next.BaseFilename = This->BaseFilename;
|
||||
Neighbours.Next.Title = This->Title;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append
|
||||
if(*EntryIndex > 0)
|
||||
{
|
||||
Neighbours.Prev.BaseFilename = This->BaseFilename;
|
||||
Neighbours.Prev.Title = This->Title;
|
||||
}
|
||||
++*EntryIndex;
|
||||
}
|
||||
}
|
||||
#else
|
||||
START_TIMING_BLOCK(" InsertIntoIndex(%s) LinearSearch: ", BaseFilename);
|
||||
char *IndexEntryStart;
|
||||
IndexEntryStart = Index->File.Buffer.Ptr;
|
||||
for(*EntryIndex = 0; *EntryIndex < Index->Header.EntryCount; ++*EntryIndex)
|
||||
{
|
||||
This = (index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
if(!StringsDiffer(This->BaseFilename, BaseFilename))
|
||||
{
|
||||
// Reinsert
|
||||
if(EntryIndex < (Index->Header.EntryCount - 1))
|
||||
if(*EntryIndex < (Index->Header.EntryCount - 1))
|
||||
{
|
||||
Next = (index_metadata *)(Index->Metadata.Buffer.Ptr + sizeof(Index->Entry));
|
||||
Neighbours.Next.BaseFilename = Next->BaseFilename;
|
||||
|
@ -4463,9 +4582,11 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl
|
|||
Neighbours.Prev.Title = This->Title;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
START_TIMING_BLOCK(" InsertIntoIndex(%s) NoSearch: ", BaseFilename);
|
||||
// NOTE(matt): Initialising new index_header
|
||||
Index->Header.CurrentDBVersion = CINERA_DB_VERSION;
|
||||
Index->Header.CurrentAppVersion = CINERA_APP_VERSION;
|
||||
|
@ -4507,6 +4628,7 @@ InsertIntoIndex(index *Index, buffers *CollationBuffers, template **BespokeTempl
|
|||
}
|
||||
closedir(OutputDirectoryHandle);
|
||||
}
|
||||
END_TIMING_BLOCK();
|
||||
|
||||
char InputFile[StringLength(BaseFilename) + StringLength(".hmml")];
|
||||
CopyString(InputFile, "%s.hmml", BaseFilename);
|
||||
|
@ -4783,7 +4905,7 @@ int DeleteNeighbourLinks(file_buffer *File, index_metadata *Metadata)
|
|||
}
|
||||
}
|
||||
|
||||
int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
|
||||
int LinkNeighbours(index *Index, int EntryIndex, char *BaseFilename, int LinkType)
|
||||
{
|
||||
switch(ReadFileIntoBuffer(&Index->Metadata, 0))
|
||||
{
|
||||
|
@ -4801,8 +4923,24 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
|
|||
index_metadata *Prev = { 0 };
|
||||
index_metadata *This = { 0 };
|
||||
index_metadata *Next = { 0 };
|
||||
int EntryIndex = 0;
|
||||
|
||||
#if BINARY_SEARCH
|
||||
START_TIMING_BLOCK(" LinkNeighbours(%s) [passing in EntryIndex]: ", BaseFilename);
|
||||
This = (index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
if(Index->Header.EntryCount != 1)
|
||||
{
|
||||
This = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * EntryIndex);
|
||||
if(EntryIndex > 0)
|
||||
{
|
||||
Prev = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (EntryIndex - 1));
|
||||
}
|
||||
if(EntryIndex < Index->Header.EntryCount - 1)
|
||||
{
|
||||
Next = (index_metadata*)(Index->Metadata.Buffer.Ptr + sizeof(index_metadata) * (EntryIndex + 1));
|
||||
}
|
||||
}
|
||||
#else
|
||||
START_TIMING_BLOCK(" LinkNeighbours(%s) LinearSearch: ", BaseFilename);
|
||||
switch(LinkType)
|
||||
{
|
||||
case LINK_INCLUDE:
|
||||
|
@ -4848,6 +4986,8 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
|
|||
}
|
||||
} break;
|
||||
}
|
||||
#endif
|
||||
END_TIMING_BLOCK();
|
||||
|
||||
if(!Prev && !Next)
|
||||
{
|
||||
|
@ -4953,7 +5093,7 @@ int LinkNeighbours(index *Index, char *BaseFilename, int LinkType)
|
|||
}
|
||||
|
||||
int
|
||||
DeleteFromIndex(index *Index, char *BaseFilename)
|
||||
DeleteFromIndex(index *Index, int *EntryIndex, char *BaseFilename)
|
||||
{
|
||||
// TODO(matt): LogError()
|
||||
switch(ReadFileIntoBuffer(&Index->Metadata, 0))
|
||||
|
@ -4985,9 +5125,23 @@ DeleteFromIndex(index *Index, char *BaseFilename)
|
|||
int DeleteMetadataFrom = -1;
|
||||
int DeleteFileFrom = -1;
|
||||
int DeleteFileTo = -1;
|
||||
int SizeAcc = 0;
|
||||
|
||||
for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata))
|
||||
#if BINARY_SEARCH
|
||||
START_TIMING_BLOCK(" DeleteFromIndex(%s) BinarySearch: ", BaseFilename);
|
||||
index_metadata *This = { 0 };
|
||||
*EntryIndex = BinarySearchForMetadataEntry(Index, &This, BaseFilename);
|
||||
if(This)
|
||||
{
|
||||
Found = TRUE;
|
||||
DeleteMetadataFrom = (char *)This - Index->Metadata.Buffer.Location;
|
||||
DeleteFileFrom = AccumulateIndexEntryInsertionOffset(Index, *EntryIndex);
|
||||
DeleteFileTo = DeleteFileFrom + This->Size;
|
||||
--Index->Header.EntryCount;
|
||||
}
|
||||
#else
|
||||
START_TIMING_BLOCK(" DeleteFromIndex(%s) LinearSearch: ", BaseFilename);
|
||||
int SizeAcc = 0;
|
||||
for(*EntryIndex = 0; *EntryIndex < Index->Header.EntryCount; ++*EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata))
|
||||
{
|
||||
index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
if(!StringsDiffer(This.BaseFilename, BaseFilename))
|
||||
|
@ -5001,6 +5155,9 @@ DeleteFromIndex(index *Index, char *BaseFilename)
|
|||
}
|
||||
SizeAcc += This.Size;
|
||||
}
|
||||
#endif
|
||||
END_TIMING_BLOCK();
|
||||
|
||||
|
||||
if(Found)
|
||||
{
|
||||
|
@ -5019,6 +5176,11 @@ DeleteFromIndex(index *Index, char *BaseFilename)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(*EntryIndex == Index->Header.EntryCount) // NOTE(matt): LinkNeighbours() requires this
|
||||
{
|
||||
--*EntryIndex;
|
||||
}
|
||||
|
||||
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; }
|
||||
|
||||
|
@ -5043,18 +5205,10 @@ DeleteFromIndex(index *Index, char *BaseFilename)
|
|||
int
|
||||
IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy malloc's CollationBuffers->Index
|
||||
{
|
||||
// TODO(matt): Consider parsing the index into a linked / skip list, or do something to save us having to iterate through
|
||||
// the index file multiple times
|
||||
|
||||
int IndexMetadataFileReadCode = ReadFileIntoBuffer(&Index->Metadata, 0);
|
||||
int IndexFileReadCode = ReadFileIntoBuffer(&Index->File, 0);
|
||||
|
||||
if(IndexMetadataFileReadCode == RC_SUCCESS && IndexFileReadCode == RC_SUCCESS)
|
||||
if(ReadFileIntoBuffer(&Index->Metadata, 0) == RC_SUCCESS)
|
||||
{
|
||||
Index->Header = *(index_header*)Index->Metadata.Buffer.Ptr;
|
||||
Index->Metadata.Buffer.Ptr += sizeof(Index->Header);
|
||||
Index->File.Buffer.Ptr += StringLength("---\n");
|
||||
char *IndexEntryStart = Index->File.Buffer.Ptr;
|
||||
|
||||
bool ProjectFound = FALSE;
|
||||
int ProjectIndex;
|
||||
|
@ -5071,12 +5225,12 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m
|
|||
{
|
||||
fprintf(stderr, "Missing Project Info for %s\n", Config.ProjectID);
|
||||
FreeBuffer(&Index->Metadata.Buffer);
|
||||
FreeBuffer(&Index->File.Buffer);
|
||||
return RC_ERROR_PROJECT;
|
||||
}
|
||||
|
||||
int ThemeStringLength = StringsDiffer(Config.Theme, "") ? (StringLength(Config.Theme) * 2) : (StringLength(Config.ProjectID) * 2);
|
||||
char queryContainer[680 + ThemeStringLength];
|
||||
char *Theme = StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID;
|
||||
int ThemeStringAllowance = StringLength(Theme) * 2;
|
||||
char queryContainer[680 + ThemeStringAllowance];
|
||||
CopyString(queryContainer,
|
||||
"<div class=\"cineraQueryContainer %s\">\n"
|
||||
" <label for=\"query\">Query:</label>\n"
|
||||
|
@ -5093,8 +5247,8 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m
|
|||
" <div id=\"cineraIndex\" class=\"%s\">\n"
|
||||
" <div id=\"cineraIndexSort\">Sort: Old to New ⏶</div>\n"
|
||||
" <div id=\"cineraIndexEntries\">\n",
|
||||
StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID,
|
||||
StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID);
|
||||
Theme,
|
||||
Theme);
|
||||
|
||||
buffer URLPrefix;
|
||||
ClaimBuffer(&URLPrefix, "URLPrefix", 1024);
|
||||
|
@ -5118,7 +5272,7 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m
|
|||
" </script>\n"
|
||||
" <script type=\"text/javascript\" src=\"%scinera_search.js\"></script>\n",
|
||||
Config.ProjectID,
|
||||
StringsDiffer(Config.Theme, "") ? Config.Theme : Config.ProjectID,
|
||||
Theme,
|
||||
Config.BaseURL,
|
||||
Config.PlayerLocation,
|
||||
StringsDiffer(Config.PlayerURLPrefix, "") ? Config.PlayerURLPrefix : Config.ProjectID,
|
||||
|
@ -5132,18 +5286,26 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m
|
|||
if(!(CollationBuffers->Index.Location = malloc(CollationBuffers->Index.Size)))
|
||||
{
|
||||
FreeBuffer(&Index->Metadata.Buffer);
|
||||
FreeBuffer(&Index->File.Buffer);
|
||||
return(RC_ERROR_MEMORY);
|
||||
}
|
||||
CollationBuffers->Index.Ptr = CollationBuffers->Index.Location;
|
||||
|
||||
CopyStringToBuffer(&CollationBuffers->Index, queryContainer);
|
||||
|
||||
for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
|
||||
char *ProjectUnit = 0;
|
||||
if(StringsDiffer(ProjectInfo[ProjectIndex].Unit, ""))
|
||||
{
|
||||
index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
char Number[16];
|
||||
CopyString(Number, This.BaseFilename + StringLength(Config.ProjectID));
|
||||
ProjectUnit = ProjectInfo[ProjectIndex].Unit;
|
||||
}
|
||||
int ProjectIDLength = StringLength(Config.ProjectID);
|
||||
char Number[16];
|
||||
char Text[1024]; // NOTE(matt): Surely this will be big enough
|
||||
index_metadata *This;
|
||||
|
||||
for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex, Index->Metadata.Buffer.Ptr += sizeof(index_metadata))
|
||||
{
|
||||
This = (index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
CopyString(Number, This->BaseFilename + ProjectIDLength);
|
||||
if(ProjectInfo[ProjectIndex].NumberingScheme == NS_LINEAR)
|
||||
{
|
||||
for(int i = 0; Number[i]; ++i)
|
||||
|
@ -5155,24 +5317,18 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m
|
|||
}
|
||||
}
|
||||
|
||||
SeekBufferForString(&Index->File.Buffer, "title: \"", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
char Title[256];
|
||||
CopyStringNoFormatT(Title, Index->File.Buffer.Ptr, '\n');
|
||||
Title[StringLength(Title) - 1] = '\0';
|
||||
ConstructPlayerURL(&PlayerURL, This->BaseFilename);
|
||||
|
||||
ConstructPlayerURL(&PlayerURL, This.BaseFilename);
|
||||
|
||||
if(StringsDiffer(ProjectInfo[ProjectIndex].Unit, ""))
|
||||
if(ProjectUnit)
|
||||
{
|
||||
CopyStringToBuffer(&CollationBuffers->Index,
|
||||
" <div>\n"
|
||||
" <a href=\"%s\">", PlayerURL.Location);
|
||||
|
||||
char Text[1024]; // NOTE(matt): Surely this will be big enough
|
||||
CopyString(Text, "%s %s: %s",
|
||||
ProjectInfo[ProjectIndex].Unit, // TODO(matt): Do we need to special-case the various numbering schemes?
|
||||
ProjectUnit, // TODO(matt): Do we need to special-case the various numbering schemes?
|
||||
Number,
|
||||
Title);
|
||||
This->Title);
|
||||
|
||||
CopyStringToBufferHTMLSafe(&CollationBuffers->Index, Text);
|
||||
|
||||
|
@ -5184,15 +5340,13 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m
|
|||
{
|
||||
CopyStringToBuffer(&CollationBuffers->Index,
|
||||
" <div>\n"
|
||||
" <a href=\"%s\">%s</a>\n"
|
||||
" </div>\n",
|
||||
PlayerURL.Location,
|
||||
Title);
|
||||
}
|
||||
" <a href=\"%s\">", PlayerURL.Location);
|
||||
|
||||
Index->Metadata.Buffer.Ptr += sizeof(Index->Entry);
|
||||
IndexEntryStart += This.Size;
|
||||
Index->File.Buffer.Ptr = IndexEntryStart;
|
||||
CopyStringToBufferHTMLSafe(&CollationBuffers->Index, This->Title);
|
||||
CopyStringToBuffer(&CollationBuffers->Index,
|
||||
"</a>\n"
|
||||
" </div>\n");
|
||||
}
|
||||
}
|
||||
|
||||
DeclaimBuffer(&PlayerURL);
|
||||
|
@ -5200,7 +5354,6 @@ IndexToBuffer(index *Index, buffers *CollationBuffers) // NOTE(matt): This guy m
|
|||
CopyStringToBuffer(&CollationBuffers->Index, Script);
|
||||
|
||||
FreeBuffer(&Index->Metadata.Buffer);
|
||||
FreeBuffer(&Index->File.Buffer);
|
||||
return RC_SUCCESS;
|
||||
}
|
||||
else
|
||||
|
@ -5242,7 +5395,7 @@ StripSurroundingSlashes(char *String) // NOTE(matt): For relative paths
|
|||
}
|
||||
|
||||
int
|
||||
GeneratePlayerPage(index *Index, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename)
|
||||
GeneratePlayerPage(index *Index, int EntryIndex, buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename)
|
||||
{
|
||||
buffer OutputDirectoryPath;
|
||||
ClaimBuffer(&OutputDirectoryPath, "OutputDirectoryPath", 1024);
|
||||
|
@ -5281,7 +5434,12 @@ GeneratePlayerPage(index *Index, buffers *CollationBuffers, template *PlayerTemp
|
|||
ReadFileIntoBuffer(&Index->Metadata, 0);
|
||||
Index->Metadata.Buffer.Ptr += sizeof(index_header);
|
||||
int MetadataInsertionOffset = 0;
|
||||
for(int EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
|
||||
#if BINARY_SEARCH
|
||||
START_TIMING_BLOCK(" GeneratePlayerPage(%s) [passing in EntryIndex]: ", BaseFilename);
|
||||
MetadataInsertionOffset = sizeof(index_header) + sizeof(index_metadata) * EntryIndex;
|
||||
#else
|
||||
START_TIMING_BLOCK(" GeneratePlayerPage(%s) LinearSearch: ", BaseFilename);
|
||||
for(EntryIndex = 0; EntryIndex < Index->Header.EntryCount; ++EntryIndex)
|
||||
{
|
||||
index_metadata This = *(index_metadata *)Index->Metadata.Buffer.Ptr;
|
||||
if(!StringsDiffer(This.BaseFilename, Index->Entry.BaseFilename))
|
||||
|
@ -5291,11 +5449,13 @@ GeneratePlayerPage(index *Index, buffers *CollationBuffers, template *PlayerTemp
|
|||
}
|
||||
Index->Metadata.Buffer.Ptr += sizeof(index_metadata);
|
||||
}
|
||||
#endif
|
||||
END_TIMING_BLOCK();
|
||||
|
||||
if(!(Index->Metadata.Handle = fopen(Index->Metadata.Path, "w"))) { FreeBuffer(&Index->Metadata.Buffer); return RC_ERROR_FILE; }
|
||||
fwrite(Index->Metadata.Buffer.Location, MetadataInsertionOffset, 1, Index->Metadata.Handle);
|
||||
fwrite(&Index->Entry, sizeof(Index->Entry), 1, Index->Metadata.Handle);
|
||||
fwrite(Index->Metadata.Buffer.Ptr + sizeof(Index->Entry), Index->Metadata.FileSize - MetadataInsertionOffset - sizeof(Index->Entry), 1, Index->Metadata.Handle);
|
||||
fwrite(Index->Metadata.Buffer.Location + MetadataInsertionOffset + sizeof(Index->Entry), Index->Metadata.FileSize - MetadataInsertionOffset - sizeof(Index->Entry), 1, Index->Metadata.Handle);
|
||||
fclose(Index->Metadata.Handle);
|
||||
FreeBuffer(&Index->Metadata.Buffer);
|
||||
|
||||
|
@ -5374,14 +5534,17 @@ DeletePlayerPageFromFilesystem(char *BaseFilename, char *PlayerLocation, bool Re
|
|||
return RC_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
DeleteEntry(index *Index, char *BaseFilename)
|
||||
{
|
||||
if(DeleteFromIndex(Index, BaseFilename) == RC_SUCCESS)
|
||||
int EntryIndex = 0;
|
||||
if(DeleteFromIndex(Index, &EntryIndex, BaseFilename) == RC_SUCCESS)
|
||||
{
|
||||
LinkNeighbours(Index, BaseFilename, LINK_EXCLUDE);
|
||||
LinkNeighbours(Index, EntryIndex, BaseFilename, LINK_EXCLUDE);
|
||||
DeletePlayerPageFromFilesystem(BaseFilename, Config.PlayerLocation, FALSE);
|
||||
return RC_SUCCESS;
|
||||
}
|
||||
return RC_NOOP;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -5419,24 +5582,28 @@ MonitorDirectory(index *Index, buffers *CollationBuffers, template *IndexTemplat
|
|||
// TODO(matt): Maybe handle IN_ALL_EVENTS
|
||||
if(Event->mask & IN_DELETE || Event->mask & IN_MOVED_FROM)
|
||||
{
|
||||
DeleteEntry(Index, BaseFilename);
|
||||
if(DeleteEntry(Index, BaseFilename) == RC_SUCCESS)
|
||||
{
|
||||
GenerateIndexPage(Index, CollationBuffers, IndexTemplate);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(InsertIntoIndex(Index, CollationBuffers, &BespokeTemplate, BaseFilename))
|
||||
int EntryIndex = 0;
|
||||
switch(InsertIntoIndex(Index, &EntryIndex, CollationBuffers, &BespokeTemplate, BaseFilename))
|
||||
{
|
||||
case RC_SUCCESS:
|
||||
case RC_UNFOUND:
|
||||
LinkNeighbours(Index, BaseFilename, LINK_INCLUDE);
|
||||
LinkNeighbours(Index, EntryIndex, BaseFilename, LINK_INCLUDE);
|
||||
{
|
||||
if(BespokeTemplate->Metadata.Filename && StringsDiffer(BespokeTemplate->Metadata.Filename, ""))
|
||||
{
|
||||
GeneratePlayerPage(Index, CollationBuffers, BespokeTemplate, BaseFilename);
|
||||
GeneratePlayerPage(Index, EntryIndex, CollationBuffers, BespokeTemplate, BaseFilename);
|
||||
DeclaimTemplate(BespokeTemplate);
|
||||
}
|
||||
else
|
||||
{
|
||||
GeneratePlayerPage(Index, CollationBuffers, PlayerTemplate, BaseFilename);
|
||||
GeneratePlayerPage(Index, EntryIndex, CollationBuffers, PlayerTemplate, BaseFilename);
|
||||
}
|
||||
GenerateIndexPage(Index, CollationBuffers, IndexTemplate);
|
||||
} break;
|
||||
|
@ -5804,20 +5971,21 @@ SyncIndexWithInput(index *Index, buffers *CollationBuffers, template *IndexTempl
|
|||
if(!(StringsDiffer(Ptr, ".hmml")))
|
||||
{
|
||||
*Ptr = '\0';
|
||||
switch(InsertIntoIndex(Index, CollationBuffers, &BespokeTemplate, ProjectFiles->d_name))
|
||||
int EntryIndex = 0;
|
||||
switch(InsertIntoIndex(Index, &EntryIndex, CollationBuffers, &BespokeTemplate, ProjectFiles->d_name))
|
||||
{
|
||||
case RC_UNFOUND:
|
||||
LinkNeighbours(Index, ProjectFiles->d_name, LINK_INCLUDE);
|
||||
LinkNeighbours(Index, EntryIndex, ProjectFiles->d_name, LINK_INCLUDE);
|
||||
case RC_SUCCESS:
|
||||
{
|
||||
if(BespokeTemplate->Metadata.Filename && StringsDiffer(BespokeTemplate->Metadata.Filename, ""))
|
||||
{
|
||||
GeneratePlayerPage(Index, CollationBuffers, BespokeTemplate, ProjectFiles->d_name);
|
||||
GeneratePlayerPage(Index, EntryIndex, CollationBuffers, BespokeTemplate, ProjectFiles->d_name);
|
||||
DeclaimTemplate(BespokeTemplate);
|
||||
}
|
||||
else
|
||||
{
|
||||
GeneratePlayerPage(Index, CollationBuffers, PlayerTemplate, ProjectFiles->d_name);
|
||||
GeneratePlayerPage(Index, EntryIndex, CollationBuffers, PlayerTemplate, ProjectFiles->d_name);
|
||||
}
|
||||
Inserted = TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue