changeset 1292:5905593d6828

Allow initial_path to contain variable references which allows the default value to be actually specified in the default config file
author Michael Pavone <pavone@retrodev.com>
date Tue, 21 Mar 2017 00:40:25 -0700
parents f17fe0d00626
children 72ea3885e7b5
files default.cfg menu.c util.c util.h
diffstat 4 files changed, 99 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/default.cfg	Sun Mar 19 18:32:49 2017 -0700
+++ b/default.cfg	Tue Mar 21 00:40:25 2017 -0700
@@ -195,9 +195,12 @@
 }
 
 ui {
+	#specifies the ROM that implements the Menu UI
 	rom menu.bin
-	#initial_path defaults to your home/user profile directory if not specified
-	#screenshot_path behaves the same way
+	#starting path for ROM browsing, accepts special variables $HOME, $EXEDIR
+	#and variables defined in the OS environment
+	initial_path $HOME
+	#screenshot_path defaults to the user's home/profile directory if not specified
 	#see strftime for the format specifiers valid in screenshot_template
 	screenshot_template blastem_%c.ppm
 }
--- a/menu.c	Sun Mar 19 18:32:49 2017 -0700
+++ b/menu.c	Tue Mar 21 00:40:25 2017 -0700
@@ -167,15 +167,16 @@
 	if (!menu) {
 		gen->extra = menu = calloc(1, sizeof(menu_context));
 		menu->curpath = tern_find_path(config, "ui\0initial_path\0").ptrval;
-		if (menu->curpath) {
-			menu->curpath = strdup(menu->curpath);
-		} else {
+		if (!menu->curpath){
 #ifdef __ANDROID__
-			menu->curpath = strdup(get_external_storage_path());
+			menu->curpath = get_external_storage_path();
 #else
-			menu->curpath = strdup(get_home_dir());
+			menu->curpath = "$HOME";
 #endif
 		}
+		tern_node *vars = tern_insert_ptr(NULL, "HOME", get_home_dir());
+		vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
+		menu->curpath = replace_vars(menu->curpath, vars, 1);
 	}
 	if (menu->state) {
 		uint32_t dst = menu->latch << 16 | value;
--- a/util.c	Sun Mar 19 18:32:49 2017 -0700
+++ b/util.c	Tue Mar 21 00:40:25 2017 -0700
@@ -57,6 +57,92 @@
 	return ret;
 }
 
+typedef struct {
+	uint32_t start;
+	uint32_t end;
+	char *value;
+} var_pos;
+
+char *replace_vars(char *base, tern_node *vars, uint8_t allow_env)
+{
+	uint32_t num_vars = 0;
+	for (char *cur = base; *cur; ++cur)
+	{
+		//TODO: Support escaping $ and allow brace syntax
+		if (*cur == '$') {
+			num_vars++;
+		}
+	}
+	var_pos *positions = calloc(num_vars, sizeof(var_pos));
+	num_vars = 0;
+	uint8_t in_var = 0;
+	uint32_t max_var_len = 0;
+	for (char *cur = base; *cur; ++cur)
+	{
+		if (in_var) {
+			if (!(*cur == '_' || isalnum(*cur))) {
+				positions[num_vars].end = cur-base;
+				if (positions[num_vars].end - positions[num_vars].start > max_var_len) {
+					max_var_len = positions[num_vars].end - positions[num_vars].start;
+				}
+				num_vars++;
+				in_var = 0;
+			}
+		} else if (*cur == '$') {
+			positions[num_vars].start = cur-base+1;
+			in_var = 1;
+		}
+	}
+	if (in_var) {
+		positions[num_vars].end = strlen(base);
+		if (positions[num_vars].end - positions[num_vars].start > max_var_len) {
+			max_var_len = positions[num_vars].end - positions[num_vars].start;
+		}
+		num_vars++;
+	}
+	char *varname = malloc(max_var_len+1);
+	uint32_t total_len = 0;
+	uint32_t cur = 0;
+	for (uint32_t i = 0; i < num_vars; i++)
+	{
+		total_len += (positions[i].start - 1) - cur;
+		cur = positions[i].start;
+		memcpy(varname, base + positions[i].start, positions[i].end-positions[i].start);
+		varname[positions[i].end-positions[i].start] = 0;
+		positions[i].value = tern_find_ptr(vars, varname);
+		if (!positions[i].value && allow_env) {
+			positions[i].value = getenv(varname);
+		}
+		if (positions[i].value) {
+			total_len += strlen(positions[i].value);
+		}
+	}
+	total_len += strlen(base+cur);
+	free(varname);
+	char *output = malloc(total_len+1);
+	cur = 0;
+	char *curout = output;
+	for (uint32_t i = 0; i < num_vars; i++)
+	{
+		if (positions[i].start-1 > cur) {
+			memcpy(curout, base + cur, (positions[i].start-1) - cur);
+			curout += (positions[i].start-1) - cur;
+		}
+		if (positions[i].value) {
+			strcpy(curout, positions[i].value);
+			curout += strlen(curout);
+		}
+		cur = positions[i].end;
+	};
+	if (base[cur]) {
+		strcpy(curout, base+cur);
+	} else {
+		*curout = 0;
+	}
+	free(positions);
+	return output;
+}
+
 void byteswap_rom(int filesize, uint16_t *cart)
 {
 	for(uint16_t *cur = cart; cur - cart < filesize/2; ++cur)
--- a/util.h	Sun Mar 19 18:32:49 2017 -0700
+++ b/util.h	Tue Mar 21 00:40:25 2017 -0700
@@ -21,6 +21,8 @@
 char * alloc_concat(char const * first, char const * second);
 //Allocates a new string containing the concatenation of the strings pointed to by parts
 char * alloc_concat_m(int num_parts, char const ** parts);
+//Returns a newly allocated string in which all variables in based are replaced with values from vars or the environment
+char *replace_vars(char *base, tern_node *vars, uint8_t allow_env);
 //Byteswaps a ROM image in memory
 void byteswap_rom(int filesize, uint16_t *cart);
 //Returns the size of a file using fseek and ftell