220 lines
6.8 KiB
C++
220 lines
6.8 KiB
C++
struct Var {
|
|
String key;
|
|
String value;
|
|
};
|
|
|
|
struct ConfigParseResult {
|
|
Array<Var> vars;
|
|
Array<String> errors;
|
|
};
|
|
|
|
struct ReplaceVar {
|
|
String replace;
|
|
String with;
|
|
};
|
|
// @todo: move the config errors to config menu!!!
|
|
|
|
char SRTCommand[512] = "\"C:\\Program Files\\VideoLAN\\VLC\\vlc.exe\" --start-time {time_in_seconds} {video}";
|
|
char PDFCommand[512] = "C:/Users/Karol/AppData/Local/SumatraPDF/SumatraPDF.exe -page {page} {file}";
|
|
char TXTCommand[512] = "notepad.exe {file}";
|
|
char ReadOnStart[512] = "-";
|
|
bool ReadFoldersRecursively = false;
|
|
|
|
void SkipWhitespace(String *s) {
|
|
while (s->len && IsWhitespace(s->data[0])) {
|
|
*s = s->skip(1);
|
|
}
|
|
}
|
|
|
|
String ParseWord(String *s) {
|
|
String result = {};
|
|
SkipWhitespace(s);
|
|
if (s->len && IsAlphabetic(s->data[0])) {
|
|
result = {s->data, 0};
|
|
while (s->len && IsAlphanumeric(s->data[0])) {
|
|
result.len += 1;
|
|
*s = s->skip(1);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool MatchString(String *s, String expect) {
|
|
SkipWhitespace(s);
|
|
if (StartsWith(*s, expect)) {
|
|
*s = s->skip(expect.len);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ConfigParseResult ParseConfig(Allocator allocator, String string) {
|
|
Scratch scratch;
|
|
Array<String> lines = Split(scratch, string, "\n");
|
|
|
|
ConfigParseResult result = {};
|
|
result.errors = {allocator};
|
|
result.vars = {allocator};
|
|
|
|
For(lines) {
|
|
String s = Trim(it);
|
|
if (s.len == 0) continue;
|
|
|
|
String key = ParseWord(&s);
|
|
if (key.len == 0) {
|
|
result.errors.add(Format(allocator, "failed to parse config at line: %d, the key is invalid", (int)lines.get_index(it)));
|
|
continue;
|
|
}
|
|
bool e = MatchString(&s, "=");
|
|
if (!e) {
|
|
result.errors.add(Format(allocator, "failed to parse config at line: %d, expected '=' assignment sign", (int)lines.get_index(it)));
|
|
continue;
|
|
}
|
|
String value = Trim(s);
|
|
if (value.len == 0) {
|
|
result.errors.add(Format(allocator, "failed to parse config at line: %d, the value is invalid", (int)lines.get_index(it)));
|
|
continue;
|
|
}
|
|
|
|
result.vars.add({key, value});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
String GetValue(Array<Var> vars, String key) {
|
|
For(vars) {
|
|
if (it.key == key) return it.value;
|
|
}
|
|
return {};
|
|
}
|
|
|
|
String SerializeConfig(Allocator allocator) {
|
|
String content = Format(allocator, "SRTCommand = %s\nPDFCommand = %s\nTXTCommand = %s\nReadOnStart = %s", SRTCommand, PDFCommand, TXTCommand, ReadOnStart);
|
|
return content;
|
|
}
|
|
|
|
String CreateDefaultConfig(String path) {
|
|
String content = SerializeConfig(Perm);
|
|
WriteFile(path, content);
|
|
return content;
|
|
}
|
|
|
|
void LoadConfig() {
|
|
Scratch scratch;
|
|
String exe_dir = GetExeDir(scratch);
|
|
String config_path = Format(scratch, "%.*s/transcript_browser.config", FmtString(exe_dir));
|
|
String config = ReadFile(Perm, config_path);
|
|
if (config.len == 0) {
|
|
config = CreateDefaultConfig(config_path);
|
|
}
|
|
|
|
ConfigParseResult result = ParseConfig(Perm, config);
|
|
For(result.errors) {
|
|
XFileLoadResults.add({"", it});
|
|
}
|
|
|
|
String pdf_command = GetValue(result.vars, "PDFCommand");
|
|
if (pdf_command.len) {
|
|
int len = ClampTop((int)pdf_command.len, (int)sizeof(PDFCommand) - 1);
|
|
memcpy(PDFCommand, pdf_command.data, len);
|
|
PDFCommand[len] = 0;
|
|
}
|
|
String txt_command = GetValue(result.vars, "TXTCommand");
|
|
if (txt_command.len) {
|
|
int len = ClampTop((int)txt_command.len, (int)sizeof(TXTCommand) - 1);
|
|
memcpy(TXTCommand, txt_command.data, len);
|
|
TXTCommand[len] = 0;
|
|
}
|
|
String srt_command = GetValue(result.vars, "SRTCommand");
|
|
if (srt_command.len) {
|
|
int len = ClampTop((int)srt_command.len, (int)sizeof(SRTCommand) - 1);
|
|
memcpy(SRTCommand, srt_command.data, len);
|
|
SRTCommand[len] = 0;
|
|
}
|
|
String read_on_start = GetValue(result.vars, "ReadOnStart");
|
|
if (read_on_start.len) {
|
|
int len = ClampTop((int)read_on_start.len, (int)sizeof(ReadOnStart) - 1);
|
|
memcpy(ReadOnStart, read_on_start.data, len);
|
|
ReadOnStart[len] = 0;
|
|
}
|
|
}
|
|
|
|
void SaveConfig() {
|
|
Scratch scratch;
|
|
String exe_dir = GetExeDir(scratch);
|
|
String config_path = Format(scratch, "%.*s/transcript_browser.config", FmtString(exe_dir));
|
|
String content = SerializeConfig(scratch);
|
|
WriteFile(config_path, content);
|
|
}
|
|
|
|
String ReplaceVars(Allocator allocator, Array<ReplaceVar> vars_to_replace, String string) {
|
|
Array<char> sb = {allocator};
|
|
for (int64_t i = 0; i < string.len; i += 1) {
|
|
if (string[i] == '{') {
|
|
|
|
// extract the variable
|
|
i += 1;
|
|
String var = {string.data + i, 0};
|
|
for (; i < string.len && string[i] != '}'; i += 1)
|
|
var.len += 1;
|
|
|
|
// find the replacement
|
|
String found = "<not found>";
|
|
For(vars_to_replace) {
|
|
if (it.replace == var) {
|
|
found = it.with;
|
|
break;
|
|
}
|
|
}
|
|
|
|
For(found) sb.add(it);
|
|
|
|
} else sb.add(string[i]);
|
|
}
|
|
|
|
sb.add('\0');
|
|
String result = {sb.data, sb.len - 1};
|
|
return result;
|
|
}
|
|
|
|
void TestReplaceVars() {
|
|
Scratch scratch;
|
|
Array<ReplaceVar> vars_to_replace = {scratch};
|
|
String exe_folder = GetExePath(scratch);
|
|
vars_to_replace.add({"exe_folder", exe_folder});
|
|
String data_folder = Format(scratch, "%.*s/data", FmtString(exe_folder));
|
|
vars_to_replace.add({"data_folder", data_folder});
|
|
|
|
{
|
|
String r = ReplaceVars(scratch, vars_to_replace, "{exe_folder}");
|
|
Assert(r == exe_folder);
|
|
}
|
|
|
|
{
|
|
String r = ReplaceVars(scratch, vars_to_replace, "{exe_folder}{data_folder}");
|
|
Assert(r == Format(scratch, "%.*s%.*s", FmtString(exe_folder), FmtString(data_folder)));
|
|
}
|
|
{
|
|
String r = ReplaceVars(scratch, vars_to_replace, "..{exe_folder}..{data_folder}..{exe_folder}asd");
|
|
Assert(r == Format(scratch, "..%.*s..%.*s..%.*sasd", FmtString(exe_folder), FmtString(data_folder), FmtString(exe_folder)));
|
|
}
|
|
}
|
|
|
|
void TestConfig() {
|
|
Scratch scratch;
|
|
{
|
|
ConfigParseResult result = ParseConfig(scratch, "\nPDFCommand = CoolCommand\nTXTCommand = ABC\nSRTCommand = DAS\n");
|
|
Assert(result.errors.len == 0);
|
|
Assert(result.vars.len == 3);
|
|
Assert(result.vars[0].key == "PDFCommand");
|
|
Assert(result.vars[1].value == "ABC");
|
|
Assert(result.vars[2].value == "DAS");
|
|
Assert(result.vars[2].key == "SRTCommand");
|
|
}
|
|
{
|
|
ConfigParseResult result = ParseConfig(scratch, "\n= CoolCommand\nTXTCommand = ABC\nSRTCommand =\n");
|
|
Assert(result.errors.len == 2);
|
|
Assert(result.vars.len == 1);
|
|
}
|
|
LoadConfig();
|
|
} |