mirror of
				https://github.com/tmux/tmux.git
				synced 2025-10-26 12:27:15 +00:00 
			
		
		
		
	Pass typed arguments out of the parser into the arguments list and let
it convert them into strings.
This commit is contained in:
		
							
								
								
									
										119
									
								
								arguments.c
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								arguments.c
									
									
									
									
									
								
							| @@ -18,9 +18,9 @@ | |||||||
|  |  | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
|  |  | ||||||
|  | #include <ctype.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <unistd.h> |  | ||||||
| #include <vis.h> | #include <vis.h> | ||||||
|  |  | ||||||
| #include "tmux.h" | #include "tmux.h" | ||||||
| @@ -66,6 +66,20 @@ args_find(struct args *args, u_char flag) | |||||||
| 	return (RB_FIND(args_tree, &args->tree, &entry)); | 	return (RB_FIND(args_tree, &args->tree, &entry)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Get value as string. */ | ||||||
|  | static char * | ||||||
|  | args_value_as_string(struct args_value *value) | ||||||
|  | { | ||||||
|  | 	switch (value->type) { | ||||||
|  | 	case ARGS_NONE: | ||||||
|  | 		return (xstrdup("")); | ||||||
|  | 	case ARGS_COMMANDS: | ||||||
|  | 		return (cmd_list_print(value->cmdlist, 0)); | ||||||
|  | 	case ARGS_STRING: | ||||||
|  | 		return (xstrdup(value->string)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Create an empty arguments set. */ | /* Create an empty arguments set. */ | ||||||
| struct args * | struct args * | ||||||
| args_create(void) | args_create(void) | ||||||
| @@ -77,42 +91,109 @@ args_create(void) | |||||||
| 	return (args); | 	return (args); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Parse an argv and argc into a new argument set. */ | /* Parse arguments into a new argument set. */ | ||||||
| struct args * | struct args * | ||||||
| args_parse(const struct args_parse *parse, int argc, char **argv) | args_parse(const struct args_parse *parse, struct args_value *values, | ||||||
|  |     u_int count) | ||||||
| { | { | ||||||
| 	struct args		*args; | 	struct args		*args; | ||||||
| 	int		 opt; | 	u_int		 	 i; | ||||||
|  | 	struct args_value	*value; | ||||||
|  | 	u_char			 flag, argument; | ||||||
|  | 	const char		*found, *string; | ||||||
|  | 	char			*s; | ||||||
|  |  | ||||||
| 	optreset = 1; | 	if (count == 0) | ||||||
| 	optind = 1; | 		return (args_create()); | ||||||
| 	optarg = NULL; |  | ||||||
|  |  | ||||||
| 	args = args_create(); | 	args = args_create(); | ||||||
| 	while ((opt = getopt(argc, argv, parse->template)) != -1) { | 	for (i = 1; i < count; /* nothing */) { | ||||||
| 		if (opt < 0) | 		value = &values[i]; | ||||||
| 			continue; |  | ||||||
| 		if (opt == '?' || strchr(parse->template, opt) == NULL) { | 		s = args_value_as_string(value); | ||||||
|  | 		log_debug("%s: %u = %s", __func__, i, s); | ||||||
|  | 		free(s); | ||||||
|  |  | ||||||
|  | 		if (value->type != ARGS_STRING) | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		string = value->string; | ||||||
|  | 		if (*string++ != '-' || *string == '\0') | ||||||
|  | 			break; | ||||||
|  | 		i++; | ||||||
|  | 		if (string[0] == '-' && string[1] == '\0') | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		for (;;) { | ||||||
|  | 			flag = *string++; | ||||||
|  | 			if (flag == '\0') | ||||||
|  | 				break; | ||||||
|  | 			if (!isalnum(flag)) { | ||||||
| 				args_free(args); | 				args_free(args); | ||||||
| 				return (NULL); | 				return (NULL); | ||||||
| 			} | 			} | ||||||
| 		args_set(args, opt, optarg); | 			found = strchr(parse->template, flag); | ||||||
| 		optarg = NULL; | 			if (found == NULL) { | ||||||
|  | 				args_free(args); | ||||||
|  | 				return (NULL); | ||||||
| 			} | 			} | ||||||
| 	argc -= optind; | 			argument = *++found; | ||||||
| 	argv += optind; | 			if (argument != ':') { | ||||||
|  | 				log_debug("%s: add -%c", __func__, flag); | ||||||
|  | 				args_set(args, flag, NULL); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
|  | 			if (*string != '\0') | ||||||
|  | 				s = xstrdup(string); | ||||||
|  | 			else { | ||||||
|  | 				if (i == count) { | ||||||
|  | 					args_free(args); | ||||||
|  | 					return (NULL); | ||||||
|  | 				} | ||||||
|  | 				s = args_value_as_string(&values[i++]); | ||||||
|  | 			} | ||||||
|  | 			log_debug("%s: add -%c = %s", __func__, flag, s); | ||||||
|  | 			args_set(args, flag, s); | ||||||
|  | 			free(s); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	log_debug("%s: flags end at %u of %u", __func__, i, count); | ||||||
|  | 	if (i != count) { | ||||||
|  | 		for (/* nothing */; i < count; i++) { | ||||||
|  | 			value = &values[i]; | ||||||
|  |  | ||||||
| 	args->argc = argc; | 			s = args_value_as_string(value); | ||||||
| 	args->argv = cmd_copy_argv(argc, argv); | 			log_debug("%s: %u = %s", __func__, i, s); | ||||||
|  | 			cmd_append_argv(&args->argc, &args->argv, s); | ||||||
|  | 			free(s); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if ((parse->lower != -1 && argc < parse->lower) || | 	if ((parse->lower != -1 && args->argc < parse->lower) || | ||||||
| 	    (parse->upper != -1 && argc > parse->upper)) { | 	    (parse->upper != -1 && args->argc > parse->upper)) { | ||||||
| 		args_free(args); | 		args_free(args); | ||||||
| 		return (NULL); | 		return (NULL); | ||||||
| 	} | 	} | ||||||
| 	return (args); | 	return (args); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Free a value. */ | ||||||
|  | void | ||||||
|  | args_free_value(struct args_value *value) | ||||||
|  | { | ||||||
|  | 	switch (value->type) { | ||||||
|  | 	case ARGS_NONE: | ||||||
|  | 		break; | ||||||
|  | 	case ARGS_STRING: | ||||||
|  | 		free(value->string); | ||||||
|  | 		break; | ||||||
|  | 	case ARGS_COMMANDS: | ||||||
|  | 		cmd_list_free(value->cmdlist); | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Free an arguments set. */ | /* Free an arguments set. */ | ||||||
| void | void | ||||||
| args_free(struct args *args) | args_free(struct args *args) | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								cmd-parse.y
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								cmd-parse.y
									
									
									
									
									
								
							| @@ -794,39 +794,48 @@ cmd_parse_build_command(struct cmd_parse_command *cmd, | |||||||
|     struct cmd_parse_input *pi, struct cmd_parse_result *pr) |     struct cmd_parse_input *pi, struct cmd_parse_result *pr) | ||||||
| { | { | ||||||
| 	struct cmd_parse_argument	*arg; | 	struct cmd_parse_argument	*arg; | ||||||
| 	struct cmd_list			*cmdlist; | 	struct cmd_list			*cmdlist = NULL; | ||||||
| 	struct cmd			*add; | 	struct cmd			*add; | ||||||
| 	char				*s, **argv = NULL, *cause; | 	char				*cause; | ||||||
| 	int				 argc = 0; | 	struct args_value		*values = NULL; | ||||||
|  | 	u_int				 count = 0, idx; | ||||||
|  |  | ||||||
| 	if (cmd_parse_expand_alias(cmd, pi, pr, &cmdlist)) | 	if (cmd_parse_expand_alias(cmd, pi, pr, &cmdlist)) | ||||||
| 		return (cmdlist); | 		return (cmdlist); | ||||||
|  |  | ||||||
| 	TAILQ_FOREACH(arg, &cmd->arguments, entry) { | 	TAILQ_FOREACH(arg, &cmd->arguments, entry) { | ||||||
|  | 		values = xreallocarray(values, count + 1, sizeof *values); | ||||||
| 		switch (arg->type) { | 		switch (arg->type) { | ||||||
| 		case CMD_PARSE_STRING: | 		case CMD_PARSE_STRING: | ||||||
| 			cmd_append_argv(&argc, &argv, arg->string); | 			values[count].type = ARGS_STRING; | ||||||
|  | 			values[count].string = xstrdup(arg->string); | ||||||
| 			break; | 			break; | ||||||
| 		case CMD_PARSE_COMMANDS: | 		case CMD_PARSE_COMMANDS: | ||||||
| 			cmd_parse_build_commands(arg->commands, pi, pr); | 			cmd_parse_build_commands(arg->commands, pi, pr); | ||||||
| 			if (pr->status != CMD_PARSE_SUCCESS) | 			if (pr->status != CMD_PARSE_SUCCESS) | ||||||
| 				return (NULL); | 				goto out; | ||||||
| 			s = cmd_list_print(pr->cmdlist, 0); | 			values[count].type = ARGS_COMMANDS; | ||||||
| 			cmd_append_argv(&argc, &argv, s); | 			values[count].cmdlist = pr->cmdlist; | ||||||
| 			free(s); | 			values[count].cmdlist->references++; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
|  | 		count++; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	add = cmd_parse(argc, argv, pi->file, pi->line, &cause); | 	add = cmd_parse(values, count, pi->file, pi->line, &cause); | ||||||
| 	if (add == NULL) { | 	if (add == NULL) { | ||||||
| 		pr->status = CMD_PARSE_ERROR; | 		pr->status = CMD_PARSE_ERROR; | ||||||
| 		pr->error = cmd_parse_get_error(pi->file, pi->line, cause); | 		pr->error = cmd_parse_get_error(pi->file, pi->line, cause); | ||||||
| 		free(cause); | 		free(cause); | ||||||
| 		return (NULL); | 		goto out; | ||||||
| 	} | 	} | ||||||
| 	cmdlist = cmd_list_new(); | 	cmdlist = cmd_list_new(); | ||||||
| 	cmd_list_append(cmdlist, add); | 	cmd_list_append(cmdlist, add); | ||||||
|  |  | ||||||
|  | out: | ||||||
|  | 	for (idx = 0; idx < count; idx++) | ||||||
|  | 		args_free_value(&values[idx]); | ||||||
|  | 	free(values); | ||||||
| 	return (cmdlist); | 	return (cmdlist); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								cmd.c
									
									
									
									
									
								
							| @@ -496,27 +496,26 @@ ambiguous: | |||||||
|  |  | ||||||
| /* Parse a single command from an argument vector. */ | /* Parse a single command from an argument vector. */ | ||||||
| struct cmd * | struct cmd * | ||||||
| cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) | cmd_parse(struct args_value *values, u_int count, const char *file, u_int line, | ||||||
|  |     char **cause) | ||||||
| { | { | ||||||
| 	const struct cmd_entry	*entry; | 	const struct cmd_entry	*entry; | ||||||
| 	const char		*name; |  | ||||||
| 	struct cmd		*cmd; | 	struct cmd		*cmd; | ||||||
| 	struct args		*args; | 	struct args		*args; | ||||||
|  |  | ||||||
| 	if (argc == 0) { | 	if (count == 0 || values[0].type != ARGS_STRING) { | ||||||
| 		xasprintf(cause, "no command"); | 		xasprintf(cause, "no command"); | ||||||
| 		return (NULL); | 		return (NULL); | ||||||
| 	} | 	} | ||||||
| 	name = argv[0]; | 	entry = cmd_find(values[0].string, cause); | ||||||
|  |  | ||||||
| 	entry = cmd_find(name, cause); |  | ||||||
| 	if (entry == NULL) | 	if (entry == NULL) | ||||||
| 		return (NULL); | 		return (NULL); | ||||||
| 	cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name); |  | ||||||
|  |  | ||||||
| 	args = args_parse(&entry->args, argc, argv); | 	args = args_parse(&entry->args, values, count); | ||||||
| 	if (args == NULL) | 	if (args == NULL) { | ||||||
| 		goto usage; | 		xasprintf(cause, "usage: %s %s", entry->name, entry->usage); | ||||||
|  | 		return (NULL); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	cmd = xcalloc(1, sizeof *cmd); | 	cmd = xcalloc(1, sizeof *cmd); | ||||||
| 	cmd->entry = entry; | 	cmd->entry = entry; | ||||||
| @@ -527,12 +526,6 @@ cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) | |||||||
| 	cmd->line = line; | 	cmd->line = line; | ||||||
|  |  | ||||||
| 	return (cmd); | 	return (cmd); | ||||||
|  |  | ||||||
| usage: |  | ||||||
| 	if (args != NULL) |  | ||||||
| 		args_free(args); |  | ||||||
| 	xasprintf(cause, "usage: %s %s", entry->name, entry->usage); |  | ||||||
| 	return (NULL); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Free a command. */ | /* Free a command. */ | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -1355,9 +1355,20 @@ struct message_entry { | |||||||
| }; | }; | ||||||
| TAILQ_HEAD(message_list, message_entry); | TAILQ_HEAD(message_list, message_entry); | ||||||
|  |  | ||||||
|  | /* Argument type. */ | ||||||
|  | enum args_type { | ||||||
|  | 	ARGS_NONE, | ||||||
|  | 	ARGS_STRING, | ||||||
|  | 	ARGS_COMMANDS | ||||||
|  | }; | ||||||
|  |  | ||||||
| /* Argument value. */ | /* Argument value. */ | ||||||
| struct args_value { | struct args_value { | ||||||
|  | 	enum args_type		 type; | ||||||
|  | 	union { | ||||||
| 		char		*string; | 		char		*string; | ||||||
|  | 		struct cmd_list	*cmdlist; | ||||||
|  | 	}; | ||||||
| 	TAILQ_ENTRY(args_value)	 entry; | 	TAILQ_ENTRY(args_value)	 entry; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -2187,8 +2198,10 @@ int		tty_keys_next(struct tty *); | |||||||
| /* arguments.c */ | /* arguments.c */ | ||||||
| void		 args_set(struct args *, u_char, const char *); | void		 args_set(struct args *, u_char, const char *); | ||||||
| struct args 	*args_create(void); | struct args 	*args_create(void); | ||||||
| struct args	*args_parse(const struct args_parse *, int, char **); | struct args	*args_parse(const struct args_parse *, struct args_value *, | ||||||
|  |     		     u_int); | ||||||
| void		 args_vector(struct args *, int *, char ***); | void		 args_vector(struct args *, int *, char ***); | ||||||
|  | void		 args_free_value(struct args_value *); | ||||||
| void		 args_free(struct args *); | void		 args_free(struct args *); | ||||||
| char		*args_print(struct args *); | char		*args_print(struct args *); | ||||||
| char		*args_escape(const char *); | char		*args_escape(const char *); | ||||||
| @@ -2250,7 +2263,8 @@ const struct cmd_entry *cmd_get_entry(struct cmd *); | |||||||
| struct args	*cmd_get_args(struct cmd *); | struct args	*cmd_get_args(struct cmd *); | ||||||
| u_int		 cmd_get_group(struct cmd *); | u_int		 cmd_get_group(struct cmd *); | ||||||
| void		 cmd_get_source(struct cmd *, const char **, u_int *); | void		 cmd_get_source(struct cmd *, const char **, u_int *); | ||||||
| struct cmd	*cmd_parse(int, char **, const char *, u_int, char **); | struct cmd	*cmd_parse(struct args_value *, u_int, const char *, u_int, | ||||||
|  | 		     char **); | ||||||
| void		 cmd_free(struct cmd *); | void		 cmd_free(struct cmd *); | ||||||
| char		*cmd_print(struct cmd *); | char		*cmd_print(struct cmd *); | ||||||
| struct cmd_list	*cmd_list_new(void); | struct cmd_list	*cmd_list_new(void); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 nicm
					nicm