From 71af5b7ddebe6b714f3be65bf8c810c952a7e0af Mon Sep 17 00:00:00 2001
From: taiyu <taiyu.len@gmail.com>
Date: Mon, 7 Sep 2015 14:29:40 -0700
Subject: [PATCH 1/3] config modes

---
 include/commands.h |   4 +-
 include/config.h   |   2 +-
 include/stringop.h |  12 ++-
 sway/commands.c    | 195 ++++++++++++++++++---------------------------
 sway/config.c      | 116 +++++++++++++--------------
 sway/handlers.c    |  11 +--
 sway/ipc.c         |   2 +-
 sway/stringop.c    | 151 +++++++++++++++++++++++++----------
 8 files changed, 261 insertions(+), 232 deletions(-)

diff --git a/include/commands.h b/include/commands.h
index 808e64eb..8fb0c1d8 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -5,7 +5,7 @@
 
 struct cmd_handler {
 	char *command;
-	bool (*handle)(struct sway_config *config, int argc, char **argv);
+	bool (*handle)(int argc, char **argv);
 	enum {
 		CMD_COMPOSITOR_READY,
 		CMD_KEYBIND,
@@ -14,7 +14,7 @@ struct cmd_handler {
 };
 
 struct cmd_handler *find_handler(char *line);
-bool handle_command(struct sway_config *config, char *command);
+bool handle_command(char *command);
 
 void remove_view_from_scratchpad();
 
diff --git a/include/config.h b/include/config.h
index 653e790f..4070c9ef 100644
--- a/include/config.h
+++ b/include/config.h
@@ -60,7 +60,7 @@ struct sway_config {
 
 bool load_config(const char *file);
 bool read_config(FILE *file, bool is_active);
-char *do_var_replacement(struct sway_config *config, char *str);
+char *do_var_replacement(char *str);
 
 extern struct sway_config *config;
 
diff --git a/include/stringop.h b/include/stringop.h
index 7d17af95..dde50f13 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -2,17 +2,25 @@
 #define _SWAY_STRINGOP_H
 #include "list.h"
 
-char *strip_whitespace(char *str, int *trimmed_start);
+// array of whitespace characters to use for delims
+extern const char *whitespace;
+
+char *strip_whitespace(char *str);
 char *strip_comments(char *str);
 
-// Must be freed with free_flat_list
+// Simply split a string with delims, free with `free_flat_list`
 list_t *split_string(const char *str, const char *delims);
 void free_flat_list(list_t *list);
 
+// Splits an argument string, keeping quotes intact
+char **split_args(const char *str, int *argc);
+void free_argv(int argc, char **argv);
+
 char *code_strchr(const char *string, char delimiter);
 char *code_strstr(const char *haystack, const char *needle);
 int unescape_string(char *string);
 char *join_args(char **argv, int argc);
 char *join_list(list_t *list, char *separator);
 
+char *strdup(const char *);
 #endif
diff --git a/sway/commands.c b/sway/commands.c
index 5c782e99..72d53ff0 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -96,7 +96,7 @@ static int bindsym_sort(const void *_lbind, const void *_rbind) {
 	return (rbind->keys->length + rmod) - (lbind->keys->length + lmod);
 }
 
-static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
+static bool cmd_bindsym(int argc, char **argv) {
 	if (!checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1)) {
 		return false;
 	};
@@ -146,7 +146,7 @@ static bool cmd_bindsym(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_exec_always(struct sway_config *config, int argc, char **argv) {
+static bool cmd_exec_always(int argc, char **argv) {
 	if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
 		return false;
 	}
@@ -171,14 +171,14 @@ static bool cmd_exec_always(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_exec(struct sway_config *config, int argc, char **argv) {
+static bool cmd_exec(int argc, char **argv) {
 	if (config->reloading) {
 		char *args = join_args(argv, argc);
 		sway_log(L_DEBUG, "Ignoring exec %s due to reload", args);
 		free(args);
 		return true;
 	}
-	return cmd_exec_always(config, argc, argv);
+	return cmd_exec_always(argc, argv);
 }
 
 static void kill_views(swayc_t *container, void *data) {
@@ -187,7 +187,7 @@ static void kill_views(swayc_t *container, void *data) {
 	}
 }
 
-static bool cmd_exit(struct sway_config *config, int argc, char **argv) {
+static bool cmd_exit(int argc, char **argv) {
 	if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)) {
 		return false;
 	}
@@ -197,7 +197,7 @@ static bool cmd_exit(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
+static bool cmd_floating(int argc, char **argv) {
 	if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)) {
 		return false;
 	}
@@ -258,7 +258,7 @@ static bool cmd_floating(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_floating_mod(struct sway_config *config, int argc, char **argv) {
+static bool cmd_floating_mod(int argc, char **argv) {
 	if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
 		return false;
 	}
@@ -282,7 +282,7 @@ static bool cmd_floating_mod(struct sway_config *config, int argc, char **argv)
 	return true;
 }
 
-static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
+static bool cmd_focus(int argc, char **argv) {
 	static int floating_toggled_index = 0;
 	static int tiled_toggled_index = 0;
 	if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
@@ -340,7 +340,7 @@ static bool cmd_focus(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_focus_follows_mouse(struct sway_config *config, int argc, char **argv) {
+static bool cmd_focus_follows_mouse(int argc, char **argv) {
 	if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
 		return false;
 	}
@@ -365,7 +365,40 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) {
 	set_focused_container(container_under_pointer());
 }
 
-static bool cmd_move(struct sway_config *config, int argc, char **argv) {
+static bool cmd_mode(int argc, char **argv) {
+	if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
+		return false;
+	}
+	const char *mode_name = argv[0];
+	struct sway_mode *mode = NULL;
+	// Find mode
+	int i, len = config->modes->length;
+	for (i = 0; i < len; ++i) {
+		struct sway_mode *find = config->modes->items[i];
+		if (strcasecmp(find->name, mode_name)==0) {
+			mode = find;
+			break;
+		}
+	}
+	// Create mode if it doesnt exist
+	if (!mode && argc >= 2 && strncmp(argv[1],"{",1) == 0) {
+		mode = malloc(sizeof*mode);
+		mode->name = malloc(strlen(mode_name) + 1);
+		mode->bindings = create_list();
+		strcpy(mode->name, mode_name);
+		list_add(config->modes, mode);
+	}
+	if (!mode) {
+		sway_log(L_ERROR, "Invalide mode `%s'", mode_name);
+		return false;
+	}
+	sway_log(L_DEBUG, "Switching to mode `%s'",mode->name);
+	// Set current mode
+	config->current_mode = mode;
+	return true;
+}
+
+static bool cmd_move(int argc, char **argv) {
 	if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
 		return false;
 	}
@@ -435,7 +468,7 @@ static bool cmd_move(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_orientation(struct sway_config *config, int argc, char **argv) {
+static bool cmd_orientation(int argc, char **argv) {
 	if (strcasecmp(argv[0], "horizontal") == 0) {
 		config->default_orientation = L_HORIZ;
 	} else if (strcasecmp(argv[0], "vertical") == 0) {
@@ -448,7 +481,7 @@ static bool cmd_orientation(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_output(struct sway_config *config, int argc, char **argv) {
+static bool cmd_output(int argc, char **argv) {
 	if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
 		return false;
 	}
@@ -513,7 +546,7 @@ static bool cmd_output(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_gaps(struct sway_config *config, int argc, char **argv) {
+static bool cmd_gaps(int argc, char **argv) {
 	if (!checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1)) {
 		return false;
 	}
@@ -655,13 +688,13 @@ static bool cmd_gaps(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_kill(struct sway_config *config, int argc, char **argv) {
+static bool cmd_kill(int argc, char **argv) {
 	swayc_t *view = get_focused_container(&root_container);
 	wlc_view_close(view->handle);
 	return true;
 }
 
-static bool cmd_layout(struct sway_config *config, int argc, char **argv) {
+static bool cmd_layout(int argc, char **argv) {
 	if (!checkarg(argc, "layout", EXPECTED_MORE_THAN, 0)) {
 		return false;
 	}
@@ -686,7 +719,7 @@ static bool cmd_layout(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_reload(struct sway_config *config, int argc, char **argv) {
+static bool cmd_reload(int argc, char **argv) {
 	if (!checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0)) {
 		return false;
 	}
@@ -697,7 +730,7 @@ static bool cmd_reload(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_resize(struct sway_config *config, int argc, char **argv) {
+static bool cmd_resize(int argc, char **argv) {
 	if (!checkarg(argc, "resize", EXPECTED_AT_LEAST, 3)) {
 		return false;
 	}
@@ -769,7 +802,7 @@ void remove_view_from_scratchpad(swayc_t *view) {
 	}
 }
 
-static bool cmd_scratchpad(struct sway_config *config, int argc, char **argv) {
+static bool cmd_scratchpad(int argc, char **argv) {
 	if (!checkarg(argc, "scratchpad", EXPECTED_EQUAL_TO, 1)) {
 		return false;
 	}
@@ -796,7 +829,7 @@ static bool cmd_scratchpad(struct sway_config *config, int argc, char **argv) {
 	}
 }
 
-static bool cmd_set(struct sway_config *config, int argc, char **argv) {
+static bool cmd_set(int argc, char **argv) {
 	if (!checkarg(argc, "set", EXPECTED_EQUAL_TO, 2)) {
 		return false;
 	}
@@ -809,7 +842,7 @@ static bool cmd_set(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool _do_split(struct sway_config *config, int argc, char **argv, int layout) {
+static bool _do_split(int argc, char **argv, int layout) {
 	char *name = layout == L_VERT  ? "splitv" :
 		layout == L_HORIZ ? "splith" : "split";
 	if (!checkarg(argc, name, EXPECTED_EQUAL_TO, 0)) {
@@ -840,15 +873,15 @@ static bool _do_split(struct sway_config *config, int argc, char **argv, int lay
 	return true;
 }
 
-static bool cmd_split(struct sway_config *config, int argc, char **argv) {
+static bool cmd_split(int argc, char **argv) {
 	if (!checkarg(argc, "split", EXPECTED_EQUAL_TO, 1)) {
 		return false;
 	}
 
 	if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) {
-		_do_split(config, argc - 1, argv + 1, L_VERT);
+		_do_split(argc - 1, argv + 1, L_VERT);
 	} else if (strcasecmp(argv[0], "h") == 0 || strcasecmp(argv[0], "horizontal") == 0) {
-		_do_split(config, argc - 1, argv + 1, L_HORIZ);
+		_do_split(argc - 1, argv + 1, L_HORIZ);
 	} else {
 		sway_log(L_ERROR, "Invalid split command (expected either horiziontal or vertical).");
 		return false;
@@ -857,15 +890,15 @@ static bool cmd_split(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_splitv(struct sway_config *config, int argc, char **argv) {
-	return _do_split(config, argc, argv, L_VERT);
+static bool cmd_splitv(int argc, char **argv) {
+	return _do_split(argc, argv, L_VERT);
 }
 
-static bool cmd_splith(struct sway_config *config, int argc, char **argv) {
-	return _do_split(config, argc, argv, L_HORIZ);
+static bool cmd_splith(int argc, char **argv) {
+	return _do_split(argc, argv, L_HORIZ);
 }
 
-static bool cmd_log_colors(struct sway_config *config, int argc, char **argv) {
+static bool cmd_log_colors(int argc, char **argv) {
 	if (!checkarg(argc, "log_colors", EXPECTED_EQUAL_TO, 1)) {
 		return false;
 	}
@@ -878,7 +911,7 @@ static bool cmd_log_colors(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
+static bool cmd_fullscreen(int argc, char **argv) {
 	if (!checkarg(argc, "fullscreen", EXPECTED_AT_LEAST, 0)) {
 		return false;
 	}
@@ -897,7 +930,7 @@ static bool cmd_fullscreen(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_workspace(struct sway_config *config, int argc, char **argv) {
+static bool cmd_workspace(int argc, char **argv) {
 	if (!checkarg(argc, "workspace", EXPECTED_AT_LEAST, 1)) {
 		return false;
 	}
@@ -953,7 +986,7 @@ static bool cmd_workspace(struct sway_config *config, int argc, char **argv) {
 	return true;
 }
 
-static bool cmd_ws_auto_back_and_forth(struct sway_config *config, int argc, char **argv) {
+static bool cmd_ws_auto_back_and_forth(int argc, char **argv) {
 	if (!checkarg(argc, "workspace_auto_back_and_forth", EXPECTED_EQUAL_TO, 1)) {
 		return false;
 	}
@@ -979,6 +1012,7 @@ static struct cmd_handler handlers[] = {
 	{ "kill", cmd_kill, CMD_KEYBIND },
 	{ "layout", cmd_layout, CMD_KEYBIND },
 	{ "log_colors", cmd_log_colors, CMD_ANYTIME },
+	{ "mode", cmd_mode, CMD_ANYTIME },
 	{ "move", cmd_move, CMD_KEYBIND },
 	{ "output", cmd_output, CMD_ANYTIME },
 	{ "reload", cmd_reload, CMD_KEYBIND },
@@ -992,58 +1026,6 @@ static struct cmd_handler handlers[] = {
 	{ "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth, CMD_ANYTIME },
 };
 
-static char **split_directive(char *line, int *argc) {
-	const char *delimiters = " ";
-	*argc = 0;
-	while (isspace(*line) && *line) ++line;
-
-	int capacity = 10;
-	char **parts = malloc(sizeof(char *) * capacity);
-
-	if (!*line) return parts;
-
-	int in_string = 0, in_character = 0;
-	int i, j, _;
-	for (i = 0, j = 0; line[i]; ++i) {
-		if (line[i] == '\\') {
-			++i;
-		} else if (line[i] == '"' && !in_character) {
-			in_string = !in_string;
-		} else if (line[i] == '\'' && !in_string) {
-			in_character = !in_character;
-		} else if (!in_character && !in_string) {
-			if (strchr(delimiters, line[i]) != NULL) {
-				char *item = malloc(i - j + 1);
-				strncpy(item, line + j, i - j);
-				item[i - j] = '\0';
-				item = strip_whitespace(item, &_);
-				if (item[0] == '\0') {
-					free(item);
-				} else {
-					if (*argc == capacity) {
-						capacity *= 2;
-						parts = realloc(parts, sizeof(char *) * capacity);
-					}
-					parts[*argc] = item;
-					j = i + 1;
-					++*argc;
-				}
-			}
-		}
-	}
-	char *item = malloc(i - j + 1);
-	strncpy(item, line + j, i - j);
-	item[i - j] = '\0';
-	item = strip_whitespace(item, &_);
-	if (*argc == capacity) {
-		capacity++;
-		parts = realloc(parts, sizeof(char *) * capacity);
-	}
-	parts[*argc] = item;
-	++*argc;
-	return parts;
-}
-
 static int handler_compare(const void *_a, const void *_b) {
 	const struct cmd_handler *a = _a;
 	const struct cmd_handler *b = _b;
@@ -1058,44 +1040,25 @@ struct cmd_handler *find_handler(char *line) {
 	return res;
 }
 
-bool handle_command(struct sway_config *config, char *exec) {
+bool handle_command(char *exec) {
 	sway_log(L_INFO, "Handling command '%s'", exec);
-	char *ptr, *cmd;
-	bool exec_success;
-
-	if ((ptr = strchr(exec, ' ')) == NULL) {
-		cmd = exec;
-	} else {
-		int index = ptr - exec;
-		cmd = malloc(index + 1);
-		strncpy(cmd, exec, index);
-		cmd[index] = '\0';
+	int argc;
+	char **argv = split_args(exec, &argc);
+	if (argc == 0) {
+		return false;
 	}
-	struct cmd_handler *handler = find_handler(cmd);
-	if (handler == NULL) {
-		sway_log(L_ERROR, "Unknown command '%s'", cmd);
-		exec_success = false; // TODO: return error, probably
-	} else {
-		int argc;
-		char **argv = split_directive(exec + strlen(handler->command), &argc);
+	struct cmd_handler *handler = find_handler(argv[0]);
+	bool exec_success = false;
+	if (handler) {
 		int i;
-
-		// Perform var subs on all parts of the command
-		for (i = 0; i < argc; ++i) {
-			argv[i] = do_var_replacement(config, argv[i]);
-		}
-
-		exec_success = handler->handle(config, argc, argv);
-		for (i = 0; i < argc; ++i) {
-			free(argv[i]);
-		}
-		free(argv);
-		if (!exec_success) {
-			sway_log(L_ERROR, "Command failed: %s", cmd);
+		for (i = 1; i < argc; ++i) {
+			argv[i] = do_var_replacement(argv[i]);
 		}
+		exec_success = handler->handle(argc - 1, argv + 1);
 	}
-	if (ptr) {
-		free(cmd);
+	if (exec_success == false) {
+		sway_log(L_ERROR, "Command failed: %s", argv[0]);
 	}
+	free_argv(argc, argv);
 	return exec_success;
 }
diff --git a/sway/config.c b/sway/config.c
index b64dd4b1..119730ca 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -13,6 +13,7 @@
 
 struct sway_config *config = NULL;
 
+
 static void free_variable(struct sway_variable *var) {
 	free(var->name);
 	free(var->value);
@@ -46,39 +47,7 @@ static void free_workspace_output(struct workspace_output *wo) {
 	free(wo);
 }
 
-static bool file_exists(const char *path) {
-	return access(path, R_OK) != -1;
-}
-
-static void config_defaults(struct sway_config *config) {
-	config->symbols = create_list();
-	config->modes = create_list();
-	config->workspace_outputs = create_list();
-	config->output_configs = create_list();
-
-	config->cmd_queue = create_list();
-
-	config->current_mode = malloc(sizeof(struct sway_mode));
-	config->current_mode->name = NULL;
-	config->current_mode->bindings = create_list();
-	list_add(config->modes, config->current_mode);
-
-	config->floating_mod = 0;
-	config->default_layout = L_NONE;
-	config->default_orientation = L_NONE;
-	// Flags
-	config->focus_follows_mouse = true;
-	config->mouse_warping = true;
-	config->reloading = false;
-	config->active = false;
-	config->failed = false;
-	config->auto_back_and_forth = false;
-
-	config->gaps_inner = 0;
-	config->gaps_outer = 0;
-}
-
-void free_config(struct sway_config *config) {
+static void free_config(struct sway_config *config) {
 	int i;
 	for (i = 0; i < config->symbols->length; ++i) {
 		free_variable(config->symbols->items[i]);
@@ -104,6 +73,40 @@ void free_config(struct sway_config *config) {
 	free(config);
 }
 
+
+static bool file_exists(const char *path) {
+	return access(path, R_OK) != -1;
+}
+
+static void config_defaults(struct sway_config *config) {
+	config->symbols = create_list();
+	config->modes = create_list();
+	config->workspace_outputs = create_list();
+	config->output_configs = create_list();
+
+	config->cmd_queue = create_list();
+
+	config->current_mode = malloc(sizeof(struct sway_mode));
+	config->current_mode->name = malloc(sizeof("default"));
+	strcpy(config->current_mode->name, "default");
+	config->current_mode->bindings = create_list();
+	list_add(config->modes, config->current_mode);
+
+	config->floating_mod = 0;
+	config->default_layout = L_NONE;
+	config->default_orientation = L_NONE;
+	// Flags
+	config->focus_follows_mouse = true;
+	config->mouse_warping = true;
+	config->reloading = false;
+	config->active = false;
+	config->failed = false;
+	config->auto_back_and_forth = false;
+
+	config->gaps_inner = 0;
+	config->gaps_outer = 0;
+}
+
 static char *get_config_path(void) {
 	char *config_path = NULL;
 	char *paths[3] = {getenv("HOME"), getenv("XDG_CONFIG_HOME"), ""};
@@ -210,34 +213,35 @@ bool load_config(const char *file) {
 }
 
 bool read_config(FILE *file, bool is_active) {
-	struct sway_config *temp_config = malloc(sizeof(struct sway_config));
-	config_defaults(temp_config);
+	struct sway_config *old_config = config;
+	struct sway_mode *default_mode;
+	config = malloc(sizeof(struct sway_config));
+
+	config_defaults(config);
+	default_mode = config->current_mode;
+
 	if (is_active) {
 		sway_log(L_DEBUG, "Performing configuration file reload");
-		temp_config->reloading = true;
-		temp_config->active = true;
+		config->reloading = true;
+		config->active = true;
 	}
-
 	bool success = true;
 
-	int temp_depth = 0; // Temporary: skip all config sections with depth
-
+	char *line;
 	while (!feof(file)) {
-		int _;
-		char *line = read_line(file);
-		line = strip_whitespace(line, &_);
+		line = read_line(file);
 		line = strip_comments(line);
-		if (!line[0]) {
+		if (line[0] == '\0') {
 			goto _continue;
 		}
-		if (temp_depth && line[0] == '}') {
-			temp_depth--;
+		if (line[0] == '}') {
+			config->current_mode = default_mode;
 			goto _continue;
 		}
 
 		// Any command which would require wlc to be initialized
 		// should be queued for later execution
-		list_t *args = split_string(line, " ");
+		list_t *args = split_string(line, whitespace);
 		struct cmd_handler *handler;
 		if ((handler = find_handler(args->items[0]))) {
 			if (handler->config_type == CMD_KEYBIND) {
@@ -246,11 +250,11 @@ bool read_config(FILE *file, bool is_active) {
 				sway_log(L_DEBUG, "Deferring command ``%s''", line);
 				char *cmd = malloc(strlen(line) + 1);
 				strcpy(cmd, line);
-				list_add(temp_config->cmd_queue, cmd);
-			} else if (!temp_depth && !handle_command(temp_config, 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;
-				temp_config->failed = true;
+				config->failed = true;
 			}
 		} else {
 			sway_log(L_ERROR, "Invalid command ``%s''", line);
@@ -258,25 +262,21 @@ bool read_config(FILE *file, bool is_active) {
 		free_flat_list(args);
 
 _continue:
-		if (line && line[strlen(line) - 1] == '{') {
-			temp_depth++;
-		}
 		free(line);
 	}
 
 	if (is_active) {
-		temp_config->reloading = false;
+		config->reloading = false;
 		arrange_windows(&root_container, -1, -1);
 	}
-	if (config) {
-		free_config(config);
+	if (old_config) {
+		free_config(old_config);
 	}
-	config = temp_config;
 
 	return success;
 }
 
-char *do_var_replacement(struct sway_config *config, char *str) {
+char *do_var_replacement(char *str) {
 	// TODO: Handle escaping $ and using $ in string literals
 	int i;
 	for (i = 0; str[i]; ++i) {
diff --git a/sway/handlers.c b/sway/handlers.c
index 482d52c6..c0472817 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -130,13 +130,6 @@ static void handle_output_resolution_change(wlc_handle output, const struct wlc_
 	if (!c) return;
 	c->width = to->w;
 	c->height = to->h;
-	if (config->default_layout == L_NONE && config->default_orientation == L_NONE) {
-		if (c->width >= c->height) {
-			((swayc_t*)c->children->items[0])->layout = L_HORIZ;
-		} else {
-			((swayc_t*)c->children->items[0])->layout = L_VERT;
-		}
-	}
 	arrange_windows(&root_container, -1, -1);
 }
 
@@ -348,7 +341,7 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
 			}
 			if (match) {
 				if (state == WLC_KEY_STATE_PRESSED) {
-					handle_command(config, binding->command);
+					handle_command(binding->command);
 					return EVENT_HANDLED;
 				} else if (state == WLC_KEY_STATE_RELEASED) {
 					// TODO: --released
@@ -486,7 +479,7 @@ static void handle_wlc_ready(void) {
 	sway_log(L_DEBUG, "Compositor is ready, executing cmds in queue");
 	// Execute commands until there are none left
 	while (config->cmd_queue->length) {
-		handle_command(config, config->cmd_queue->items[0]);
+		handle_command(config->cmd_queue->items[0]);
 		free(config->cmd_queue->items[0]);
 		list_del(config->cmd_queue, 0);
 	}
diff --git a/sway/ipc.c b/sway/ipc.c
index f6217bfd..abf2ed0c 100644
--- a/sway/ipc.c
+++ b/sway/ipc.c
@@ -198,7 +198,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
 	case IPC_COMMAND:
 	{
 		buf[client->payload_length] = '\0';
-		bool success = handle_command(config, buf);
+		bool success = handle_command(buf);
 		char reply[64];
 		int length = snprintf(reply, sizeof(reply), "{\"success\":%s}", success ? "true" : "false");
 		ipc_send_reply(client, reply, (uint32_t) length);
diff --git a/sway/stringop.c b/sway/stringop.c
index c39e2c34..d2b74655 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -1,34 +1,26 @@
-#include "stringop.h"
 #include <stdlib.h>
 #include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include "stringop.h"
+#include "log.h"
 #include "string.h"
 #include "list.h"
-#include <strings.h>
-#include <log.h>
+
+const char *whitespace = " \f\n\r\t\v";
 
 /* Note: This returns 8 characters for trimmed_start per tab character. */
-char *strip_whitespace(char *_str, int *trimmed_start) {
-	*trimmed_start = 0;
-	if (*_str == '\0')
-		return _str;
-	char *strold = _str;
-	while (*_str == ' ' || *_str == '\t') {
-		if (*_str == '\t') {
-			*trimmed_start += 8;
-		} else {
-			*trimmed_start += 1;
-		}
-		_str++;
-	}
-	char *str = malloc(strlen(_str) + 1);
-	strcpy(str, _str);
-	free(strold);
-	int i;
-	for (i = 0; str[i] != '\0'; ++i);
+char *strip_whitespace(char *_str) {
+	int ws = strspn(_str, whitespace);
+	int len = strlen(_str) - ws + 1;
+	sway_log(L_DEBUG,"%d, %d..",ws,len);
+	char *str = malloc(len);
+	strcpy(str, _str+ws);
+	free(_str);
 	do {
-		i--;
-	} while (i >= 0 && (str[i] == ' ' || str[i] == '\t'));
-	str[i + 1] = '\0';
+		len--;
+	} while (len >= 0 && (str[len] == ' ' || str[len] == '\t'));
+	str[len + 1] = '\0';
 	return str;
 }
 
@@ -41,7 +33,7 @@ char *strip_comments(char *str) {
 		} else if (str[i] == '\'' && !in_string) {
 			in_character = !in_character;
 		} else if (!in_character && !in_string) {
-			if (str[i] == '#' && i == 0) {
+			if (str[i] == '#') {
 				str[i] = '\0';
 				break;
 			}
@@ -51,26 +43,45 @@ char *strip_comments(char *str) {
 	return str;
 }
 
+void strip_quotes(char *str) {
+	bool in_str = false;
+	bool in_chr = false;
+	bool escaped = false;
+	char *end = strchr(str,0);
+	while (*str) {
+		if (*str == '\'' && !in_str && !escaped) {
+			in_chr = !in_chr;
+			goto shift_over;
+		} else if (*str == '\"' && !in_chr && !escaped) {
+			in_str = !in_str;
+			goto shift_over;
+		} else if (*str == '\\') {
+			escaped = !escaped;
+			++str;
+			continue;
+		}
+		escaped = false;
+		++str;
+		continue;
+		shift_over:
+		memmove(str, str+1, end-- - str);
+	}
+	*end = '\0';
+}
+
 list_t *split_string(const char *str, const char *delims) {
 	list_t *res = create_list();
-	int i, j;
-	int len = strlen(str);
-	for (i = 0, j = 0; i < len + 1; ++i) {
-		if (strchr(delims, str[i]) || i == len) {
-			if (i - j == 0) {
-				continue;
-			}
-			char *left = malloc(i - j + 1);
-			memcpy(left, str + j, i - j);
-			left[i - j] = 0;
-			list_add(res, left);
-			j = i + 1;
-			while (j <= len && str[j] && strchr(delims, str[j])) {
-				j++;
-				i++;
-			}
-		}
+	char *copy = malloc(strlen(str) + 1);
+	char *token;
+	strcpy(copy, str);
+
+	token = strtok(copy, delims);
+	while(token) {
+		token = strdup(token);
+		list_add(res, token);
+		token = strtok(NULL, delims);
 	}
+	free(copy);
 	return res;
 }
 
@@ -82,6 +93,60 @@ void free_flat_list(list_t *list) {
 	list_free(list);
 }
 
+char **split_args(const char *start, int *argc) {
+	*argc = 0;
+	int alloc = 2;
+	char **parts = malloc(sizeof(char *) * alloc);
+	bool in_token = false;
+	bool in_string = false;
+	bool in_char = false;
+	bool escaped = false;
+	const char *end = start;
+	while (*start) {
+		if (!in_token) {
+			start = (end += strspn(end, whitespace));
+			in_token = true;
+		}
+		if (*end == '"' && !in_char && !escaped) {
+			in_string = !in_string;
+		} else if (*end == '\'' && !in_string && !escaped) {
+			in_char = !in_char;
+		} else if (*end == '\\') {
+			escaped = !escaped;
+		} else if (*end == '\0' || (!in_string && !in_char && !escaped
+				&& strchr(whitespace, *end))) {
+			goto add_part;
+		}
+		if (*end != '\\') {
+			escaped = false;
+		}
+		++end;
+		continue;
+		add_part:
+		if (end - start > 0) {
+			char *token = malloc(end - start + 1);
+			strncpy(token, start, end - start + 1);
+			token[end - start] = '\0';
+			strip_quotes(token);
+			unescape_string(token);
+			parts[*argc] = token;
+			if (++*argc == alloc) {
+				parts = realloc(parts, (alloc *= 2) * sizeof(char *));
+			}
+		}
+		in_token = false;
+		escaped = false;
+	}
+	return parts;
+}
+
+void free_argv(int argc, char **argv) {
+	while (--argc) {
+		free(argv[argc]);
+	}
+	free(argv);
+}
+
 char *code_strstr(const char *haystack, const char *needle) {
 	/* TODO */
 	return strstr(haystack, needle);
@@ -177,7 +242,7 @@ int unescape_string(char *string) {
 					string[i - 1] = c;
 				}
 			}
-			memmove(string + i, string + i + shift, len - i);
+			memmove(string + i, string + i + shift, len - i + 1);
 		}
 	}
 	return len;

From 47ff0006975a2fcab2178b729deec675c2283363 Mon Sep 17 00:00:00 2001
From: taiyu <taiyu.len@gmail.com>
Date: Mon, 7 Sep 2015 14:40:23 -0700
Subject: [PATCH 2/3] put strip_whitespace back

---
 sway/config.c   |  1 +
 sway/stringop.c | 23 ++++++++++++++---------
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/sway/config.c b/sway/config.c
index 119730ca..95cd8b0d 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -230,6 +230,7 @@ bool read_config(FILE *file, bool is_active) {
 	char *line;
 	while (!feof(file)) {
 		line = read_line(file);
+		line = strip_whitespace(line);
 		line = strip_comments(line);
 		if (line[0] == '\0') {
 			goto _continue;
diff --git a/sway/stringop.c b/sway/stringop.c
index d2b74655..77faf3f1 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -11,16 +11,21 @@ const char *whitespace = " \f\n\r\t\v";
 
 /* Note: This returns 8 characters for trimmed_start per tab character. */
 char *strip_whitespace(char *_str) {
-	int ws = strspn(_str, whitespace);
-	int len = strlen(_str) - ws + 1;
-	sway_log(L_DEBUG,"%d, %d..",ws,len);
-	char *str = malloc(len);
-	strcpy(str, _str+ws);
-	free(_str);
+	if (*_str == '\0')
+		return _str;
+	char *strold = _str;
+	while (*_str == ' ' || *_str == '\t') {
+		_str++;
+	}
+	char *str = malloc(strlen(_str) + 1);
+	strcpy(str, _str);
+	free(strold);
+	int i;
+	for (i = 0; str[i] != '\0'; ++i);
 	do {
-		len--;
-	} while (len >= 0 && (str[len] == ' ' || str[len] == '\t'));
-	str[len + 1] = '\0';
+		i--;
+	} while (i >= 0 && (str[i] == ' ' || str[i] == '\t')); 
+	str[i + 1] = '\0';
 	return str;
 }
 

From 3eb29ea7364724af99e4f4a5f7a6f633e17baf8d Mon Sep 17 00:00:00 2001
From: taiyu <taiyu.len@gmail.com>
Date: Mon, 7 Sep 2015 15:03:04 -0700
Subject: [PATCH 3/3] strdup + style

---
 sway/commands.c | 9 +++------
 sway/config.c   | 3 +--
 sway/stringop.c | 8 +++-----
 3 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/sway/commands.c b/sway/commands.c
index 72d53ff0..e7ddfa71 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -383,9 +383,8 @@ static bool cmd_mode(int argc, char **argv) {
 	// Create mode if it doesnt exist
 	if (!mode && argc >= 2 && strncmp(argv[1],"{",1) == 0) {
 		mode = malloc(sizeof*mode);
-		mode->name = malloc(strlen(mode_name) + 1);
+		mode->name = strdup(mode_name);
 		mode->bindings = create_list();
-		strcpy(mode->name, mode_name);
 		list_add(config->modes, mode);
 	}
 	if (!mode) {
@@ -834,10 +833,8 @@ static bool cmd_set(int argc, char **argv) {
 		return false;
 	}
 	struct sway_variable *var = malloc(sizeof(struct sway_variable));
-	var->name = malloc(strlen(argv[0]) + 1);
-	strcpy(var->name, argv[0]);
-	var->value = malloc(strlen(argv[1]) + 1);
-	strcpy(var->value, argv[1]);
+	var->name = strdup(argv[0]);
+	var->value = strdup(argv[1]);
 	list_add(config->symbols, var);
 	return true;
 }
diff --git a/sway/config.c b/sway/config.c
index 95cd8b0d..5ece2810 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -249,8 +249,7 @@ bool read_config(FILE *file, bool is_active) {
 				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 = malloc(strlen(line) + 1);
-				strcpy(cmd, 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);
diff --git a/sway/stringop.c b/sway/stringop.c
index 77faf3f1..1ba54ec6 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -17,14 +17,13 @@ char *strip_whitespace(char *_str) {
 	while (*_str == ' ' || *_str == '\t') {
 		_str++;
 	}
-	char *str = malloc(strlen(_str) + 1);
-	strcpy(str, _str);
+	char *str = strdup(_str);
 	free(strold);
 	int i;
 	for (i = 0; str[i] != '\0'; ++i);
 	do {
 		i--;
-	} while (i >= 0 && (str[i] == ' ' || str[i] == '\t')); 
+	} while (i >= 0 && (str[i] == ' ' || str[i] == '\t'));
 	str[i + 1] = '\0';
 	return str;
 }
@@ -76,9 +75,8 @@ void strip_quotes(char *str) {
 
 list_t *split_string(const char *str, const char *delims) {
 	list_t *res = create_list();
-	char *copy = malloc(strlen(str) + 1);
+	char *copy = strdup(str);
 	char *token;
-	strcpy(copy, str);
 
 	token = strtok(copy, delims);
 	while(token) {