author);
if(Config.Edition == EDITION_NETWORK)
@@ -1846,7 +1960,7 @@ HMMLToBuffers(arena *MemoryArena, buffers *CollationBuffers, config Config, char
}
else if(Anno->markers[MarkerIndex].type == HMML_CATEGORY)
{
- switch(GenerateTopicColours(Anno->markers[MarkerIndex].marker, Config.CSSDir))
+ switch(GenerateTopicColours(Anno->markers[MarkerIndex].marker))
{
case RC_SUCCESS:
case RC_NOOP:
@@ -1859,8 +1973,7 @@ HMMLToBuffers(arena *MemoryArena, buffers *CollationBuffers, config Config, char
{
HasFilterMenu = TRUE;
}
- InsertCategory(&Topics, &Media, Anno->markers[MarkerIndex].marker); // Global
- InsertCategory(&LocalTopics, &LocalMedia, Anno->markers[MarkerIndex].marker); // Local
+ InsertCategory(&Topics, &LocalTopics, &Media, &LocalMedia, Anno->markers[MarkerIndex].marker);
}
}
@@ -1876,9 +1989,9 @@ HMMLToBuffers(arena *MemoryArena, buffers *CollationBuffers, config Config, char
"
\n");
- if(BuildReference(ReferencesArray, RefIdentifier, UniqueRefs, *CurrentRef, *Anno) == 1)
+ if(BuildReference(ReferencesArray, RefIdentifier, UniqueRefs, CurrentRef, Anno) == 1)
{
- LogError(Config, LOG_ERROR, "Reference combination processing failed: %s:%d", Filename, Anno->line);
+ LogError(LOG_ERROR, "Reference combination processing failed: %s:%d", Filename, Anno->line);
fprintf(stderr, "%s:%d: Cannot process new combination of reference info\n"
"\n"
"Either tweak your annotation, or contact matt@handmadedev.org\n"
@@ -1898,7 +2011,7 @@ HMMLToBuffers(arena *MemoryArena, buffers *CollationBuffers, config Config, char
{
if(ReferencesArray[i].IdentifierCount == REF_MAX_IDENTIFIER)
{
- LogError(Config, LOG_EMERGENCY, "REF_MAX_IDENTIFIER (%d) reached. Contact matt@handmadedev.org", REF_MAX_IDENTIFIER);
+ LogError(LOG_EMERGENCY, "REF_MAX_IDENTIFIER (%d) reached. Contact matt@handmadedev.org", REF_MAX_IDENTIFIER);
fprintf(stderr, "%s:%d: Too many timecodes associated with one reference (increase REF_MAX_IDENTIFIER)\n", Filename, Anno->line);
hmml_free(&HMML);
return RC_ERROR_MAX_REFS;
@@ -1925,16 +2038,16 @@ HMMLToBuffers(arena *MemoryArena, buffers *CollationBuffers, config Config, char
}
else
{
- LogError(Config, LOG_ERROR, "Reference missing ISBN or URL: %s:%d", Filename, Anno->line);
+ LogError(LOG_ERROR, "Reference missing ISBN or URL: %s:%d", Filename, Anno->line);
fprintf(stderr, "%s:%d: Reference must have an ISBN or URL\n", Filename, Anno->line);
hmml_free(&HMML);
return RC_INVALID_REFERENCE;
}
}
- if(BuildReference(ReferencesArray, RefIdentifier, UniqueRefs, *CurrentRef, *Anno) == 1)
+ if(BuildReference(ReferencesArray, RefIdentifier, UniqueRefs, CurrentRef, Anno) == 1)
{
- LogError(Config, LOG_ERROR, "Reference combination processing failed: %s:%d", Filename, Anno->line);
+ LogError(LOG_ERROR, "Reference combination processing failed: %s:%d", Filename, Anno->line);
fprintf(stderr, "%s:%d: Cannot process new combination of reference info\n"
"\n"
"Either tweak your annotation, or contact matt@handmadedev.org\n"
@@ -1959,7 +2072,7 @@ AppendedIdentifier:
}
else
{
- LogError(Config, LOG_ERROR, "Reference missing ISBN or URL: %s:%d", Filename, Anno->line);
+ LogError(LOG_ERROR, "Reference missing ISBN or URL: %s:%d", Filename, Anno->line);
fprintf(stderr, "%s:%d: Reference must have an ISBN or URL\n", Filename, Anno->line);
hmml_free(&HMML);
return RC_INVALID_REFERENCE;
@@ -1979,7 +2092,7 @@ AppendedIdentifier:
}
else
{
- LogError(Config, LOG_ERROR, "Reference missing ISBN or URL: %s:%d", Filename, Anno->line);
+ LogError(LOG_ERROR, "Reference missing ISBN or URL: %s:%d", Filename, Anno->line);
fprintf(stderr, "%s:%d: Reference must have an ISBN or URL", Filename, Anno->line);
hmml_free(&HMML);
return RC_INVALID_REFERENCE;
@@ -2058,10 +2171,9 @@ AppendedIdentifier:
char *Speaker = Anno->quote.author ? Anno->quote.author : HMML.metadata.stream_username ? HMML.metadata.stream_username : HMML.metadata.member;
if(BuildQuote(&QuoteInfo,
Speaker,
- Anno->quote.id,
- Config.CacheDir) == 1)
+ Anno->quote.id) == 1)
{
- LogError(Config, LOG_ERROR, "Quote #%s %d not found: %s:%d", Speaker, Anno->quote.id, Filename, Anno->line);
+ LogError(LOG_ERROR, "Quote #%s %d not found: %s:%d", Speaker, Anno->quote.id, Filename, Anno->line);
fprintf(stderr, "%s:%d: Quote #%s %d not found. Skipping this file...\n",
Filename,
Anno->line,
@@ -2109,7 +2221,7 @@ AppendedIdentifier:
while(MarkerIndex < Anno->marker_count)
{
- switch(GenerateTopicColours(Anno->markers[MarkerIndex].marker, Config.CSSDir))
+ switch(GenerateTopicColours(Anno->markers[MarkerIndex].marker))
{
case RC_SUCCESS:
case RC_NOOP:
@@ -2122,21 +2234,16 @@ AppendedIdentifier:
{
HasFilterMenu = TRUE;
}
- if(Anno->markers[MarkerIndex].marker)
- {
- InsertCategory(&Topics, &Media, Anno->markers[MarkerIndex].marker);
- }
- InsertCategory(&LocalTopics, &LocalMedia, Anno->markers[MarkerIndex].marker);
+ InsertCategory(&Topics, &LocalTopics, &Media, &LocalMedia, Anno->markers[MarkerIndex].marker);
++MarkerIndex;
}
if(LocalMedia.Count == 0)
{
- InsertCategory(&Topics, &Media, Config.DefaultMedium);
- InsertCategory(&LocalTopics, &LocalMedia, Config.DefaultMedium);
+ InsertCategory(&Topics, &LocalTopics, &Media, &LocalMedia, Config.DefaultMedium);
}
- BuildCategories(&AnnotationClass, &TopicDots, LocalTopics, LocalMedia, &MarkerIndex);
+ BuildCategories(&AnnotationClass, &TopicDots, &LocalTopics, &LocalMedia, &MarkerIndex);
CopyBuffer(&AnnotationHeader, &AnnotationClass);
if(HasQuote || HasReference)
@@ -2187,12 +2294,12 @@ AppendedIdentifier:
// AnnotationHeader
// Annotation
- DeclaimBuffer(MemoryArena, &TopicDots);
- DeclaimBuffer(MemoryArena, &Text);
- DeclaimBuffer(MemoryArena, &AnnotationData);
- DeclaimBuffer(MemoryArena, &AnnotationClass);
- DeclaimBuffer(MemoryArena, &AnnotationHeader);
- DeclaimBuffer(MemoryArena, &Annotation);
+ DeclaimBuffer(&TopicDots);
+ DeclaimBuffer(&Text);
+ DeclaimBuffer(&AnnotationData);
+ DeclaimBuffer(&AnnotationClass);
+ DeclaimBuffer(&AnnotationHeader);
+ DeclaimBuffer(&Annotation);
}
#if DEBUG
@@ -2909,18 +3016,18 @@ AppendedIdentifier:
// QuoteMenu
Cleanup:
- DeclaimBuffer(MemoryArena, &FilterState);
+ DeclaimBuffer(&FilterState);
- DeclaimBuffer(MemoryArena, &CreditsMenu);
- DeclaimBuffer(MemoryArena, &FilterMedia);
- DeclaimBuffer(MemoryArena, &FilterTopics);
- DeclaimBuffer(MemoryArena, &FilterMenu);
- DeclaimBuffer(MemoryArena, &ReferenceMenu);
- DeclaimBuffer(MemoryArena, &QuoteMenu);
+ DeclaimBuffer(&CreditsMenu);
+ DeclaimBuffer(&FilterMedia);
+ DeclaimBuffer(&FilterTopics);
+ DeclaimBuffer(&FilterMenu);
+ DeclaimBuffer(&ReferenceMenu);
+ DeclaimBuffer(&QuoteMenu);
}
else
{
- LogError(Config, LOG_ERROR, "%s:%d: %s", Filename, HMML.error.line, HMML.error.message);
+ LogError(LOG_ERROR, "%s:%d: %s", Filename, HMML.error.line, HMML.error.message);
fprintf(stderr, "%s:%d: %s\n", Filename, HMML.error.line, HMML.error.message);
hmml_free(&HMML);
return RC_ERROR_HMML;
@@ -2930,110 +3037,107 @@ Cleanup:
}
int
-BuffersToHTML(arena *MemoryArena, buffers CollationBuffers, template *TemplateMetadata, config Config, char *OutputPath, int PageType)
+BuffersToHTML(buffers *CollationBuffers, template *Template, char *OutputPath, int PageType)
{
#if DEBUG
printf("\n\n --- Buffer Collation ---\n"
- " %s\n\n\n", OutputPath);
+ " %s\n\n\n", OutputPath ? OutputPath : Config->OutLocation);
+#endif
+
+#if DEBUG_MEM
+ FILE *MemLog = fopen("/home/matt/cinera_mem", "a+");
+ fprintf(MemLog, "\nEntered BuffersToHTML(%s)\n", OutputPath ? OutputPath : Config->OutLocation);
+ fclose(MemLog);
#endif
if(Config.Mode == MODE_INTEGRATE)
{
- if(TemplateMetadata->Validity & PageType)
+ if(Template->Metadata.Validity & PageType)
{
- // TODO(matt): Maybe enable the Template(s) to stick around for the duration of RefreshProject()
- buffer Template;
- Template.ID = TemplateMetadata->Filename;
- FILE *TemplateFile;
- if(!(TemplateFile = fopen(TemplateMetadata->Filename, "r")))
- {
- LogError(Config, LOG_ERROR, "Unable to open template %s: %s", TemplateMetadata->Filename, strerror(errno));
- return RC_ERROR_FILE;
- }
- fseek(TemplateFile, 0, SEEK_END);
- Template.Size = ftell(TemplateFile);
- fseek(TemplateFile, 0, SEEK_SET);
- if(!(Template.Location = malloc(Template.Size)))
- {
- LogError(Config, LOG_ERROR, "BuffersToHTML(): %s",
- strerror(errno));
- fclose(TemplateFile);
- return RC_ERROR_MEMORY;
- }
- Template.Ptr = Template.Location;
- fread(Template.Location, Template.Size, 1, TemplateFile);
- fclose(TemplateFile);
-
buffer Output;
- Output.Size = Template.Size + (Kilobytes(512));
+ Output.Size = Template->Buffer.Size + (Kilobytes(512));
Output.ID = "Output";
if(!(Output.Location = malloc(Output.Size)))
{
- LogError(Config, LOG_ERROR, "BuffersToHTML(): %s",
+ LogError(LOG_ERROR, "BuffersToHTML(): %s",
strerror(errno));
- FreeBuffer(&Template);
return RC_ERROR_MEMORY;
}
+
+#if DEBUG_MEM
+ MemLog = fopen("/home/matt/cinera_mem", "a+");
+ fprintf(MemLog, " Allocated Output (%d)\n", Output.Size);
+ fclose(MemLog);
+ printf(" Allocated Output (%d)\n", Output.Size);
+#endif
+
Output.Ptr = Output.Location;
- Template.Ptr = Template.Location;
- for(int i = 0; i < TemplateMetadata->TagCount; ++i)
+ Template->Buffer.Ptr = Template->Buffer.Location;
+ for(int i = 0; i < Template->Metadata.TagCount; ++i)
{
int j = 0;
- while(TemplateMetadata->Tag[i].Offset > j)
+ while(Template->Metadata.Tag[i].Offset > j)
{
- *Output.Ptr++ = *Template.Ptr++;
+ *Output.Ptr++ = *Template->Buffer.Ptr++;
++j;
}
- switch(TemplateMetadata->Tag[i].TagCode)
+ switch(Template->Metadata.Tag[i].TagCode)
{
case TAG_TITLE:
- CopyStringToBuffer(&Output, CollationBuffers.Title);
+ CopyStringToBuffer(&Output, CollationBuffers->Title);
break;
case TAG_INDEX:
- CopyBuffer(&Output, &CollationBuffers.Index);
+ CopyBuffer(&Output, &CollationBuffers->Index);
break;
case TAG_INCLUDES:
- if(PageType == PAGE_PLAYER)
- {
- CopyBuffer(&Output, &CollationBuffers.IncludesPlayer);
- }
- else
- {
- CopyBuffer(&Output, &CollationBuffers.IncludesIndex);
- }
+ CopyBuffer(&Output, PageType == PAGE_PLAYER ? &CollationBuffers->IncludesPlayer : &CollationBuffers->IncludesIndex);
break;
case TAG_MENUS:
- CopyBuffer(&Output, &CollationBuffers.Menus);
+ CopyBuffer(&Output, &CollationBuffers->Menus);
break;
case TAG_PLAYER:
- CopyBuffer(&Output, &CollationBuffers.Player);
+ CopyBuffer(&Output, &CollationBuffers->Player);
break;
case TAG_SCRIPT:
- CopyBuffer(&Output, &CollationBuffers.Script);
+ CopyBuffer(&Output, &CollationBuffers->Script);
break;
}
- DepartComment(&Template);
+ DepartComment(&Template->Buffer);
}
- while(Template.Ptr - Template.Location < Template.Size)
+ while(Template->Buffer.Ptr - Template->Buffer.Location < Template->Buffer.Size)
{
- *Output.Ptr++ = *Template.Ptr++;
+ *Output.Ptr++ = *Template->Buffer.Ptr++;
}
- FreeBuffer(&Template);
-
FILE *OutFile;
if(!(OutFile = fopen(Config.Edition == EDITION_PROJECT ? OutputPath : Config.OutIntegratedLocation, "w")))
{
- LogError(Config, LOG_ERROR, "Unable to open output file %s: %s", Config.Edition == EDITION_PROJECT ? OutputPath : Config.OutIntegratedLocation, strerror(errno));
+ LogError(LOG_ERROR, "Unable to open output file %s: %s", Config.Edition == EDITION_PROJECT ? OutputPath : Config.OutIntegratedLocation, strerror(errno));
free(Output.Location);
+
+#if DEBUG_MEM
+ MemLog = fopen("/home/matt/cinera_mem", "a+");
+ fprintf(MemLog, " Freed Output\n");
+ fclose(MemLog);
+ printf(" Freed Output\n");
+#endif
+
return RC_ERROR_FILE;
}
fwrite(Output.Location, Output.Ptr - Output.Location, 1, OutFile);
fclose(OutFile);
free(Output.Location);
+
+#if DEBUG_MEM
+ MemLog = fopen("/home/matt/cinera_mem", "a+");
+ fprintf(MemLog, " Freed Output\n");
+ fclose(MemLog);
+ printf(" Freed Output\n");
+#endif
+
return RC_SUCCESS;
}
else
@@ -3044,13 +3148,13 @@ BuffersToHTML(arena *MemoryArena, buffers CollationBuffers, template *TemplateMe
else
{
buffer Master;
- if(ClaimBuffer(MemoryArena, &Master, "Master", Kilobytes(512)) == RC_ARENA_FULL) { return RC_ARENA_FULL; };
+ if(ClaimBuffer(&Master, "Master", Kilobytes(512)) == RC_ARENA_FULL) { return RC_ARENA_FULL; };
CopyStringToBuffer(&Master,
"\n"
" \n");
- CopyBuffer(&Master, PageType == PAGE_PLAYER ? &CollationBuffers.IncludesPlayer : &CollationBuffers.IncludesIndex);
+ CopyBuffer(&Master, PageType == PAGE_PLAYER ? &CollationBuffers->IncludesPlayer : &CollationBuffers->IncludesIndex);
CopyStringToBuffer(&Master, "\n");
CopyStringToBuffer(&Master,
@@ -3058,16 +3162,16 @@ BuffersToHTML(arena *MemoryArena, buffers CollationBuffers, template *TemplateMe
" \n");
if(PageType == PAGE_PLAYER)
{
- CopyBuffer(&Master, &CollationBuffers.Menus);
+ CopyBuffer(&Master, &CollationBuffers->Menus);
CopyStringToBuffer(&Master, "\n");
- CopyBuffer(&Master, &CollationBuffers.Player);
+ CopyBuffer(&Master, &CollationBuffers->Player);
CopyStringToBuffer(&Master, "\n");
- CopyBuffer(&Master, &CollationBuffers.Script);
+ CopyBuffer(&Master, &CollationBuffers->Script);
CopyStringToBuffer(&Master, "\n");
}
else
{
- CopyBuffer(&Master, &CollationBuffers.Index);
+ CopyBuffer(&Master, &CollationBuffers->Index);
}
CopyStringToBuffer(&Master,
@@ -3077,281 +3181,390 @@ BuffersToHTML(arena *MemoryArena, buffers CollationBuffers, template *TemplateMe
FILE *OutFile;
if(!(OutFile = fopen(Config.Edition == EDITION_PROJECT ? OutputPath : Config.OutLocation, "w")))
{
- LogError(Config, LOG_ERROR, "Unable to open output file %s: %s", Config.Edition == EDITION_PROJECT ? OutputPath : Config.OutLocation, strerror(errno));
- DeclaimBuffer(MemoryArena, &Master);
+ LogError(LOG_ERROR, "Unable to open output file %s: %s", Config.Edition == EDITION_PROJECT ? OutputPath : Config.OutLocation, strerror(errno));
+ DeclaimBuffer(&Master);
return RC_ERROR_FILE;
}
fwrite(Master.Location, Master.Ptr - Master.Location, 1, OutFile);
fclose(OutFile);
- DeclaimBuffer(MemoryArena, &Master);
+ DeclaimBuffer(&Master);
return RC_SUCCESS;
}
}
int
-RefreshIndex(arena *MemoryArena, buffers *CollationBuffers, config Config, char *BaseFilename)
+ReadFileIntoBuffer(file_buffer *File, int BufferPadding)
{
- char IndexPath[255];
- CopyString(IndexPath, "%s/%s.index", Config.CacheDir, CollationBuffers->Project);
- FILE *IndexFile;
- if(!(IndexFile = fopen(IndexPath, "a+")))
+ if(!(File->Handle = fopen(File->Path, "r")))
{
- LogError(Config, LOG_ERROR, "Unable to open index file %s: %s", IndexPath, strerror(errno));
return RC_ERROR_FILE;
}
- buffer Index;
- Index.ID = "Index";
- fseek(IndexFile, 0, SEEK_END);
- int IndexFileSize = ftell(IndexFile);
- Index.Size = IndexFileSize + StringLength(BaseFilename) + StringLength(CollationBuffers->Title) + 3;
- fseek(IndexFile, 0, SEEK_SET);
+ fseek(File->Handle, 0, SEEK_END);
+ File->FileSize = ftell(File->Handle);
+ File->Buffer.Size = File->FileSize + 1 + BufferPadding; // NOTE(matt): +1 to accommodate a NULL terminator
+ fseek(File->Handle, 0, SEEK_SET);
- if(!(Index.Location = malloc(Index.Size)))
+ // TODO(matt): Consider using the MemoryArena? Maybe have separate ReadFileIntoMemory() and ReadFileIntoArena()
+ if(!(File->Buffer.Location = malloc(File->Buffer.Size)))
{
- LogError(Config, LOG_ERROR, "RefreshIndex(): %s", strerror(errno));
+ fclose(File->Handle);
return RC_ERROR_MEMORY;
}
- Index.Ptr = Index.Location;
- fread(Index.Location, IndexFileSize, 1, IndexFile);
+ File->Buffer.Ptr = File->Buffer.Location;
- bool Found = FALSE;
- bool Inserted = FALSE;
-
- int EntryCount = 0;
- while(Index.Ptr - Index.Location < IndexFileSize)
- {
- char IndexedFile[32];
- char *Ptr = IndexedFile;
- Index.Ptr += CopyStringNoFormatT(Ptr, Index.Ptr, ',');
- if(!StringsDiffer(IndexedFile, BaseFilename))
- {
- Found = TRUE;
- break;
- }
- else if(StringsDiffer(IndexedFile, BaseFilename) > 0)
- {
- while(Index.Ptr > Index.Location && *Index.Ptr != '\n')
- {
- --Index.Ptr;
- }
- if(Index.Ptr > Index.Location)
- {
- ++Index.Ptr;
- }
-
- int Head = Index.Ptr - Index.Location;
- buffer Scratch;
- Scratch.Size = IndexFileSize;
- if(!(Scratch.Location = malloc(Scratch.Size + 1)))
- {
- LogError(Config, LOG_ERROR, "RefreshIndex(): %s", strerror(errno));
- free(Index.Location);
- fclose(IndexFile);
- return RC_ERROR_MEMORY;
- }
- Scratch.Ptr = Scratch.Location;
- while(Index.Ptr - Index.Location < IndexFileSize)
- {
- *Scratch.Ptr++ = *Index.Ptr++;
- }
- *Scratch.Ptr = '\0';
-
- Index.Ptr = Index.Location + Head;
- CopyStringToBuffer(&Index, "%s,%s\n"
- "%s",
- BaseFilename, CollationBuffers->Title,
- Scratch.Location);
-
- free(Scratch.Location);
- Index.Size = Index.Ptr - Index.Location;
-
- fclose(IndexFile);
- IndexFile = fopen(IndexPath, "w");
- fwrite(Index.Location, Index.Size, 1, IndexFile);
-
- Inserted = TRUE;
- }
- else
- {
- while(Index.Ptr - Index.Location < IndexFileSize && *Index.Ptr != '\n')
- {
- ++Index.Ptr;
- }
- ++Index.Ptr;
- }
- ++EntryCount;
- }
-
- if(!Found)
- {
- ++EntryCount;
- // TODO(matt): Write the EntryCount into the index
- if(!Inserted)
- {
- CopyStringToBuffer(&Index, "%s,%s\n", BaseFilename, CollationBuffers->Title);
- fprintf(IndexFile, "%s,%s\n", BaseFilename, CollationBuffers->Title);
- }
-
- RewindBuffer(&CollationBuffers->Index);
- Index.Size = Index.Ptr - Index.Location;
- RewindBuffer(&Index);
-
- CopyStringToBuffer(&CollationBuffers->Index, "
\n");
- while(Index.Ptr - Index.Location < Index.Size)
- {
- char IndexedFile[32];
- char *Ptr = IndexedFile;
- Index.Ptr += CopyStringNoFormatT(Ptr, Index.Ptr, ',') + 1;
-
- char Title[255];
- Ptr = Title;
- Index.Ptr += CopyStringNoFormatT(Ptr, Index.Ptr, '\n') + 1;
-
- // TODO(matt): Fully figure out why the Table of Contents doesn't always get all the stuff from the index
- // Steps to reproduce:
- // 1. mv riscy04{4..6}.hmml out of the way
- // 2. Call the program
- // 3. mv riscy046.hmml into the project directory
- // 4. See that riscy046 is in the index file, has its own player page, but is not mentioned in the Table of Contents
-
- CopyStringToBuffer(&CollationBuffers->Index,
-" - \n"
-" %s\n"
-"
\n",
- IndexedFile, Title);
-
- }
- CopyStringToBuffer(&CollationBuffers->Index, "
");
- }
-
- fclose(IndexFile);
- FreeBuffer(&Index);
- return Found ? RC_NOOP : RC_REFRESHED;
+ fread(File->Buffer.Location, File->FileSize, 1, File->Handle);
+ File->Buffer.Location[File->FileSize] = '\0';
+ fclose(File->Handle);
+ return RC_SUCCESS;
}
+// NOTE(matt): Currently unused
int
-RefreshProject(arena *MemoryArena, buffers *CollationBuffers,
- template *IndexTemplateMetadata, template *PlayerTemplateMetadata,
- config Config)
+WriteBufferToFile(file_buffer *File, buffer *Buffer, int BytesToWrite, bool KeepFileHandleOpen)
{
- DIR *ProjectDirHandle;
- if(!(ProjectDirHandle = opendir(Config.ProjectDir)))
+ if(!(File->Handle = fopen(File->Path, "w")))
{
- LogError(Config, LOG_ERROR, "Unable to scan project directory %s: %s", Config.ProjectDir, strerror(errno));
- fprintf(stderr, "Unable to scan project directory %s: %s\n", Config.ProjectDir, strerror(errno));
- return RC_ERROR_DIRECTORY;
+ return RC_ERROR_FILE;
}
- struct dirent *ProjectFiles;
- int FileIndex = 0;
-
-NextFile:
- while((ProjectFiles = readdir(ProjectDirHandle)))
+ fwrite(Buffer->Location, BytesToWrite, 1, File->Handle);
+ if(!KeepFileHandleOpen)
{
- // TODO(matt): Loft out into a function, maybe?
- char *Ptr;
- Ptr = ProjectFiles->d_name;
- Ptr += (StringLength(ProjectFiles->d_name) - StringLength(".hmml"));
- if(!(StringsDiffer(Ptr, ".hmml")))
- {
- *Ptr = '\0';
- char BaseFilename[255];
- CopyString(BaseFilename, ProjectFiles->d_name);
- *Ptr = '.';
-
- switch(HMMLToBuffers(MemoryArena, CollationBuffers, Config, ProjectFiles->d_name))
- {
- // TODO(matt): Actually sort out the fatality of these cases, once we are always-on
- case RC_ERROR_FILE:
- case RC_ERROR_FATAL:
- closedir(ProjectDirHandle);
- return RC_ERROR_FATAL;
- case RC_ERROR_HMML:
- case RC_ERROR_MAX_REFS:
- case RC_ERROR_QUOTE:
- case RC_INVALID_REFERENCE:
- goto NextFile;
- case RC_SUCCESS:
- break;
- };
-
- switch(RefreshIndex(MemoryArena, CollationBuffers, Config, BaseFilename))
- {
- // TODO(matt): Actually sort out the fatality of these cases, once we are always-on
- case RC_ERROR_FILE:
- case RC_ERROR_MEMORY:
- closedir(ProjectDirHandle);
- return RC_ERROR_FATAL;
- case RC_NOOP:
- break;
- case RC_REFRESHED:
- {
- char OutputDir[255];
- CopyString(OutputDir, "%s/%s", Config.BaseDir, BaseFilename);
- char OutputPath[255];
- CopyString(OutputPath, "%s/index.html", OutputDir);
- DIR *OutputDirectoryHandle;
- if(!(OutputDirectoryHandle = opendir(OutputDir)))
- {
- if(MakeDir(OutputDir) == RC_ERROR_DIRECTORY)
- {
- LogError(Config, LOG_ERROR, "Unable to create directory %s: %s", OutputDir, strerror(errno));
- fprintf(stderr, "Unable to create directory %s: %s\n", OutputDir, strerror(errno));
- closedir(ProjectDirHandle);
- return RC_ERROR_DIRECTORY;
- };
- }
- closedir(OutputDirectoryHandle);
- // TODO(matt): Implement checksumming?
-
- char IndexPagePath[255];
- CopyString(IndexPagePath, "%s/index.html", Config.BaseDir);
- switch(BuffersToHTML(MemoryArena, *CollationBuffers, IndexTemplateMetadata, Config, IndexPagePath, PAGE_INDEX))
- {
- // TODO(matt): Actually sort out the fatality of these cases, once we are always-on
- case RC_INVALID_TEMPLATE:
- LogError(Config, LOG_ERROR, "Invalid index template: %s", IndexTemplateMetadata->Filename);
- fprintf(stderr, "Invalid index template: %s\n", IndexTemplateMetadata->Filename);
- closedir(ProjectDirHandle);
- case RC_ERROR_MEMORY:
- case RC_ERROR_FILE:
- case RC_ARENA_FULL:
- return RC_ERROR_FATAL;
- case RC_SUCCESS:
- break;
- }
-
- switch(BuffersToHTML(MemoryArena, *CollationBuffers, PlayerTemplateMetadata, Config, OutputPath, PAGE_PLAYER))
- {
- // TODO(matt): Actually sort out the fatality of these cases, once we are always-on
- case RC_INVALID_TEMPLATE:
- LogError(Config, LOG_ERROR, "Invalid player template: %s", PlayerTemplateMetadata->Filename);
- fprintf(stderr, "Invalid player template: %s\n", PlayerTemplateMetadata->Filename);
- closedir(ProjectDirHandle);
- case RC_ERROR_MEMORY:
- case RC_ERROR_FILE:
- case RC_ARENA_FULL:
- return RC_ERROR_FATAL;
- case RC_SUCCESS:
- break;
- }
- }
- break;
- }
-
- ++FileIndex;
- }
+ fclose(File->Handle);
}
- closedir(ProjectDirHandle);
return RC_SUCCESS;
}
int
-MonitorDirectory(arena *MemoryArena, buffers *CollationBuffers, template *IndexTemplateMetadata, template *PlayerTemplateMetadata, config Config, int inotifyInstance, int WatchDescriptor)
+InsertIntoIndex(buffers *CollationBuffers, char *BaseFilename)
{
+ file_buffer Index;
+ Index.Buffer.ID = "Index";
+ CopyString(Index.Path, "%s/%s.index", Config.CacheDir, Config.ProjectID);
+ int FileReadCode = ReadFileIntoBuffer(&Index, 0);
+ switch(FileReadCode)
+ {
+ case RC_ERROR_MEMORY:
+ return RC_ERROR_MEMORY;
+ case RC_ERROR_FILE:
+ case RC_SUCCESS:
+ break;
+ }
+
+ int EntryInsertionOffset = -1;
+ int TitleInsertionOffset = -1;
+ int TitleInsertionEnd = -1;
+ int EntryCount = 0;
+
+ char InputFile[255];
+ CopyString(InputFile, "%s.hmml", BaseFilename);
+ HMMLToBuffers(CollationBuffers, InputFile);
+
+ if(FileReadCode == RC_SUCCESS)
+ {
+ EntryCount = *(int *)Index.Buffer.Ptr;
+ Index.Buffer.Ptr += sizeof(int);
+
+ while(Index.Buffer.Ptr - Index.Buffer.Location < Index.FileSize)
+ {
+ char IndexedFile[32];
+ char *Ptr = IndexedFile;
+ Index.Buffer.Ptr += CopyStringNoFormatT(Ptr, Index.Buffer.Ptr, ',') + 1;
+ if(!StringsDiffer(IndexedFile, BaseFilename))
+ {
+ if(!StringsDifferT(CollationBuffers->Title, Index.Buffer.Ptr, '\n'))
+ {
+ FreeBuffer(&Index.Buffer);
+ return RC_NOOP;
+ }
+ else
+ {
+ TitleInsertionOffset = Index.Buffer.Ptr - Index.Buffer.Location;
+ while(*Index.Buffer.Ptr != '\n' && Index.Buffer.Ptr - Index.Buffer.Location < Index.FileSize)
+ {
+ ++Index.Buffer.Ptr;
+ }
+ ++Index.Buffer.Ptr;
+ TitleInsertionEnd = Index.Buffer.Ptr - Index.Buffer.Location;
+ break;
+ }
+ }
+ else if(StringsDiffer(IndexedFile, BaseFilename) > 0)
+ {
+ while(*Index.Buffer.Ptr != '\n' && Index.Buffer.Ptr > Index.Buffer.Location + sizeof(int))
+ {
+ --Index.Buffer.Ptr;
+ }
+ if(Index.Buffer.Ptr > Index.Buffer.Location + sizeof(int))
+ {
+ ++Index.Buffer.Ptr;
+ }
+ EntryInsertionOffset = Index.Buffer.Ptr - Index.Buffer.Location;
+ break;
+ }
+ else
+ {
+ while(*Index.Buffer.Ptr != '\n' && Index.Buffer.Ptr - Index.Buffer.Location < Index.FileSize)
+ {
+ ++Index.Buffer.Ptr;
+ }
+ ++Index.Buffer.Ptr;
+ }
+ }
+ }
+
+ if(!(Index.Handle = fopen(Index.Path, "w"))) { FreeBuffer(&Index.Buffer); return RC_ERROR_FILE; }
+
+ if(FileReadCode == RC_ERROR_FILE)
+ {
+ Index.Buffer.Size = sizeof(int);
+ if(!(Index.Buffer.Location = malloc(Index.Buffer.Size)))
+ {
+ fclose(Index.Handle);
+ return RC_ERROR_MEMORY;
+ }
+ }
+
+ if(TitleInsertionOffset < 0) { EntryCount++; }
+
+ Index.Buffer.Ptr = Index.Buffer.Location;
+ *(int *)Index.Buffer.Ptr = EntryCount;
+ fwrite(Index.Buffer.Ptr, sizeof(int), 1, Index.Handle);
+ Index.Buffer.Ptr += sizeof(int);
+
+ if(EntryInsertionOffset >= 0)
+ {
+ fwrite(Index.Buffer.Ptr, EntryInsertionOffset - sizeof(int), 1, Index.Handle);
+ fprintf(Index.Handle, "%s,%s\n", BaseFilename, CollationBuffers->Title);
+ fwrite(Index.Buffer.Ptr + EntryInsertionOffset - sizeof(int), Index.FileSize - EntryInsertionOffset, 1, Index.Handle);
+ LogError(LOG_NOTICE, "Inserted %s - %s", BaseFilename, CollationBuffers->Title);
+ fprintf(stderr, "Inserted %s - %s\n", BaseFilename, CollationBuffers->Title);
+ }
+ else if(TitleInsertionOffset >= 0)
+ {
+ fwrite(Index.Buffer.Ptr, TitleInsertionOffset - sizeof(int), 1, Index.Handle);
+ fprintf(Index.Handle, "%s\n", CollationBuffers->Title);
+ fwrite(Index.Buffer.Ptr + TitleInsertionEnd - sizeof(int), Index.FileSize - TitleInsertionEnd, 1, Index.Handle);
+ LogError(LOG_NOTICE, "Edited %s - %s", BaseFilename, CollationBuffers->Title);
+ fprintf(stderr, "Edited %s - %s\n", BaseFilename, CollationBuffers->Title);
+ }
+ else
+ {
+ if(FileReadCode == RC_SUCCESS)
+ {
+ fwrite(Index.Buffer.Ptr, Index.FileSize - sizeof(int), 1, Index.Handle); // Write existing stuff back out
+ }
+ fprintf(Index.Handle, "%s,%s\n", BaseFilename, CollationBuffers->Title);
+ LogError(LOG_NOTICE, "Inserted %s - %s", BaseFilename, CollationBuffers->Title);
+ fprintf(stderr, "Inserted %s - %s\n", BaseFilename, CollationBuffers->Title);
+ }
+
+ fclose(Index.Handle);
+ FreeBuffer(&Index.Buffer);
+ return RC_SUCCESS;
+}
+
+int
+DeleteFromIndex(char *BaseFilename)
+{
+ // TODO(matt): LogError()
+ file_buffer Index;
+ Index.Buffer.ID = "Index";
+ CopyString(Index.Path, "%s/%s.index", Config.CacheDir, Config.ProjectID);
+
+ switch(ReadFileIntoBuffer(&Index, 0))
+ {
+ case RC_ERROR_FILE:
+ return RC_ERROR_FILE;
+ break;
+ case RC_ERROR_MEMORY:
+ LogError(LOG_ERROR, "DeleteFromIndex(): %s", strerror(errno));
+ return RC_ERROR_MEMORY;
+ break;
+ case RC_SUCCESS:
+ break;
+ }
+
+ int EntryCount = *(int *)Index.Buffer.Ptr;
+ Index.Buffer.Ptr += sizeof(int);
+
+ bool Found = FALSE;
+ int DeleteFrom = -1;
+ int DeleteTo = -1;
+
+ while(Index.Buffer.Ptr - Index.Buffer.Location < Index.FileSize)
+ {
+ if(!StringsDifferT(BaseFilename, Index.Buffer.Ptr, ','))
+ {
+ Found = TRUE;
+ --EntryCount;
+ DeleteFrom = Index.Buffer.Ptr - Index.Buffer.Location;
+ while(*Index.Buffer.Ptr != '\n' && Index.Buffer.Ptr - Index.Buffer.Location < Index.FileSize)
+ {
+ ++Index.Buffer.Ptr;
+ }
+ ++Index.Buffer.Ptr;
+ DeleteTo = Index.Buffer.Ptr - Index.Buffer.Location;
+ break;
+ }
+ ++Index.Buffer.Ptr;
+ }
+
+ if(Found)
+ {
+ if(EntryCount == 0)
+ {
+ remove(Index.Path);
+ }
+ else
+ {
+ if(!(Index.Handle = fopen(Index.Path, "w")))
+ {
+ free(Index.Buffer.Location);
+ return RC_ERROR_FILE;
+ }
+ Index.Buffer.Ptr = Index.Buffer.Location;
+ *(int *)Index.Buffer.Ptr = EntryCount;
+ fwrite(Index.Buffer.Ptr, DeleteFrom, 1, Index.Handle);
+ fwrite(Index.Buffer.Ptr + DeleteTo, Index.FileSize - DeleteTo, 1, Index.Handle);
+ fclose(Index.Handle);
+ }
+ }
+
+ free(Index.Buffer.Location);
+ return Found ? RC_SUCCESS : RC_NOOP;
+}
+
+int
+IndexToBuffer(buffers *CollationBuffers)
+{
+ RewindBuffer(&CollationBuffers->Index);
+ // TODO(matt): Consider parsing the index into a linked list, or do something to save us having to iterate through the index
+ // file multiple times
+
+ file_buffer Index;
+ Index.Buffer.ID = "Index";
+ CopyString(Index.Path, "%s/%s.index", Config.CacheDir, Config.ProjectID);
+ ReadFileIntoBuffer(&Index, 0);
+
+ //int EntryCount = *(int *)Index.Buffer.Ptr;
+ Index.Buffer.Ptr += sizeof(int);
+
+ CopyStringToBuffer(&CollationBuffers->Index, "
\n");
+ while(Index.Buffer.Ptr - Index.Buffer.Location < Index.FileSize)
+ {
+ char IndexedFile[32];
+ char *Ptr = IndexedFile;
+ Index.Buffer.Ptr += CopyStringNoFormatT(Ptr, Index.Buffer.Ptr, ',') + 1;
+
+ char Title[255];
+ Ptr = Title;
+ Index.Buffer.Ptr += CopyStringNoFormatT(Ptr, Index.Buffer.Ptr, '\n') + 1;
+
+ CopyStringToBuffer(&CollationBuffers->Index,
+ " - \n"
+ " %s\n"
+ "
\n",
+ IndexedFile, Title);
+
+ }
+ CopyStringToBuffer(&CollationBuffers->Index, "
");
+
+ FreeBuffer(&Index.Buffer);
+ return RC_SUCCESS;
+}
+
+int
+GeneratePlayerPage(buffers *CollationBuffers, template *PlayerTemplate, char *BaseFilename)
+{
+ char OutputDir[255];
+ CopyString(OutputDir, "%s/%s", Config.BaseDir, BaseFilename);
+ char PlayerPagePath[255];
+ CopyString(PlayerPagePath, "%s/index.html", OutputDir);
+
+ DIR *OutputDirectoryHandle;
+ if(!(OutputDirectoryHandle = opendir(OutputDir)))
+ {
+ if(MakeDir(OutputDir) == RC_ERROR_DIRECTORY)
+ {
+ LogError(LOG_ERROR, "Unable to create directory %s: %s", OutputDir, strerror(errno));
+ fprintf(stderr, "Unable to create directory %s: %s\n", OutputDir, strerror(errno));
+ return RC_ERROR_DIRECTORY;
+ };
+ }
+
+ closedir(OutputDirectoryHandle);
+ BuffersToHTML(CollationBuffers, PlayerTemplate, PlayerPagePath, PAGE_PLAYER);
+ return RC_SUCCESS;
+}
+
+int
+GenerateIndexPage(buffers *CollationBuffers, template *IndexTemplate)
+{
+ char IndexPagePath[255];
+ CopyString(IndexPagePath, "%s/index.html", Config.BaseDir);
+ IndexToBuffer(CollationBuffers);
+ BuffersToHTML(CollationBuffers, IndexTemplate, IndexPagePath, PAGE_INDEX);
+ return RC_SUCCESS;
+}
+
+int
+DeletePlayerPageFromFilesystem(char *BaseFilename)
+{
+ // NOTE(matt): Once we have the notion of an output filename format, we'll need to use that here
+ char PlayerDirPath[255];
+ CopyString(PlayerDirPath, "%s/%s", Config.BaseDir, BaseFilename);
+ DIR *PlayerDir;
+
+ if((PlayerDir = opendir(PlayerDirPath))) // There is a directory for the Player, which there probably should be if not for manual intervention
+ {
+ char PlayerPagePath[255];
+ CopyString(PlayerPagePath, "%s/index.html", PlayerDirPath);
+ FILE *PlayerPage;
+ if((PlayerPage = fopen(PlayerPagePath, "r")))
+ {
+ fclose(PlayerPage);
+ remove(PlayerPagePath);
+ }
+
+ closedir(PlayerDir);
+ if((remove(PlayerDirPath) == -1))
+ {
+ LogError(LOG_NOTICE, "Mostly removed %s. Unable to remove directory %s: %s", BaseFilename, PlayerDirPath, strerror(errno));
+ fprintf(stderr, "Mostly removed %s. Unable to remove directory %s: %s", BaseFilename, PlayerDirPath, strerror(errno));
+ }
+ else
+ {
+ LogError(LOG_INFORMATIONAL, "Fully removed %s from the system", BaseFilename);
+ fprintf(stderr, "Fully removed %s from the system\n", BaseFilename);
+ }
+ }
+ return RC_SUCCESS;
+}
+
+void
+DeleteEntry(char *BaseFilename)
+{
+ if(DeleteFromIndex(BaseFilename) == RC_SUCCESS)
+ {
+ DeletePlayerPageFromFilesystem(BaseFilename);
+ }
+}
+
+int
+MonitorDirectory(buffers *CollationBuffers, template *IndexTemplate, template *PlayerTemplate, int inotifyInstance, int WatchDescriptor)
+{
+
+#if DEBUG_MEM
+ FILE *MemLog = fopen("/home/matt/cinera_mem", "a+");
+ fprintf(MemLog, "\nCalled MonitorDirectory()\n");
+ fclose(MemLog);
+#endif
+
+ // TODO(matt): Maybe straight up store the IndexPath in the Config to save us having to derive it near / at the usage site
buffer Events;
- if(ClaimBuffer(MemoryArena, &Events, "inotify Events", Kilobytes(4)) == RC_ARENA_FULL) { return RC_ARENA_FULL; };
+ if(ClaimBuffer(&Events, "inotify Events", Kilobytes(4)) == RC_ARENA_FULL) { return RC_ARENA_FULL; };
struct inotify_event *Event;
int BytesRead;
@@ -3359,23 +3572,166 @@ MonitorDirectory(arena *MemoryArena, buffers *CollationBuffers, template *IndexT
while((BytesRead = read(inotifyInstance, Events.Location, Events.Size)) != -1 && errno == EAGAIN && BytesRead > 0)
{
for(Events.Ptr = Events.Location;
- Events.Ptr < Events.Location + BytesRead;
+ Events.Ptr < Events.Location + BytesRead && Events.Ptr - Events.Location < Events.Size;
Events.Ptr += sizeof(struct inotify_event) + Event->len)
{
Event = (struct inotify_event *)Events.Ptr;
- switch(RefreshProject(MemoryArena, CollationBuffers, IndexTemplateMetadata, PlayerTemplateMetadata, Config))
+
+ char *Ptr;
+ Ptr = Event->name;
+ Ptr += (StringLength(Event->name) - StringLength(".hmml"));
+ if(!(StringsDiffer(Ptr, ".hmml")))
{
- case RC_ERROR_DIRECTORY:
- case RC_ERROR_FATAL:
- DeclaimBuffer(MemoryArena, &Events);
- return RC_ERROR_FATAL;
- case RC_SUCCESS:
- break;
+ *Ptr = '\0';
+ char BaseFilename[255];
+ CopyString(BaseFilename, Event->name);
+ *Ptr = '.';
+
+ if(Event->mask & IN_DELETE || Event->mask & IN_MOVED_FROM)
+ {
+ // TODO(matt): Remove from Index and synchronise Table of Contents and player pages accordingly
+ DeleteEntry(BaseFilename);
+ GenerateIndexPage(CollationBuffers, IndexTemplate);
+ }
+ else
+ {
+ switch(InsertIntoIndex(CollationBuffers, BaseFilename))
+ {
+ case RC_SUCCESS:
+ GeneratePlayerPage(CollationBuffers, PlayerTemplate, BaseFilename);
+ GenerateIndexPage(CollationBuffers, IndexTemplate);
+ break;
+ case RC_NOOP:
+ break;
+ }
+ }
}
}
}
- DeclaimBuffer(MemoryArena, &Events);
+ DeclaimBuffer(&Events);
+ return RC_NOOP;
+}
+
+typedef struct
+{
+ bool Present;
+ char ID[32];
+} index_entry;
+
+int
+DeleteDeadIndexEntries()
+{
+ file_buffer Index;
+ Index.Buffer.ID = "Index";
+ CopyString(Index.Path, "%s/%s.index", Config.CacheDir, Config.ProjectID);
+ if(ReadFileIntoBuffer(&Index, 0) == RC_ERROR_FILE)
+ {
+ return RC_ERROR_FILE;
+ }
+
+ // TODO(matt): Stuff entries into an array, through which we can iterate, marking off input files that are still present
+ int EntryCount = *(int *)Index.Buffer.Ptr;
+ Index.Buffer.Ptr += sizeof(int);
+
+ index_entry Entries[EntryCount];
+
+ int i = 0;
+ while(Index.Buffer.Ptr - Index.Buffer.Location < Index.FileSize)
+ {
+ Index.Buffer.Ptr += CopyStringNoFormatT(Entries[i].ID, Index.Buffer.Ptr, ',');
+ Entries[i].Present = FALSE;
+ while(*Index.Buffer.Ptr != '\n')
+ {
+ ++Index.Buffer.Ptr;
+ }
+ ++Index.Buffer.Ptr, ++i;
+ }
+
+ DIR *ProjectDirHandle;
+ if(!(ProjectDirHandle = opendir(Config.ProjectDir)))
+ {
+ LogError(LOG_ERROR, "Unable to scan project directory %s: %s", Config.ProjectDir, strerror(errno));
+ fprintf(stderr, "Unable to scan project directory %s: %s\n", Config.ProjectDir, strerror(errno));
+ return RC_ERROR_DIRECTORY;
+ }
+
+ struct dirent *ProjectFiles;
+
+ while((ProjectFiles = readdir(ProjectDirHandle)))
+ {
+ char *Ptr;
+ Ptr = ProjectFiles->d_name;
+ Ptr += (StringLength(ProjectFiles->d_name) - StringLength(".hmml"));
+ if(!(StringsDiffer(Ptr, ".hmml")))
+ {
+ *Ptr = '\0';
+ for(int i = 0; i < EntryCount; ++i)
+ {
+ if(!StringsDiffer(Entries[i].ID, ProjectFiles->d_name))
+ {
+ Entries[i].Present = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ closedir(ProjectDirHandle);
+
+ bool Deleted = FALSE;
+ for(int i = 0; i < EntryCount; ++i)
+ {
+ if(Entries[i].Present == FALSE)
+ {
+ Deleted = TRUE;
+ DeleteEntry(Entries[i].ID);
+ }
+ }
+
+ FreeBuffer(&Index.Buffer);
+ return Deleted ? RC_SUCCESS : RC_NOOP;
+}
+
+int
+SyncIndexWithInput(buffers *CollationBuffers, template *IndexTemplate, template *PlayerTemplate)
+{
+ DeleteDeadIndexEntries();
+
+ DIR *ProjectDirHandle;
+ if(!(ProjectDirHandle = opendir(Config.ProjectDir)))
+ {
+ LogError(LOG_ERROR, "Unable to scan project directory %s: %s", Config.ProjectDir, strerror(errno));
+ fprintf(stderr, "Unable to scan project directory %s: %s\n", Config.ProjectDir, strerror(errno));
+ return RC_ERROR_DIRECTORY;
+ }
+
+ struct dirent *ProjectFiles;
+ bool Inserted = FALSE;
+
+ while((ProjectFiles = readdir(ProjectDirHandle)))
+ {
+ char *Ptr = ProjectFiles->d_name;
+ Ptr += (StringLength(ProjectFiles->d_name) - StringLength(".hmml"));
+ if(!(StringsDiffer(Ptr, ".hmml")))
+ {
+ *Ptr = '\0';
+ switch(InsertIntoIndex(CollationBuffers, ProjectFiles->d_name))
+ {
+ case RC_SUCCESS:
+ GeneratePlayerPage(CollationBuffers, PlayerTemplate, ProjectFiles->d_name);
+ Inserted = TRUE;
+ break;
+ case RC_NOOP:
+ break;
+ }
+ }
+ }
+ closedir(ProjectDirHandle);
+
+ if(Inserted)
+ {
+ GenerateIndexPage(CollationBuffers, IndexTemplate);
+ }
return RC_SUCCESS;
}
@@ -3389,15 +3745,18 @@ main(int ArgC, char **Args)
.Edition = EDITION_SINGLE,
.ImagesDir = ".",
.JSDir = ".",
- .LogLevel = LOG_DEBUG,
+ .LogLevel = LOG_EMERGENCY,
.DefaultMedium = "programming",
.Mode = getenv("CINERA_MODE") ? MODE_INTEGRATE : MODE_BARE,
.OutLocation = "out.html",
.OutIntegratedLocation = "out_integrated.html",
.ForceIntegration = FALSE,
.ProjectDir = ".",
+ .ProjectID = "",
+ .RootDir = ".",
.TemplatePlayerLocation = "template_player.html",
- .TemplateIndexLocation = "template_index.html"
+ .TemplateIndexLocation = "template_index.html",
+ .UpdateInterval = 4
};
if(getenv("XDG_CACHE_HOME"))
@@ -3409,16 +3768,16 @@ main(int ArgC, char **Args)
CopyString(DefaultConfig.CacheDir, "%s/.cache/cinera", getenv("HOME"));
}
- config Config = DefaultConfig;
+ Config = DefaultConfig;
if(ArgC < 2)
{
- PrintUsage(Args[0], DefaultConfig);
+ PrintUsage(Args[0], &DefaultConfig);
return RC_RIP;
}
char CommandLineArg;
- while((CommandLineArg = getopt(ArgC, Args, "b:c:fi:j:l:m:o:p:q:t:x:h")) != -1)
+ while((CommandLineArg = getopt(ArgC, Args, "b:c:fhi:I:j:l:m:o:p:r:t:u:x:")) != -1)
{
switch(CommandLineArg)
{
@@ -3434,6 +3793,9 @@ main(int ArgC, char **Args)
case 'i':
Config.ImagesDir = optarg;
break;
+ case 'I':
+ Config.ProjectID = optarg;
+ break;
case 'j':
Config.JSDir = optarg;
break;
@@ -3451,28 +3813,42 @@ main(int ArgC, char **Args)
case 'p':
Config.ProjectDir = optarg;
break;
+ case 'r':
+ Config.RootDir = optarg;
+ break;
case 't':
Config.TemplatePlayerLocation = optarg;
Config.Mode = MODE_INTEGRATE;
break;
+ case 'u':
+ Config.UpdateInterval = StringToInt(optarg);
+ break;
case 'x':
Config.TemplateIndexLocation = optarg;
Config.Mode = MODE_INTEGRATE;
break;
- //case 'c':
- // Override config path, once we even have a default!
case 'h':
default:
- PrintUsage(Args[0], DefaultConfig);
+ PrintUsage(Args[0], &DefaultConfig);
return 1;
}
}
+ // TODO(matt): Sanitise this entry into Project Mode, probably once we switch to the config system
if(StringsDiffer(Config.BaseDir, ".") || StringsDiffer(Config.ProjectDir, "."))
{
if(StringsDiffer(Config.BaseDir, ".") && StringsDiffer(Config.ProjectDir, "."))
{
- Config.Edition = EDITION_PROJECT;
+ if(StringsDiffer(Config.ProjectID, ""))
+ {
+ Config.Edition = EDITION_PROJECT;
+ }
+ else
+ {
+ fprintf(stderr, "%s: Project ID must be set using the -I flag in order for us to enter Project Mode\n", Args[0]);
+ return 1;
+
+ }
}
else
{
@@ -3523,45 +3899,54 @@ main(int ArgC, char **Args)
// In our case here, we just want to straight up validate a template if Config.Mode == MODE_INTEGRATE
// And, in that same state, we gotta keep a Template buffer around
- // NOTE(matt): Init MemoryArena
- arena MemoryArena;
+ // NOTE(matt): Init MemoryArena (it is global)
MemoryArena.Size = Megabytes(4);
if(!(MemoryArena.Location = calloc(MemoryArena.Size, 1)))
{
- LogError(Config, LOG_EMERGENCY, "%s: %s", Args[0], strerror(errno));
+ LogError(LOG_EMERGENCY, "%s: %s", Args[0], strerror(errno));
return RC_RIP;
}
MemoryArena.Ptr = MemoryArena.Location;
- buffer Errors;
- if(ClaimBuffer(&MemoryArena, &Errors, "Errors", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
+#if DEBUG_MEM
+ FILE *MemLog = fopen("/home/matt/cinera_mem", "a+");
+ fprintf(MemLog, " Allocated MemoryArena (%d)\n", MemoryArena.Size);
+ fclose(MemLog);
+ printf(" Allocated MemoryArena (%d)\n", MemoryArena.Size);
+#endif
- // NOTE(matt): Setup buffers and ptrs
- //char *InPtr;
+#if DEBUG
+ printf("Allocated MemoryArena: %d\n\n", MemoryArena.Size);
+#endif
+
+ buffer Errors;
+ if(ClaimBuffer(&Errors, "Errors", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
// NOTE(matt): Tree structure of buffer dependencies
// IncludesPlayer
// Menus
// Player
// Script
+ //
+ // IncludesIndex
+ // Index
buffers CollationBuffers;
- if(ClaimBuffer(&MemoryArena, &CollationBuffers.IncludesPlayer, "IncludesPlayer", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
- if(ClaimBuffer(&MemoryArena, &CollationBuffers.Menus, "Menus", Kilobytes(24)) == RC_ARENA_FULL) { goto RIP; };
- if(ClaimBuffer(&MemoryArena, &CollationBuffers.Player, "Player", Kilobytes(256)) == RC_ARENA_FULL) { goto RIP; };
- if(ClaimBuffer(&MemoryArena, &CollationBuffers.Script, "Script", Kilobytes(8)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.IncludesPlayer, "IncludesPlayer", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.Menus, "Menus", Kilobytes(24)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.Player, "Player", Kilobytes(256)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.Script, "Script", Kilobytes(8)) == RC_ARENA_FULL) { goto RIP; };
- if(ClaimBuffer(&MemoryArena, &CollationBuffers.IncludesIndex, "IncludesIndex", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
- if(ClaimBuffer(&MemoryArena, &CollationBuffers.Index, "Index", Kilobytes(8)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.IncludesIndex, "IncludesIndex", Kilobytes(1)) == RC_ARENA_FULL) { goto RIP; };
+ if(ClaimBuffer(&CollationBuffers.Index, "Index", Kilobytes(8)) == RC_ARENA_FULL) { goto RIP; };
*CollationBuffers.Title = '\0';
- template *PlayerTemplateMetadata;
- template *IndexTemplateMetadata;
+ template *PlayerTemplate;
+ template *IndexTemplate;
if(Config.Mode == MODE_INTEGRATE)
{
- if(ClaimTemplate(&MemoryArena, &PlayerTemplateMetadata, Config.TemplatePlayerLocation) == RC_ARENA_FULL) { goto RIP; };
- switch(ValidateTemplate(&Errors, PlayerTemplateMetadata, Config, PAGE_PLAYER))
+ switch(ValidateTemplate(&Errors, &PlayerTemplate, PAGE_PLAYER))
{
case RC_INVALID_TEMPLATE: // Invalid template
case RC_ERROR_FILE: // Could not load template
@@ -3573,8 +3958,7 @@ main(int ArgC, char **Args)
if(Config.Edition == EDITION_PROJECT)
{
- if(ClaimTemplate(&MemoryArena, &IndexTemplateMetadata, Config.TemplateIndexLocation) == RC_ARENA_FULL) { goto RIP; };
- switch(ValidateTemplate(&Errors, IndexTemplateMetadata, Config, PAGE_INDEX))
+ switch(ValidateTemplate(&Errors, &IndexTemplate, PAGE_INDEX))
{
case RC_INVALID_TEMPLATE: // Invalid template
case RC_ERROR_MEMORY: // Could not allocate memory for template
@@ -3595,22 +3979,31 @@ main(int ArgC, char **Args)
if(Config.Edition == EDITION_PROJECT)
{
- switch(RefreshProject(&MemoryArena, &CollationBuffers, IndexTemplateMetadata, PlayerTemplateMetadata, Config))
- {
- case RC_ERROR_DIRECTORY:
- case RC_ERROR_FATAL:
- goto RIP;
- case RC_SUCCESS:
- break;
- }
+
+#if DEBUG_MEM
+ FILE *MemLog = fopen("/home/matt/cinera_mem", "w+");
+ fprintf(MemLog, "Entered Project Edition\n");
+ fclose(MemLog);
+#endif
+
+ printf("[Cinera %s]\n"
+ "\n"
+ "Project ID: %s\n"
+ "Project Directory: %s\n"
+ "\n"
+ "Synchronising with annotation files in Project Directory\n", CINERA_VERSION, Config.ProjectID, Config.ProjectDir);
+
+ SyncIndexWithInput(&CollationBuffers, IndexTemplate, PlayerTemplate);
+
+ printf("\nMonitoring Project Directory for new, edited or deleted .hmml files\n");
int inotifyInstance = inotify_init1(IN_NONBLOCK);
- int WatchDescriptor = inotify_add_watch(inotifyInstance, Config.ProjectDir, IN_CLOSE_WRITE | IN_MOVED_TO);
+ // 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);
- while(MonitorDirectory(&MemoryArena, &CollationBuffers, IndexTemplateMetadata, PlayerTemplateMetadata, Config, inotifyInstance, WatchDescriptor) == RC_SUCCESS)
+ while(MonitorDirectory(&CollationBuffers, IndexTemplate, PlayerTemplate, inotifyInstance, WatchDescriptor) != RC_ERROR_FATAL)
{
- // TODO(matt): Make this update frequency configurable
- sleep(1);
+ sleep(Config.UpdateInterval);
}
}
else
@@ -3618,14 +4011,14 @@ main(int ArgC, char **Args)
if(optind == ArgC)
{
fprintf(stderr, "%s: requires at least one input .hmml file\n", Args[0]);
- PrintUsage(Args[0], DefaultConfig);
+ PrintUsage(Args[0], &DefaultConfig);
goto RIP;
}
NextFile:
for(int FileIndex = optind; FileIndex < ArgC; ++FileIndex)
{
- switch(HMMLToBuffers(&MemoryArena, &CollationBuffers, Config, Args[FileIndex]))
+ switch(HMMLToBuffers(&CollationBuffers, Args[FileIndex]))
{
// TODO(matt): Actually sort out the fatality of these cases, once we are always-on
case RC_ERROR_FILE:
@@ -3640,11 +4033,11 @@ NextFile:
case RC_SUCCESS:
break;
};
- switch(BuffersToHTML(&MemoryArena, CollationBuffers, PlayerTemplateMetadata, Config, 0, PAGE_PLAYER))
+ switch(BuffersToHTML(&CollationBuffers, PlayerTemplate, 0, PAGE_PLAYER))
{
// TODO(matt): Actually sort out the fatality of these cases, once we are always-on
case RC_INVALID_TEMPLATE:
- LogError(Config, LOG_ERROR, "Invalid player template: %s", PlayerTemplateMetadata->Filename);
+ LogError(LOG_ERROR, "Invalid player template: %s", PlayerTemplate->Metadata.Filename);
case RC_ERROR_MEMORY:
case RC_ERROR_FILE:
case RC_ARENA_FULL:
@@ -3657,20 +4050,28 @@ NextFile:
if(Config.Mode == MODE_INTEGRATE)
{
- DeclaimTemplate(&MemoryArena, &PlayerTemplateMetadata);
+ DeclaimTemplate(PlayerTemplate);
if(Config.Edition == EDITION_PROJECT)
{
- DeclaimTemplate(&MemoryArena, &IndexTemplateMetadata);
+ DeclaimTemplate(IndexTemplate);
}
}
- DeclaimBuffer(&MemoryArena, &CollationBuffers.Index);
- DeclaimBuffer(&MemoryArena, &CollationBuffers.IncludesIndex);
- DeclaimBuffer(&MemoryArena, &CollationBuffers.Script);
- DeclaimBuffer(&MemoryArena, &CollationBuffers.Player);
- DeclaimBuffer(&MemoryArena, &CollationBuffers.Menus);
- DeclaimBuffer(&MemoryArena, &CollationBuffers.IncludesPlayer);
- DeclaimBuffer(&MemoryArena, &Errors);
+ DeclaimBuffer(&CollationBuffers.Index);
+ DeclaimBuffer(&CollationBuffers.IncludesIndex);
+ DeclaimBuffer(&CollationBuffers.Script);
+ DeclaimBuffer(&CollationBuffers.Player);
+ DeclaimBuffer(&CollationBuffers.Menus);
+ DeclaimBuffer(&CollationBuffers.IncludesPlayer);
+ DeclaimBuffer(&Errors);
RIP:
free(MemoryArena.Location);
+
+#if DEBUG_MEM
+ MemLog = fopen("/home/matt/cinera_mem", "a+");
+ fprintf(MemLog, " Freed MemoryArena\n");
+ fclose(MemLog);
+ printf(" Freed MemoryArena\n");
+#endif
+
}