cinera: Lock database and config files
This commit aims to help Cinera instances coordinate themselves by throwing an error upon being instructed to use a database or config file currently in use by another instance.
This commit is contained in:
parent
1cf703e346
commit
f60cf3087f
666
cinera/cinera.c
666
cinera/cinera.c
File diff suppressed because it is too large
Load Diff
|
@ -8,12 +8,6 @@ exit
|
|||
|
||||
// config
|
||||
//
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define ArgCountPointer(...) (sizeof((void *[]){__VA_ARGS__})/sizeof(void *))
|
||||
|
||||
#define DigitsInInt(I) DigitsInInt_(I, sizeof(*I))
|
||||
|
@ -348,6 +342,15 @@ PushTokens(memory_book *TokensList)
|
|||
return This;
|
||||
}
|
||||
|
||||
void
|
||||
PopTokens(memory_book *TokensList)
|
||||
{
|
||||
--TokensList->ItemCount;
|
||||
tokens *This = GetPlaceInBook(TokensList, TokensList->ItemCount);
|
||||
FreeBook(&This->Token);
|
||||
This->CurrentLine = 0;
|
||||
}
|
||||
|
||||
void
|
||||
FreeTokensList(memory_book *TokensList)
|
||||
{
|
||||
|
@ -357,7 +360,8 @@ FreeTokensList(memory_book *TokensList)
|
|||
This->CurrentIndex = 0;
|
||||
This->CurrentLine = 0;
|
||||
FreeBook(&This->Token);
|
||||
FreeFile(&This->File);
|
||||
FreeFileBufferAndPath(&This->File); // NOTE(matt): Not closing file because the next time we touch this handle is in
|
||||
// RemoveAndFreeWatchHandles() where we will close it
|
||||
}
|
||||
TokensList->ItemCount = 0;
|
||||
}
|
||||
|
@ -588,194 +592,204 @@ typedef struct
|
|||
} config;
|
||||
|
||||
char *ExpandPath(string Path, string *RelativeToFile); // NOTE(matt): Forward declared. Consider reorganising the code?
|
||||
void PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *Project, asset *Asset); // NOTE(matt): Forward declared. Consider reorganising the code?
|
||||
watch_file *PushWatchHandle(string Path, extension_id Extension, watch_type Type, project *Project, asset *Asset); // NOTE(matt): Forward declared. Consider reorganising the code?
|
||||
|
||||
tokens *
|
||||
Tokenise(memory_book *TokensList, string Path)
|
||||
Tokenise(memory_book *TokensList, string Path, string *Filename, uint64_t LineNumber)
|
||||
{
|
||||
tokens *Result = 0;
|
||||
char *Path0 = MakeString0("l", &Path);
|
||||
FILE *Handle = 0;
|
||||
PushWatchHandle(Path, EXT_NULL, WT_CONFIG, 0, 0);
|
||||
if((Handle = fopen(Path0, "r")))
|
||||
watch_file *WatchFile = PushWatchHandle(Path, EXT_NULL, WT_CONFIG, 0, 0);
|
||||
|
||||
Result = PushTokens(TokensList);
|
||||
Result->File = InitFile(0, &Path, EXT_NULL, TRUE);
|
||||
switch(ReadFileIntoBuffer(&Result->File))
|
||||
{
|
||||
fclose(Handle);
|
||||
|
||||
Result = PushTokens(TokensList);
|
||||
Result->File = InitFile(0, &Path, EXT_NULL);
|
||||
ReadFileIntoBuffer(&Result->File);
|
||||
buffer *B = &Result->File.Buffer;
|
||||
SkipWhitespace(Result, B);
|
||||
while(B->Ptr - B->Location < B->Size)
|
||||
{
|
||||
token T = {};
|
||||
uint64_t Advancement = 0;
|
||||
|
||||
if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_SINGLE], B))
|
||||
case RC_ERROR_FILE_LOCKED:
|
||||
{
|
||||
T.Type = TOKEN_COMMENT;
|
||||
B->Ptr += StringLength(TokenStrings[TOKEN_COMMENT_SINGLE]);
|
||||
SkipWhitespace(Result, B);
|
||||
T.Content.Base = B->Ptr;
|
||||
while(B->Ptr && *B->Ptr != '\n')
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
if(*B->Ptr == '\n')
|
||||
{
|
||||
++Result->CurrentLine;
|
||||
}
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_MULTI_OPEN], B))
|
||||
ConfigErrorLockedConfigLocation(Filename, LineNumber, &Path);
|
||||
FreeFile(&Result->File, TRUE);
|
||||
PopTokens(TokensList);
|
||||
Result = 0;
|
||||
} break;
|
||||
case RC_ERROR_FILE:
|
||||
{
|
||||
uint64_t CommentDepth = 1;
|
||||
T.Type = TOKEN_COMMENT;
|
||||
B->Ptr += StringLength(TokenStrings[TOKEN_COMMENT_MULTI_OPEN]);
|
||||
ConfigErrorUnopenableConfigLocation(Filename, LineNumber, &Path);
|
||||
FreeFile(&Result->File, TRUE);
|
||||
PopTokens(TokensList);
|
||||
Result = 0;
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
WatchFile->Handle = Result->File.Handle;
|
||||
|
||||
buffer *B = &Result->File.Buffer;
|
||||
SkipWhitespace(Result, B);
|
||||
T.Content.Base = B->Ptr;
|
||||
while(B->Ptr - B->Location < B->Size && CommentDepth)
|
||||
while(B->Ptr - B->Location < B->Size)
|
||||
{
|
||||
if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE], B))
|
||||
token T = {};
|
||||
uint64_t Advancement = 0;
|
||||
|
||||
if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_SINGLE], B))
|
||||
{
|
||||
--CommentDepth;
|
||||
B->Ptr += StringLength(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE]);
|
||||
}
|
||||
else if(B->Ptr - B->Location < B->Size && *B->Ptr == '\n')
|
||||
{
|
||||
++Result->CurrentLine;
|
||||
++B->Ptr;
|
||||
T.Type = TOKEN_COMMENT;
|
||||
B->Ptr += StringLength(TokenStrings[TOKEN_COMMENT_SINGLE]);
|
||||
SkipWhitespace(Result, B);
|
||||
T.Content.Base = B->Ptr;
|
||||
while(B->Ptr && *B->Ptr != '\n')
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
if(*B->Ptr == '\n')
|
||||
{
|
||||
++Result->CurrentLine;
|
||||
}
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_MULTI_OPEN], B))
|
||||
{
|
||||
++CommentDepth;
|
||||
uint64_t CommentDepth = 1;
|
||||
T.Type = TOKEN_COMMENT;
|
||||
B->Ptr += StringLength(TokenStrings[TOKEN_COMMENT_MULTI_OPEN]);
|
||||
SkipWhitespace(Result, B);
|
||||
T.Content.Base = B->Ptr;
|
||||
while(B->Ptr - B->Location < B->Size && CommentDepth)
|
||||
{
|
||||
if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE], B))
|
||||
{
|
||||
--CommentDepth;
|
||||
B->Ptr += StringLength(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE]);
|
||||
}
|
||||
else if(B->Ptr - B->Location < B->Size && *B->Ptr == '\n')
|
||||
{
|
||||
++Result->CurrentLine;
|
||||
++B->Ptr;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_MULTI_OPEN], B))
|
||||
{
|
||||
++CommentDepth;
|
||||
B->Ptr += StringLength(TokenStrings[TOKEN_COMMENT_MULTI_OPEN]);
|
||||
}
|
||||
else
|
||||
{
|
||||
++B->Ptr;
|
||||
}
|
||||
}
|
||||
T.Content.Length = B->Ptr - T.Content.Base;
|
||||
Advancement = 0;//StringLength(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE]);
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE], B))
|
||||
{
|
||||
Advancement = 2;
|
||||
T.Type = TOKEN_NULL;
|
||||
string Char = { .Base = B->Ptr, .Length = 2 };
|
||||
string Filepath = Wrap0(Result->File.Path);
|
||||
ConfigError(&Filepath, Result->CurrentLine, S_WARNING, "Mismatched closing multiline comment marker: ", &Char);
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_DOUBLEQUOTE], B))
|
||||
{
|
||||
T.Type = TOKEN_STRING;
|
||||
++B->Ptr;
|
||||
T.Content.Base = B->Ptr;
|
||||
while(B->Ptr - B->Location < B->Size && *B->Ptr != '"')
|
||||
{
|
||||
if(*B->Ptr == '\\')
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_MINUS], B))
|
||||
{
|
||||
T.Type = TOKEN_MINUS;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_ASSIGN], B))
|
||||
{
|
||||
T.Type = TOKEN_ASSIGN;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_OPEN_BRACE], B))
|
||||
{
|
||||
T.Type = TOKEN_OPEN_BRACE;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_CLOSE_BRACE], B))
|
||||
{
|
||||
T.Type = TOKEN_CLOSE_BRACE;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_SEMICOLON], B))
|
||||
{
|
||||
T.Type = TOKEN_SEMICOLON;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(IsValidIdentifierCharacter(*B->Ptr))
|
||||
{
|
||||
T.Type = TOKEN_IDENTIFIER;
|
||||
T.Content.Base = B->Ptr;
|
||||
while(IsValidIdentifierCharacter(*B->Ptr))
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
Advancement = 0;
|
||||
}
|
||||
else if(IsNumber(*B->Ptr))
|
||||
{
|
||||
T.Type = TOKEN_NUMBER;
|
||||
T.Content.Base = B->Ptr;
|
||||
while(IsNumber(*B->Ptr))
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
Advancement = 0;
|
||||
}
|
||||
else if(*B->Ptr == '\n')
|
||||
{
|
||||
T.Type = TOKEN_NEWLINE;
|
||||
T.Content.Base = B->Ptr;
|
||||
T.Content.Length = 1;
|
||||
++Result->CurrentLine;
|
||||
Advancement = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++B->Ptr;
|
||||
T.Type = TOKEN_NULL;
|
||||
string Char = GetUTF8Character(B->Ptr, B->Size - (B->Ptr - B->Location));
|
||||
Advancement = Char.Length;
|
||||
string Filepath = Wrap0(Result->File.Path);
|
||||
if(Char.Base)
|
||||
{
|
||||
ConfigError(&Filepath, Result->CurrentLine, S_WARNING, "Unhandled character (ignored): ", &Char);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigErrorInt(&Filepath, Result->CurrentLine, S_WARNING, "Malformed UTF-8 bytes encountered (skipped): ", Char.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
T.Content.Length = B->Ptr - T.Content.Base;
|
||||
Advancement = 0;//StringLength(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE]);
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_COMMENT_MULTI_CLOSE], B))
|
||||
{
|
||||
Advancement = 2;
|
||||
T.Type = TOKEN_NULL;
|
||||
string Char = { .Base = B->Ptr, .Length = 2 };
|
||||
string Filepath = Wrap0(Result->File.Path);
|
||||
ConfigError(&Filepath, Result->CurrentLine, S_WARNING, "Mismatched closing multiline comment marker: ", &Char);
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_DOUBLEQUOTE], B))
|
||||
{
|
||||
T.Type = TOKEN_STRING;
|
||||
++B->Ptr;
|
||||
T.Content.Base = B->Ptr;
|
||||
while(B->Ptr - B->Location < B->Size && *B->Ptr != '"')
|
||||
{
|
||||
if(*B->Ptr == '\\')
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_MINUS], B))
|
||||
{
|
||||
T.Type = TOKEN_MINUS;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_ASSIGN], B))
|
||||
{
|
||||
T.Type = TOKEN_ASSIGN;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_OPEN_BRACE], B))
|
||||
{
|
||||
T.Type = TOKEN_OPEN_BRACE;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_CLOSE_BRACE], B))
|
||||
{
|
||||
T.Type = TOKEN_CLOSE_BRACE;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(!StringsDifferS(TokenStrings[TOKEN_SEMICOLON], B))
|
||||
{
|
||||
T.Type = TOKEN_SEMICOLON;
|
||||
T.Content.Base = B->Ptr;
|
||||
++T.Content.Length;
|
||||
Advancement = 1;
|
||||
}
|
||||
else if(IsValidIdentifierCharacter(*B->Ptr))
|
||||
{
|
||||
T.Type = TOKEN_IDENTIFIER;
|
||||
T.Content.Base = B->Ptr;
|
||||
while(IsValidIdentifierCharacter(*B->Ptr))
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
Advancement = 0;
|
||||
}
|
||||
else if(IsNumber(*B->Ptr))
|
||||
{
|
||||
T.Type = TOKEN_NUMBER;
|
||||
T.Content.Base = B->Ptr;
|
||||
while(IsNumber(*B->Ptr))
|
||||
{
|
||||
++T.Content.Length;
|
||||
++B->Ptr;
|
||||
}
|
||||
Advancement = 0;
|
||||
}
|
||||
else if(*B->Ptr == '\n')
|
||||
{
|
||||
T.Type = TOKEN_NEWLINE;
|
||||
T.Content.Base = B->Ptr;
|
||||
T.Content.Length = 1;
|
||||
++Result->CurrentLine;
|
||||
Advancement = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
T.Type = TOKEN_NULL;
|
||||
string Char = GetUTF8Character(B->Ptr, B->Size - (B->Ptr - B->Location));
|
||||
Advancement = Char.Length;
|
||||
string Filepath = Wrap0(Result->File.Path);
|
||||
if(Char.Base)
|
||||
{
|
||||
ConfigError(&Filepath, Result->CurrentLine, S_WARNING, "Unhandled character (ignored): ", &Char);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigErrorInt(&Filepath, Result->CurrentLine, S_WARNING, "Malformed UTF-8 bytes encountered (skipped): ", Char.Length);
|
||||
}
|
||||
}
|
||||
|
||||
PushToken(Result, &T);
|
||||
Advance(B, Advancement);
|
||||
SkipWhitespace(Result, B);
|
||||
}
|
||||
PushToken(Result, &T);
|
||||
Advance(B, Advancement);
|
||||
SkipWhitespace(Result, B);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigError(0, 0, S_WARNING, "Unable to open config file: ", &Path);
|
||||
}
|
||||
Free(Path0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -2341,7 +2355,8 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
|
|||
}
|
||||
if(!I)
|
||||
{
|
||||
I = Tokenise(TokensList, IncludePathL);
|
||||
token *This = GetPlaceInBook(&T->Token, IncludePathTokenIndex);
|
||||
I = Tokenise(TokensList, IncludePathL, &Filepath, This->LineNumber);
|
||||
}
|
||||
if(I)
|
||||
{
|
||||
|
@ -2352,11 +2367,6 @@ ScopeTokens(scope_tree *Tree, memory_book *TokensList, tokens *T, memory_book *T
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
token *This = GetPlaceInBook(&T->Token, IncludePathTokenIndex);
|
||||
ConfigFileIncludeError(&Filepath, This->LineNumber, Wrap0(IncludePath));
|
||||
}
|
||||
Free(IncludePath);
|
||||
}
|
||||
else
|
||||
|
@ -4977,7 +4987,7 @@ ParseConfig(string Path, memory_book *TokensList)
|
|||
MEM_LOOP_POST("InitTypeSpecs")
|
||||
#endif
|
||||
config *Result = 0;
|
||||
tokens *T = Tokenise(TokensList, Path);
|
||||
tokens *T = Tokenise(TokensList, Path, NA, NA);
|
||||
|
||||
#if 0
|
||||
MEM_LOOP_PRE_FREE("Tokenise")
|
||||
|
@ -4993,7 +5003,7 @@ ParseConfig(string Path, memory_book *TokensList)
|
|||
scope_tree *ScopeTree = InitRootScopeTree();
|
||||
SetTypeSpec(ScopeTree, &TypeSpecs);
|
||||
SetDefaults(ScopeTree, &TypeSpecs);
|
||||
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, 0);
|
||||
ScopeTree = ScopeTokens(ScopeTree, TokensList, T, &TypeSpecs, NA);
|
||||
|
||||
// TODO(matt): Mem testing
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue