From b133f15a11eafbef301503c0c80ab8061c48ab7a Mon Sep 17 00:00:00 2001 From: Matt Mascarenhas Date: Fri, 15 Sep 2017 02:11:39 +0100 Subject: [PATCH] hmml_to_html.c: Always On --- hmml_to_html/hmml_to_html.c | 78 ++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 10 deletions(-) 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; };