mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	
						commit
						4944996170
					
				
					 9 changed files with 316 additions and 152 deletions
				
			
		| 
						 | 
					@ -3,13 +3,15 @@
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cmd_handler {
 | 
					
 | 
				
			||||||
	char *command;
 | 
					enum  cmd_status {
 | 
				
			||||||
	enum  cmd_status {
 | 
						CMD_SUCCESS,
 | 
				
			||||||
		CMD_SUCCESS,
 | 
						CMD_FAILURE,
 | 
				
			||||||
		CMD_FAILURE,
 | 
						CMD_INVALID,
 | 
				
			||||||
		CMD_DEFER,
 | 
						CMD_DEFER,
 | 
				
			||||||
	} (*handle)(int argc, char **argv);
 | 
						// Config Blocks
 | 
				
			||||||
 | 
						CMD_BLOCK_END,
 | 
				
			||||||
 | 
						CMD_BLOCK_MODE,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum cmd_status handle_command(char *command);
 | 
					enum cmd_status handle_command(char *command);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,11 @@ extern int setenv(const char *, const char *, int);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// array of whitespace characters to use for delims
 | 
					// array of whitespace characters to use for delims
 | 
				
			||||||
extern const char *whitespace;
 | 
					extern const char whitespace[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *strip_whitespace(char *str);
 | 
					char *strip_whitespace(char *str);
 | 
				
			||||||
char *strip_comments(char *str);
 | 
					char *strip_comments(char *str);
 | 
				
			||||||
 | 
					void strip_quotes(char *str);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Simply split a string with delims, free 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);
 | 
					list_t *split_string(const char *str, const char *delims);
 | 
				
			||||||
| 
						 | 
					@ -27,5 +28,10 @@ int unescape_string(char *string);
 | 
				
			||||||
char *join_args(char **argv, int argc);
 | 
					char *join_args(char **argv, int argc);
 | 
				
			||||||
char *join_list(list_t *list, char *separator);
 | 
					char *join_list(list_t *list, char *separator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// split string into 2 by delim.
 | 
				
			||||||
 | 
					char *cmdsep(char **stringp, const char *delim);
 | 
				
			||||||
 | 
					// Split string into 2 by delim, handle quotes
 | 
				
			||||||
 | 
					char *argsep(char **stringp, const char *delim);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *strdup(const char *);
 | 
					char *strdup(const char *);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										237
									
								
								sway/commands.c
									
										
									
									
									
								
							
							
						
						
									
										237
									
								
								sway/commands.c
									
										
									
									
									
								
							| 
						 | 
					@ -20,6 +20,40 @@
 | 
				
			||||||
#include "sway.h"
 | 
					#include "sway.h"
 | 
				
			||||||
#include "resize.h"
 | 
					#include "resize.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum cmd_status sway_cmd(int argc, char **argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_handler {
 | 
				
			||||||
 | 
						char *command;
 | 
				
			||||||
 | 
						sway_cmd *handle;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static sway_cmd cmd_bindsym;
 | 
				
			||||||
 | 
					static sway_cmd cmd_orientation;
 | 
				
			||||||
 | 
					static sway_cmd cmd_exec;
 | 
				
			||||||
 | 
					static sway_cmd cmd_exec_always;
 | 
				
			||||||
 | 
					static sway_cmd cmd_exit;
 | 
				
			||||||
 | 
					static sway_cmd cmd_floating;
 | 
				
			||||||
 | 
					static sway_cmd cmd_floating_mod;
 | 
				
			||||||
 | 
					static sway_cmd cmd_focus;
 | 
				
			||||||
 | 
					static sway_cmd cmd_focus_follows_mouse;
 | 
				
			||||||
 | 
					static sway_cmd cmd_fullscreen;
 | 
				
			||||||
 | 
					static sway_cmd cmd_gaps;
 | 
				
			||||||
 | 
					static sway_cmd cmd_kill;
 | 
				
			||||||
 | 
					static sway_cmd cmd_layout;
 | 
				
			||||||
 | 
					static sway_cmd cmd_log_colors;
 | 
				
			||||||
 | 
					static sway_cmd cmd_mode;
 | 
				
			||||||
 | 
					static sway_cmd cmd_move;
 | 
				
			||||||
 | 
					static sway_cmd cmd_output;
 | 
				
			||||||
 | 
					static sway_cmd cmd_reload;
 | 
				
			||||||
 | 
					static sway_cmd cmd_resize;
 | 
				
			||||||
 | 
					static sway_cmd cmd_scratchpad;
 | 
				
			||||||
 | 
					static sway_cmd cmd_set;
 | 
				
			||||||
 | 
					static sway_cmd cmd_split;
 | 
				
			||||||
 | 
					static sway_cmd cmd_splith;
 | 
				
			||||||
 | 
					static sway_cmd cmd_splitv;
 | 
				
			||||||
 | 
					static sway_cmd cmd_workspace;
 | 
				
			||||||
 | 
					static sway_cmd cmd_ws_auto_back_and_forth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
swayc_t *sp_view;
 | 
					swayc_t *sp_view;
 | 
				
			||||||
int sp_index = 0;
 | 
					int sp_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,37 +181,33 @@ static enum cmd_status cmd_bindsym(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_exec_always(int argc, char **argv) {
 | 
					static enum cmd_status cmd_exec_always(int argc, char **argv) {
 | 
				
			||||||
 | 
						if (!config->active) return CMD_DEFER;
 | 
				
			||||||
	if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
 | 
						if (!checkarg(argc, "exec_always", EXPECTED_MORE_THAN, 0)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!config->active) {
 | 
						// Put argument into cmd array
 | 
				
			||||||
		return CMD_DEFER;
 | 
						char *tmp = join_args(argv, argc);
 | 
				
			||||||
	}
 | 
						char cmd[4096];
 | 
				
			||||||
 | 
						strcpy(cmd, tmp);
 | 
				
			||||||
 | 
						free(tmp);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	pid_t pid = fork();
 | 
						char *args[] = {"sh", "-c", cmd, 0 };
 | 
				
			||||||
	/* Failed to fork */
 | 
						sway_log(L_DEBUG, "Executing %s", cmd);
 | 
				
			||||||
	if (pid  < 0) {
 | 
					
 | 
				
			||||||
		sway_log(L_ERROR, "exec command failed, sway did not fork");
 | 
						pid_t pid;
 | 
				
			||||||
 | 
						if ((pid = fork()) == 0) {
 | 
				
			||||||
 | 
							execv("/bin/sh", args);
 | 
				
			||||||
 | 
							_exit(-1);
 | 
				
			||||||
 | 
						} else if (pid < 0) {
 | 
				
			||||||
 | 
							sway_log(L_ERROR, "exec command failed, sway could not fork");
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* Child process */
 | 
					 | 
				
			||||||
	if (pid == 0) {
 | 
					 | 
				
			||||||
		char *args = join_args(argv, argc);
 | 
					 | 
				
			||||||
		sway_log(L_DEBUG, "Executing %s", args);
 | 
					 | 
				
			||||||
		execl("/bin/sh", "sh", "-c", args, (char *)NULL);
 | 
					 | 
				
			||||||
		/* Execl doesnt return unless failure */
 | 
					 | 
				
			||||||
		sway_log(L_ERROR, "could not find /bin/sh");
 | 
					 | 
				
			||||||
		free(args);
 | 
					 | 
				
			||||||
		exit(-1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* Parent */
 | 
					 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_exec(int argc, char **argv) {
 | 
					static enum cmd_status cmd_exec(int argc, char **argv) {
 | 
				
			||||||
	if (!config->active) {
 | 
						if (!config->active) return CMD_DEFER;
 | 
				
			||||||
		return CMD_DEFER;
 | 
					
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (config->reloading) {
 | 
						if (config->reloading) {
 | 
				
			||||||
		char *args = join_args(argv, argc);
 | 
							char *args = join_args(argv, argc);
 | 
				
			||||||
		sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
 | 
							sway_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args);
 | 
				
			||||||
| 
						 | 
					@ -194,8 +224,8 @@ static void kill_views(swayc_t *container, void *data) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_exit(int argc, char **argv) {
 | 
					static enum cmd_status cmd_exit(int argc, char **argv) {
 | 
				
			||||||
	if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)
 | 
						if (config->reading) return CMD_INVALID;
 | 
				
			||||||
			|| config->reading || !config->active) {
 | 
						if (!checkarg(argc, "exit", EXPECTED_EQUAL_TO, 0)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Close all views
 | 
						// Close all views
 | 
				
			||||||
| 
						 | 
					@ -205,8 +235,8 @@ static enum cmd_status cmd_exit(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_floating(int argc, char **argv) {
 | 
					static enum cmd_status cmd_floating(int argc, char **argv) {
 | 
				
			||||||
	if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)
 | 
						if (config->reading) return CMD_INVALID;
 | 
				
			||||||
			|| config->reading || !config->active) {
 | 
						if (!checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -267,8 +297,8 @@ static enum cmd_status cmd_floating(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_floating_mod(int argc, char **argv) {
 | 
					static enum cmd_status cmd_floating_mod(int argc, char **argv) {
 | 
				
			||||||
	if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)
 | 
						if (!config->reading) return CMD_INVALID;
 | 
				
			||||||
			|| !config->reading) {
 | 
						if (!checkarg(argc, "floating_modifier", EXPECTED_EQUAL_TO, 1)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	int i, j;
 | 
						int i, j;
 | 
				
			||||||
| 
						 | 
					@ -292,10 +322,10 @@ static enum cmd_status cmd_floating_mod(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_focus(int argc, char **argv) {
 | 
					static enum cmd_status cmd_focus(int argc, char **argv) {
 | 
				
			||||||
 | 
						if (config->reading) return CMD_INVALID;
 | 
				
			||||||
	static int floating_toggled_index = 0;
 | 
						static int floating_toggled_index = 0;
 | 
				
			||||||
	static int tiled_toggled_index = 0;
 | 
						static int tiled_toggled_index = 0;
 | 
				
			||||||
	if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)
 | 
						if (!checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1)) {
 | 
				
			||||||
			|| config->reading || !config->active) {
 | 
					 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (strcasecmp(argv[0], "left") == 0) {
 | 
						if (strcasecmp(argv[0], "left") == 0) {
 | 
				
			||||||
| 
						 | 
					@ -350,6 +380,7 @@ static enum cmd_status cmd_focus(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
 | 
					static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
 | 
				
			||||||
 | 
						if (!config->reading) return CMD_INVALID;
 | 
				
			||||||
	if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
 | 
						if (!checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -359,7 +390,7 @@ static enum cmd_status cmd_focus_follows_mouse(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void hide_view_in_scratchpad(swayc_t *sp_view) {
 | 
					static void hide_view_in_scratchpad(swayc_t *sp_view) {
 | 
				
			||||||
	if(sp_view == NULL) {
 | 
						if (sp_view == NULL) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -375,15 +406,19 @@ static void hide_view_in_scratchpad(swayc_t *sp_view) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_mode(int argc, char **argv) {
 | 
					static enum cmd_status cmd_mode(int argc, char **argv) {
 | 
				
			||||||
	if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
 | 
						if (!checkarg(argc, "mode", EXPECTED_AT_LEAST, 1)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool mode_make = !strcmp(argv[argc-1], "{");
 | 
						char *mode_name = join_args(argv, argc);
 | 
				
			||||||
	if (mode_make && !config->reading) {
 | 
						int mode_len = strlen(mode_name);
 | 
				
			||||||
		return CMD_FAILURE;
 | 
						bool mode_make = mode_name[mode_len-1] == '{';
 | 
				
			||||||
 | 
						if (mode_make) {
 | 
				
			||||||
 | 
							if (!config->reading) return CMD_INVALID;
 | 
				
			||||||
 | 
							// Trim trailing spaces
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								mode_name[--mode_len] = 0;
 | 
				
			||||||
 | 
							} while(isspace(mode_name[mode_len-1]));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	char *mode_name = join_args(argv, argc - mode_make);
 | 
					 | 
				
			||||||
	struct sway_mode *mode = NULL;
 | 
						struct sway_mode *mode = NULL;
 | 
				
			||||||
	// Find mode
 | 
						// Find mode
 | 
				
			||||||
	int i, len = config->modes->length;
 | 
						int i, len = config->modes->length;
 | 
				
			||||||
| 
						 | 
					@ -406,16 +441,18 @@ static enum cmd_status cmd_mode(int argc, char **argv) {
 | 
				
			||||||
		free(mode_name);
 | 
							free(mode_name);
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sway_log(L_DEBUG, "Switching to mode `%s'",mode->name);
 | 
						if ((config->reading && mode_make) || (!config->reading && !mode_make)) {
 | 
				
			||||||
 | 
							sway_log(L_DEBUG, "Switching to mode `%s'",mode->name);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	free(mode_name);
 | 
						free(mode_name);
 | 
				
			||||||
	// Set current mode
 | 
						// Set current mode
 | 
				
			||||||
	config->current_mode = mode;
 | 
						config->current_mode = mode;
 | 
				
			||||||
	return CMD_SUCCESS;
 | 
						return mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_move(int argc, char **argv) {
 | 
					static enum cmd_status cmd_move(int argc, char **argv) {
 | 
				
			||||||
	if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)
 | 
						if (config->reading) return CMD_FAILURE;
 | 
				
			||||||
			|| config->reading || !config->active) {
 | 
						if (!checkarg(argc, "move", EXPECTED_AT_LEAST, 1)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -485,10 +522,11 @@ static enum cmd_status cmd_move(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_orientation(int argc, char **argv) {
 | 
					static enum cmd_status cmd_orientation(int argc, char **argv) {
 | 
				
			||||||
	if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)
 | 
						if (!config->reading) return CMD_FAILURE;
 | 
				
			||||||
			|| !config->reading) {
 | 
						if (!checkarg(argc, "orientation", EXPECTED_EQUAL_TO, 1)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (strcasecmp(argv[0], "horizontal") == 0) {
 | 
						if (strcasecmp(argv[0], "horizontal") == 0) {
 | 
				
			||||||
		config->default_orientation = L_HORIZ;
 | 
							config->default_orientation = L_HORIZ;
 | 
				
			||||||
	} else if (strcasecmp(argv[0], "vertical") == 0) {
 | 
						} else if (strcasecmp(argv[0], "vertical") == 0) {
 | 
				
			||||||
| 
						 | 
					@ -502,6 +540,7 @@ static enum cmd_status cmd_orientation(int argc, char **argv) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum cmd_status cmd_output(int argc, char **argv) {
 | 
					static enum cmd_status cmd_output(int argc, char **argv) {
 | 
				
			||||||
 | 
						if (!config->reading) return CMD_FAILURE;
 | 
				
			||||||
	if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
 | 
						if (!checkarg(argc, "output", EXPECTED_AT_LEAST, 1)) {
 | 
				
			||||||
		return CMD_FAILURE;
 | 
							return CMD_FAILURE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -512,7 +551,6 @@ static enum cmd_status cmd_output(int argc, char **argv) {
 | 
				
			||||||
	output->enabled = true;
 | 
						output->enabled = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// TODO: atoi doesn't handle invalid numbers
 | 
						// TODO: atoi doesn't handle invalid numbers
 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	if (strcasecmp(argv[1], "disable") == 0) {
 | 
						if (strcasecmp(argv[1], "disable") == 0) {
 | 
				
			||||||
		output->enabled = false;
 | 
							output->enabled = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -953,7 +991,7 @@ static enum cmd_status cmd_log_colors(int argc, char **argv) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (strcasecmp(argv[0], "no") == 0) {
 | 
						if (strcasecmp(argv[0], "no") == 0) {
 | 
				
			||||||
		sway_log_colors(0);
 | 
							sway_log_colors(0);
 | 
				
			||||||
	} else if(strcasecmp(argv[0], "yes") == 0) {
 | 
						} else if (strcasecmp(argv[0], "yes") == 0) {
 | 
				
			||||||
		sway_log_colors(1);
 | 
							sway_log_colors(1);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		sway_log(L_ERROR, "Invalid log_colors command (expected `yes` or `no`, got '%s')", argv[0]);
 | 
							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) {
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum cmd_status handle_command(char *exec) {
 | 
					enum cmd_status handle_command(char *_exec) {
 | 
				
			||||||
	sway_log(L_INFO, "Handling command '%s'", exec);
 | 
						enum cmd_status status = CMD_SUCCESS;
 | 
				
			||||||
	int argc;
 | 
						char *exec = strdup(_exec);
 | 
				
			||||||
	char **argv = split_args(exec, &argc);
 | 
						char *head = exec;
 | 
				
			||||||
	enum cmd_status status = CMD_FAILURE;
 | 
						char *cmdlist;
 | 
				
			||||||
	struct cmd_handler *handler;
 | 
						char *cmd;
 | 
				
			||||||
	if (!argc) {
 | 
						char *criteria __attribute__((unused));
 | 
				
			||||||
		return status;
 | 
					
 | 
				
			||||||
	}
 | 
						head = exec;
 | 
				
			||||||
	if ((handler = find_handler(argv[0])) == NULL
 | 
						do {
 | 
				
			||||||
			|| (status = handler->handle(argc - 1, argv + 1)) != CMD_SUCCESS) {
 | 
							// Handle criteria
 | 
				
			||||||
		sway_log(L_ERROR, "Command failed: %s", argv[0]);
 | 
							if (*head == '[') {
 | 
				
			||||||
	}
 | 
								criteria = argsep(&head, "]");
 | 
				
			||||||
	free_argv(argc, argv);
 | 
								if (head) {
 | 
				
			||||||
 | 
									++head;
 | 
				
			||||||
 | 
									// TODO handle criteria
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									sway_log(L_ERROR, "Unmatched [");
 | 
				
			||||||
 | 
									status = CMD_INVALID;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Skip leading whitespace
 | 
				
			||||||
 | 
								head += strspn(head, whitespace);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Split command list
 | 
				
			||||||
 | 
							cmdlist = argsep(&head, ";");
 | 
				
			||||||
 | 
							cmdlist += strspn(cmdlist, whitespace);
 | 
				
			||||||
 | 
							do {
 | 
				
			||||||
 | 
								// Split commands
 | 
				
			||||||
 | 
								cmd = argsep(&cmdlist, ",");
 | 
				
			||||||
 | 
								cmd += strspn(cmd, whitespace);
 | 
				
			||||||
 | 
								sway_log(L_INFO, "Handling command '%s'", cmd);
 | 
				
			||||||
 | 
								//TODO better handling of argv
 | 
				
			||||||
 | 
								int argc;
 | 
				
			||||||
 | 
								char **argv = split_args(cmd, &argc);
 | 
				
			||||||
 | 
								if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
 | 
				
			||||||
 | 
									strip_quotes(argv[1]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								struct cmd_handler *handler = find_handler(argv[0]);
 | 
				
			||||||
 | 
								enum cmd_status res = CMD_INVALID;
 | 
				
			||||||
 | 
								if (!handler
 | 
				
			||||||
 | 
										|| (res = handler->handle(argc-1, argv+1)) != CMD_SUCCESS) {
 | 
				
			||||||
 | 
									sway_log(L_ERROR, "Command '%s' failed", cmd);
 | 
				
			||||||
 | 
									free_argv(argc, argv);
 | 
				
			||||||
 | 
									status = res;
 | 
				
			||||||
 | 
									goto cleanup;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								free_argv(argc, argv);
 | 
				
			||||||
 | 
							} while(cmdlist);
 | 
				
			||||||
 | 
						} while(head);
 | 
				
			||||||
 | 
						cleanup:
 | 
				
			||||||
 | 
						free(exec);
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum cmd_status config_command(char *exec) {
 | 
					enum cmd_status config_command(char *exec) {
 | 
				
			||||||
	sway_log(L_INFO, "handling config command '%s'", exec);
 | 
						enum cmd_status status = CMD_SUCCESS;
 | 
				
			||||||
	int argc;
 | 
						int argc;
 | 
				
			||||||
	char **argv = split_args(exec, &argc);
 | 
						char **argv = split_args(exec, &argc);
 | 
				
			||||||
	enum cmd_status status = CMD_FAILURE;
 | 
						if (!argc) goto cleanup;
 | 
				
			||||||
	struct cmd_handler *handler;
 | 
					
 | 
				
			||||||
	if (!argc) {
 | 
						sway_log(L_INFO, "handling config command '%s'", exec);
 | 
				
			||||||
		status = CMD_SUCCESS;
 | 
						// Endblock
 | 
				
			||||||
 | 
						if (**argv == '}') {
 | 
				
			||||||
 | 
							status = CMD_BLOCK_END;
 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// TODO better block handling
 | 
						struct cmd_handler *handler = find_handler(argv[0]);
 | 
				
			||||||
	if (strncmp(argv[0], "}", 1) == 0) {
 | 
						if (!handler) {
 | 
				
			||||||
		config->current_mode = config->modes->items[0];
 | 
							status = CMD_INVALID;
 | 
				
			||||||
		status = CMD_SUCCESS;
 | 
					 | 
				
			||||||
		goto cleanup;
 | 
							goto cleanup;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ((handler = find_handler(argv[0]))) {
 | 
						int i;
 | 
				
			||||||
		// Dont replace first argument in cmd_set
 | 
						// Var replacement, for all but first argument of set
 | 
				
			||||||
		int i = handler->handle == cmd_set ? 2 : 1;
 | 
						for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
 | 
				
			||||||
		int e = argc;
 | 
							argv[i] = do_var_replacement(argv[i]);
 | 
				
			||||||
		for (; i < e; ++i) {
 | 
					 | 
				
			||||||
			argv[i] = do_var_replacement(argv[i]);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		status = handler->handle(argc - 1, argv + 1);
 | 
					 | 
				
			||||||
		if (status == CMD_FAILURE) {
 | 
					 | 
				
			||||||
			sway_log(L_ERROR, "Config load failed for line `%s'", exec);
 | 
					 | 
				
			||||||
		} else if (status == CMD_DEFER) {
 | 
					 | 
				
			||||||
			sway_log(L_DEBUG, "Defferring command `%s'", exec);
 | 
					 | 
				
			||||||
			list_add(config->cmd_queue, strdup(exec));
 | 
					 | 
				
			||||||
			status = CMD_SUCCESS;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		sway_log(L_ERROR, "Unknown command `%s'", exec);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						/* Strip quotes for first argument.
 | 
				
			||||||
 | 
						 * TODO This part needs to be handled much better */
 | 
				
			||||||
 | 
						if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) {
 | 
				
			||||||
 | 
							strip_quotes(argv[1]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						status = handler->handle(argc-1, argv+1);
 | 
				
			||||||
	cleanup:
 | 
						cleanup:
 | 
				
			||||||
	free_argv(argc, argv);
 | 
						free_argv(argc, argv);
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,47 +110,49 @@ static void config_defaults(struct sway_config *config) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *get_config_path(void) {
 | 
					static char *get_config_path(void) {
 | 
				
			||||||
	char *config_path = NULL;
 | 
						char *config_path = NULL;
 | 
				
			||||||
	char *paths[3] = {getenv("HOME"), getenv("XDG_CONFIG_HOME"), ""};
 | 
						char *paths[3] = { getenv("HOME"), getenv("XDG_CONFIG_HOME"), "" };
 | 
				
			||||||
	int pathlen[3] = {0, 0, 0};
 | 
						int pathlen[3] = { 0, 0, 0 };
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
#define home paths[0]
 | 
					#define home paths[0]
 | 
				
			||||||
#define conf paths[1]
 | 
					#define conf paths[1]
 | 
				
			||||||
	// Get home and config directories
 | 
						// Get home and config directories
 | 
				
			||||||
 | 
						conf = conf ? strdup(conf) : NULL;
 | 
				
			||||||
	home = home ? strdup(home) : NULL;
 | 
						home = home ? strdup(home) : NULL;
 | 
				
			||||||
	if (conf) {
 | 
						// If config folder is unset, set it to $HOME/.config
 | 
				
			||||||
		conf = strdup(conf);
 | 
						if (!conf && home) {
 | 
				
			||||||
	} else if (home) {
 | 
					 | 
				
			||||||
		const char *def = "/.config";
 | 
							const char *def = "/.config";
 | 
				
			||||||
		conf = malloc(strlen(home) + strlen(def) + 1);
 | 
							conf = malloc(strlen(home) + strlen(def) + 1);
 | 
				
			||||||
		strcpy(conf, home);
 | 
							strcpy(conf, home);
 | 
				
			||||||
		strcat(conf, def);
 | 
							strcat(conf, def);
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		home = strdup("");
 | 
					 | 
				
			||||||
		conf = strdup("");
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pathlen[0] = strlen(home);
 | 
						// Get path lengths
 | 
				
			||||||
	pathlen[1] = strlen(conf);
 | 
						pathlen[0] = home ? strlen(home) : 0;
 | 
				
			||||||
 | 
						pathlen[1] = conf ? strlen(conf) : 0;
 | 
				
			||||||
#undef home
 | 
					#undef home
 | 
				
			||||||
#undef conf
 | 
					#undef conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Search for config file from search paths
 | 
						// Search for config file from search paths
 | 
				
			||||||
	static const char *search_paths[] = {
 | 
						static const char *search_paths[] = {
 | 
				
			||||||
		"/.sway/config", // Prepend with $home
 | 
							"/.sway/config", // Prepend with $home
 | 
				
			||||||
		"/sway/config", // Prepend with $config
 | 
							"/sway/config", // Prepend with $config
 | 
				
			||||||
		"/etc/sway/config",
 | 
							"/etc/sway/config",
 | 
				
			||||||
		"/.i3/config", // $home
 | 
							"/.i3/config", // $home
 | 
				
			||||||
		"/.i3/config", // $config
 | 
							"/i3/config", // $config
 | 
				
			||||||
		"/etc/i3/config"
 | 
							"/etc/i3/config"
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	for (i = 0; i < (int)(sizeof(search_paths) / sizeof(char *)); ++i) {
 | 
						for (i = 0; i < (int)(sizeof(search_paths) / sizeof(char *)); ++i) {
 | 
				
			||||||
		char *test = malloc(pathlen[i%3] + strlen(search_paths[i]) + 1);
 | 
							// Only try path if it is set by enviroment variables
 | 
				
			||||||
		strcpy(test, paths[i%3]);
 | 
							if (paths[i%3]) {
 | 
				
			||||||
		strcat(test, search_paths[i]);
 | 
								char *test = malloc(pathlen[i%3] + strlen(search_paths[i]) + 1);
 | 
				
			||||||
		sway_log(L_DEBUG, "Checking for config at %s", test);
 | 
								strcpy(test, paths[i%3]);
 | 
				
			||||||
		if (file_exists(test)) {
 | 
								strcpy(test + pathlen[i%3], search_paths[i]);
 | 
				
			||||||
			config_path = test;
 | 
								sway_log(L_DEBUG, "Checking for config at %s", test);
 | 
				
			||||||
			goto cleanup;
 | 
								if (file_exists(test)) {
 | 
				
			||||||
 | 
									config_path = test;
 | 
				
			||||||
 | 
									goto cleanup;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								free(test);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		free(test);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
 | 
						sway_log(L_DEBUG, "Trying to find config in XDG_CONFIG_DIRS");
 | 
				
			||||||
| 
						 | 
					@ -225,14 +227,46 @@ bool read_config(FILE *file, bool is_active) {
 | 
				
			||||||
		config->active = true;
 | 
							config->active = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bool success = true;
 | 
						bool success = true;
 | 
				
			||||||
 | 
						enum cmd_status block = CMD_BLOCK_END;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *line;
 | 
						char *line;
 | 
				
			||||||
	while (!feof(file)) {
 | 
						while (!feof(file)) {
 | 
				
			||||||
		line = read_line(file);
 | 
							line = read_line(file);
 | 
				
			||||||
		line = strip_comments(line);
 | 
							line = strip_comments(line);
 | 
				
			||||||
		if (config_command(line) == CMD_FAILURE) {
 | 
							switch(config_command(line)) {
 | 
				
			||||||
 | 
							case CMD_FAILURE:
 | 
				
			||||||
 | 
							case CMD_INVALID:
 | 
				
			||||||
			sway_log(L_ERROR, "Error on line '%s'", line);
 | 
								sway_log(L_ERROR, "Error on line '%s'", line);
 | 
				
			||||||
			success = false;
 | 
								success = false;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case CMD_DEFER:
 | 
				
			||||||
 | 
								sway_log(L_DEBUG, "Defferring command `%s'", line);
 | 
				
			||||||
 | 
								list_add(config->cmd_queue, strdup(line));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case CMD_BLOCK_MODE:
 | 
				
			||||||
 | 
								if (block == CMD_BLOCK_END) {
 | 
				
			||||||
 | 
									block = CMD_BLOCK_MODE;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									sway_log(L_ERROR, "Invalid block '%s'", line);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case CMD_BLOCK_END:
 | 
				
			||||||
 | 
								switch(block) {
 | 
				
			||||||
 | 
								case CMD_BLOCK_MODE:
 | 
				
			||||||
 | 
									sway_log(L_DEBUG, "End of mode block");
 | 
				
			||||||
 | 
									config->current_mode = config->modes->items[0];
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case CMD_BLOCK_END:
 | 
				
			||||||
 | 
									sway_log(L_ERROR, "Unmatched }");
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								default:;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							default:;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		free(line);
 | 
							free(line);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -405,7 +405,7 @@ swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *dat
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool test_name(swayc_t *view, void *data) {
 | 
					static bool test_name(swayc_t *view, void *data) {
 | 
				
			||||||
	if (!view && !view->name) {
 | 
						if (!view || !view->name) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return strcmp(view->name, data) == 0;
 | 
						return strcmp(view->name, data) == 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -331,7 +331,7 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
 | 
				
			||||||
		struct sway_binding *binding = mode->bindings->items[i];
 | 
							struct sway_binding *binding = mode->bindings->items[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if ((modifiers->mods ^ binding->modifiers) == 0) {
 | 
							if ((modifiers->mods ^ binding->modifiers) == 0) {
 | 
				
			||||||
			bool match;
 | 
								bool match = false;
 | 
				
			||||||
			int j;
 | 
								int j;
 | 
				
			||||||
			for (j = 0; j < binding->keys->length; ++j) {
 | 
								for (j = 0; j < binding->keys->length; ++j) {
 | 
				
			||||||
				xkb_keysym_t *key = binding->keys->items[j];
 | 
									xkb_keysym_t *key = binding->keys->items[j];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,7 +206,8 @@ void swap_geometry(swayc_t *a, swayc_t *b) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void move_container(swayc_t *container, enum movement_direction dir) {
 | 
					void move_container(swayc_t *container, enum movement_direction dir) {
 | 
				
			||||||
	enum swayc_layouts layout;
 | 
						enum swayc_layouts layout;
 | 
				
			||||||
	if (container->is_floating) {
 | 
						if (container->is_floating
 | 
				
			||||||
 | 
								|| (container->type != C_VIEW && container->type != C_CONTAINER)) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (dir == MOVE_UP || dir == MOVE_DOWN) {
 | 
						if (dir == MOVE_UP || dir == MOVE_DOWN) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,10 @@ int colored = 1;
 | 
				
			||||||
log_importance_t v = L_SILENT;
 | 
					log_importance_t v = L_SILENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *verbosity_colors[] = {
 | 
					static const char *verbosity_colors[] = {
 | 
				
			||||||
	"", // L_SILENT
 | 
						[L_SILENT] = "",
 | 
				
			||||||
	"\x1B[1;31m", // L_ERROR
 | 
						[L_ERROR ] = "\x1B[1;31m",
 | 
				
			||||||
	"\x1B[1;34m", // L_INFO
 | 
						[L_INFO  ] = "\x1B[1;34m",
 | 
				
			||||||
	"\x1B[1;30m", // L_DEBUG
 | 
						[L_DEBUG ] = "\x1B[1;30m",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void init_log(log_importance_t verbosity) {
 | 
					void init_log(log_importance_t verbosity) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										118
									
								
								sway/stringop.c
									
										
									
									
									
								
							
							
						
						
									
										118
									
								
								sway/stringop.c
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
#include <ctype.h>
 | 
					#include <ctype.h>
 | 
				
			||||||
#include "stringop.h"
 | 
					#include "stringop.h"
 | 
				
			||||||
| 
						 | 
					@ -7,7 +8,7 @@
 | 
				
			||||||
#include "string.h"
 | 
					#include "string.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *whitespace = " \f\n\r\t\v";
 | 
					const char whitespace[] = " \f\n\r\t\v";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Note: This returns 8 characters for trimmed_start per tab character. */
 | 
					/* Note: This returns 8 characters for trimmed_start per tab character. */
 | 
				
			||||||
char *strip_whitespace(char *_str) {
 | 
					char *strip_whitespace(char *_str) {
 | 
				
			||||||
| 
						 | 
					@ -105,40 +106,40 @@ char **split_args(const char *start, int *argc) {
 | 
				
			||||||
	bool in_char = false;
 | 
						bool in_char = false;
 | 
				
			||||||
	bool escaped = false;
 | 
						bool escaped = false;
 | 
				
			||||||
	const char *end = start;
 | 
						const char *end = start;
 | 
				
			||||||
	while (*start) {
 | 
						if (start) {
 | 
				
			||||||
		if (!in_token) {
 | 
							while (*start) {
 | 
				
			||||||
			start = (end += strspn(end, whitespace));
 | 
								if (!in_token) {
 | 
				
			||||||
			in_token = true;
 | 
									start = (end += strspn(end, whitespace));
 | 
				
			||||||
		}
 | 
									in_token = true;
 | 
				
			||||||
		if (*end == '"' && !in_char && !escaped) {
 | 
								}
 | 
				
			||||||
			in_string = !in_string;
 | 
								if (*end == '"' && !in_char && !escaped) {
 | 
				
			||||||
		} else if (*end == '\'' && !in_string && !escaped) {
 | 
									in_string = !in_string;
 | 
				
			||||||
			in_char = !in_char;
 | 
								} else if (*end == '\'' && !in_string && !escaped) {
 | 
				
			||||||
		} else if (*end == '\\') {
 | 
									in_char = !in_char;
 | 
				
			||||||
			escaped = !escaped;
 | 
								} else if (*end == '\\') {
 | 
				
			||||||
		} else if (*end == '\0' || (!in_string && !in_char && !escaped
 | 
									escaped = !escaped;
 | 
				
			||||||
				&& strchr(whitespace, *end))) {
 | 
								} else if (*end == '\0' || (!in_string && !in_char && !escaped
 | 
				
			||||||
			goto add_part;
 | 
											&& strchr(whitespace, *end))) {
 | 
				
			||||||
		}
 | 
									goto add_token;
 | 
				
			||||||
		if (*end != '\\') {
 | 
								}
 | 
				
			||||||
 | 
								if (*end != '\\') {
 | 
				
			||||||
 | 
									escaped = false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								++end;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
								add_token:
 | 
				
			||||||
 | 
								if (end - start > 0) {
 | 
				
			||||||
 | 
									char *token = malloc(end - start + 1);
 | 
				
			||||||
 | 
									strncpy(token, start, end - start + 1);
 | 
				
			||||||
 | 
									token[end - start] = '\0';
 | 
				
			||||||
 | 
									argv[*argc] = token;
 | 
				
			||||||
 | 
									if (++*argc + 1 == alloc) {
 | 
				
			||||||
 | 
										argv = realloc(argv, (alloc *= 2) * sizeof(char *));
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								in_token = false;
 | 
				
			||||||
			escaped = false;
 | 
								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);
 | 
					 | 
				
			||||||
			argv[*argc] = token;
 | 
					 | 
				
			||||||
			if (++*argc + 1 == alloc) {
 | 
					 | 
				
			||||||
				argv = realloc(argv, (alloc *= 2) * sizeof(char *));
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		in_token = false;
 | 
					 | 
				
			||||||
		escaped = false;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	argv[*argc] = NULL;
 | 
						argv[*argc] = NULL;
 | 
				
			||||||
	return argv;
 | 
						return argv;
 | 
				
			||||||
| 
						 | 
					@ -312,6 +313,56 @@ char *join_list(list_t *list, char *separator) {
 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *cmdsep(char **stringp, const char *delim) {
 | 
				
			||||||
 | 
						// skip over leading delims
 | 
				
			||||||
 | 
						char *head = *stringp + strspn(*stringp, delim);
 | 
				
			||||||
 | 
						// Find end token
 | 
				
			||||||
 | 
						char *tail = *stringp += strcspn(*stringp, delim);
 | 
				
			||||||
 | 
						// Set stringp to begining of next token
 | 
				
			||||||
 | 
						*stringp += strspn(*stringp, delim);
 | 
				
			||||||
 | 
						// Set stringp to null if last token
 | 
				
			||||||
 | 
						if (!**stringp) *stringp = NULL;
 | 
				
			||||||
 | 
						// Nullify end of first token
 | 
				
			||||||
 | 
						*tail = 0;
 | 
				
			||||||
 | 
						return head;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *argsep(char **stringp, const char *delim) {
 | 
				
			||||||
 | 
						char *start = *stringp;
 | 
				
			||||||
 | 
						char *end = start;
 | 
				
			||||||
 | 
						bool in_string = false;
 | 
				
			||||||
 | 
						bool in_char = false;
 | 
				
			||||||
 | 
						bool escaped = false;
 | 
				
			||||||
 | 
						while (1) {
 | 
				
			||||||
 | 
							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') {
 | 
				
			||||||
 | 
								*stringp = NULL;
 | 
				
			||||||
 | 
								goto found;
 | 
				
			||||||
 | 
							} else if (!in_string && !in_char && !escaped && strchr(delim, *end)) {
 | 
				
			||||||
 | 
								if (end - start) {
 | 
				
			||||||
 | 
									*(end++) = 0;
 | 
				
			||||||
 | 
									*stringp = end + strspn(end, delim);;
 | 
				
			||||||
 | 
									if (!**stringp) *stringp = NULL;
 | 
				
			||||||
 | 
									goto found;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									++start;
 | 
				
			||||||
 | 
									end = start;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (*end != '\\') {
 | 
				
			||||||
 | 
								escaped = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							++end;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						found:
 | 
				
			||||||
 | 
						return start;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *strdup(const char *str) {
 | 
					char *strdup(const char *str) {
 | 
				
			||||||
	char *dup = malloc(strlen(str) + 1);
 | 
						char *dup = malloc(strlen(str) + 1);
 | 
				
			||||||
	if (dup) {
 | 
						if (dup) {
 | 
				
			||||||
| 
						 | 
					@ -319,3 +370,4 @@ char *strdup(const char *str) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return dup;
 | 
						return dup;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue