diff --git a/hmml_to_html/hmml_to_html.c b/hmml_to_html/hmml_to_html.c
index 2f834b8..3c0b8c1 100644
--- a/hmml_to_html/hmml_to_html.c
+++ b/hmml_to_html/hmml_to_html.c
@@ -25,7 +25,8 @@ typedef unsigned int bool;
#include
#include // NOTE(matt): strerror
#include //NOTE(matt): errno
-
+#include // NOTE(matt): inotify
+#include // NOTE(matt): sleep()
#define Kilobytes(Bytes) Bytes << 10
#define Megabytes(Bytes) Bytes << 20
@@ -450,6 +451,7 @@ MakeDir(char *Path)
void
LogUsage(buffer Buffer, char *CacheDir)
{
+#if DEBUG
char LogPath[255];
CopyString(LogPath, "%s/%s", CacheDir, "buffers.log");
FILE *LogFile;
@@ -468,6 +470,7 @@ LogUsage(buffer Buffer, char *CacheDir)
Buffer.Ptr - Buffer.Location,
Buffer.Size);
fclose(LogFile);
+#endif
}
__attribute__ ((format (printf, 3, 4)))
@@ -3144,6 +3147,7 @@ RefreshIndex(arena *MemoryArena, buffers *CollationBuffers, config Config, char
{
LogError(Config, LOG_ERROR, "RefreshIndex(): %s", strerror(errno));
free(Index.Location);
+ fclose(IndexFile);
return RC_ERROR_MEMORY;
}
Scratch.Ptr = Scratch.Location;
@@ -3154,14 +3158,17 @@ RefreshIndex(arena *MemoryArena, buffers *CollationBuffers, config Config, char
*Scratch.Ptr = '\0';
Index.Ptr = Index.Location + Head;
- CopyStringToBuffer(&Index, "%s,%s\n", BaseFilename, CollationBuffers->Title);
+ CopyStringToBuffer(&Index, "%s,%s\n"
+ "%s",
+ BaseFilename, CollationBuffers->Title,
+ Scratch.Location);
- CopyStringToBuffer(&Index, Scratch.Location);
free(Scratch.Location);
+ Index.Size = Index.Ptr - Index.Location;
fclose(IndexFile);
IndexFile = fopen(IndexPath, "w");
- fwrite(Index.Location, Index.Ptr - Index.Location, 1, IndexFile);
+ fwrite(Index.Location, Index.Size, 1, IndexFile);
Inserted = TRUE;
}
@@ -3176,19 +3183,22 @@ RefreshIndex(arena *MemoryArena, buffers *CollationBuffers, config Config, char
++EntryCount;
}
- if(Found == FALSE)
+ if(!Found)
{
++EntryCount;
// TODO(matt): Write the EntryCount into the index
- if(Inserted == FALSE)
+ 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");
- Index.Ptr = Index.Location;
- while(Index.Ptr - Index.Location < IndexFileSize)
+ while(Index.Ptr - Index.Location < Index.Size)
{
char IndexedFile[32];
char *Ptr = IndexedFile;
@@ -3198,6 +3208,13 @@ RefreshIndex(arena *MemoryArena, buffers *CollationBuffers, config Config, char
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"
@@ -3330,6 +3347,38 @@ NextFile:
return RC_SUCCESS;
}
+int
+MonitorDirectory(arena *MemoryArena, buffers *CollationBuffers, template *IndexTemplateMetadata, template *PlayerTemplateMetadata, config Config, int inotifyInstance, int WatchDescriptor)
+{
+ buffer Events;
+ if(ClaimBuffer(MemoryArena, &Events, "inotify Events", Kilobytes(4)) == RC_ARENA_FULL) { return RC_ARENA_FULL; };
+
+ struct inotify_event *Event;
+ int BytesRead;
+
+ 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 += sizeof(struct inotify_event) + Event->len)
+ {
+ Event = (struct inotify_event *)Events.Ptr;
+ switch(RefreshProject(MemoryArena, CollationBuffers, IndexTemplateMetadata, PlayerTemplateMetadata, Config))
+ {
+ case RC_ERROR_DIRECTORY:
+ case RC_ERROR_FATAL:
+ DeclaimBuffer(MemoryArena, &Events);
+ return RC_ERROR_FATAL;
+ case RC_SUCCESS:
+ break;
+ }
+ }
+ }
+
+ DeclaimBuffer(MemoryArena, &Events);
+ return RC_SUCCESS;
+}
+
int
main(int ArgC, char **Args)
{
@@ -3550,11 +3599,19 @@ main(int ArgC, char **Args)
{
case RC_ERROR_DIRECTORY:
case RC_ERROR_FATAL:
- // HERE
goto RIP;
case RC_SUCCESS:
break;
}
+
+ int inotifyInstance = inotify_init1(IN_NONBLOCK);
+ int WatchDescriptor = inotify_add_watch(inotifyInstance, Config.ProjectDir, IN_CLOSE_WRITE | IN_MOVED_TO);
+
+ while(MonitorDirectory(&MemoryArena, &CollationBuffers, IndexTemplateMetadata, PlayerTemplateMetadata, Config, inotifyInstance, WatchDescriptor) == RC_SUCCESS)
+ {
+ // TODO(matt): Make this update frequency configurable
+ sleep(1);
+ }
}
else
{
@@ -3578,7 +3635,8 @@ NextFile:
case RC_ERROR_MAX_REFS:
case RC_ERROR_QUOTE:
case RC_INVALID_REFERENCE:
- goto NextFile;
+ if(FileIndex < (ArgC - 1)) { goto NextFile; }
+ else { goto RIP; }
case RC_SUCCESS:
break;
};