summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2022-11-02 21:00:33 -0400
committerpommicket <pommicket@gmail.com>2022-11-02 21:00:33 -0400
commit237412362b6c9476ff98c7eaf63d63ebea136be2 (patch)
tree716ab68e608a72e45e4a08789a78c2a8ea3c016e
parent760526ec4071f9392e5bfca77b19cb20f98c588e (diff)
multiline config value strings, fix search_cwd (debug feature)
-rw-r--r--config.c130
-rw-r--r--gl.c25
-rw-r--r--main.c52
-rw-r--r--ted.c15
-rw-r--r--ted.h3
-rw-r--r--text.c2
6 files changed, 149 insertions, 78 deletions
diff --git a/config.c b/config.c
index fdbd05f..ee147de 100644
--- a/config.c
+++ b/config.c
@@ -394,7 +394,7 @@ static void config_init_options(void) {
void config_read(Ted *ted, ConfigPart **parts, char const *filename) {
FILE *fp = fopen(filename, "rb");
if (!fp) {
- ted_seterr(ted, "Couldn't open config file %s.", filename);
+ ted_seterr(ted, "Couldn't open config file %s: %s.", filename, strerror(errno));
return;
}
@@ -488,9 +488,61 @@ static int config_part_qsort_cmp(const void *av, const void *bv) {
return config_part_cmp(av, bv, true);
}
-static void config_parse_line(ConfigReader *cfg, Settings *settings, const ConfigPart *part, const char *line) {
+static i64 config_read_string(Ted *ted, ConfigReader *cfg, char **ptext) {
+ char *p;
+ int backslashes = 0;
+ u32 start_line = cfg->line_number;
+ char *start = *ptext + 1;
+ for (p = start; ; ++p) {
+ bool done = false;
+ switch (*p) {
+ case '\\':
+ ++backslashes;
+ break;
+ case '"':
+ if (backslashes % 2 == 0)
+ done = true;
+ break;
+ case '\n':
+ ++cfg->line_number;
+ break;
+ case '\0':
+ cfg->line_number = start_line;
+ config_err(cfg, "String doesn't end.");
+ *ptext += strlen(*ptext);
+ return -1;
+ }
+ if (done) break;
+ }
+
+ i64 str_idx = -1;
+ if (ted->nstrings < TED_MAX_STRINGS) {
+ char *str = strn_dup(start, (size_t)(p - start));
+ str_idx = ted->nstrings;
+ ted->strings[ted->nstrings++] = str;
+ }
+ *ptext = p + 1;
+ return str_idx;
+}
+
+// reads a single "line" of the config file, but it may include a multiline string,
+// so it may read multiple lines.
+static void config_parse_line(ConfigReader *cfg, Settings *settings, const ConfigPart *part, char **pline) {
+ char *line = *pline;
Ted *ted = cfg->ted;
+ char *newline = strchr(line, '\n');
+ if (!newline) {
+ config_err(cfg, "No newline at end of file?");
+ *pline += strlen(*pline);
+ return;
+ }
+
+ if (newline) *newline = '\0';
+ char *carriage_return = strchr(line, '\r');
+ if (carriage_return) *carriage_return = '\0';
+ *pline = newline + 1;
+
if (part->section == 0) {
// there was an error reading this section. don't bother with anything else.
return;
@@ -509,9 +561,9 @@ static void config_parse_line(ConfigReader *cfg, Settings *settings, const Confi
return;
}
- char const *key = line;
+ char *key = line;
*equals = '\0';
- char const *value = equals + 1;
+ char *value = equals + 1;
while (isspace(*key)) ++key;
while (isspace(*value)) ++value;
if (equals != line) {
@@ -556,31 +608,20 @@ static void config_parse_line(ConfigReader *cfg, Settings *settings, const Confi
value = endp;
} else if (*value == '"') {
// string argument
- int backslashes = 0;
- char const *p;
- for (p = value + 1; *p; ++p) {
- bool done = false;
- switch (*p) {
- case '\\':
- ++backslashes;
- break;
- case '"':
- if (backslashes % 2 == 0)
- done = true;
- break;
- }
- if (done) break;
- }
- if (!*p) {
- config_err(cfg, "String doesn't end.");
- break;
- }
- if (ted->nstrings < TED_MAX_STRINGS) {
- char *str = strn_dup(value + 1, (size_t)(p - (value + 1)));
- argument = ted->nstrings | ARG_STRING;
- ted->strings[ted->nstrings++] = str;
+
+ // restore newline to handle multi-line strings
+ // a little bit hacky oh well
+ *newline = '\n';
+ argument = config_read_string(ted, cfg, &value);
+
+ newline = strchr(value, '\n');
+ if (!newline) {
+ config_err(cfg, "No newline at end of file?");
+ *pline += strlen(*pline);
+ return;
}
- value = p + 1;
+ *newline = '\0';
+ *pline = newline + 1;
}
while (isspace(*value)) ++value; // skip past space following argument
if (*value == ':') {
@@ -634,6 +675,26 @@ static void config_parse_line(ConfigReader *cfg, Settings *settings, const Confi
is_bool = true;
boolean = false;
}
+
+ if (value[0] == '"') {
+ // restore newline to handle multi-line strings
+ // a little bit hacky oh well
+ *newline = '\n';
+
+ i64 string = config_read_string(ted, cfg, &value);
+
+ newline = strchr(value, '\n');
+ if (!newline) {
+ config_err(cfg, "No newline at end of file?");
+ *pline += strlen(*pline);
+ return;
+ }
+ *newline = '\0';
+ *pline = newline + 1;
+ if (string >= 0 && string < TED_MAX_STRINGS) {
+ value = ted->strings[string];
+ }
+ }
// go through all options
bool recognized = false;
@@ -747,22 +808,11 @@ void config_parse(Ted *ted, ConfigPart **pparts) {
arr_add(part->text, '\0'); // null termination
char *line = part->text;
while (*line) {
- char *newline = strchr(line, '\n');
- if (!newline) {
- config_err(cfg, "No newline at end of file?");
- break;
- }
-
- if (newline) *newline = '\0';
- char *carriage_return = strchr(line, '\r');
- if (carriage_return) *carriage_return = '\0';
-
- config_parse_line(cfg, settings, part, line);
+ config_parse_line(cfg, settings, part, &line);
if (cfg->error) break;
++cfg->line_number;
- line = newline + 1;
}
}
diff --git a/gl.c b/gl.c
index 8326de6..1d6cb14 100644
--- a/gl.c
+++ b/gl.c
@@ -78,7 +78,7 @@ static void gl_get_procs(void) {
}
// compile a GLSL shader
-static GLuint gl_compile_shader(char const *code, GLenum shader_type) {
+static GLuint gl_compile_shader(char error_buf[256], char const *code, GLenum shader_type) {
GLuint shader = glCreateShader(shader_type);
glShaderSource(shader, 1, &code, NULL);
glCompileShader(shader);
@@ -87,14 +87,17 @@ static GLuint gl_compile_shader(char const *code, GLenum shader_type) {
if (status == GL_FALSE) {
char log[1024] = {0};
glGetShaderInfoLog(shader, sizeof log - 1, NULL, log);
- debug_println("Error compiling shader: %s", log);
+ if (error_buf)
+ str_printf(error_buf, 256, "Error compiling shader: %s", log);
+ else
+ debug_println("Error compiling shader: %s", log);
return 0;
}
return shader;
}
// link together GL shaders
-static GLuint gl_link_program(GLuint *shaders, size_t count) {
+static GLuint gl_link_program(char error_buf[256], GLuint *shaders, size_t count) {
GLuint program = glCreateProgram();
if (program) {
for (size_t i = 0; i < count; ++i) {
@@ -110,7 +113,11 @@ static GLuint gl_link_program(GLuint *shaders, size_t count) {
if (status == GL_FALSE) {
char log[1024] = {0};
glGetProgramInfoLog(program, sizeof log - 1, NULL, log);
- debug_println("Error linking shaders: %s", log);
+ if (error_buf) {
+ str_printf(error_buf, 256, "Error linking shaders: %s", log);
+ } else {
+ debug_println("Error linking shaders: %s", log);
+ }
glDeleteProgram(program);
return 0;
}
@@ -118,11 +125,11 @@ static GLuint gl_link_program(GLuint *shaders, size_t count) {
return program;
}
-static GLuint gl_compile_and_link_shaders(char const *vshader_code, char const *fshader_code) {
+static GLuint gl_compile_and_link_shaders(char error_buf[256], char const *vshader_code, char const *fshader_code) {
GLuint shaders[2];
- shaders[0] = gl_compile_shader(vshader_code, GL_VERTEX_SHADER);
- shaders[1] = gl_compile_shader(fshader_code, GL_FRAGMENT_SHADER);
- GLuint program = gl_link_program(shaders, 2);
+ shaders[0] = gl_compile_shader(error_buf, vshader_code, GL_VERTEX_SHADER);
+ shaders[1] = gl_compile_shader(error_buf, fshader_code, GL_FRAGMENT_SHADER);
+ GLuint program = gl_link_program(error_buf, shaders, 2);
if (shaders[0]) glDeleteShader(shaders[0]);
if (shaders[1]) glDeleteShader(shaders[1]);
if (program) {
@@ -180,7 +187,7 @@ static void gl_geometry_init(void) {
}\n\
";
- gl_geometry_program = gl_compile_and_link_shaders(vshader_code, fshader_code);
+ gl_geometry_program = gl_compile_and_link_shaders(NULL, vshader_code, fshader_code);
gl_geometry_v_pos = gl_attrib_loc(gl_geometry_program, "v_pos");
gl_geometry_v_color = gl_attrib_loc(gl_geometry_program, "v_color");
diff --git a/main.c b/main.c
index 4579c55..0bd2c85 100644
--- a/main.c
+++ b/main.c
@@ -1,10 +1,10 @@
/*
FUTURE FEATURES:
-- [/path//extensions]
- custom shaders
- texture, time, time since last save
- config variables
- config multi-line strings
+- plugins?
*/
#include "base.h"
@@ -272,7 +272,7 @@ int main(int argc, char **argv) {
#endif
PROFILE_TIME(init_start)
PROFILE_TIME(basic_init_start)
-
+
#if __unix__
{
struct sigaction act = {0};
@@ -330,6 +330,7 @@ int main(int argc, char **argv) {
// make sure signal handler has access to ted.
error_signal_handler_ted = ted;
+ fs_get_cwd(ted->start_cwd, sizeof ted->start_cwd);
{ // get local and global data directory
#if _WIN32
wchar_t *appdata = NULL;
@@ -395,7 +396,7 @@ int main(int argc, char **argv) {
char *last_slash = strrchr(executable_path, '/');
if (last_slash) {
*last_slash = '\0';
- ted->search_cwd = streq(cwd, executable_path);
+ ted->search_start_cwd = streq(cwd, executable_path);
}
}
#endif
@@ -438,27 +439,36 @@ int main(int argc, char **argv) {
PROFILE_TIME(window_end)
PROFILE_TIME(gl_start)
- gl_version_major = 4;
- gl_version_minor = 3;
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, gl_version_major);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, gl_version_minor);
-#if DEBUG
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
-#endif
- SDL_GLContext *glctx = SDL_GL_CreateContext(window);
- if (!glctx) {
- debug_println("Couldn't get GL 4.3 context. Falling back to 2.0.");
- gl_version_major = 2;
- gl_version_minor = 0;
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, gl_version_major);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, gl_version_minor);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
- glctx = SDL_GL_CreateContext(window);
+ SDL_GLContext *glctx = NULL;
+ { // get OpenGL context
+ int gl_versions[][2] = {
+ {4,3},
+ {3,0},
+ {2,0},
+ {0,0},
+ };
+ for (int i = 0; gl_versions[i][0]; ++i) {
+ gl_version_major = gl_versions[i][0];
+ gl_version_minor = gl_versions[i][1];
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, gl_version_major);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, gl_version_minor);
+ #if DEBUG
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
+ #endif
+ glctx = SDL_GL_CreateContext(window);
+ if (!glctx) {
+ debug_println("Couldn't get GL %d.%d context. Falling back to %d.%d.",
+ gl_versions[i][0], gl_versions[i][1], gl_versions[i+1][0], gl_versions[i+1][1]);
+ gl_version_major = 3;
+ gl_version_minor = 0;
+ }
+ }
+
if (!glctx)
die("%s", SDL_GetError());
+ gl_get_procs();
}
- gl_get_procs();
-
+
#if DEBUG
if (gl_version_major * 100 + gl_version_minor >= 403) {
GLint flags = 0;
diff --git a/ted.c b/ted.c
index 73df785..2d19a02 100644
--- a/ted.c
+++ b/ted.c
@@ -66,9 +66,9 @@ static bool ted_is_regular_buffer(Ted *ted, TextBuffer *buffer) {
// Check the various places a file could be, and return the full path.
static Status ted_get_file(Ted const *ted, char const *name, char *out, size_t outsz) {
- if (ted->search_cwd && fs_file_exists(name)) {
- // check in current working directory
- str_cpy(out, outsz, name);
+ if (ted->search_start_cwd && fs_file_exists(name)) {
+ // check in start_cwd
+ path_full(ted->start_cwd, name, out, outsz);
return true;
}
if (*ted->local_data_dir) {
@@ -380,9 +380,12 @@ void ted_load_configs(Ted *ted, bool reloading) {
ConfigPart *parts = NULL;
config_read(ted, &parts, global_config_filename);
config_read(ted, &parts, local_config_filename);
- if (ted->search_cwd) {
- // read config in cwd
- config_read(ted, &parts, TED_CFG);
+ if (ted->search_start_cwd) {
+ // read config in start_cwd
+ char start_cwd_filename[TED_PATH_MAX];
+ strbuf_printf(start_cwd_filename, "%s" PATH_SEPARATOR_STR TED_CFG, ted->start_cwd);
+
+ config_read(ted, &parts, start_cwd_filename);
}
config_parse(ted, &parts);
diff --git a/ted.h b/ted.h
index 9f49fdd..8681ab6 100644
--- a/ted.h
+++ b/ted.h
@@ -353,7 +353,8 @@ typedef struct Ted {
TextBuffer argument_buffer; // used for command selector
double error_time; // time error box was opened (in seconds -- see time_get_seconds)
double cursor_error_time; // time which the cursor error animation started (cursor turns red, e.g. when there's no autocomplete suggestion)
- bool search_cwd; // should the working directory be searched for files? set to true if the executable isn't "installed"
+ bool search_start_cwd; // should start_cwd be searched for files? set to true if the executable isn't "installed"
+ char start_cwd[TED_PATH_MAX];
bool quit; // if set to true, the window will close next frame. NOTE: this doesn't check for unsaved changes!!
bool find; // is the find or find+replace menu open?
bool replace; // is the find+replace menu open?
diff --git a/text.c b/text.c
index 1aaebe8..144a7a0 100644
--- a/text.c
+++ b/text.c
@@ -112,7 +112,7 @@ void main() {\n\
}\n\
";
- text_program = gl_compile_and_link_shaders(vshader_code, fshader_code);
+ text_program = gl_compile_and_link_shaders(NULL, vshader_code, fshader_code);
text_v_pos = gl_attrib_loc(text_program, "v_pos");
text_v_color = gl_attrib_loc(text_program, "v_color");
text_v_tex_coord = gl_attrib_loc(text_program, "v_tex_coord");