diff options
-rw-r--r-- | include/commands.h | 16 | ||||
-rw-r--r-- | include/stringop.h | 8 | ||||
-rw-r--r-- | sway/commands.c | 239 | ||||
-rw-r--r-- | sway/config.c | 74 | ||||
-rw-r--r-- | sway/container.c | 2 | ||||
-rw-r--r-- | sway/handlers.c | 6 | ||||
-rw-r--r-- | sway/layout.c | 42 | ||||
-rw-r--r-- | sway/log.c | 8 | ||||
-rw-r--r-- | sway/stringop.c | 118 |
9 files changed, 342 insertions, 171 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 | ||
6 | struct cmd_handler { | 6 | |
7 | char *command; | 7 | enum 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 | ||
15 | enum cmd_status handle_command(char *command); | 17 | enum 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 |
11 | extern const char *whitespace; | 11 | extern const char whitespace[]; |
12 | 12 | ||
13 | char *strip_whitespace(char *str); | 13 | char *strip_whitespace(char *str); |
14 | char *strip_comments(char *str); | 14 | char *strip_comments(char *str); |
15 | void 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` |
17 | list_t *split_string(const char *str, const char *delims); | 18 | list_t *split_string(const char *str, const char *delims); |
@@ -27,5 +28,10 @@ int unescape_string(char *string); | |||
27 | char *join_args(char **argv, int argc); | 28 | char *join_args(char **argv, int argc); |
28 | char *join_list(list_t *list, char *separator); | 29 | char *join_list(list_t *list, char *separator); |
29 | 30 | ||
31 | // split string into 2 by delim. | ||
32 | char *cmdsep(char **stringp, const char *delim); | ||
33 | // Split string into 2 by delim, handle quotes | ||
34 | char *argsep(char **stringp, const char *delim); | ||
35 | |||
30 | char *strdup(const char *); | 36 | char *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 | ||
23 | typedef enum cmd_status sway_cmd(int argc, char **argv); | ||
24 | |||
25 | struct cmd_handler { | ||
26 | char *command; | ||
27 | sway_cmd *handle; | ||
28 | }; | ||
29 | |||
30 | static sway_cmd cmd_bindsym; | ||
31 | static sway_cmd cmd_orientation; | ||
32 | static sway_cmd cmd_exec; | ||
33 | static sway_cmd cmd_exec_always; | ||
34 | static sway_cmd cmd_exit; | ||
35 | static sway_cmd cmd_floating; | ||
36 | static sway_cmd cmd_floating_mod; | ||
37 | static sway_cmd cmd_focus; | ||
38 | static sway_cmd cmd_focus_follows_mouse; | ||
39 | static sway_cmd cmd_fullscreen; | ||
40 | static sway_cmd cmd_gaps; | ||
41 | static sway_cmd cmd_kill; | ||
42 | static sway_cmd cmd_layout; | ||
43 | static sway_cmd cmd_log_colors; | ||
44 | static sway_cmd cmd_mode; | ||
45 | static sway_cmd cmd_move; | ||
46 | static sway_cmd cmd_output; | ||
47 | static sway_cmd cmd_reload; | ||
48 | static sway_cmd cmd_resize; | ||
49 | static sway_cmd cmd_scratchpad; | ||
50 | static sway_cmd cmd_set; | ||
51 | static sway_cmd cmd_split; | ||
52 | static sway_cmd cmd_splith; | ||
53 | static sway_cmd cmd_splitv; | ||
54 | static sway_cmd cmd_workspace; | ||
55 | static sway_cmd cmd_ws_auto_back_and_forth; | ||
56 | |||
23 | swayc_t *sp_view; | 57 | swayc_t *sp_view; |
24 | int sp_index = 0; | 58 | int sp_index = 0; |
25 | 59 | ||
@@ -147,37 +181,33 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) { | |||
147 | } | 181 | } |
148 | 182 | ||
149 | static enum cmd_status cmd_exec_always(int argc, char **argv) { | 183 | static 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 | ||
177 | static enum cmd_status cmd_exec(int argc, char **argv) { | 208 | static 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 | ||
196 | static enum cmd_status cmd_exit(int argc, char **argv) { | 226 | static 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 | ||
207 | static enum cmd_status cmd_floating(int argc, char **argv) { | 237 | static 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 | ||
269 | static enum cmd_status cmd_floating_mod(int argc, char **argv) { | 299 | static 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 | ||
294 | static enum cmd_status cmd_focus(int argc, char **argv) { | 324 | static 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 | ||
352 | static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) { | 382 | static 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 | ||
361 | static void hide_view_in_scratchpad(swayc_t *sp_view) { | 392 | static 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 | ||
377 | static enum cmd_status cmd_mode(int argc, char **argv) { | 408 | static 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 | ||
416 | static enum cmd_status cmd_move(int argc, char **argv) { | 453 | static 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 | ||
487 | static enum cmd_status cmd_orientation(int argc, char **argv) { | 524 | static 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 | ||
504 | static enum cmd_status cmd_output(int argc, char **argv) { | 542 | static 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 | ||
1092 | enum cmd_status handle_command(char *exec) { | 1130 | enum 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 | ||
1109 | enum cmd_status config_command(char *exec) { | 1184 | enum 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 | ||
111 | static char *get_config_path(void) { | 111 | static 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 | ||
407 | static bool test_name(swayc_t *view, void *data) { | 407 | static 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 096df53c..cf07bc8b 100644 --- a/sway/handlers.c +++ b/sway/handlers.c | |||
@@ -253,8 +253,8 @@ static void handle_view_focus(wlc_handle view, bool focus) { | |||
253 | } | 253 | } |
254 | 254 | ||
255 | static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { | 255 | static void handle_view_geometry_request(wlc_handle handle, const struct wlc_geometry *geometry) { |
256 | sway_log(L_DEBUG, "geometry request %d x %d : %d x %d", | 256 | sway_log(L_DEBUG, "geometry request for %ld %dx%d : %dx%d", |
257 | geometry->origin.x, geometry->origin.y, geometry->size.w, geometry->size.h); | 257 | handle, geometry->origin.x, geometry->origin.y, geometry->size.w, geometry->size.h); |
258 | // If the view is floating, then apply the geometry. | 258 | // If the view is floating, then apply the geometry. |
259 | // Otherwise save the desired width/height for the view. | 259 | // Otherwise save the desired width/height for the view. |
260 | // This will not do anything for the time being as WLC improperly sends geometry requests | 260 | // This will not do anything for the time being as WLC improperly sends geometry requests |
@@ -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 bef1b88d..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 | ||
207 | void move_container(swayc_t *container, enum movement_direction dir) { | 207 | void 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) { |
@@ -280,7 +281,6 @@ void move_container(swayc_t *container, enum movement_direction dir) { | |||
280 | // Dirty hack to fix a certain case | 281 | // Dirty hack to fix a certain case |
281 | arrange_windows(parent, -1, -1); | 282 | arrange_windows(parent, -1, -1); |
282 | arrange_windows(parent->parent, -1, -1); | 283 | arrange_windows(parent->parent, -1, -1); |
283 | update_visibility(parent->parent); | ||
284 | set_focused_container_for(parent->parent, container); | 284 | set_focused_container_for(parent->parent, container); |
285 | } | 285 | } |
286 | 286 | ||
@@ -319,31 +319,34 @@ void update_geometry(swayc_t *container) { | |||
319 | if (container->type != C_VIEW) { | 319 | if (container->type != C_VIEW) { |
320 | return; | 320 | return; |
321 | } | 321 | } |
322 | int gap = swayc_gap(container); | 322 | swayc_t *ws = swayc_parent_by_type(container, C_WORKSPACE); |
323 | swayc_t *op = ws->parent; | ||
324 | int gap = container->is_floating ? 0 : swayc_gap(container); | ||
325 | |||
323 | struct wlc_geometry geometry = { | 326 | struct wlc_geometry geometry = { |
324 | .origin = { | 327 | .origin = { |
325 | .x = container->x + (container->is_floating ? 0 : gap / 2), | 328 | .x = container->x + gap/2 < op->width ? container->x + gap/2 : op->width-1, |
326 | .y = container->y + (container->is_floating ? 0 : gap / 2) | 329 | .y = container->y + gap/2 < op->height ? container->y + gap/2 : op->height-1 |
327 | }, | 330 | }, |
328 | .size = { | 331 | .size = { |
329 | .w = container->width > (container->is_floating ? 0 : gap) ? | 332 | .w = container->width > gap ? container->width - gap : 1, |
330 | container->width - (container->is_floating ? 0 : gap) : 0, | 333 | .h = container->height > gap ? container->height - gap : 1, |
331 | .h = container->height > (container->is_floating ? 0 : gap) ? | ||
332 | container->height - (container->is_floating ? 0 : gap) : 0, | ||
333 | } | 334 | } |
334 | }; | 335 | }; |
335 | if (swayc_is_fullscreen(container)) { | 336 | if (swayc_is_fullscreen(container)) { |
336 | swayc_t *parent = swayc_parent_by_type(container, C_OUTPUT); | ||
337 | geometry.origin.x = 0; | 337 | geometry.origin.x = 0; |
338 | geometry.origin.y = 0; | 338 | geometry.origin.y = 0; |
339 | geometry.size.w = parent->width; | 339 | geometry.size.w = op->width; |
340 | geometry.size.h = parent->height; | 340 | geometry.size.h = op->height; |
341 | if (op->focused == ws) { | ||
342 | wlc_view_bring_to_front(container->handle); | ||
343 | } | ||
341 | } | 344 | } |
342 | wlc_view_set_geometry(container->handle, 0, &geometry); | 345 | wlc_view_set_geometry(container->handle, 0, &geometry); |
343 | return; | 346 | return; |
344 | } | 347 | } |
345 | 348 | ||
346 | void arrange_windows(swayc_t *container, double width, double height) { | 349 | static void arrange_windows_r(swayc_t *container, double width, double height) { |
347 | int i; | 350 | int i; |
348 | if (width == -1 || height == -1) { | 351 | if (width == -1 || height == -1) { |
349 | sway_log(L_DEBUG, "Arranging layout for %p", container); | 352 | sway_log(L_DEBUG, "Arranging layout for %p", container); |
@@ -357,7 +360,7 @@ void arrange_windows(swayc_t *container, double width, double height) { | |||
357 | for (i = 0; i < container->children->length; ++i) { | 360 | for (i = 0; i < container->children->length; ++i) { |
358 | swayc_t *child = container->children->items[i]; | 361 | swayc_t *child = container->children->items[i]; |
359 | sway_log(L_DEBUG, "Arranging output at %d", x); | 362 | sway_log(L_DEBUG, "Arranging output at %d", x); |
360 | arrange_windows(child, -1, -1); | 363 | arrange_windows_r(child, -1, -1); |
361 | x += child->width; | 364 | x += child->width; |
362 | } | 365 | } |
363 | return; | 366 | return; |
@@ -373,7 +376,7 @@ void arrange_windows(swayc_t *container, double width, double height) { | |||
373 | child->width = width - gap * 2; | 376 | child->width = width - gap * 2; |
374 | child->height = height - gap * 2; | 377 | child->height = height - gap * 2; |
375 | sway_log(L_DEBUG, "Arranging workspace #%d at %f, %f", i, child->x, child->y); | 378 | sway_log(L_DEBUG, "Arranging workspace #%d at %f, %f", i, child->x, child->y); |
376 | arrange_windows(child, -1, -1); | 379 | arrange_windows_r(child, -1, -1); |
377 | } | 380 | } |
378 | return; | 381 | return; |
379 | case C_VIEW: | 382 | case C_VIEW: |
@@ -417,7 +420,7 @@ void arrange_windows(swayc_t *container, double width, double height) { | |||
417 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale); | 420 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, width, scale); |
418 | child->x = x + container->x; | 421 | child->x = x + container->x; |
419 | child->y = y + container->y; | 422 | child->y = y + container->y; |
420 | arrange_windows(child, child->width * scale, height); | 423 | arrange_windows_r(child, child->width * scale, height); |
421 | x += child->width; | 424 | x += child->width; |
422 | } | 425 | } |
423 | } | 426 | } |
@@ -444,7 +447,7 @@ void arrange_windows(swayc_t *container, double width, double height) { | |||
444 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale); | 447 | sway_log(L_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, height, scale); |
445 | child->x = x + container->x; | 448 | child->x = x + container->x; |
446 | child->y = y + container->y; | 449 | child->y = y + container->y; |
447 | arrange_windows(child, width, child->height * scale); | 450 | arrange_windows_r(child, width, child->height * scale); |
448 | y += child->height; | 451 | y += child->height; |
449 | } | 452 | } |
450 | } | 453 | } |
@@ -466,6 +469,11 @@ void arrange_windows(swayc_t *container, double width, double height) { | |||
466 | } | 469 | } |
467 | } | 470 | } |
468 | } | 471 | } |
472 | } | ||
473 | |||
474 | void arrange_windows(swayc_t *container, double width, double height) { | ||
475 | update_visibility(container); | ||
476 | arrange_windows_r(container, width, height); | ||
469 | layout_log(&root_container, 0); | 477 | layout_log(&root_container, 0); |
470 | } | 478 | } |
471 | 479 | ||
@@ -14,10 +14,10 @@ int colored = 1; | |||
14 | log_importance_t v = L_SILENT; | 14 | log_importance_t v = L_SILENT; |
15 | 15 | ||
16 | static const char *verbosity_colors[] = { | 16 | static 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 | ||
23 | void init_log(log_importance_t verbosity) { | 23 | void 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 | ||
10 | const char *whitespace = " \f\n\r\t\v"; | 11 | const 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. */ |
13 | char *strip_whitespace(char *_str) { | 14 | char *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 | ||
316 | char *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 | |||
330 | char *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 | |||
315 | char *strdup(const char *str) { | 366 | char *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 | |||