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:
		
							
								
								
									
										125
									
								
								arguments.c
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								arguments.c
									
									
									
									
									
								
							| @@ -18,9 +18,9 @@ | ||||
|  | ||||
| #include <sys/types.h> | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <vis.h> | ||||
|  | ||||
| #include "tmux.h" | ||||
| @@ -66,6 +66,20 @@ args_find(struct args *args, u_char flag) | ||||
| 	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. */ | ||||
| struct args * | ||||
| args_create(void) | ||||
| @@ -77,42 +91,109 @@ args_create(void) | ||||
| 	return (args); | ||||
| } | ||||
|  | ||||
| /* Parse an argv and argc into a new argument set. */ | ||||
| /* Parse arguments into a new argument set. */ | ||||
| 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; | ||||
| 	int		 opt; | ||||
| 	struct args		*args; | ||||
| 	u_int		 	 i; | ||||
| 	struct args_value	*value; | ||||
| 	u_char			 flag, argument; | ||||
| 	const char		*found, *string; | ||||
| 	char			*s; | ||||
|  | ||||
| 	optreset = 1; | ||||
| 	optind = 1; | ||||
| 	optarg = NULL; | ||||
| 	if (count == 0) | ||||
| 		return (args_create()); | ||||
|  | ||||
| 	args = args_create(); | ||||
| 	while ((opt = getopt(argc, argv, parse->template)) != -1) { | ||||
| 		if (opt < 0) | ||||
| 			continue; | ||||
| 		if (opt == '?' || strchr(parse->template, opt) == NULL) { | ||||
| 			args_free(args); | ||||
| 			return (NULL); | ||||
| 	for (i = 1; i < count; /* nothing */) { | ||||
| 		value = &values[i]; | ||||
|  | ||||
| 		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); | ||||
| 				return (NULL); | ||||
| 			} | ||||
| 			found = strchr(parse->template, flag); | ||||
| 			if (found == NULL) { | ||||
| 				args_free(args); | ||||
| 				return (NULL); | ||||
| 			} | ||||
| 			argument = *++found; | ||||
| 			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; | ||||
| 		} | ||||
| 		args_set(args, opt, optarg); | ||||
| 		optarg = NULL; | ||||
| 	} | ||||
| 	argc -= optind; | ||||
| 	argv += optind; | ||||
| 	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; | ||||
| 	args->argv = cmd_copy_argv(argc, argv); | ||||
| 			s = args_value_as_string(value); | ||||
| 			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) || | ||||
| 	    (parse->upper != -1 && argc > parse->upper)) { | ||||
| 	if ((parse->lower != -1 && args->argc < parse->lower) || | ||||
| 	    (parse->upper != -1 && args->argc > parse->upper)) { | ||||
| 		args_free(args); | ||||
| 		return (NULL); | ||||
| 	} | ||||
| 	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. */ | ||||
| void | ||||
| 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_argument	*arg; | ||||
| 	struct cmd_list			*cmdlist; | ||||
| 	struct cmd_list			*cmdlist = NULL; | ||||
| 	struct cmd			*add; | ||||
| 	char				*s, **argv = NULL, *cause; | ||||
| 	int				 argc = 0; | ||||
| 	char				*cause; | ||||
| 	struct args_value		*values = NULL; | ||||
| 	u_int				 count = 0, idx; | ||||
|  | ||||
| 	if (cmd_parse_expand_alias(cmd, pi, pr, &cmdlist)) | ||||
| 		return (cmdlist); | ||||
|  | ||||
| 	TAILQ_FOREACH(arg, &cmd->arguments, entry) { | ||||
| 		values = xreallocarray(values, count + 1, sizeof *values); | ||||
| 		switch (arg->type) { | ||||
| 		case CMD_PARSE_STRING: | ||||
| 			cmd_append_argv(&argc, &argv, arg->string); | ||||
| 			values[count].type = ARGS_STRING; | ||||
| 			values[count].string = xstrdup(arg->string); | ||||
| 			break; | ||||
| 		case CMD_PARSE_COMMANDS: | ||||
| 			cmd_parse_build_commands(arg->commands, pi, pr); | ||||
| 			if (pr->status != CMD_PARSE_SUCCESS) | ||||
| 				return (NULL); | ||||
| 			s = cmd_list_print(pr->cmdlist, 0); | ||||
| 			cmd_append_argv(&argc, &argv, s); | ||||
| 			free(s); | ||||
| 				goto out; | ||||
| 			values[count].type = ARGS_COMMANDS; | ||||
| 			values[count].cmdlist = pr->cmdlist; | ||||
| 			values[count].cmdlist->references++; | ||||
| 			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) { | ||||
| 		pr->status = CMD_PARSE_ERROR; | ||||
| 		pr->error = cmd_parse_get_error(pi->file, pi->line, cause); | ||||
| 		free(cause); | ||||
| 		return (NULL); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	cmdlist = cmd_list_new(); | ||||
| 	cmd_list_append(cmdlist, add); | ||||
|  | ||||
| out: | ||||
| 	for (idx = 0; idx < count; idx++) | ||||
| 		args_free_value(&values[idx]); | ||||
| 	free(values); | ||||
| 	return (cmdlist); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										25
									
								
								cmd.c
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								cmd.c
									
									
									
									
									
								
							| @@ -496,27 +496,26 @@ ambiguous: | ||||
|  | ||||
| /* Parse a single command from an argument vector. */ | ||||
| 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 char		*name; | ||||
| 	struct cmd		*cmd; | ||||
| 	struct args		*args; | ||||
|  | ||||
| 	if (argc == 0) { | ||||
| 	if (count == 0 || values[0].type != ARGS_STRING) { | ||||
| 		xasprintf(cause, "no command"); | ||||
| 		return (NULL); | ||||
| 	} | ||||
| 	name = argv[0]; | ||||
|  | ||||
| 	entry = cmd_find(name, cause); | ||||
| 	entry = cmd_find(values[0].string, cause); | ||||
| 	if (entry == NULL) | ||||
| 		return (NULL); | ||||
| 	cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name); | ||||
|  | ||||
| 	args = args_parse(&entry->args, argc, argv); | ||||
| 	if (args == NULL) | ||||
| 		goto usage; | ||||
| 	args = args_parse(&entry->args, values, count); | ||||
| 	if (args == NULL) { | ||||
| 		xasprintf(cause, "usage: %s %s", entry->name, entry->usage); | ||||
| 		return (NULL); | ||||
| 	} | ||||
|  | ||||
| 	cmd = xcalloc(1, sizeof *cmd); | ||||
| 	cmd->entry = entry; | ||||
| @@ -527,12 +526,6 @@ cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause) | ||||
| 	cmd->line = line; | ||||
|  | ||||
| 	return (cmd); | ||||
|  | ||||
| usage: | ||||
| 	if (args != NULL) | ||||
| 		args_free(args); | ||||
| 	xasprintf(cause, "usage: %s %s", entry->name, entry->usage); | ||||
| 	return (NULL); | ||||
| } | ||||
|  | ||||
| /* Free a command. */ | ||||
|   | ||||
							
								
								
									
										20
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								tmux.h
									
									
									
									
									
								
							| @@ -1355,9 +1355,20 @@ struct message_entry { | ||||
| }; | ||||
| TAILQ_HEAD(message_list, message_entry); | ||||
|  | ||||
| /* Argument type. */ | ||||
| enum args_type { | ||||
| 	ARGS_NONE, | ||||
| 	ARGS_STRING, | ||||
| 	ARGS_COMMANDS | ||||
| }; | ||||
|  | ||||
| /* Argument value. */ | ||||
| struct args_value { | ||||
| 	char			*string; | ||||
| 	enum args_type		 type; | ||||
| 	union { | ||||
| 		char		*string; | ||||
| 		struct cmd_list	*cmdlist; | ||||
| 	}; | ||||
| 	TAILQ_ENTRY(args_value)	 entry; | ||||
| }; | ||||
|  | ||||
| @@ -2187,8 +2198,10 @@ int		tty_keys_next(struct tty *); | ||||
| /* arguments.c */ | ||||
| void		 args_set(struct args *, u_char, const char *); | ||||
| 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_free_value(struct args_value *); | ||||
| void		 args_free(struct args *); | ||||
| char		*args_print(struct args *); | ||||
| 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 *); | ||||
| u_int		 cmd_get_group(struct cmd *); | ||||
| 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 *); | ||||
| char		*cmd_print(struct cmd *); | ||||
| struct cmd_list	*cmd_list_new(void); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 nicm
					nicm