cinera.c: Fix segfault and event handling
• Segfault was due to a read access violation on an unset entry pointer, which in turn was due to stale neighbourhood data. To fix it we simply reset the neighbourhood when starting to delete an entry. Additionally we now check that those entry pointers are set before accessing them. • Event handling of the trio of events triggered when vim saves a file. We now read in a second set of events while processing the first if we were on the verge of processing a deletion. If we get any more events, we continue to squash those ones if possible, to always end up having seen the entire trio of events associated with a file save, and then process it as an insertion / reinsertion, not a deletion. • Sort the asset landmarks by their offset. • Change GenerateTopicColours() to initially open cinera_topics.css as "r" to search it for the incoming topic, and only if that topic is absent reopen it as "a+", thus triggering an IN_CLOSE_WRITE event.
This commit is contained in:
parent
7edcecfd40
commit
0959fa2774
540
cinera/cinera.c
540
cinera/cinera.c
|
@ -23,7 +23,7 @@ typedef struct
|
||||||
version CINERA_APP_VERSION = {
|
version CINERA_APP_VERSION = {
|
||||||
.Major = 0,
|
.Major = 0,
|
||||||
.Minor = 7,
|
.Minor = 7,
|
||||||
.Patch = 13
|
.Patch = 14
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <stdarg.h> // NOTE(matt): varargs
|
#include <stdarg.h> // NOTE(matt): varargs
|
||||||
|
@ -4238,14 +4238,20 @@ BinarySearchForMetadataLandmark(db_asset *Asset, landmark_range ProjectRange, in
|
||||||
void
|
void
|
||||||
PrintEntryIndex(db_project_index Project, int64_t EntryIndex)
|
PrintEntryIndex(db_project_index Project, int64_t EntryIndex)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s%i:%i%s %s%3li%s",
|
fprintf(stderr, "%s%2i:%2i%s %s%3li%s",
|
||||||
ColourStrings[CS_MAGENTA], Project.Generation, Project.Index, ColourStrings[CS_END],
|
ColourStrings[CS_MAGENTA], Project.Generation, Project.Index, ColourStrings[CS_END],
|
||||||
ColourStrings[CS_BLUE_BOLD], EntryIndex, ColourStrings[CS_END]);
|
ColourStrings[CS_BLUE_BOLD], EntryIndex, ColourStrings[CS_END]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PrintLandmark(db_landmark *L)
|
PrintLandmark(db_landmark *L, uint16_t *Index)
|
||||||
{
|
{
|
||||||
|
if(Index)
|
||||||
|
{
|
||||||
|
Colourise(CS_BLACK_BOLD);
|
||||||
|
fprintf(stderr, "[%4u] ", *Index);
|
||||||
|
Colourise(CS_END);
|
||||||
|
}
|
||||||
PrintEntryIndex(L->Project, L->EntryIndex);
|
PrintEntryIndex(L->Project, L->EntryIndex);
|
||||||
fprintf(stderr, " %6u", L->Position);
|
fprintf(stderr, " %6u", L->Position);
|
||||||
}
|
}
|
||||||
|
@ -4256,7 +4262,7 @@ PrintAsset(db_asset *A, uint16_t *Index)
|
||||||
if(Index)
|
if(Index)
|
||||||
{
|
{
|
||||||
Colourise(CS_BLACK_BOLD);
|
Colourise(CS_BLACK_BOLD);
|
||||||
fprintf(stderr, "[%i]", *Index);
|
fprintf(stderr, "[%4u]", *Index);
|
||||||
Colourise(CS_END);
|
Colourise(CS_END);
|
||||||
}
|
}
|
||||||
string FilenameL = Wrap0i(A->Filename, sizeof(A->Filename));
|
string FilenameL = Wrap0i(A->Filename, sizeof(A->Filename));
|
||||||
|
@ -4301,7 +4307,7 @@ PrintAssetAndLandmarks(db_asset *A, uint16_t *Index)
|
||||||
db_landmark *FirstLandmark = LocateFirstLandmark(A);
|
db_landmark *FirstLandmark = LocateFirstLandmark(A);
|
||||||
//Colourise(CS_BLACK_BOLD); fprintf(stderr, "%4u ", 0); Colourise(CS_END);
|
//Colourise(CS_BLACK_BOLD); fprintf(stderr, "%4u ", 0); Colourise(CS_END);
|
||||||
//PrintLandmark(FirstLandmark);
|
//PrintLandmark(FirstLandmark);
|
||||||
for(int i = 0; i < A->LandmarkCount; ++i)
|
for(uint16_t i = 0; i < A->LandmarkCount; ++i)
|
||||||
{
|
{
|
||||||
db_landmark *This = FirstLandmark + i;
|
db_landmark *This = FirstLandmark + i;
|
||||||
if((i % 8) == 0)
|
if((i % 8) == 0)
|
||||||
|
@ -4312,8 +4318,8 @@ PrintAssetAndLandmarks(db_asset *A, uint16_t *Index)
|
||||||
{
|
{
|
||||||
PrintC(CS_BLACK_BOLD, " │ ");
|
PrintC(CS_BLACK_BOLD, " │ ");
|
||||||
}
|
}
|
||||||
Colourise(CS_BLACK_BOLD); fprintf(stderr, "%4u ", i); Colourise(CS_END);
|
//Colourise(CS_BLACK_BOLD); fprintf(stderr, "%4u ", i); Colourise(CS_END);
|
||||||
PrintLandmark(This);
|
PrintLandmark(This, &i);
|
||||||
}
|
}
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
|
@ -4789,7 +4795,7 @@ SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum)
|
||||||
{
|
{
|
||||||
PrintC(CS_ERROR, "\nInvalid landmark (aborting update): ");
|
PrintC(CS_ERROR, "\nInvalid landmark (aborting update): ");
|
||||||
PrintAsset(Asset, 0);
|
PrintAsset(Asset, 0);
|
||||||
PrintLandmark(Landmark);
|
PrintLandmark(Landmark, 0);
|
||||||
Result = RC_FAILURE;
|
Result = RC_FAILURE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -6904,9 +6910,10 @@ BuildQuote(quote_info *Info, string Speaker, int ID, bool ShouldFetchQuotes)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
rc
|
||||||
GenerateTopicColours(neighbourhood *N, string Topic)
|
GenerateTopicColours(neighbourhood *N, string Topic)
|
||||||
{
|
{
|
||||||
|
// TODO(matt): Maybe straighten out the return code situation?
|
||||||
// NOTE(matt): Stack-string
|
// NOTE(matt): Stack-string
|
||||||
char SanitisedTopic[Topic.Length + 1];
|
char SanitisedTopic[Topic.Length + 1];
|
||||||
CopyString(SanitisedTopic, sizeof(SanitisedTopic), "%.*s", (int)Topic.Length, Topic.Base);
|
CopyString(SanitisedTopic, sizeof(SanitisedTopic), "%.*s", (int)Topic.Length, Topic.Base);
|
||||||
|
@ -6949,43 +6956,27 @@ GenerateTopicColours(neighbourhood *N, string Topic)
|
||||||
closedir(CSSDirHandle);
|
closedir(CSSDirHandle);
|
||||||
*Ptr = '/';
|
*Ptr = '/';
|
||||||
|
|
||||||
if((Topics.Handle = fopen(Topics.Path, "a+")))
|
ReadFileIntoBuffer(&Topics);
|
||||||
|
|
||||||
|
bool Exists = FALSE;
|
||||||
|
while(Topics.Buffer.Ptr - Topics.Buffer.Location < Topics.Buffer.Size)
|
||||||
{
|
{
|
||||||
fseek(Topics.Handle, 0, SEEK_END);
|
Topics.Buffer.Ptr += StringLength(".category.");
|
||||||
Topics.Buffer.Size = ftell(Topics.Handle);
|
if(!StringsDifferT(SanitisedTopic, Topics.Buffer.Ptr, ' '))
|
||||||
fseek(Topics.Handle, 0, SEEK_SET);
|
|
||||||
|
|
||||||
if(!(Topics.Buffer.Location = malloc(Topics.Buffer.Size)))
|
|
||||||
{
|
{
|
||||||
return RC_ERROR_MEMORY;
|
Exists = TRUE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
while(Topics.Buffer.Ptr - Topics.Buffer.Location < Topics.Buffer.Size && *Topics.Buffer.Ptr != '\n')
|
||||||
#if DEBUG_MEM
|
|
||||||
FILE *MemLog = fopen("/home/matt/cinera_mem", "a+");
|
|
||||||
fprintf(MemLog, " Allocated Topics (%ld)\n", Topics.Buffer.Size);
|
|
||||||
fclose(MemLog);
|
|
||||||
printf(" Allocated Topics (%ld)\n", Topics.Buffer.Size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Topics.Buffer.Ptr = Topics.Buffer.Location;
|
|
||||||
fread(Topics.Buffer.Location, Topics.Buffer.Size, 1, Topics.Handle);
|
|
||||||
|
|
||||||
while(Topics.Buffer.Ptr - Topics.Buffer.Location < Topics.Buffer.Size)
|
|
||||||
{
|
{
|
||||||
Topics.Buffer.Ptr += StringLength(".category.");
|
|
||||||
if(!StringsDifferT(SanitisedTopic, Topics.Buffer.Ptr, ' '))
|
|
||||||
{
|
|
||||||
FreeBuffer(&Topics.Buffer);
|
|
||||||
fclose(Topics.Handle);
|
|
||||||
return RC_NOOP;
|
|
||||||
}
|
|
||||||
while(Topics.Buffer.Ptr - Topics.Buffer.Location < Topics.Buffer.Size && *Topics.Buffer.Ptr != '\n')
|
|
||||||
{
|
|
||||||
++Topics.Buffer.Ptr;
|
|
||||||
}
|
|
||||||
++Topics.Buffer.Ptr;
|
++Topics.Buffer.Ptr;
|
||||||
}
|
}
|
||||||
|
++Topics.Buffer.Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Exists)
|
||||||
|
{
|
||||||
|
Topics.Handle = fopen(Topics.Path, "a+");
|
||||||
if(!StringsDifferLv0(Topic, "nullTopic"))
|
if(!StringsDifferLv0(Topic, "nullTopic"))
|
||||||
{
|
{
|
||||||
fprintf(Topics.Handle, ".category.%s { border: 1px solid transparent; background: transparent; }\n",
|
fprintf(Topics.Handle, ".category.%s { border: 1px solid transparent; background: transparent; }\n",
|
||||||
|
@ -6999,14 +6990,15 @@ GenerateTopicColours(neighbourhood *N, string Topic)
|
||||||
SanitisedTopic, Colour.Hue, Colour.Saturation, Colour.Lightness, Colour.Hue, Colour.Saturation, Colour.Lightness);
|
SanitisedTopic, Colour.Hue, Colour.Saturation, Colour.Lightness, Colour.Hue, Colour.Saturation, Colour.Lightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(Topics.Handle);
|
|
||||||
#if DEBUG_MEM
|
#if DEBUG_MEM
|
||||||
MemLog = fopen("/home/matt/cinera_mem", "a+");
|
MemLog = fopen("/home/matt/cinera_mem", "a+");
|
||||||
fprintf(MemLog, " Freed Topics (%ld)\n", Topics.Buffer.Size);
|
fprintf(MemLog, " Freed Topics (%ld)\n", Topics.Buffer.Size);
|
||||||
fclose(MemLog);
|
fclose(MemLog);
|
||||||
printf(" Freed Topics (%ld)\n", Topics.Buffer.Size);
|
printf(" Freed Topics (%ld)\n", Topics.Buffer.Size);
|
||||||
#endif
|
#endif
|
||||||
FreeBuffer(&Topics.Buffer);
|
|
||||||
|
fclose(Topics.Handle);
|
||||||
|
FreeFile(&Topics);
|
||||||
|
|
||||||
asset *Asset = GetPlaceInBook(&Assets, ASSET_CSS_TOPICS);
|
asset *Asset = GetPlaceInBook(&Assets, ASSET_CSS_TOPICS);
|
||||||
if(Asset->Known)
|
if(Asset->Known)
|
||||||
|
@ -7020,14 +7012,8 @@ GenerateTopicColours(neighbourhood *N, string Topic)
|
||||||
asset *CSSTopics = BuiltinAssets + ASSET_CSS_TOPICS;
|
asset *CSSTopics = BuiltinAssets + ASSET_CSS_TOPICS;
|
||||||
PlaceAsset(Wrap0(CSSTopics->Filename), CSSTopics->Type, CSSTopics->Variants, CSSTopics->Associated, ASSET_CSS_TOPICS);
|
PlaceAsset(Wrap0(CSSTopics->Filename), CSSTopics->Type, CSSTopics->Variants, CSSTopics->Associated, ASSET_CSS_TOPICS);
|
||||||
}
|
}
|
||||||
return RC_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// NOTE(matt): Maybe it shouldn't be possible to hit this case now that we MakeDir the actual dir...
|
|
||||||
perror(Topics.Path);
|
|
||||||
return RC_ERROR_FILE;
|
|
||||||
}
|
}
|
||||||
|
return RC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -7166,8 +7152,8 @@ enable syntax highlighting:"));
|
||||||
// Defaults
|
// Defaults
|
||||||
//
|
//
|
||||||
NewSection("Defaults", &IndentationLevel);
|
NewSection("Defaults", &IndentationLevel);
|
||||||
scope_tree *ScopeTree = calloc(1, sizeof(scope_tree));
|
|
||||||
InitScopeBooks(ScopeTree);
|
scope_tree *ScopeTree = InitRootScopeTree();
|
||||||
SetTypeSpec(ScopeTree, &TypeSpecs);
|
SetTypeSpec(ScopeTree, &TypeSpecs);
|
||||||
SetDefaults(ScopeTree, &TypeSpecs);
|
SetDefaults(ScopeTree, &TypeSpecs);
|
||||||
PrintScopeTree(ScopeTree, IndentationLevel);
|
PrintScopeTree(ScopeTree, IndentationLevel);
|
||||||
|
@ -9303,6 +9289,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
||||||
case RC_ERROR_MEMORY:
|
case RC_ERROR_MEMORY:
|
||||||
HMMLCleanup();
|
HMMLCleanup();
|
||||||
return RC_ERROR_FATAL;
|
return RC_ERROR_FATAL;
|
||||||
|
default: break;
|
||||||
};
|
};
|
||||||
if(!HasFilterMenu)
|
if(!HasFilterMenu)
|
||||||
{
|
{
|
||||||
|
@ -9587,6 +9574,7 @@ AppendedIdentifier:
|
||||||
case RC_ERROR_MEMORY:
|
case RC_ERROR_MEMORY:
|
||||||
HMMLCleanup();
|
HMMLCleanup();
|
||||||
return RC_ERROR_FATAL;
|
return RC_ERROR_FATAL;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
if(!HasFilterMenu)
|
if(!HasFilterMenu)
|
||||||
{
|
{
|
||||||
|
@ -9607,6 +9595,7 @@ AppendedIdentifier:
|
||||||
case RC_ERROR_MEMORY:
|
case RC_ERROR_MEMORY:
|
||||||
HMMLCleanup();
|
HMMLCleanup();
|
||||||
return RC_ERROR_FATAL;
|
return RC_ERROR_FATAL;
|
||||||
|
default: break;
|
||||||
};
|
};
|
||||||
InsertCategory(&Topics, &LocalTopics, &Media, &LocalMedia, Wrap0("nullTopic"));
|
InsertCategory(&Topics, &LocalTopics, &Media, &LocalMedia, Wrap0("nullTopic"));
|
||||||
}
|
}
|
||||||
|
@ -10424,9 +10413,48 @@ GenerateNavigation(config *C, project *Target, navigation_buffer *NavBuffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
|
SortLandmarks(memory_book *A)
|
||||||
|
{
|
||||||
|
for(int AssetIndex = 0; AssetIndex < A->ItemCount; ++AssetIndex)
|
||||||
|
{
|
||||||
|
asset *This = GetPlaceInBook(A, AssetIndex);
|
||||||
|
for(int SearchLandmarkIndex = 0; SearchLandmarkIndex < This->SearchLandmarkCount; ++SearchLandmarkIndex)
|
||||||
|
{
|
||||||
|
landmark *A = This->Search + SearchLandmarkIndex;
|
||||||
|
for(int TestIndex = SearchLandmarkIndex + 1; TestIndex < This->SearchLandmarkCount; ++TestIndex)
|
||||||
|
{
|
||||||
|
landmark *B = This->Search + TestIndex;
|
||||||
|
if(A->Offset > B->Offset)
|
||||||
|
{
|
||||||
|
landmark Temp = *A;
|
||||||
|
*A = *B;
|
||||||
|
*B = Temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int PlayerLandmarkIndex = 0; PlayerLandmarkIndex < This->PlayerLandmarkCount; ++PlayerLandmarkIndex)
|
||||||
|
{
|
||||||
|
landmark *A = This->Player + PlayerLandmarkIndex;
|
||||||
|
for(int TestIndex = PlayerLandmarkIndex + 1; TestIndex < This->PlayerLandmarkCount; ++TestIndex)
|
||||||
|
{
|
||||||
|
landmark *B = This->Player + TestIndex;
|
||||||
|
if(A->Offset > B->Offset)
|
||||||
|
{
|
||||||
|
landmark Temp = *A;
|
||||||
|
*A = *B;
|
||||||
|
*B = Temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc
|
||||||
BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *Template, char *OutputPath, page_type PageType, unsigned int *PlayerOffset)
|
BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *Template, char *OutputPath, page_type PageType, unsigned int *PlayerOffset)
|
||||||
{
|
{
|
||||||
|
rc Result = RC_SUCCESS;
|
||||||
MEM_TEST_INITIAL();
|
MEM_TEST_INITIAL();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf("\n\n --- Buffer Collation ---\n"
|
printf("\n\n --- Buffer Collation ---\n"
|
||||||
|
@ -10465,7 +10493,8 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *
|
||||||
LogError(LOG_ERROR, "BuffersToHTML(): %s",
|
LogError(LOG_ERROR, "BuffersToHTML(): %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_ERROR_MEMORY;
|
Result = RC_ERROR_MEMORY;
|
||||||
|
goto End;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_MEM
|
#if DEBUG_MEM
|
||||||
|
@ -10619,7 +10648,8 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_ERROR_FILE;
|
Result = RC_ERROR_FILE;
|
||||||
|
goto End;
|
||||||
}
|
}
|
||||||
fwrite(Master.Location, Master.Ptr - Master.Location, 1, OutFile);
|
fwrite(Master.Location, Master.Ptr - Master.Location, 1, OutFile);
|
||||||
fclose(OutFile);
|
fclose(OutFile);
|
||||||
|
@ -10634,16 +10664,14 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_SUCCESS;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_INVALID_TEMPLATE;
|
Result = RC_INVALID_TEMPLATE;
|
||||||
}
|
}
|
||||||
#endif // AFE
|
#endif // AFE
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_SUCCESS; // NOTE(matt): We added this simply to squash the "end of non-void function" warning
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -10657,7 +10685,8 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *
|
||||||
LogError(LOG_ERROR, "BuffersToHTML(): %s",
|
LogError(LOG_ERROR, "BuffersToHTML(): %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_ERROR_MEMORY;
|
Result = RC_ERROR_MEMORY;
|
||||||
|
goto End;
|
||||||
}
|
}
|
||||||
MEM_TEST_MID("BuffersToHTML3");
|
MEM_TEST_MID("BuffersToHTML3");
|
||||||
Master.Ptr = Master.Location;
|
Master.Ptr = Master.Location;
|
||||||
|
@ -10700,7 +10729,8 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *
|
||||||
LogError(LOG_ERROR, "Unable to open output file %s: %s", OutputPath, strerror(errno));
|
LogError(LOG_ERROR, "Unable to open output file %s: %s", OutputPath, strerror(errno));
|
||||||
DeclaimBuffer(&Master);
|
DeclaimBuffer(&Master);
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_ERROR_FILE;
|
Result = RC_ERROR_FILE;
|
||||||
|
goto End;
|
||||||
}
|
}
|
||||||
MEM_TEST_MID("BuffersToHTML13");
|
MEM_TEST_MID("BuffersToHTML13");
|
||||||
fwrite(Master.Location, Master.Ptr - Master.Location, 1, OutFile);
|
fwrite(Master.Location, Master.Ptr - Master.Location, 1, OutFile);
|
||||||
|
@ -10710,8 +10740,11 @@ BuffersToHTML(config *C, project *Project, buffers *CollationBuffers, template *
|
||||||
OutFile = 0;
|
OutFile = 0;
|
||||||
FreeBuffer(&Master);
|
FreeBuffer(&Master);
|
||||||
MEM_TEST_AFTER("BuffersToHTML");
|
MEM_TEST_AFTER("BuffersToHTML");
|
||||||
return RC_SUCCESS;
|
Result = RC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
End:
|
||||||
|
SortLandmarks(&Assets);
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -11042,14 +11075,11 @@ GetNeighbourhoodForAddition(neighbourhood *N, edit_type_id EditType)
|
||||||
void
|
void
|
||||||
GetNeighbourhoodForDeletion(neighbourhood *N)
|
GetNeighbourhoodForDeletion(neighbourhood *N)
|
||||||
{
|
{
|
||||||
char *Ptr = (char *)N->Project;
|
db_entry *FirstEntry = LocateFirstEntry(N->Project);
|
||||||
Ptr += sizeof(*N->Project);
|
|
||||||
db_entry *FirstEntry = (db_entry *)Ptr;
|
|
||||||
db_entry *Entry = FirstEntry + N->ThisIndex;
|
|
||||||
|
|
||||||
N->PreDeletionThisIndex = N->ThisIndex;
|
N->PreDeletionThisIndex = N->ThisIndex;
|
||||||
N->This = Entry;
|
|
||||||
|
|
||||||
|
db_entry *Entry;
|
||||||
int EntryIndex;
|
int EntryIndex;
|
||||||
|
|
||||||
N->DeletedEntryWasFirst = TRUE;
|
N->DeletedEntryWasFirst = TRUE;
|
||||||
|
@ -11608,7 +11638,6 @@ AddLandmarks(neighbourhood *N, project *P, edit_type_id EditType)
|
||||||
for(int j = 0; j < AssetInMemory->PlayerLandmarkCount; ++j)
|
for(int j = 0; j < AssetInMemory->PlayerLandmarkCount; ++j)
|
||||||
{
|
{
|
||||||
db_landmark Landmark = {};
|
db_landmark Landmark = {};
|
||||||
// TODO(matt): Actually make sure that the correct project_index is set!
|
|
||||||
Landmark.Project = P->Index;
|
Landmark.Project = P->Index;
|
||||||
Landmark.EntryIndex = N->ThisIndex;
|
Landmark.EntryIndex = N->ThisIndex;
|
||||||
Landmark.Position = AssetInMemory->Player[j].Offset;
|
Landmark.Position = AssetInMemory->Player[j].Offset;
|
||||||
|
@ -11718,31 +11747,45 @@ VerifyLandmarks_(neighbourhood *N, int LineNumber)
|
||||||
|
|
||||||
db_block_assets *Block = LocateBlock(B_ASET);
|
db_block_assets *Block = LocateBlock(B_ASET);
|
||||||
db_asset *Asset = LocateFirstAsset(Block);
|
db_asset *Asset = LocateFirstAsset(Block);
|
||||||
for(int i = 0; i < Block->Count; ++i)
|
bool Malformed = FALSE;
|
||||||
|
for(uint16_t i = 0; i < Block->Count; ++i)
|
||||||
{
|
{
|
||||||
|
bool Titled = FALSE;
|
||||||
db_landmark *Landmark = LocateFirstLandmark(Asset);
|
db_landmark *Landmark = LocateFirstLandmark(Asset);
|
||||||
for(int j = 0; j < Asset->LandmarkCount; ++j, ++Landmark)
|
for(uint16_t j = 0; j < Asset->LandmarkCount; ++j, ++Landmark)
|
||||||
{
|
{
|
||||||
if(j + 1 < Asset->LandmarkCount)
|
if(j + 1 < Asset->LandmarkCount)
|
||||||
{
|
{
|
||||||
db_landmark *Next = Landmark + 1;
|
db_landmark *Next = Landmark + 1;
|
||||||
if((ProjectIndicesDiffer(Next->Project, Landmark->Project) < 0) ||
|
if((ProjectIndicesDiffer(Next->Project, Landmark->Project) < 0) ||
|
||||||
(ProjectIndicesMatch(Next->Project, Landmark->Project) && Next->EntryIndex < Landmark->EntryIndex))
|
(ProjectIndicesMatch(Next->Project, Landmark->Project) && Next->EntryIndex < Landmark->EntryIndex) ||
|
||||||
|
(ProjectIndicesMatch(Next->Project, Landmark->Project) && Next->EntryIndex == Landmark->EntryIndex && Next->Position < Landmark->Position))
|
||||||
{
|
{
|
||||||
PrintC(CS_ERROR, "We fail, sadly\n");
|
if(!Titled)
|
||||||
PrintAssetsBlock(0);
|
{
|
||||||
PrintLandmark(Landmark);
|
fprintf(stderr, "\nOut-of-order landmarks\n");
|
||||||
fprintf(stderr, " vs ");
|
PrintAsset(Asset, &i);
|
||||||
PrintLandmark(Next);
|
Titled = TRUE;
|
||||||
|
}
|
||||||
|
//PrintAssetsBlock(0);
|
||||||
|
PrintLandmark(Landmark, &j);
|
||||||
|
PrintC(CS_YELLOW, " vs ");
|
||||||
|
PrintLandmark(Next, 0);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
PrintNeighbourhood(N);
|
//PrintNeighbourhood(N);
|
||||||
_exit(1);
|
//_exit(1);
|
||||||
|
Malformed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Asset = SkipAsset(Asset);
|
Asset = SkipAsset(Asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Malformed)
|
||||||
|
{
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location;
|
DB.Metadata.Buffer.Ptr = DB.Metadata.Buffer.Location;
|
||||||
DB.Header = *(db_header *)DB.Metadata.Buffer.Ptr;
|
DB.Header = *(db_header *)DB.Metadata.Buffer.Ptr;
|
||||||
|
@ -12263,57 +12306,97 @@ LinkOverDeletedEntry(neighbourhood *N)
|
||||||
{
|
{
|
||||||
if(N->DeletedEntryWasFirst)
|
if(N->DeletedEntryWasFirst)
|
||||||
{
|
{
|
||||||
N->PreLinkNextOffsetTotal = N->Next->LinkOffsets.PrevEnd
|
if(N->Next) // NOTE(matt): Should be impossible to fail this test
|
||||||
+ N->Next->LinkOffsets.NextStart
|
{
|
||||||
+ N->Next->LinkOffsets.NextEnd;
|
N->PreLinkNextOffsetTotal = N->Next->LinkOffsets.PrevEnd
|
||||||
|
+ N->Next->LinkOffsets.NextStart
|
||||||
|
+ N->Next->LinkOffsets.NextEnd;
|
||||||
|
|
||||||
MarkNextAsFirst(N);
|
MarkNextAsFirst(N);
|
||||||
|
|
||||||
N->NextOffsetModifier = N->Next->LinkOffsets.PrevEnd
|
N->NextOffsetModifier = N->Next->LinkOffsets.PrevEnd
|
||||||
+ N->Next->LinkOffsets.NextStart
|
+ N->Next->LinkOffsets.NextStart
|
||||||
+ N->Next->LinkOffsets.NextEnd
|
+ N->Next->LinkOffsets.NextEnd
|
||||||
- N->PreLinkNextOffsetTotal;
|
- N->PreLinkNextOffsetTotal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintC(CS_ERROR, "Error: Malformed neighbourhood");
|
||||||
|
PrintNeighbourhood(N);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(N->DeletedEntryWasFinal)
|
else if(N->DeletedEntryWasFinal)
|
||||||
{
|
{
|
||||||
N->PreLinkPrevOffsetTotal = N->Prev->LinkOffsets.PrevEnd
|
if(N->Prev) // NOTE(matt): Should be impossible to fail this test
|
||||||
+ N->Prev->LinkOffsets.NextStart
|
{
|
||||||
+ N->Prev->LinkOffsets.NextEnd;
|
N->PreLinkPrevOffsetTotal = N->Prev->LinkOffsets.PrevEnd
|
||||||
|
+ N->Prev->LinkOffsets.NextStart
|
||||||
|
+ N->Prev->LinkOffsets.NextEnd;
|
||||||
|
|
||||||
MarkPrevAsFinal(N);
|
MarkPrevAsFinal(N);
|
||||||
|
|
||||||
N->PrevOffsetModifier = N->Prev->LinkOffsets.PrevEnd
|
N->PrevOffsetModifier = N->Prev->LinkOffsets.PrevEnd
|
||||||
+ N->Prev->LinkOffsets.NextStart
|
+ N->Prev->LinkOffsets.NextStart
|
||||||
+ N->Prev->LinkOffsets.NextEnd
|
+ N->Prev->LinkOffsets.NextEnd
|
||||||
- N->PreLinkPrevOffsetTotal;
|
- N->PreLinkPrevOffsetTotal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintC(CS_ERROR, "Error: Malformed neighbourhood");
|
||||||
|
PrintNeighbourhood(N);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Assert(N->PrevIndex >= 0 && N->NextIndex >= 0)
|
// Assert(N->PrevIndex >= 0 && N->NextIndex >= 0)
|
||||||
N->PreLinkPrevOffsetTotal = N->Prev->LinkOffsets.PrevEnd
|
|
||||||
+ N->Prev->LinkOffsets.NextStart
|
|
||||||
+ N->Prev->LinkOffsets.NextEnd;
|
|
||||||
|
|
||||||
|
if(N->Prev)
|
||||||
|
{
|
||||||
|
N->PreLinkPrevOffsetTotal = N->Prev->LinkOffsets.PrevEnd
|
||||||
|
+ N->Prev->LinkOffsets.NextStart
|
||||||
|
+ N->Prev->LinkOffsets.NextEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintC(CS_ERROR, "Error: Malformed neighbourhood");
|
||||||
|
PrintNeighbourhood(N);
|
||||||
|
}
|
||||||
|
|
||||||
N->PreLinkNextOffsetTotal = N->Next->LinkOffsets.PrevEnd
|
if(N->Next)
|
||||||
+ N->Next->LinkOffsets.NextStart
|
{
|
||||||
+ N->Next->LinkOffsets.NextEnd;
|
N->PreLinkNextOffsetTotal = N->Next->LinkOffsets.PrevEnd
|
||||||
|
+ N->Next->LinkOffsets.NextStart
|
||||||
|
+ N->Next->LinkOffsets.NextEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintC(CS_ERROR, "Error: Malformed neighbourhood");
|
||||||
|
PrintNeighbourhood(N);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertNeighbourLink(N->Project, N->Prev, N->Next, LINK_FORWARDS, N->FormerIsFirst);
|
if(N->Prev && N->Next)
|
||||||
InsertNeighbourLink(N->Project, N->Next, N->Prev, LINK_BACKWARDS, N->LatterIsFinal);
|
{
|
||||||
|
InsertNeighbourLink(N->Project, N->Prev, N->Next, LINK_FORWARDS, N->FormerIsFirst);
|
||||||
|
InsertNeighbourLink(N->Project, N->Next, N->Prev, LINK_BACKWARDS, N->LatterIsFinal);
|
||||||
|
|
||||||
N->PrevOffsetModifier = N->Prev->LinkOffsets.PrevEnd
|
N->PrevOffsetModifier = N->Prev->LinkOffsets.PrevEnd
|
||||||
+ N->Prev->LinkOffsets.NextStart
|
+ N->Prev->LinkOffsets.NextStart
|
||||||
+ N->Prev->LinkOffsets.NextEnd
|
+ N->Prev->LinkOffsets.NextEnd
|
||||||
- N->PreLinkPrevOffsetTotal;
|
- N->PreLinkPrevOffsetTotal;
|
||||||
|
|
||||||
N->NextOffsetModifier = N->Next->LinkOffsets.PrevEnd
|
N->NextOffsetModifier = N->Next->LinkOffsets.PrevEnd
|
||||||
+ N->Next->LinkOffsets.NextStart
|
+ N->Next->LinkOffsets.NextStart
|
||||||
+ N->Next->LinkOffsets.NextEnd
|
+ N->Next->LinkOffsets.NextEnd
|
||||||
- N->PreLinkNextOffsetTotal;
|
- N->PreLinkNextOffsetTotal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrintC(CS_ERROR, "Error: Malformed neighbourhood");
|
||||||
|
PrintNeighbourhood(N);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12334,6 +12417,7 @@ LinkNeighbours(neighbourhood *N, enum8(link_types) LinkType)
|
||||||
rc
|
rc
|
||||||
DeleteFromDB(neighbourhood *N, string BaseFilename)
|
DeleteFromDB(neighbourhood *N, string BaseFilename)
|
||||||
{
|
{
|
||||||
|
ResetNeighbourhood(N);
|
||||||
// TODO(matt): LogError()
|
// TODO(matt): LogError()
|
||||||
db_entry *Entry = 0;
|
db_entry *Entry = 0;
|
||||||
int EntryIndex = BinarySearchForMetadataEntry(N->Project, &Entry, BaseFilename);
|
int EntryIndex = BinarySearchForMetadataEntry(N->Project, &Entry, BaseFilename);
|
||||||
|
@ -14813,49 +14897,76 @@ SyncProject(project *P, neighbourhood *N, buffers *CollationBuffers, template *B
|
||||||
PushWatchHandle(P->HMMLDir, EXT_HMML, WT_HMML, P, 0);
|
PushWatchHandle(P->HMMLDir, EXT_HMML, WT_HMML, P, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *inotifyEventStrings[] =
|
||||||
|
{
|
||||||
|
/* 0x00000001 */ "IN_ACCESS",
|
||||||
|
/* 0x00000002 */ "IN_MODIFY",
|
||||||
|
/* 0x00000004 */ "IN_ATTRIB",
|
||||||
|
/* 0x00000008 */ "IN_CLOSE_WRITE",
|
||||||
|
/* 0x00000010 */ "IN_CLOSE_NOWRITE",
|
||||||
|
/* 0x00000020 */ "IN_OPEN",
|
||||||
|
/* 0x00000040 */ "IN_MOVED_FROM",
|
||||||
|
/* 0x00000080 */ "IN_MOVED_TO",
|
||||||
|
/* 0x00000100 */ "IN_CREATE",
|
||||||
|
/* 0x00000200 */ "IN_DELETE",
|
||||||
|
/* 0x00000400 */ "IN_DELETE_SELF",
|
||||||
|
/* 0x00000800 */ "IN_MOVE_SELF",
|
||||||
|
/* 0x00001000 */ "", // NOTE(matt): Apparently doesn't exist
|
||||||
|
/* 0x00002000 */ "IN_UNMOUNT",
|
||||||
|
/* 0x00004000 */ "IN_Q_OVERFLOW",
|
||||||
|
/* 0x00008000 */ "IN_IGNORED",
|
||||||
|
/* 0x00010000 */ "",
|
||||||
|
/* 0x00020000 */ "",
|
||||||
|
/* 0x00040000 */ "",
|
||||||
|
/* 0x00080000 */ "",
|
||||||
|
/* 0x00100000 */ "",
|
||||||
|
/* 0x00200000 */ "",
|
||||||
|
/* 0x00400000 */ "",
|
||||||
|
/* 0x00800000 */ "",
|
||||||
|
/* 0x01000000 */ "IN_ONLYDIR",
|
||||||
|
/* 0x02000000 */ "IN_DONT_FOLLOW",
|
||||||
|
/* 0x04000000 */ "IN_EXCL_UNLINK",
|
||||||
|
/* 0x08000000 */ "", // NOTE(matt): Apparently doesn't exist
|
||||||
|
/* 0x10000000 */ "IN_MASK_CREATE",
|
||||||
|
/* 0x20000000 */ "IN_MASK_ADD",
|
||||||
|
/* 0x40000000 */ "IN_ISDIR",
|
||||||
|
/* 0x80000000 */ "IN_ONESHOT",
|
||||||
|
};
|
||||||
|
|
||||||
#define DEBUG_EVENTS 0
|
#define DEBUG_EVENTS 0
|
||||||
#if DEBUG_EVENTS
|
#if DEBUG_EVENTS
|
||||||
void
|
void
|
||||||
PrintEvent(struct inotify_event *Event, int EventIndex)
|
PrintEvent(struct inotify_event *Event, int EventIndex, int Indentation)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "\n\n");
|
||||||
|
Indent(Indentation);
|
||||||
|
fprintf(stderr, "Event[%d]\n", EventIndex);
|
||||||
|
Indent(Indentation);
|
||||||
|
fprintf(stderr, " wd: %d\n", Event->wd);
|
||||||
|
Indent(Indentation);
|
||||||
|
fprintf(stderr, " mask: 0x%08X", Event->mask);
|
||||||
|
|
||||||
printf("\nEvent[%d]\n"
|
for(int i = 0; i < ArrayCount(inotifyEventStrings); ++i)
|
||||||
" wd: %d\n"
|
{
|
||||||
" mask: %d\n",
|
if(Event->mask & (1 << i))
|
||||||
EventIndex,
|
{
|
||||||
Event->wd,
|
fprintf(stderr, "\n");
|
||||||
Event->mask);
|
Indent(Indentation);
|
||||||
|
fprintf(stderr, " %s", inotifyEventStrings[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(Event->mask & IN_ACCESS) { printf(" IN_ACCESS\n"); }
|
fprintf(stderr, "\n");
|
||||||
if(Event->mask & IN_ATTRIB) { printf(" IN_ATTRIB\n"); }
|
Indent(Indentation);
|
||||||
if(Event->mask & IN_CLOSE_WRITE) { printf(" IN_CLOSE_WRITE\n"); }
|
fprintf(stderr, " cookie: %d", Event->cookie);
|
||||||
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"
|
fprintf(stderr, "\n");
|
||||||
" len: %d\n"
|
Indent(Indentation);
|
||||||
" name: %s\n",
|
fprintf(stderr, " len: %d", Event->len);
|
||||||
Event->cookie,
|
|
||||||
Event->len,
|
fprintf(stderr, "\n");
|
||||||
Event->name);
|
Indent(Indentation);
|
||||||
|
fprintf(stderr, " name: %s", Event->name);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -14995,6 +15106,56 @@ ParseAndEitherPrintConfigOrInitAll(string ConfigPath, memory_book *TokensList, n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG_EVENTS
|
||||||
|
void
|
||||||
|
SquashEventsD(buffer *Events, int BytesRead, struct inotify_event **Event, int *DebugEventIndex)
|
||||||
|
{
|
||||||
|
char *PeekPtr = Events->Ptr + sizeof(struct inotify_event) + (*Event)->len;
|
||||||
|
struct inotify_event *Peek = (struct inotify_event *)PeekPtr;
|
||||||
|
bool Squashed = FALSE;
|
||||||
|
while(PeekPtr - Events->Location < BytesRead && (*Event)->wd == Peek->wd && StringsMatch(Wrap0((*Event)->name), Wrap0(Peek->name)))
|
||||||
|
{
|
||||||
|
if(!Squashed)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "\n\n"
|
||||||
|
" Squashing events:");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintEvent(Peek, ++*DebugEventIndex, 1);
|
||||||
|
|
||||||
|
Squashed = TRUE;
|
||||||
|
|
||||||
|
*Event = Peek;
|
||||||
|
Events->Ptr = PeekPtr;
|
||||||
|
|
||||||
|
PeekPtr = Events->Ptr + sizeof(struct inotify_event) + (*Event)->len;
|
||||||
|
Peek = (struct inotify_event *)PeekPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Squashed)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "\n\n"
|
||||||
|
" Finished squashing\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
SquashEvents(buffer *Events, int BytesRead, struct inotify_event **Event)
|
||||||
|
{
|
||||||
|
char *PeekPtr = Events->Ptr + sizeof(struct inotify_event) + (*Event)->len;
|
||||||
|
struct inotify_event *Peek = (struct inotify_event *)PeekPtr;
|
||||||
|
while(PeekPtr - Events->Location < BytesRead && (*Event)->wd == Peek->wd && StringsMatch(Wrap0((*Event)->name), Wrap0(Peek->name)))
|
||||||
|
{
|
||||||
|
*Event = Peek;
|
||||||
|
Events->Ptr = PeekPtr;
|
||||||
|
|
||||||
|
PeekPtr = Events->Ptr + sizeof(struct inotify_event) + (*Event)->len;
|
||||||
|
Peek = (struct inotify_event *)PeekPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate, string ConfigPath, memory_book *TokensList)
|
MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *BespokeTemplate, string ConfigPath, memory_book *TokensList)
|
||||||
{
|
{
|
||||||
|
@ -15004,9 +15165,6 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke
|
||||||
|
|
||||||
struct inotify_event *Event;
|
struct inotify_event *Event;
|
||||||
int BytesRead = read(inotifyInstance, Events.Location, Events.Size); // TODO(matt): Handle error EINVAL
|
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
|
#if DEBUG_EVENTS
|
||||||
if(BytesRead > 0)
|
if(BytesRead > 0)
|
||||||
{
|
{
|
||||||
|
@ -15031,46 +15189,56 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke
|
||||||
Event = (struct inotify_event *)Events.Ptr;
|
Event = (struct inotify_event *)Events.Ptr;
|
||||||
|
|
||||||
#if DEBUG_EVENTS
|
#if DEBUG_EVENTS
|
||||||
PrintEvent(Event, DebugEventIndex);
|
PrintEvent(Event, DebugEventIndex, 0);
|
||||||
//PrintWatchHandles();
|
//PrintWatchHandles();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
watch_file *WatchFile = GetWatchFileForEvent(Event);
|
watch_file *WatchFile = GetWatchFileForEvent(Event);
|
||||||
if(WatchFile)
|
if(WatchFile)
|
||||||
{
|
{
|
||||||
char *PeekPtr = Events.Ptr + sizeof(struct inotify_event) + Event->len;
|
|
||||||
struct inotify_event *Peek = (struct inotify_event *)PeekPtr;
|
|
||||||
while(PeekPtr - Events.Location < BytesRead && Event->wd == Peek->wd && StringsMatch(Wrap0i(Event->name, Event->len), Wrap0i(Peek->name, Peek->len)))
|
|
||||||
{
|
|
||||||
#if DEBUG_EVENTS
|
#if DEBUG_EVENTS
|
||||||
fprintf(stderr, "Squashing events:\n"
|
SquashEventsD(&Events, BytesRead, &Event, &DebugEventIndex);
|
||||||
" ");
|
#else
|
||||||
PrintEvent(Event, DebugEventIndex++);
|
SquashEvents(&Events, BytesRead, &Event);
|
||||||
fprintf(stderr, "\n"
|
|
||||||
" ");
|
|
||||||
PrintEvent(Peek, DebugEventIndex);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
#endif
|
#endif
|
||||||
|
bool WouldHaveDeleted = (Event->mask & (IN_DELETE | IN_MOVED_FROM)) ? TRUE : FALSE;
|
||||||
|
|
||||||
Event = Peek;
|
if(WouldHaveDeleted && (Events.Ptr + sizeof(struct inotify_event) + Event->len) - Events.Location == BytesRead)
|
||||||
Events.Ptr = PeekPtr;
|
{
|
||||||
|
fprintf(stderr, "Sleeping before polling for more filesystem events");
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
PeekPtr = Events.Ptr + sizeof(struct inotify_event) + Event->len;
|
struct inotify_event EventN = *Event;
|
||||||
Peek = (struct inotify_event *)PeekPtr;
|
char EventNName[Event->len + 1];
|
||||||
|
ClearCopyStringNoFormat(EventNName, sizeof(EventNName), Wrap0(Event->name));
|
||||||
|
|
||||||
|
char *EventSlot1 = Events.Location + sizeof(struct inotify_event) + Event->len;
|
||||||
|
|
||||||
|
int NewBytesRead = read(inotifyInstance, EventSlot1, Events.Size - (EventSlot1 - Events.Location)); // TODO(matt): Handle error EINVAL
|
||||||
|
if(NewBytesRead >= 0)
|
||||||
|
{
|
||||||
|
BytesRead = sizeof(struct inotify_event) + EventN.len + NewBytesRead;
|
||||||
|
struct inotify_event *Event0 = (struct inotify_event *)Events.Location;
|
||||||
|
*Event0 = EventN;
|
||||||
|
CopyStringNoFormat(Event0->name, Event0->len, Wrap0(EventNName));
|
||||||
|
Event = Event0;
|
||||||
|
Events.Ptr = Events.Location;
|
||||||
|
#if DEBUG_EVENTS
|
||||||
|
SquashEventsD(&Events, BytesRead, &Event, &DebugEventIndex);
|
||||||
|
#else
|
||||||
|
SquashEvents(&Events, BytesRead, &Event);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(WatchFile->Type)
|
switch(WatchFile->Type)
|
||||||
{
|
{
|
||||||
// TODO(matt): We're probably watching for too many events when the target directory exists
|
|
||||||
case WT_HMML:
|
case WT_HMML:
|
||||||
{
|
{
|
||||||
SetCurrentProject(WatchFile->Project, N);
|
SetCurrentProject(WatchFile->Project, N);
|
||||||
//PrintLineage(CurrentProject->Lineage, TRUE);
|
|
||||||
|
|
||||||
string BaseFilename = GetBaseFilename(Wrap0(Event->name), WatchFile->Extension);
|
string BaseFilename = GetBaseFilename(Wrap0(Event->name), WatchFile->Extension);
|
||||||
if(Event->mask & (IN_DELETE | IN_MOVED_FROM))
|
if(Event->mask & (IN_DELETE | IN_MOVED_FROM))
|
||||||
{
|
{
|
||||||
// TODO(matt): Why are we getting here after editing a .hmml file? We should just reinsert
|
|
||||||
Deleted |= (DeleteEntry(N, BaseFilename) == RC_SUCCESS);
|
Deleted |= (DeleteEntry(N, BaseFilename) == RC_SUCCESS);
|
||||||
}
|
}
|
||||||
else if(Event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO))
|
else if(Event->mask & (IN_CLOSE_WRITE | IN_MOVED_TO))
|
||||||
|
@ -15080,8 +15248,6 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke
|
||||||
} break;
|
} break;
|
||||||
case WT_ASSET:
|
case WT_ASSET:
|
||||||
{
|
{
|
||||||
// TODO(matt): Why are we getting here after editing a .hmml file?
|
|
||||||
//PrintAssetsBlock(0);
|
|
||||||
UpdateAsset(WatchFile->Asset, FALSE);
|
UpdateAsset(WatchFile->Asset, FALSE);
|
||||||
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
|
||||||
#if DEBUG_LANDMARKS
|
#if DEBUG_LANDMARKS
|
||||||
|
@ -15210,6 +15376,7 @@ main(int ArgC, char **Args)
|
||||||
InitWatchHandles((IN_CREATE | IN_MOVED_FROM | IN_MOVED_TO | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF), Kilobytes(4));
|
InitWatchHandles((IN_CREATE | IN_MOVED_FROM | IN_MOVED_TO | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF), Kilobytes(4));
|
||||||
|
|
||||||
inotifyInstance = inotify_init1(IN_NONBLOCK);
|
inotifyInstance = inotify_init1(IN_NONBLOCK);
|
||||||
|
int inotifyError = errno;
|
||||||
|
|
||||||
string ConfigPathL = Wrap0(ConfigPath);
|
string ConfigPathL = Wrap0(ConfigPath);
|
||||||
PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0);
|
PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0);
|
||||||
|
@ -15250,24 +15417,31 @@ main(int ArgC, char **Args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//PrintWatchHandles();
|
if(inotifyInstance)
|
||||||
while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
|
||||||
{
|
{
|
||||||
// TODO(matt): Refetch the quotes and rebuild player pages if needed
|
while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
||||||
//
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
// The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a
|
|
||||||
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
|
||||||
// the player page(s) accordingly.
|
|
||||||
//
|
|
||||||
if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
|
||||||
{
|
{
|
||||||
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
// TODO(matt): Refetch the quotes and rebuild player pages if needed
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a
|
||||||
|
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
||||||
|
// the player page(s) accordingly.
|
||||||
|
//
|
||||||
|
if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
||||||
|
{
|
||||||
|
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||||
|
}
|
||||||
|
sleep(GLOBAL_UPDATE_INTERVAL);
|
||||||
}
|
}
|
||||||
sleep(GLOBAL_UPDATE_INTERVAL);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: Quitting because inotify initialisation failed with message\n"
|
||||||
|
" %s\n", strerror(inotifyError));
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscardAllAndFreeConfig();
|
DiscardAllAndFreeConfig();
|
||||||
|
|
|
@ -1543,6 +1543,14 @@ InitScopeBooks(scope_tree *Scope)
|
||||||
InitBook(&Scope->BoolPairs, sizeof(config_bool_pair), 4, MBT_CONFIG_BOOL_PAIR);
|
InitBook(&Scope->BoolPairs, sizeof(config_bool_pair), 4, MBT_CONFIG_BOOL_PAIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope_tree *
|
||||||
|
InitRootScopeTree(void)
|
||||||
|
{
|
||||||
|
scope_tree *Result = calloc(1, sizeof(scope_tree));
|
||||||
|
InitScopeBooks(Result);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
scope_tree *
|
scope_tree *
|
||||||
PushScope(memory_book *TypeSpecs, scope_tree *Parent, config_pair *ID)
|
PushScope(memory_book *TypeSpecs, scope_tree *Parent, config_pair *ID)
|
||||||
{
|
{
|
||||||
|
@ -4583,8 +4591,7 @@ ParseConfig(string Path, memory_book *TokensList)
|
||||||
|
|
||||||
if(T)
|
if(T)
|
||||||
{
|
{
|
||||||
scope_tree *ScopeTree = calloc(1, sizeof(scope_tree));
|
scope_tree *ScopeTree = InitRootScopeTree();
|
||||||
InitScopeBooks(ScopeTree);
|
|
||||||
SetTypeSpec(ScopeTree, &TypeSpecs);
|
SetTypeSpec(ScopeTree, &TypeSpecs);
|
||||||
SetDefaults(ScopeTree, &TypeSpecs);
|
SetDefaults(ScopeTree, &TypeSpecs);
|
||||||
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0);
|
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0);
|
||||||
|
@ -4597,8 +4604,7 @@ ParseConfig(string Path, memory_book *TokensList)
|
||||||
FreeTokensList(TokensList);
|
FreeTokensList(TokensList);
|
||||||
MEM_LOOP_PRE_WORK()
|
MEM_LOOP_PRE_WORK()
|
||||||
T = Tokenise(TokensList, Path);
|
T = Tokenise(TokensList, Path);
|
||||||
ScopeTree = calloc(1, sizeof(scope_tree));
|
ScopeTree = InitRootScopeTree();
|
||||||
InitScopeBooks(ScopeTree);
|
|
||||||
SetTypeSpec(ScopeTree, &TypeSpecs);
|
SetTypeSpec(ScopeTree, &TypeSpecs);
|
||||||
SetDefaults(ScopeTree, &TypeSpecs);
|
SetDefaults(ScopeTree, &TypeSpecs);
|
||||||
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0);
|
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0);
|
||||||
|
|
Loading…
Reference in New Issue