From aa22dc31132fb7ef504bc90a03a14cc122fcc4e1 Mon Sep 17 00:00:00 2001
From: taiyu <taiyu.len@gmail.com>
Date: Tue, 8 Sep 2015 10:27:09 -0700
Subject: [PATCH] var replacement changes

---
 include/commands.h |  2 ++
 sway/commands.c    | 59 +++++++++++++++++++++++++++++++++++++---------
 sway/config.c      | 29 ++---------------------
 sway/stringop.c    | 46 ++++++++++++++++++++----------------
 4 files changed, 78 insertions(+), 58 deletions(-)

diff --git a/include/commands.h b/include/commands.h
index 8fb0c1d8..e521306c 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -15,6 +15,8 @@ struct cmd_handler {
 
 struct cmd_handler *find_handler(char *line);
 bool handle_command(char *command);
+// Handles commands during config
+bool config_command(char *command);
 
 void remove_view_from_scratchpad();
 
diff --git a/sway/commands.c b/sway/commands.c
index 44407bfa..edc56466 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -835,7 +835,7 @@ static int compare_set(const void *_l, const void *_r) {
 }
 
 static bool cmd_set(int argc, char **argv) {
-	if (!checkarg(argc, "set", EXPECTED_EQUAL_TO, 2)) {
+	if (!checkarg(argc, "set", EXPECTED_AT_LEAST, 2)) {
 		return false;
 	}
 	struct sway_variable *var = NULL;
@@ -856,7 +856,7 @@ static bool cmd_set(int argc, char **argv) {
 		list_add(config->symbols, var);
 		list_sort(config->symbols, compare_set);
 	}
-	var->value = strdup(argv[1]);
+	var->value = join_args(argv + 1, argc - 1);
 	return true;
 }
 
@@ -1067,17 +1067,54 @@ bool handle_command(char *exec) {
 	}
 	struct cmd_handler *handler = find_handler(argv[0]);
 	bool exec_success = false;
-	if (handler) {
-		int i;
-		// Skip var replacement for first value of cmd_set
-		for (i = (handler->handle == cmd_set ? 2 : 1); i < argc; ++i) {
-			argv[i] = do_var_replacement(argv[i]);
-		}
-		exec_success = handler->handle(argc - 1, argv + 1);
-	}
-	if (exec_success == false) {
+	if (handler && !(handler->handle(argc - 1, argv + 1))) {
 		sway_log(L_ERROR, "Command failed: %s", argv[0]);
 	}
 	free_argv(argc, argv);
 	return exec_success;
 }
+
+bool config_command(char *exec) {
+	sway_log(L_INFO, "handling config command '%s'", exec);
+	struct cmd_handler *handler;
+	int argc;
+	char **argv = split_args(exec, &argc);
+	bool res = false;
+	if (!argc) {
+		return true;
+	}
+	//TODO make this better, it only handles modes right now, and very
+	//simply at that
+	if (strncmp(argv[0], "}", 1) == 0) {
+		config->current_mode = config->modes->items[0];
+		res = true;
+		goto cleanup;
+	}
+	if ((handler = find_handler(argv[0]))) {
+		int i = 1, e = argc;
+		// dont var replace first argument
+		if (handler->handle == cmd_set) {
+			i = 2;
+		}
+		for (; i < e; ++i) {
+			argv[i] = do_var_replacement(argv[i]);
+		}
+		if (handler->config_type == CMD_KEYBIND) {
+			sway_log(L_ERROR, "Invalid command during config `%s'", exec);
+		} else if (handler->config_type == CMD_COMPOSITOR_READY && !config->active) {
+			sway_log(L_DEBUG, "Defferring command `%s'", exec);
+			char *cmd = join_args(argv, argc);
+			list_add(config->cmd_queue, cmd);
+			res = true;
+		} else if (!handler->handle(argc-1, argv+1)) {
+			sway_log(L_DEBUG, "Config load failed for line `%s'", exec);
+		} else {
+			res = true;
+		}
+	} else {
+		sway_log(L_ERROR, "Unknown command `%s'", exec);
+	}
+	cleanup:
+	free_argv(argc, argv);
+	return res;
+}
diff --git a/sway/config.c b/sway/config.c
index 6d445ec6..7d3104c7 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -231,34 +231,9 @@ bool read_config(FILE *file, bool is_active) {
 	while (!feof(file)) {
 		line = read_line(file);
 		line = strip_comments(line);
-		list_t *args = split_string(line, whitespace);
-		if (!args->length) {
-			goto cleanup;
+		if (!config_command(line)) {
+			success = false;
 		}
-		//TODO make this better, it only handles modes right now, and very
-		//simply at that
-		if (strncmp(args->items[0], "}", 1) == 0) {
-			config->current_mode = default_mode;
-			goto cleanup;
-		}
-		struct cmd_handler *handler;
-		if ((handler = find_handler(args->items[0]))) {
-			if (handler->config_type == CMD_KEYBIND) {
-				sway_log(L_ERROR, "Invalid command during config ``%s''", line);
-			} else if (handler->config_type == CMD_COMPOSITOR_READY && !is_active) {
-				sway_log(L_DEBUG, "Deferring command ``%s''", line);
-				char *cmd = strdup(line);
-				list_add(config->cmd_queue, cmd);
-			} else if (!handle_command(line)) {
-				sway_log(L_DEBUG, "Config load failed for line ``%s''", line);
-				success = false;
-				config->failed = true;
-			}
-		} else {
-			sway_log(L_ERROR, "Invalid command ``%s''", line);
-		}
-		cleanup:
-		free_flat_list(args);
 		free(line);
 	}
 
diff --git a/sway/stringop.c b/sway/stringop.c
index 1ba54ec6..7de6eded 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -179,76 +179,82 @@ int unescape_string(char *string) {
 	int i;
 	for (i = 0; string[i]; ++i) {
 		if (string[i] == '\\') {
-			--len;
-			int shift = 0;
 			switch (string[++i]) {
 			case '0':
 				string[i - 1] = '\0';
-				shift = 1;
-				break;
+				return i - 1;
 			case 'a':
 				string[i - 1] = '\a';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case 'b':
 				string[i - 1] = '\b';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case 'f':
 				string[i - 1] = '\f';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case 'n':
 				string[i - 1] = '\n';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case 'r':
 				string[i - 1] = '\r';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case 't':
 				string[i - 1] = '\t';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case 'v':
 				string[i - 1] = '\v';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case '\\':
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case '\'':
 				string[i - 1] = '\'';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case '\"':
 				string[i - 1] = '\"';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case '?':
 				string[i - 1] = '?';
-				shift = 1;
+				string[i] = '\0';
 				break;
 			case 'x':
 				{
 					unsigned char c = 0;
-					shift = 1;
 					if (string[i+1] >= '0' && string[i+1] <= '9') {
-						shift = 2;
 						c = string[i+1] - '0';
 						if (string[i+2] >= '0' && string[i+2] <= '9') {
-							shift = 3;
 							c *= 0x10;
 							c += string[i+2] - '0';
+							string[i+2] = '\0';
 						}
+						string[i+1] = '\0';
 					}
+					string[i] = '\0';
 					string[i - 1] = c;
 				}
 			}
-			memmove(string + i, string + i + shift, len - i + 1);
 		}
 	}
-	return len;
+	// Shift characters over nullspaces
+	int shift = 0;
+	for (i = 0; i < len; ++i) {
+		if (string[i] == 0) {
+			shift++;
+			continue;
+		}
+		string[i-shift] = string[i];
+	}
+	string[len - shift] = 0;
+	return len - shift;
 }
 
 char *join_args(char **argv, int argc) {