cinera.c: Clean up string copy functions

This commit replaces ClearCopyStringNoFormat() with
ClearCopyStringNoFormatOrTerminate(). All calls to that function
passed an implicitly 0-terminated string as the destination, meaning
that we don't need to 0-terminate them and, in not doing, we free up a
byte to store data.

It also deduplicates code as CopyBytes(), and does a little bounds
checking before actually trying to copy.
This commit is contained in:
Matt Mascarenhas 2023-01-13 12:01:26 +00:00
parent 6b09247cd2
commit 1280142d45
1 changed files with 64 additions and 105 deletions

View File

@ -23,7 +23,7 @@ typedef struct
version CINERA_APP_VERSION = {
.Major = 0,
.Minor = 10,
.Patch = 20
.Patch = 21
};
#define __USE_XOPEN2K8 // NOTE(matt): O_NOFOLLOW
@ -478,14 +478,20 @@ typedef struct
uint64_t Length;
} string;
int
CopyBytes(char *Dest, char *Src, int Count)
{
for(int i = 0; i < Count; ++i)
{
Dest[i] = Src[i];
}
return Count;
}
int
CopyStringToBarePtr(char *Dest, string Src)
{
for(int i = 0; i < Src.Length; ++i)
{
*Dest++ = Src.Base[i];
}
return Src.Length;
return CopyBytes(Dest, Src.Base, Src.Length);
}
typedef struct
@ -4275,10 +4281,7 @@ CopyStringNoFormat_(int LineNumber, char *Dest, int DestSize, string String)
"%.*s\n", LineNumber, DestSize, String.Length, (int)String.Length, String.Base);
__asm__("int3");
}
for(int i = 0; i < String.Length; ++i)
{
*Dest++ = String.Base[i];
}
Dest += CopyBytes(Dest, String.Base, String.Length);
*Dest = '\0';
return String.Length;
}
@ -4295,31 +4298,7 @@ ClearCopyStringNoFormatOrTerminate_(int LineNumber, char *Dest, int DestSize, st
}
Clear(Dest, DestSize);
for(int i = 0; i < String.Length; ++i)
{
*Dest++ = String.Base[i];
}
return String.Length;
}
#define ClearCopyStringNoFormat(Dest, DestSize, String) ClearCopyStringNoFormat_(__LINE__, Dest, DestSize, String)
int
ClearCopyStringNoFormat_(int LineNumber, char *Dest, int DestSize, string String)
{
if(String.Length + 1 > DestSize)
{
printf("ClearCopyStringNoFormat() call on line %d has been passed a buffer too small (%d bytes) to contain null-terminated %ld(+1)-character string:\n"
"%.*s\n", LineNumber, DestSize, String.Length, (int)String.Length, String.Base);
__asm__("int3");
}
Clear(Dest, DestSize);
for(int i = 0; i < String.Length; ++i)
{
*Dest++ = String.Base[i];
}
*Dest = '\0';
return String.Length;
return CopyBytes(Dest, String.Base, String.Length);
}
// TODO(matt): Maybe do a version of this that takes a string as a Terminator
@ -4327,21 +4306,20 @@ ClearCopyStringNoFormat_(int LineNumber, char *Dest, int DestSize, string String
int
CopyStringNoFormatT_(int LineNumber, char *Dest, int DestSize, char *String, char Terminator)
{
int Length = 0;
char *Start = String;
while(*String != Terminator)
int BytesToWrite = 0;
while(String[BytesToWrite] && String[BytesToWrite] != Terminator)
{
*Dest++ = *String++;
++Length;
++BytesToWrite;
}
if(Length >= DestSize)
if(BytesToWrite >= DestSize)
{
printf("CopyStringNoFormatT() call on line %d has been passed a buffer too small (%d bytes) to contain %c-terminated %d(+1)-character string:\n"
"%.*s\n", LineNumber, DestSize, Terminator == 0 ? '0' : Terminator, Length, Length, Start);
"%.*s\n", LineNumber, DestSize, Terminator == 0 ? '0' : Terminator, BytesToWrite, BytesToWrite, String);
__asm__("int3");
}
Dest += CopyBytes(Dest, String, BytesToWrite);
*Dest = '\0';
return Length;
return BytesToWrite;
}
#define CopyStringToBuffer(Dest, Format, ...) CopyStringToBuffer_(__LINE__, Dest, Format, ##__VA_ARGS__)
@ -4418,10 +4396,7 @@ CopyStringToBufferNoFormat_(int LineNumber, buffer *Dest, string String)
"%.*s\n", BufferIDStrings[Dest->ID], LineNumber, String.Length, (int)String.Length, String.Base);
__asm__("int3");
}
for(int i = 0; i < String.Length; ++i)
{
*Dest->Ptr++ = String.Base[i];
}
Dest->Ptr += CopyBytes(Dest->Ptr, String.Base, String.Length);
*Dest->Ptr = '\0';
}
@ -4435,27 +4410,20 @@ CopyStringToBufferNoTerminate_(int LineNumber, buffer *Dest, string Src)
"%.*s\n", BufferIDStrings[Dest->ID], LineNumber, Src.Length, (int)Src.Length, Src.Base);
__asm__("int3");
}
for(int i = 0; i < Src.Length; ++i)
{
*Dest->Ptr++ = Src.Base[i];
}
Dest->Ptr += CopyBytes(Dest->Ptr, Src.Base, Src.Length);
}
#define CopyStringToBufferNoFormatL(Dest, Length, String) CopyStringToBufferNoFormatL_(__LINE__, Dest, Length, String)
void
CopyStringToBufferNoFormatL_(int LineNumber, buffer *Dest, int Length, char *String)
{
char *Start = String;
for(int i = 0; i < Length; ++i)
if(Dest->Ptr - Dest->Location + Length + 1 >= Dest->Size)
{
*Dest->Ptr++ = *String++;
}
if(Dest->Ptr - Dest->Location >= Dest->Size)
{
fprintf(stderr, "CopyStringToBufferNoFormat(%s) call on line %d cannot accommodate %ld-character string:\n"
"%s\n", BufferIDStrings[Dest->ID], LineNumber, StringLength(Start), Start);
fprintf(stderr, "CopyStringToBufferNoFormat(%s) call on line %d cannot accommodate %ld(+1)-character string:\n"
"%s\n", BufferIDStrings[Dest->ID], LineNumber, StringLength(String), String);
__asm__("int3");
}
Dest->Ptr += CopyBytes(Dest->Ptr, String, Length);
*Dest->Ptr = '\0';
}
@ -4599,10 +4567,7 @@ CopyBuffer_(int LineNumber, buffer *Dest, buffer *Src)
fprintf(stderr, "CopyBuffer(%s) call on line %d cannot accommodate %ld(+1)-character %s\n", BufferIDStrings[Dest->ID], LineNumber, StringLength(Src->Location), BufferIDStrings[Src->ID]);
__asm__("int3");
}
for(int i = 0; i < Src->Ptr - Src->Location; ++i)
{
*Dest->Ptr++ = Src->Location[i];
}
Dest->Ptr += CopyBytes(Dest->Ptr, Src->Location, Src->Ptr - Src->Location);
*Dest->Ptr = '\0';
}
@ -4662,10 +4627,7 @@ CopyLandmarkedBuffer_(int LineNumber, buffer *Dest, buffer *Src, uint32_t *PrevS
if(PrevStartLinkOffset) { *PrevStartLinkOffset += Dest->Ptr - Dest->Location; }
OffsetLandmarks(Dest, Src, PageType);
for(int i = 0; i < Src->Ptr - Src->Location; ++i)
{
*Dest->Ptr++ = Src->Location[i];
}
Dest->Ptr += CopyBytes(Dest->Ptr, Src->Location, Src->Ptr - Src->Location);
*Dest->Ptr = '\0';
}
@ -4679,10 +4641,7 @@ CopyBufferSized_(int LineNumber, buffer *Dest, buffer *Src, uint64_t Size)
fprintf(stderr, "CopyBufferSized(%s) call on line %d cannot accommodate %ld-character %s\n", BufferIDStrings[Dest->ID], LineNumber, Size, BufferIDStrings[Src->ID]);
__asm__("int3");
}
for(int i = 0; i < Size; ++i)
{
*Dest->Ptr++ = Src->Location[i];
}
Dest->Ptr += CopyBytes(Dest->Ptr, Src->Location, Size);
}
void
@ -6659,7 +6618,7 @@ UpdateAssetInDB(asset *Asset)
StoredAsset.Height = Asset->Dimensions.Height;
StoredAsset.Associated = Asset->Associated;
ClearCopyStringNoFormat(StoredAsset.Filename, sizeof(StoredAsset.Filename), Wrap0i(Asset->Filename));
ClearCopyStringNoFormatOrTerminate(StoredAsset.Filename, sizeof(StoredAsset.Filename), Wrap0i(Asset->Filename));
fwrite(&StoredAsset, sizeof(StoredAsset), 1, DB.Metadata.File.Handle);
AccumulateFileEditSize(&DB.Metadata, sizeof(StoredAsset));
@ -10995,7 +10954,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
}
else
{
ClearCopyStringNoFormat(CollationBuffers->Title, sizeof(CollationBuffers->Title), Wrap0(HMML.metadata.title));
ClearCopyStringNoFormatOrTerminate(CollationBuffers->Title, sizeof(CollationBuffers->Title), Wrap0(HMML.metadata.title));
Title = Wrap0(HMML.metadata.title);
}
@ -11084,7 +11043,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
}
else
{
ClearCopyStringNoFormat(N->WorkingThis.Number, sizeof(N->WorkingThis.Number), Wrap0(HMML.metadata.number));
ClearCopyStringNoFormatOrTerminate(N->WorkingThis.Number, sizeof(N->WorkingThis.Number), Wrap0(HMML.metadata.number));
}
}
@ -13035,9 +12994,9 @@ InsertIntoDB(neighbourhood *N, buffers *CollationBuffers, template *BespokeTempl
VideoIsPrivate = TRUE;
}
ClearCopyStringNoFormat(N->WorkingThis.HMMLBaseFilename, sizeof(N->WorkingThis.HMMLBaseFilename), BaseFilename);
ClearCopyStringNoFormatOrTerminate(N->WorkingThis.HMMLBaseFilename, sizeof(N->WorkingThis.HMMLBaseFilename), BaseFilename);
if(!VideoIsPrivate) { ClearCopyStringNoFormat(N->WorkingThis.Title, sizeof(N->WorkingThis.Title), Wrap0i(CollationBuffers->Title)); }
if(!VideoIsPrivate) { ClearCopyStringNoFormatOrTerminate(N->WorkingThis.Title, sizeof(N->WorkingThis.Title), Wrap0i(CollationBuffers->Title)); }
if(!DB.File.Buffer.Location)
{
@ -15445,11 +15404,11 @@ UpgradeDB(int OriginalDBVersion)
DB.AssetsBlock.BlockID = FOURCC("ASET");
DB.AssetsBlock.Count = 0;
ClearCopyStringNoFormat(DB.AssetsBlock.RootDir, sizeof(DB.AssetsBlock.RootDir), Config->AssetsRootDir);
ClearCopyStringNoFormat(DB.AssetsBlock.RootURL, sizeof(DB.AssetsBlock.RootURL), Config->AssetsRootURL);
ClearCopyStringNoFormat(DB.AssetsBlock.CSSDir, sizeof(DB.AssetsBlock.CSSDir), Config->CSSDir);
ClearCopyStringNoFormat(DB.AssetsBlock.ImagesDir, sizeof(DB.AssetsBlock.ImagesDir), Config->ImagesDir);
ClearCopyStringNoFormat(DB.AssetsBlock.JSDir, sizeof(DB.AssetsBlock.JSDir), Config->JSDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.RootDir, sizeof(DB.AssetsBlock.RootDir), Config->AssetsRootDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.RootURL, sizeof(DB.AssetsBlock.RootURL), Config->AssetsRootURL);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.CSSDir, sizeof(DB.AssetsBlock.CSSDir), Config->CSSDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.ImagesDir, sizeof(DB.AssetsBlock.ImagesDir), Config->ImagesDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.JSDir, sizeof(DB.AssetsBlock.JSDir), Config->JSDir);
++DB.Header.BlockCount;
OpenFileForWriting(&DB.Metadata.File);
@ -15497,7 +15456,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
char *OldPlayerDirectory = ConstructDirectoryPath(&OldBaseDir, &OldPlayerLocation, 0);
db_header_project NewProjectHeader = *N->Project;
ClearCopyStringNoFormat(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir);
ClearCopyStringNoFormatOrTerminate(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir);
string NewBaseDir = Wrap0i(NewProjectHeader.BaseDir);
char *NewPlayerDirectory = ConstructDirectoryPath(&NewBaseDir, &CurrentProject->PlayerLocation, 0);
@ -15521,7 +15480,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
}
Free(OldPlayerDirectory);
ClearCopyStringNoFormat(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation), CurrentProject->PlayerLocation);
ClearCopyStringNoFormatOrTerminate(N->Project->PlayerLocation, sizeof(N->Project->PlayerLocation), CurrentProject->PlayerLocation);
HasNewPlayerLocation = TRUE;
}
@ -15533,8 +15492,8 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
char *OldSearchDirectory = ConstructDirectoryPath(&OldBaseDir, &OldSearchLocation, 0);
db_header_project NewProjectHeader = *N->Project;
ClearCopyStringNoFormat(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir);
ClearCopyStringNoFormat(NewProjectHeader.SearchLocation, sizeof(NewProjectHeader.SearchLocation), CurrentProject->SearchLocation);
ClearCopyStringNoFormatOrTerminate(NewProjectHeader.BaseDir, sizeof(NewProjectHeader.BaseDir), CurrentProject->BaseDir);
ClearCopyStringNoFormatOrTerminate(NewProjectHeader.SearchLocation, sizeof(NewProjectHeader.SearchLocation), CurrentProject->SearchLocation);
string NewBaseDir = Wrap0i(NewProjectHeader.BaseDir);
string NewSearchLocation = Wrap0i(NewProjectHeader.SearchLocation);
@ -15569,13 +15528,13 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
remove(OldSearchDirectory);
Free(OldSearchDirectory);
ClearCopyStringNoFormat(N->Project->SearchLocation, sizeof(N->Project->SearchLocation), CurrentProject->SearchLocation);
ClearCopyStringNoFormatOrTerminate(N->Project->SearchLocation, sizeof(N->Project->SearchLocation), CurrentProject->SearchLocation);
HasNewSearchLocation = TRUE;
}
if(StringsDiffer(CurrentProject->BaseDir, Wrap0i(N->Project->BaseDir)))
{
ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
ClearCopyStringNoFormatOrTerminate(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
OpenFileForWriting(&DB.Metadata.File);
WriteFromByteToEnd(&DB.Metadata.File, 0);
CycleSignpostedFile(&DB.Metadata);
@ -15585,7 +15544,7 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
if(StringsDiffer(CurrentProject->BaseURL, Wrap0i(N->Project->BaseURL)))
{
ClearCopyStringNoFormat(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
ClearCopyStringNoFormatOrTerminate(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
OpenFileForWriting(&DB.Metadata.File);
WriteFromByteToEnd(&DB.Metadata.File, 0);
CycleSignpostedFile(&DB.Metadata);
@ -15596,8 +15555,8 @@ DeleteDeadDBEntries(neighbourhood *N, bool *Modified)
if(HasNewPlayerLocation || HasNewSearchLocation)
{
if(!(OpenFileForWriting(&DB.Metadata.File))) { FreeBuffer(&DB.Metadata.File.Buffer); return RC_ERROR_FILE; }
ClearCopyStringNoFormat(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
ClearCopyStringNoFormat(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
ClearCopyStringNoFormatOrTerminate(N->Project->BaseDir, sizeof(N->Project->BaseDir), CurrentProject->BaseDir);
ClearCopyStringNoFormatOrTerminate(N->Project->BaseURL, sizeof(N->Project->BaseURL), CurrentProject->BaseURL);
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
CycleSignpostedFile(&DB.Metadata);
UpdateNeighbourhoodPointers(N, &DB.Metadata.Signposts);
@ -15670,7 +15629,7 @@ SyncDBWithInput(neighbourhood *N, buffers *CollationBuffers, template *BespokeTe
bool Modified = FALSE;
if(StringsDiffer(CurrentProject->Title, Wrap0i(N->Project->Title)))
{
ClearCopyStringNoFormat(N->Project->Title, sizeof(N->Project->Title), CurrentProject->Title);
ClearCopyStringNoFormatOrTerminate(N->Project->Title, sizeof(N->Project->Title), CurrentProject->Title);
OpenFileForWriting(&DB.Metadata.File);
WriteFromByteToEnd(&DB.Metadata.File, 0);
CycleSignpostedFile(&DB.Metadata);
@ -15680,7 +15639,7 @@ SyncDBWithInput(neighbourhood *N, buffers *CollationBuffers, template *BespokeTe
if(StringsDiffer(CurrentProject->Theme, Wrap0i(N->Project->Theme)))
{
ClearCopyStringNoFormat(N->Project->Theme, sizeof(N->Project->Theme), CurrentProject->Theme);
ClearCopyStringNoFormatOrTerminate(N->Project->Theme, sizeof(N->Project->Theme), CurrentProject->Theme);
OpenFileForWriting(&DB.Metadata.File);
WriteFromByteToEnd(&DB.Metadata.File, 0);
CycleSignpostedFile(&DB.Metadata);
@ -15690,7 +15649,7 @@ SyncDBWithInput(neighbourhood *N, buffers *CollationBuffers, template *BespokeTe
if(StringsDiffer(CurrentProject->Numbering.Unit, Wrap0i(N->Project->Unit)))
{
ClearCopyStringNoFormat(N->Project->Unit, sizeof(N->Project->Unit), CurrentProject->Numbering.Unit);
ClearCopyStringNoFormatOrTerminate(N->Project->Unit, sizeof(N->Project->Unit), CurrentProject->Numbering.Unit);
OpenFileForWriting(&DB.Metadata.File);
WriteFromByteToEnd(&DB.Metadata.File, 0);
CycleSignpostedFile(&DB.Metadata);
@ -15922,18 +15881,18 @@ InitDB(void)
DB.Header.BlockCount = 0;
DB.ProjectsBlock.BlockID = FOURCC("PROJ");
ClearCopyStringNoFormat(DB.ProjectsBlock.GlobalSearchDir, sizeof(DB.ProjectsBlock.GlobalSearchDir), Config->GlobalSearchDir);
ClearCopyStringNoFormat(DB.ProjectsBlock.GlobalSearchURL, sizeof(DB.ProjectsBlock.GlobalSearchURL), Config->GlobalSearchURL);
ClearCopyStringNoFormatOrTerminate(DB.ProjectsBlock.GlobalSearchDir, sizeof(DB.ProjectsBlock.GlobalSearchDir), Config->GlobalSearchDir);
ClearCopyStringNoFormatOrTerminate(DB.ProjectsBlock.GlobalSearchURL, sizeof(DB.ProjectsBlock.GlobalSearchURL), Config->GlobalSearchURL);
DB.ProjectsBlock.Count = 0;
++DB.Header.BlockCount;
DB.AssetsBlock.BlockID = FOURCC("ASET");
DB.AssetsBlock.Count = 0;
ClearCopyStringNoFormat(DB.AssetsBlock.RootDir, sizeof(DB.AssetsBlock.RootDir), Config->AssetsRootDir);
ClearCopyStringNoFormat(DB.AssetsBlock.RootURL, sizeof(DB.AssetsBlock.RootURL), Config->AssetsRootURL);
ClearCopyStringNoFormat(DB.AssetsBlock.CSSDir, sizeof(DB.AssetsBlock.CSSDir), Config->CSSDir);
ClearCopyStringNoFormat(DB.AssetsBlock.ImagesDir, sizeof(DB.AssetsBlock.ImagesDir), Config->ImagesDir);
ClearCopyStringNoFormat(DB.AssetsBlock.JSDir, sizeof(DB.AssetsBlock.JSDir), Config->JSDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.RootDir, sizeof(DB.AssetsBlock.RootDir), Config->AssetsRootDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.RootURL, sizeof(DB.AssetsBlock.RootURL), Config->AssetsRootURL);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.CSSDir, sizeof(DB.AssetsBlock.CSSDir), Config->CSSDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.ImagesDir, sizeof(DB.AssetsBlock.ImagesDir), Config->ImagesDir);
ClearCopyStringNoFormatOrTerminate(DB.AssetsBlock.JSDir, sizeof(DB.AssetsBlock.JSDir), Config->JSDir);
++DB.Header.BlockCount;
char *DatabaseLocation0 = MakeString0("l", &Config->DatabaseLocation);
@ -16735,13 +16694,13 @@ SyncGlobalPagesWithInput(neighbourhood *N, buffers *CollationBuffers)
char *StoredGlobalSearchDir0 = MakeString0("l", &StoredGlobalSearchDir);
if(StringsDiffer(StoredGlobalSearchDir, Config->GlobalSearchDir))
{
ClearCopyStringNoFormat(ProjectsBlock->GlobalSearchDir, sizeof(ProjectsBlock->GlobalSearchDir), Config->GlobalSearchDir);
ClearCopyStringNoFormatOrTerminate(ProjectsBlock->GlobalSearchDir, sizeof(ProjectsBlock->GlobalSearchDir), Config->GlobalSearchDir);
WriteEntireDatabase(N);
}
if(StringsDiffer(StoredGlobalSearchURL, Config->GlobalSearchURL))
{
ClearCopyStringNoFormat(ProjectsBlock->GlobalSearchURL, sizeof(ProjectsBlock->GlobalSearchURL), Config->GlobalSearchURL);
ClearCopyStringNoFormatOrTerminate(ProjectsBlock->GlobalSearchURL, sizeof(ProjectsBlock->GlobalSearchURL), Config->GlobalSearchURL);
WriteEntireDatabase(N);
}
@ -17257,8 +17216,8 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke
sleep(1); // NOTE(matt): Give any remaining events time to occur
struct inotify_event EventN = *Event;
char EventNName[Event->len + 1];
ClearCopyStringNoFormat(EventNName, sizeof(EventNName), Wrap0(Event->name));
char EventNName[Event->len];
ClearCopyStringNoFormatOrTerminate(EventNName, sizeof(EventNName), Wrap0(Event->name));
char *EventSlot1 = Events.Location + sizeof(struct inotify_event) + Event->len;
@ -17268,7 +17227,7 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke
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));
ClearCopyStringNoFormatOrTerminate(Event0->name, Event0->len, Wrap0i(EventNName));
Event = Event0;
Events.Ptr = Events.Location;
#if DEBUG_EVENTS