aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/commands.h16
-rw-r--r--include/stringop.h8
-rw-r--r--sway/commands.c239
-rw-r--r--sway/config.c74
-rw-r--r--sway/container.c2
-rw-r--r--sway/handlers.c2
-rw-r--r--sway/layout.c3
-rw-r--r--sway/log.c8
-rw-r--r--sway/stringop.c118
9 files changed, 317 insertions, 153 deletions
diff --git a/include/commands.h b/include/commands.h
index 5c87be51..1b4cd9ca 100644
--- a/include/commands.h
+++ b/include/commands.h
@@ -3,13 +3,15 @@
3#include <stdbool.h> 3#include <stdbool.h>
4#include "config.h" 4#include "config.h"
5 5
6struct cmd_handler { 6
7 char *command; 7enum cmd_status {
8 enum cmd_status { 8 CMD_SUCCESS,
9 CMD_SUCCESS, 9 CMD_FAILURE,
10 CMD_FAILURE, 10 CMD_INVALID,
11 CMD_DEFER, 11 CMD_DEFER,
12 } (*handle)(int argc, char **argv); 12 // Config Blocks
13 CMD_BLOCK_END,
14 CMD_BLOCK_MODE,
13}; 15};
14 16
15enum cmd_status handle_command(char *command); 17enum cmd_status handle_command(char *command);
diff --git a/include/stringop.h b/include/stringop.h
index f9f3130c..49bfa771 100644
--- a/include/stringop.h
+++ b/include/stringop.h
@@ -8,10 +8,11 @@ extern int setenv(const char *, const char *, int);
8#endif 8#endif
9 9
10// array of whitespace characters to use for delims 10// array of whitespace characters to use for delims
11extern const char *whitespace; 11extern const char whitespace[];
12 12
13char *strip_whitespace(char *str); 13char *strip_whitespace(char *str);
14char *strip_comments(char *str); 14char *strip_comments(char *str);
15void strip_quotes(char *str);
15 16
16// Simply split a string with delims, free with `free_flat_list` 17// Simply split a string with delims, free with `free_flat_list`
17list_t *split_string(const char *str, const char *delims); 18list_t *split_string(const char *str, const char *delims);
@@ -27,5 +28,10 @@ int unescape_string(char *string);
27char *join_args(char **argv, int argc); 28char *join_args(char **argv, int argc);
28char *join_list(list_t *list, char *separator); 29char *join_list(list_t *list, char *separator);
29 30
31// split string into 2 by delim.
32char *cmdsep(char **stringp, const char *delim);
33// Split string into 2 by delim, handle quotes
34char *argsep(char **stringp, const char *delim);
35
30char *strdup(const char *); 36char *strdup(const char *);
31#endif 37#endif
diff --git a/sway/commands.c b/sway/commands.c
index 68bdff2c..03c682d7 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -20,6 +20,40 @@
20#include "sway.h" 20#include "sway.h"
21#include "resize.h" 21#include "resize.h"
22 22
23typedef enum cmd_status sway_cmd(int argc, char **argv);
24
25struct cmd_handler {
26 char *command;
27 sway_cmd *handle;
28};
29
30static sway_cmd cmd_bindsym;
31static sway_cmd cmd_orientation;
32static sway_cmd cmd_exec;
33static sway_cmd cmd_exec_always;
34static sway_cmd cmd_exit;
35static sway_cmd cmd_floating;
36static sway_cmd cmd_floating_mod;
37static sway_cmd cmd_focus;
38static sway_cmd cmd_focus_follows_mouse;
39static sway_cmd cmd_fullscreen;
40static sway_cmd cmd_gaps;
41static sway_cmd cmd_kill;
42static sway_cmd cmd_layout;
43static sway_cmd cmd_log_colors;
44static sway_cmd cmd_mode;
45static sway_cmd cmd_move;
46static sway_cmd cmd_output;
47static sway_cmd cmd_reload;
48static sway_cmd cmd_resize;
49static sway_cmd cmd_scratchpad;
50static sway_cmd cmd_set;
51static sway_cmd cmd_split;
52static sway_cmd cmd_splith;
53static sway_cmd cmd_splitv;
54static sway_cmd cmd_workspace;
55static sway_cmd cmd_ws_auto_back_and_forth;
56
23swayc_t *sp_view; 57swayc_t *sp_view;
24int sp_index = 0; 58int sp_index = 0;
25 59
@@ -147,37 +181,33 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
147} 181}
148 182
149static enum cmd_status cmd_exec_always(int argc, char **argv) { 183static enum cmd_status cmd_exec_always(int argc, char **argv) {
184 if (!config->active) return CMD_DEFER;
150 if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) { 185 if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
151 return CMD_FAILURE; 186 return CMD_FAILURE;
152 } 187 }
153 if (!config->active) { 188 // Put argument into cmd array
154 return CMD_DEFER; 189 char *tmp = join_args(argv, argc);
155 } 190 char cmd[4096];
156 191 strcpy(cmd, tmp);
157 pid_t pid = fork(); 192 free(tmp);
158 /* Failed to fork */ 193
159 if (pid < 0) { 194 char *args[] = {"sh", "-c", cmd, 0 };
160 sway_log(L_ERROR, "exec command failed, sway did not fork"); 195 sway_log(L_DEBUG, "Executing %s", cmd);
196
197 pid_t pid;
198 if ((pid = fork()) == 0) {
199 execv("/bin/sh", args);
200 _exit(-1);
201 } else if (pid < 0) {
202 sway_log(L_ERROR, "exec command failed, sway could not fork");
161 return CMD_FAILURE; 203 return CMD_FAILURE;
162 } 204 }
163 /* Child process */
164 if (pid == 0) {
165 char *args = join_args(argv, argc);
166 sway_log(L_DEBUG, "Executing %s", args);
167 execl("/bin/sh", "sh", "-c", args, (char *)NULL);
168 /* Execl doesnt return unless failure */
169 sway_log(L_ERROR, "could not find /bin/sh");
170 free(args);
171 exit(-1);
172 }
173 /* Parent */
174 return CMD_SUCCESS; 205 return CMD_SUCCESS;
175} 206}
176 207
177static enum cmd_status cmd_exec(int argc, char **argv) { 208static enum cmd_status cmd_exec(int argc, char **argv) {
178 if (!config->active) { 209 if (!config->active) return CMD_DEFER;
179 return CMD_DEFER; 210
180 }
181 if (config->reloading) { 211 if (config->reloading) {
182 char *args = join_args(argv, argc); 212 char *args = join_args(argv, argc);
183 sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); 213 sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
@@ -194,8 +224,8 @@ static void kill_views(swayc_t *container, void *data) {
194} 224}
195 225
196static enum cmd_status cmd_exit(int argc, char **argv) { 226static enum cmd_status cmd_exit(int argc, char **argv) {
197 if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0) 227 if (config->reading) return CMD_INVALID;
198 || config->reading || !config->active) { 228 if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)) {
199 return CMD_FAILURE; 229 return CMD_FAILURE;
200 } 230 }
201 // Close all views 231 // Close all views
@@ -205,8 +235,8 @@ static enum cmd_status cmd_exit(int argc, char **argv) {
205} 235}
206 236
207static enum cmd_status cmd_floating(int argc, char **argv) { 237static enum cmd_status cmd_floating(int argc, char **argv) {
208 if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1) 238 if (config->reading) return CMD_INVALID;
209 || config->reading || !config->active) { 239 if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)) {
210 return CMD_FAILURE; 240 return CMD_FAILURE;
211 } 241 }
212 242
@@ -267,8 +297,8 @@ static enum cmd_status cmd_floating(int argc, char **argv) {
267} 297}
268 298
269static enum cmd_status cmd_floating_mod(int argc, char **argv) { 299static enum cmd_status cmd_floating_mod(int argc, char **argv) {
270 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1) 300 if (!config->reading) return CMD_INVALID;
271 || !config->reading) { 301 if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
272 return CMD_FAILURE; 302 return CMD_FAILURE;
273 } 303 }
274 int i, j; 304 int i, j;
@@ -292,10 +322,10 @@ static enum cmd_status cmd_floating_mod(int argc, char **argv) {
292} 322}
293 323
294static enum cmd_status cmd_focus(int argc, char **argv) { 324static enum cmd_status cmd_focus(int argc, char **argv) {
325 if (config->reading) return CMD_INVALID;
295 static int floating_toggled_index = 0; 326 static int floating_toggled_index = 0;
296 static int tiled_toggled_index = 0; 327 static int tiled_toggled_index = 0;
297 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1) 328 if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
298 || config->reading || !config->active) {
299 return CMD_FAILURE; 329 return CMD_FAILURE;
300 } 330 }
301 if (strcasecmp(argv[0], "left") == 0) { 331 if (strcasecmp(argv[0], "left") == 0) {
@@ -350,6 +380,7 @@ static enum cmd_status cmd_focus(int argc, char **argv) {
350} 380}
351 381
352static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) { 382static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
383 if (!config->reading) return CMD_INVALID;
353 if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) { 384 if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
354 return CMD_FAILURE; 385 return CMD_FAILURE;
355 } 386 }
@@ -359,7 +390,7 @@ static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
359} 390}
360 391
361static void hide_view_in_scratchpad(swayc_t *sp_view) { 392static void hide_view_in_scratchpad(swayc_t *sp_view) {
362 if(sp_view == NULL) { 393 if (sp_view == NULL) {
363 return; 394 return;
364 } 395 }
365 396
@@ -375,15 +406,19 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) {
375} 406}
376 407
377static enum cmd_status cmd_mode(int argc, char **argv) { 408static enum cmd_status cmd_mode(int argc, char **argv) {
378 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) { 409 if (!checkarg(argc, "mode", EXPECTED_AT_LEAST, 1)) {
379 return CMD_FAILURE; 410 return CMD_FAILURE;
380 } 411 }
381 bool mode_make = !strcmp(argv[argc-1], "{"); 412 char *mode_name = join_args(argv, argc);
382 if (mode_make && !config->reading) { 413 int mode_len = strlen(mode_name);
383 return CMD_FAILURE; 414 bool mode_make = mode_name[mode_len-1] == '{';
415 if (mode_make) {
416 if (!config->reading) return CMD_INVALID;
417 // Trim trailing spaces
418 do {
419 mode_name[--mode_len] = 0;
420 } while(isspace(mode_name[mode_len-1]));
384 } 421 }
385
386 char *mode_name = join_args(argv, argc - mode_make);
387 struct sway_mode *mode = NULL; 422 struct sway_mode *mode = NULL;
388 // Find mode 423 // Find mode
389 int i, len = config->modes->length; 424 int i, len = config->modes->length;
@@ -406,16 +441,18 @@ static enum cmd_status cmd_mode(int argc, char **argv) {
406 free(mode_name); 441 free(mode_name);
407 return CMD_FAILURE; 442 return CMD_FAILURE;
408 } 443 }
409 sway_log(L_DEBUG, "Switching to mode `%s'",mode->name); 444 if ((config->reading && mode_make) || (!config->reading && !mode_make)) {
445 sway_log(L_DEBUG, "Switching to mode `%s'",mode->name);
446 }
410 free(mode_name); 447 free(mode_name);
411 // Set current mode 448 // Set current mode
412 config->current_mode = mode; 449 config->current_mode = mode;
413 return CMD_SUCCESS; 450 return mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS;
414} 451}
415 452
416static enum cmd_status cmd_move(int argc, char **argv) { 453static enum cmd_status cmd_move(int argc, char **argv) {
417 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1) 454 if (config->reading) return CMD_FAILURE;
418 || config->reading || !config->active) { 455 if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
419 return CMD_FAILURE; 456 return CMD_FAILURE;
420 } 457 }
421 458
@@ -485,10 +522,11 @@ static enum cmd_status cmd_move(int argc, char **argv) {
485} 522}
486 523
487static enum cmd_status cmd_orientation(int argc, char **argv) { 524static enum cmd_status cmd_orientation(int argc, char **argv) {
488 if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1) 525 if (!config->reading) return CMD_FAILURE;
489 || !config->reading) { 526 if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)) {
490 return CMD_FAILURE; 527 return CMD_FAILURE;
491 } 528 }
529
492 if (strcasecmp(argv[0], "horizontal") == 0) { 530 if (strcasecmp(argv[0], "horizontal") == 0) {
493 config->default_orientation = L_HORIZ; 531 config->default_orientation = L_HORIZ;
494 } else if (strcasecmp(argv[0], "vertical") == 0) { 532 } else if (strcasecmp(argv[0], "vertical") == 0) {
@@ -502,6 +540,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) {
502} 540}
503 541
504static enum cmd_status cmd_output(int argc, char **argv) { 542static enum cmd_status cmd_output(int argc, char **argv) {
543 if (!config->reading) return CMD_FAILURE;
505 if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) { 544 if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
506 return CMD_FAILURE; 545 return CMD_FAILURE;
507 } 546 }
@@ -512,7 +551,6 @@ static enum cmd_status cmd_output(int argc, char **argv) {
512 output->enabled = true; 551 output->enabled = true;
513 552
514 // TODO: atoi doesn't handle invalid numbers 553 // TODO: atoi doesn't handle invalid numbers
515
516 if (strcasecmp(argv[1], "disable") == 0) { 554 if (strcasecmp(argv[1], "disable") == 0) {
517 output->enabled = false; 555 output->enabled = false;
518 } 556 }
@@ -953,7 +991,7 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) {
953 } 991 }
954 if (strcasecmp(argv[0], "no") == 0) { 992 if (strcasecmp(argv[0], "no") == 0) {
955 sway_log_colors(0); 993 sway_log_colors(0);
956 } else if(strcasecmp(argv[0], "yes") == 0) { 994 } else if (strcasecmp(argv[0], "yes") == 0) {
957 sway_log_colors(1); 995 sway_log_colors(1);
958 } else { 996 } else {
959 sway_log(L_ERROR, "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]); 997 sway_log(L_ERROR, "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]);
@@ -1089,57 +1127,88 @@ static struct cmd_handler *find_handler(char *line) {
1089 return res; 1127 return res;
1090} 1128}
1091 1129
1092enum cmd_status handle_command(char *exec) { 1130enum cmd_status handle_command(char *_exec) {
1093 sway_log(L_INFO, "Handling command '%s'", exec); 1131 enum cmd_status status = CMD_SUCCESS;
1094 int argc; 1132 char *exec = strdup(_exec);
1095 char **argv = split_args(exec, &argc); 1133 char *head = exec;
1096 enum cmd_status status = CMD_FAILURE; 1134 char *cmdlist;
1097 struct cmd_handler *handler; 1135 char *cmd;
1098 if (!argc) { 1136 char *criteria __attribute__((unused));
1099 return status; 1137
1100 } 1138 head = exec;
1101 if ((handler = find_handler(argv[0])) == NULL 1139 do {
1102 || (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) { 1140 // Handle criteria
1103 sway_log(L_ERROR, "Command failed: %s", argv[0]); 1141 if (*head == '[') {
1104 } 1142 criteria = argsep(&head, "]");
1105 free_argv(argc, argv); 1143 if (head) {
1144 ++head;
1145 // TODO handle criteria
1146 } else {
1147 sway_log(L_ERROR, "Unmatched [");
1148 status = CMD_INVALID;
1149 }
1150 // Skip leading whitespace
1151 head += strspn(head, whitespace);
1152 }
1153 // Split command list
1154 cmdlist = argsep(&head, ";");
1155 cmdlist += strspn(cmdlist, whitespace);
1156 do {
1157 // Split commands
1158 cmd = argsep(&cmdlist, ",");
1159 cmd += strspn(cmd, whitespace);
1160 sway_log(L_INFO, "Handling command '%s'", cmd);
1161 //TODO better handling of argv
1162 int argc;
1163 char **argv = split_args(cmd, &argc);
1164 if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
1165 strip_quotes(argv[1]);
1166 }
1167 struct cmd_handler *handler = find_handler(argv[0]);
1168 enum cmd_status res = CMD_INVALID;
1169 if (!handler
1170 || (res = handler->handle(argc-1, argv+1)) != CMD_SUCCESS) {
1171 sway_log(L_ERROR, "Command '%s' failed", cmd);
1172 free_argv(argc, argv);
1173 status = res;
1174 goto cleanup;
1175 }
1176 free_argv(argc, argv);
1177 } while(cmdlist);
1178 } while(head);
1179 cleanup:
1180 free(exec);
1106 return status; 1181 return status;
1107} 1182}
1108 1183
1109enum cmd_status config_command(char *exec) { 1184enum cmd_status config_command(char *exec) {
1110 sway_log(L_INFO, "handling config command '%s'", exec); 1185 enum cmd_status status = CMD_SUCCESS;
1111 int argc; 1186 int argc;
1112 char **argv = split_args(exec, &argc); 1187 char **argv = split_args(exec, &argc);
1113 enum cmd_status status = CMD_FAILURE; 1188 if (!argc) goto cleanup;
1114 struct cmd_handler *handler; 1189
1115 if (!argc) { 1190 sway_log(L_INFO, "handling config command '%s'", exec);
1116 status = CMD_SUCCESS; 1191 // Endblock
1192 if (**argv == '}') {
1193 status = CMD_BLOCK_END;
1117 goto cleanup; 1194 goto cleanup;
1118 } 1195 }
1119 // TODO better block handling 1196 struct cmd_handler *handler = find_handler(argv[0]);
1120 if (strncmp(argv[0], "}", 1) == 0) { 1197 if (!handler) {
1121 config->current_mode = config->modes->items[0]; 1198 status = CMD_INVALID;
1122 status = CMD_SUCCESS;
1123 goto cleanup; 1199 goto cleanup;
1124 } 1200 }
1125 if ((handler = find_handler(argv[0]))) { 1201 int i;
1126 // Dont replace first argument in cmd_set 1202 // Var replacement, for all but first argument of set
1127 int i = handler->handle == cmd_set ? 2 : 1; 1203 for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
1128 int e = argc; 1204 argv[i] = do_var_replacement(argv[i]);
1129 for (; i < e; ++i) { 1205 }
1130 argv[i] = do_var_replacement(argv[i]); 1206 /* Strip quotes for first argument.
1131 } 1207 * TODO This part needs to be handled much better */
1132 status = handler->handle(argc - 1, argv + 1); 1208 if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
1133 if (status == CMD_FAILURE) { 1209 strip_quotes(argv[1]);
1134 sway_log(L_ERROR, "Config load failed for line `%s'", exec);
1135 } else if (status == CMD_DEFER) {
1136 sway_log(L_DEBUG, "Defferring command `%s'", exec);
1137 list_add(config->cmd_queue, strdup(exec));
1138 status = CMD_SUCCESS;
1139 }
1140 } else {
1141 sway_log(L_ERROR, "Unknown command `%s'", exec);
1142 } 1210 }
1211 status = handler->handle(argc-1, argv+1);
1143 cleanup: 1212 cleanup:
1144 free_argv(argc, argv); 1213 free_argv(argc, argv);
1145 return status; 1214 return status;
diff --git a/sway/config.c b/sway/config.c
index 23d6ac0d..46a26424 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -110,47 +110,49 @@ static void config_defaults(struct sway_config *config) {
110 110
111static char *get_config_path(void) { 111static char *get_config_path(void) {
112 char *config_path = NULL; 112 char *config_path = NULL;
113 char *paths[3] = {getenv("HOME"), getenv("XDG_CONFIG_HOME"), ""}; 113 char *paths[3] = { getenv("HOME"), getenv("XDG_CONFIG_HOME"), "" };
114 int pathlen[3] = {0, 0, 0}; 114 int pathlen[3] = { 0, 0, 0 };
115 int i; 115 int i;
116#define home paths[0] 116#define home paths[0]
117#define conf paths[1] 117#define conf paths[1]
118 // Get home and config directories 118 // Get home and config directories
119 conf = conf ? strdup(conf) : NULL;
119 home = home ? strdup(home) : NULL; 120 home = home ? strdup(home) : NULL;
120 if (conf) { 121 // If config folder is unset, set it to $HOME/.config
121 conf = strdup(conf); 122 if (!conf && home) {
122 } else if (home) {
123 const char *def = "/.config"; 123 const char *def = "/.config";
124 conf = malloc(strlen(home) + strlen(def) + 1); 124 conf = malloc(strlen(home) + strlen(def) + 1);
125 strcpy(conf, home); 125 strcpy(conf, home);
126 strcat(conf, def); 126 strcat(conf, def);
127 } else {
128 home = strdup("");
129 conf = strdup("");
130 } 127 }
131 pathlen[0] = strlen(home); 128 // Get path lengths
132 pathlen[1] = strlen(conf); 129 pathlen[0] = home ? strlen(home) : 0;
130 pathlen[1] = conf ? strlen(conf) : 0;
133#undef home 131#undef home
134#undef conf 132#undef conf
133
135 // Search for config file from search paths 134 // Search for config file from search paths
136 static const char *search_paths[] = { 135 static const char *search_paths[] = {
137 "/.sway/config", // Prepend with $home 136 "/.sway/config", // Prepend with $home
138 "/sway/config", // Prepend with $config 137 "/sway/config", // Prepend with $config
139 "/etc/sway/config", 138 "/etc/sway/config",
140 "/.i3/config", // $home 139 "/.i3/config", // $home
141 "/.i3/config", // $config 140 "/i3/config", // $config
142 "/etc/i3/config" 141 "/etc/i3/config"
143 }; 142 };
144 for (i = 0; i < (int)(sizeof(search_paths) / sizeof(char *)); ++i) { 143 for (i = 0; i < (int)(sizeof(search_paths) / sizeof(char *)); ++i) {
145 char *test = malloc(pathlen[i%3] + strlen(search_paths[i]) + 1); 144 // Only try path if it is set by enviroment variables
146 strcpy(test, paths[i%3]); 145 if (paths[i%3]) {
147 strcat(test, search_paths[i]); 146 char *test = malloc(pathlen[i%3] + strlen(search_paths[i]) + 1);
148 sway_log(L_DEBUG, "Checking for config at %s", test); 147 strcpy(test, paths[i%3]);
149 if (file_exists(test)) { 148 strcpy(test + pathlen[i%3], search_paths[i]);
150 config_path = test; 149 sway_log(L_DEBUG, "Checking for config at %s", test);
151 goto cleanup; 150 if (file_exists(test)) {
151 config_path = test;
152 goto cleanup;
153 }
154 free(test);
152 } 155 }
153 free(test);
154 } 156 }
155 157
156 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS"); 158 sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
@@ -225,14 +227,46 @@ bool read_config(FILE *file, bool is_active) {
225 config->active = true; 227 config->active = true;
226 } 228 }
227 bool success = true; 229 bool success = true;
230 enum cmd_status block = CMD_BLOCK_END;
228 231
229 char *line; 232 char *line;
230 while (!feof(file)) { 233 while (!feof(file)) {
231 line = read_line(file); 234 line = read_line(file);
232 line = strip_comments(line); 235 line = strip_comments(line);
233 if (config_command(line) == CMD_FAILURE) { 236 switch(config_command(line)) {
237 case CMD_FAILURE:
238 case CMD_INVALID:
234 sway_log(L_ERROR, "Error on line '%s'", line); 239 sway_log(L_ERROR, "Error on line '%s'", line);
235 success = false; 240 success = false;
241 break;
242
243 case CMD_DEFER:
244 sway_log(L_DEBUG, "Defferring command `%s'", line);
245 list_add(config->cmd_queue, strdup(line));
246 break;
247
248 case CMD_BLOCK_MODE:
249 if (block == CMD_BLOCK_END) {
250 block = CMD_BLOCK_MODE;
251 } else {
252 sway_log(L_ERROR, "Invalid block '%s'", line);
253 }
254 break;
255
256 case CMD_BLOCK_END:
257 switch(block) {
258 case CMD_BLOCK_MODE:
259 sway_log(L_DEBUG, "End of mode block");
260 config->current_mode = config->modes->items[0];
261 break;
262
263 case CMD_BLOCK_END:
264 sway_log(L_ERROR, "Unmatched }");
265 break;
266
267 default:;
268 }
269 default:;
236 } 270 }
237 free(line); 271 free(line);
238 } 272 }
diff --git a/sway/container.c b/sway/container.c
index 85b169a1..4c523827 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -405,7 +405,7 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
405} 405}
406 406
407static bool test_name(swayc_t *view, void *data) { 407static bool test_name(swayc_t *view, void *data) {
408 if (!view && !view->name) { 408 if (!view || !view->name) {
409 return false; 409 return false;
410 } 410 }
411 return strcmp(view->name, data) == 0; 411 return strcmp(view->name, data) == 0;
diff --git a/sway/handlers.c b/sway/handlers.c
index cef4a980..cf07bc8b 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -331,7 +331,7 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
331 struct sway_binding *binding = mode->bindings->items[i]; 331 struct sway_binding *binding = mode->bindings->items[i];
332 332
333 if ((modifiers->mods ^ binding->modifiers) == 0) { 333 if ((modifiers->mods ^ binding->modifiers) == 0) {
334 bool match; 334 bool match = false;
335 int j; 335 int j;
336 for (j = 0; j < binding->keys->length; ++j) { 336 for (j = 0; j < binding->keys->length; ++j) {
337 xkb_keysym_t *key = binding->keys->items[j]; 337 xkb_keysym_t *key = binding->keys->items[j];
diff --git a/sway/layout.c b/sway/layout.c
index 086dc542..3cd873d6 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -206,7 +206,8 @@ void swap_geometry(swayc_t *a, swayc_t *b) {
206 206
207void move_container(swayc_t *container, enum movement_direction dir) { 207void move_container(swayc_t *container, enum movement_direction dir) {
208 enum swayc_layouts layout; 208 enum swayc_layouts layout;
209 if (container->is_floating) { 209 if (container->is_floating
210 || (container->type != C_VIEW && container->type != C_CONTAINER)) {
210 return; 211 return;
211 } 212 }
212 if (dir == MOVE_UP || dir == MOVE_DOWN) { 213 if (dir == MOVE_UP || dir == MOVE_DOWN) {
diff --git a/sway/log.c b/sway/log.c
index a6582172..a206d971 100644
--- a/sway/log.c
+++ b/sway/log.c
@@ -14,10 +14,10 @@ int colored = 1;
14log_importance_t v = L_SILENT; 14log_importance_t v = L_SILENT;
15 15
16static const char *verbosity_colors[] = { 16static const char *verbosity_colors[] = {
17 "", // L_SILENT 17 [L_SILENT] = "",
18 "\x1B[1;31m", // L_ERROR 18 [L_ERROR ] = "\x1B[1;31m",
19 "\x1B[1;34m", // L_INFO 19 [L_INFO ] = "\x1B[1;34m",
20 "\x1B[1;30m", // L_DEBUG 20 [L_DEBUG ] = "\x1B[1;30m",
21}; 21};
22 22
23void init_log(log_importance_t verbosity) { 23void init_log(log_importance_t verbosity) {
diff --git a/sway/stringop.c b/sway/stringop.c
index 7a2c8317..31a036c3 100644
--- a/sway/stringop.c
+++ b/sway/stringop.c
@@ -1,5 +1,6 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include <stdio.h> 2#include <stdio.h>
3#include <string.h>
3#include <strings.h> 4#include <strings.h>
4#include <ctype.h> 5#include <ctype.h>
5#include "stringop.h" 6#include "stringop.h"
@@ -7,7 +8,7 @@
7#include "string.h" 8#include "string.h"
8#include "list.h" 9#include "list.h"
9 10
10const char *whitespace = " \f\n\r\t\v"; 11const char whitespace[] = " \f\n\r\t\v";
11 12
12/* Note: This returns 8 characters for trimmed_start per tab character. */ 13/* Note: This returns 8 characters for trimmed_start per tab character. */
13char *strip_whitespace(char *_str) { 14char *strip_whitespace(char *_str) {
@@ -105,40 +106,40 @@ char **split_args(const char *start, int *argc) {
105 bool in_char = false; 106 bool in_char = false;
106 bool escaped = false; 107 bool escaped = false;
107 const char *end = start; 108 const char *end = start;
108 while (*start) { 109 if (start) {
109 if (!in_token) { 110 while (*start) {
110 start = (end += strspn(end, whitespace)); 111 if (!in_token) {
111 in_token = true; 112 start = (end += strspn(end, whitespace));
112 } 113 in_token = true;
113 if (*end == '"' && !in_char && !escaped) { 114 }
114 in_string = !in_string; 115 if (*end == '"' && !in_char && !escaped) {
115 } else if (*end == '\'' && !in_string && !escaped) { 116 in_string = !in_string;
116 in_char = !in_char; 117 } else if (*end == '\'' && !in_string && !escaped) {
117 } else if (*end == '\\') { 118 in_char = !in_char;
118 escaped = !escaped; 119 } else if (*end == '\\') {
119 } else if (*end == '\0' || (!in_string && !in_char && !escaped 120 escaped = !escaped;
120 && strchr(whitespace, *end))) { 121 } else if (*end == '\0' || (!in_string && !in_char && !escaped
121 goto add_part; 122 && strchr(whitespace, *end))) {
122 } 123 goto add_token;
123 if (*end != '\\') { 124 }
124 escaped = false; 125 if (*end != '\\') {
125 } 126 escaped = false;
126 ++end; 127 }
127 continue; 128 ++end;
128 add_part: 129 continue;
129 if (end - start > 0) { 130 add_token:
130 char *token = malloc(end - start + 1); 131 if (end - start > 0) {
131 strncpy(token, start, end - start + 1); 132 char *token = malloc(end - start + 1);
132 token[end - start] = '\0'; 133 strncpy(token, start, end - start + 1);
133 strip_quotes(token); 134 token[end - start] = '\0';
134 unescape_string(token); 135 argv[*argc] = token;
135 argv[*argc] = token; 136 if (++*argc + 1 == alloc) {
136 if (++*argc + 1 == alloc) { 137 argv = realloc(argv, (alloc *= 2) * sizeof(char *));
137 argv = realloc(argv, (alloc *= 2) * sizeof(char *)); 138 }
138 } 139 }
140 in_token = false;
141 escaped = false;
139 } 142 }
140 in_token = false;
141 escaped = false;
142 } 143 }
143 argv[*argc] = NULL; 144 argv[*argc] = NULL;
144 return argv; 145 return argv;
@@ -312,6 +313,56 @@ char *join_list(list_t *list, char *separator) {
312 return res; 313 return res;
313} 314}
314 315
316char *cmdsep(char **stringp, const char *delim) {
317 // skip over leading delims
318 char *head = *stringp + strspn(*stringp, delim);
319 // Find end token
320 char *tail = *stringp += strcspn(*stringp, delim);
321 // Set stringp to begining of next token
322 *stringp += strspn(*stringp, delim);
323 // Set stringp to null if last token
324 if (!**stringp) *stringp = NULL;
325 // Nullify end of first token
326 *tail = 0;
327 return head;
328}
329
330char *argsep(char **stringp, const char *delim) {
331 char *start = *stringp;
332 char *end = start;
333 bool in_string = false;
334 bool in_char = false;
335 bool escaped = false;
336 while (1) {
337 if (*end == '"' && !in_char && !escaped) {
338 in_string = !in_string;
339 } else if (*end == '\'' && !in_string && !escaped) {
340 in_char = !in_char;
341 } else if (*end == '\\') {
342 escaped = !escaped;
343 } else if (*end == '\0') {
344 *stringp = NULL;
345 goto found;
346 } else if (!in_string && !in_char && !escaped && strchr(delim, *end)) {
347 if (end - start) {
348 *(end++) = 0;
349 *stringp = end + strspn(end, delim);;
350 if (!**stringp) *stringp = NULL;
351 goto found;
352 } else {
353 ++start;
354 end = start;
355 }
356 }
357 if (*end != '\\') {
358 escaped = false;
359 }
360 ++end;
361 }
362 found:
363 return start;
364}
365
315char *strdup(const char *str) { 366char *strdup(const char *str) {
316 char *dup = malloc(strlen(str) + 1); 367 char *dup = malloc(strlen(str) + 1);
317 if (dup) { 368 if (dup) {
@@ -319,3 +370,4 @@ char *strdup(const char *str) {
319 } 370 }
320 return dup; 371 return dup;
321} 372}
373