Skip to content

Commit

Permalink
Pass typed arguments out of the parser into the arguments list and let
Browse files Browse the repository at this point in the history
it convert them into strings.
  • Loading branch information
nicm committed Aug 21, 2021
1 parent 762c2d2 commit fb147d8
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 56 deletions.
129 changes: 105 additions & 24 deletions usr.bin/tmux/arguments.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: arguments.c,v 1.41 2021/08/21 10:28:05 nicm Exp $ */
/* $OpenBSD: arguments.c,v 1.42 2021/08/21 18:39:07 nicm Exp $ */

/*
* Copyright (c) 2010 Nicholas Marriott <[email protected]>
Expand All @@ -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"
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}
}
log_debug("%s: flags end at %u of %u", __func__, i, count);
if (i != count) {
for (/* nothing */; i < count; i++) {
value = &values[i];

s = args_value_as_string(value);
log_debug("%s: %u = %s", __func__, i, s);
cmd_append_argv(&args->argc, &args->argv, s);
free(s);
}
args_set(args, opt, optarg);
optarg = NULL;
}
argc -= optind;
argv += optind;

args->argc = argc;
args->argv = cmd_copy_argv(argc, argv);

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)
Expand Down
31 changes: 20 additions & 11 deletions usr.bin/tmux/cmd-parse.y
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: cmd-parse.y,v 1.39 2021/08/21 17:25:32 nicm Exp $ */
/* $OpenBSD: cmd-parse.y,v 1.40 2021/08/21 18:39:07 nicm Exp $ */

/*
* Copyright (c) 2019 Nicholas Marriott <[email protected]>
Expand Down Expand Up @@ -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);
}

Expand Down
27 changes: 10 additions & 17 deletions usr.bin/tmux/cmd.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: cmd.c,v 1.169 2021/08/21 14:10:08 nicm Exp $ */
/* $OpenBSD: cmd.c,v 1.170 2021/08/21 18:39:07 nicm Exp $ */

/*
* Copyright (c) 2007 Nicholas Marriott <[email protected]>
Expand Down Expand Up @@ -496,27 +496,26 @@ cmd_find(const char *name, char **cause)

/* 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;
Expand All @@ -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. */
Expand Down
22 changes: 18 additions & 4 deletions usr.bin/tmux/tmux.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: tmux.h,v 1.1132 2021/08/21 17:25:32 nicm Exp $ */
/* $OpenBSD: tmux.h,v 1.1133 2021/08/21 18:39:07 nicm Exp $ */

/*
* Copyright (c) 2007 Nicholas Marriott <[email protected]>
Expand Down Expand Up @@ -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;
};

Expand Down Expand Up @@ -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 *);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit fb147d8

Please sign in to comment.