summaryrefslogtreecommitdiffstats
path: root/arguments.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:34:56 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 03:34:56 +0000
commit28b8b866c574d712aa5b814b000bc490c89e603e (patch)
treebc842acf3aab38f2e66e8812a18d6106a5d9bae1 /arguments.c
parentAdding upstream version 3.3a. (diff)
downloadtmux-upstream.tar.xz
tmux-upstream.zip
Adding upstream version 3.4.upstream/3.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'arguments.c')
-rw-r--r--arguments.c343
1 files changed, 264 insertions, 79 deletions
diff --git a/arguments.c b/arguments.c
index d0dc2d4..669375e 100644
--- a/arguments.c
+++ b/arguments.c
@@ -37,6 +37,10 @@ struct args_entry {
u_char flag;
struct args_values values;
u_int count;
+
+ int flags;
+#define ARGS_ENTRY_OPTIONAL_VALUE 0x1
+
RB_ENTRY(args_entry) entry;
};
@@ -94,6 +98,22 @@ args_copy_value(struct args_value *to, struct args_value *from)
}
}
+/* Type to string. */
+static const char *
+args_type_to_string (enum args_type type)
+{
+ switch (type)
+ {
+ case ARGS_NONE:
+ return "NONE";
+ case ARGS_STRING:
+ return "STRING";
+ case ARGS_COMMANDS:
+ return "COMMANDS";
+ }
+ return "INVALID";
+}
+
/* Get value as string. */
static const char *
args_value_as_string(struct args_value *value)
@@ -122,6 +142,99 @@ args_create(void)
return (args);
}
+/* Parse a single flag. */
+static int
+args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
+ struct args *args, u_int *i, const char *string, int flag,
+ int optional_argument)
+{
+ struct args_value *argument, *new;
+ const char *s;
+
+ new = xcalloc(1, sizeof *new);
+ if (*string != '\0') {
+ new->type = ARGS_STRING;
+ new->string = xstrdup(string);
+ goto out;
+ }
+
+ if (*i == count)
+ argument = NULL;
+ else {
+ argument = &values[*i];
+ if (argument->type != ARGS_STRING) {
+ xasprintf(cause, "-%c argument must be a string", flag);
+ return (-1);
+ }
+ }
+ if (argument == NULL) {
+ if (optional_argument) {
+ log_debug("%s: -%c (optional)", __func__, flag);
+ args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
+ return (0); /* either - or end */
+ }
+ xasprintf(cause, "-%c expects an argument", flag);
+ return (-1);
+ }
+ args_copy_value(new, argument);
+ (*i)++;
+
+out:
+ s = args_value_as_string(new);
+ log_debug("%s: -%c = %s", __func__, flag, s);
+ args_set(args, flag, new, 0);
+ return (0);
+}
+
+/* Parse flags argument. */
+static int
+args_parse_flags(const struct args_parse *parse, struct args_value *values,
+ u_int count, char **cause, struct args *args, u_int *i)
+{
+ struct args_value *value;
+ u_char flag;
+ const char *found, *string;
+ int optional_argument;
+
+ value = &values[*i];
+ if (value->type != ARGS_STRING)
+ return (1);
+
+ string = value->string;
+ log_debug("%s: next %s", __func__, string);
+ if (*string++ != '-' || *string == '\0')
+ return (1);
+ (*i)++;
+ if (string[0] == '-' && string[1] == '\0')
+ return (1);
+
+ for (;;) {
+ flag = *string++;
+ if (flag == '\0')
+ return (0);
+ if (flag == '?')
+ return (-1);
+ if (!isalnum(flag)) {
+ xasprintf(cause, "invalid flag -%c", flag);
+ return (-1);
+ }
+
+ found = strchr(parse->template, flag);
+ if (found == NULL) {
+ xasprintf(cause, "unknown flag -%c", flag);
+ return (-1);
+ }
+ if (found[1] != ':') {
+ log_debug("%s: -%c", __func__, flag);
+ args_set(args, flag, NULL, 0);
+ continue;
+ }
+ optional_argument = (found[2] == ':');
+ return (args_parse_flag_argument(values, count, cause, args, i,
+ string, flag, optional_argument));
+ }
+}
+
/* Parse arguments into a new argument set. */
struct args *
args_parse(const struct args_parse *parse, struct args_value *values,
@@ -131,86 +244,21 @@ args_parse(const struct args_parse *parse, struct args_value *values,
u_int i;
enum args_parse_type type;
struct args_value *value, *new;
- u_char flag;
- const char *found, *string, *s;
- int optional_argument;
+ const char *s;
+ int stop;
if (count == 0)
return (args_create());
args = args_create();
for (i = 1; i < count; /* nothing */) {
- value = &values[i];
- 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 (flag == '?') {
- args_free(args);
- return (NULL);
- }
- if (!isalnum(flag)) {
- xasprintf(cause, "invalid flag -%c", flag);
- args_free(args);
- return (NULL);
- }
- found = strchr(parse->template, flag);
- if (found == NULL) {
- xasprintf(cause, "unknown flag -%c", flag);
- args_free(args);
- return (NULL);
- }
- if (*++found != ':') {
- log_debug("%s: -%c", __func__, flag);
- args_set(args, flag, NULL);
- continue;
- }
- if (*found == ':') {
- optional_argument = 1;
- found++;
- }
- new = xcalloc(1, sizeof *new);
- if (*string != '\0') {
- new->type = ARGS_STRING;
- new->string = xstrdup(string);
- } else {
- if (i == count) {
- if (optional_argument) {
- log_debug("%s: -%c", __func__,
- flag);
- args_set(args, flag, NULL);
- continue;
- }
- xasprintf(cause,
- "-%c expects an argument",
- flag);
- args_free(args);
- return (NULL);
- }
- if (values[i].type != ARGS_STRING) {
- xasprintf(cause,
- "-%c argument must be a string",
- flag);
- args_free(args);
- return (NULL);
- }
- args_copy_value(new, &values[i++]);
- }
- s = args_value_as_string(new);
- log_debug("%s: -%c = %s", __func__, flag, s);
- args_set(args, flag, new);
- break;
+ stop = args_parse_flags(parse, values, count, cause, args, &i);
+ if (stop == -1) {
+ args_free(args);
+ return (NULL);
}
+ if (stop == 1)
+ break;
}
log_debug("%s: flags end at %u of %u", __func__, i, count);
if (i != count) {
@@ -218,8 +266,8 @@ args_parse(const struct args_parse *parse, struct args_value *values,
value = &values[i];
s = args_value_as_string(value);
- log_debug("%s: %u = %s (type %d)", __func__, i, s,
- value->type);
+ log_debug("%s: %u = %s (type %s)", __func__, i, s,
+ args_type_to_string (value->type));
if (parse->cb != NULL) {
type = parse->cb(args, args->count, cause);
@@ -323,13 +371,13 @@ args_copy(struct args *args, int argc, char **argv)
RB_FOREACH(entry, args_tree, &args->tree) {
if (TAILQ_EMPTY(&entry->values)) {
for (i = 0; i < entry->count; i++)
- args_set(new_args, entry->flag, NULL);
+ args_set(new_args, entry->flag, NULL, 0);
continue;
}
TAILQ_FOREACH(value, &entry->values, entry) {
new_value = xcalloc(1, sizeof *new_value);
args_copy_copy_value(new_value, value, argc, argv);
- args_set(new_args, entry->flag, new_value);
+ args_set(new_args, entry->flag, new_value, 0);
}
}
if (args->count == 0)
@@ -487,6 +535,7 @@ args_print(struct args *args)
char *buf;
u_int i, j;
struct args_entry *entry;
+ struct args_entry *last = NULL;
struct args_value *value;
len = 1;
@@ -494,6 +543,8 @@ args_print(struct args *args)
/* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) {
+ if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE)
+ continue;
if (!TAILQ_EMPTY(&entry->values))
continue;
@@ -505,6 +556,16 @@ args_print(struct args *args)
/* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) {
+ if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE) {
+ if (*buf != '\0')
+ args_print_add(&buf, &len, " -%c", entry->flag);
+ else
+ args_print_add(&buf, &len, "-%c", entry->flag);
+ last = entry;
+ continue;
+ }
+ if (TAILQ_EMPTY(&entry->values))
+ continue;
TAILQ_FOREACH(value, &entry->values, entry) {
if (*buf != '\0')
args_print_add(&buf, &len, " -%c", entry->flag);
@@ -512,7 +573,10 @@ args_print(struct args *args)
args_print_add(&buf, &len, "-%c", entry->flag);
args_print_add_value(&buf, &len, value);
}
+ last = entry;
}
+ if (last && (last->flags & ARGS_ENTRY_OPTIONAL_VALUE))
+ args_print_add(&buf, &len, " --");
/* And finally the argument vector. */
for (i = 0; i < args->count; i++)
@@ -582,7 +646,7 @@ args_has(struct args *args, u_char flag)
/* Set argument value in the arguments tree. */
void
-args_set(struct args *args, u_char flag, struct args_value *value)
+args_set(struct args *args, u_char flag, struct args_value *value, int flags)
{
struct args_entry *entry;
@@ -591,6 +655,7 @@ args_set(struct args *args, u_char flag, struct args_value *value)
entry = xcalloc(1, sizeof *entry);
entry->flag = flag;
entry->count = 1;
+ entry->flags = flags;
TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry);
} else
@@ -696,6 +761,7 @@ args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
struct args_value *value;
struct args_command_state *state;
const char *cmd;
+ const char *file;
state = xcalloc(1, sizeof *state);
@@ -722,7 +788,9 @@ args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
if (wait)
state->pi.item = item;
- cmd_get_source(self, &state->pi.file, &state->pi.line);
+ cmd_get_source(self, &file, &state->pi.line);
+ if (file != NULL)
+ state->pi.file = xstrdup(file);
state->pi.c = tc;
if (state->pi.c != NULL)
state->pi.c->references++;
@@ -747,6 +815,8 @@ args_make_commands(struct args_command_state *state, int argc, char **argv,
}
cmd = xstrdup(state->cmd);
+ log_debug("%s: %s", __func__, cmd);
+ cmd_log_argv(argc, argv, __func__);
for (i = 0; i < argc; i++) {
new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
@@ -775,6 +845,7 @@ args_make_commands_free(struct args_command_state *state)
cmd_list_free(state->cmdlist);
if (state->pi.c != NULL)
server_client_unref(state->pi.c);
+ free((void *)state->pi.file);
free(state->cmd);
free(state);
}
@@ -848,6 +919,41 @@ args_strtonum(struct args *args, u_char flag, long long minval,
return (ll);
}
+/* Convert an argument value to a number, and expand formats. */
+long long
+args_strtonum_and_expand(struct args *args, u_char flag, long long minval,
+ long long maxval, struct cmdq_item *item, char **cause)
+{
+ const char *errstr;
+ char *formatted;
+ long long ll;
+ struct args_entry *entry;
+ struct args_value *value;
+
+ if ((entry = args_find(args, flag)) == NULL) {
+ *cause = xstrdup("missing");
+ return (0);
+ }
+ value = TAILQ_LAST(&entry->values, args_values);
+ if (value == NULL ||
+ value->type != ARGS_STRING ||
+ value->string == NULL) {
+ *cause = xstrdup("missing");
+ return (0);
+ }
+
+ formatted = format_single_from_target(item, value->string);
+ ll = strtonum(formatted, minval, maxval, &errstr);
+ free(formatted);
+ if (errstr != NULL) {
+ *cause = xstrdup(errstr);
+ return (0);
+ }
+
+ *cause = NULL;
+ return (ll);
+}
+
/* Convert an argument to a number which may be a percentage. */
long long
args_percentage(struct args *args, u_char flag, long long minval,
@@ -860,6 +966,10 @@ args_percentage(struct args *args, u_char flag, long long minval,
*cause = xstrdup("missing");
return (0);
}
+ if (TAILQ_EMPTY(&entry->values)) {
+ *cause = xstrdup("empty");
+ return (0);
+ }
value = TAILQ_LAST(&entry->values, args_values)->string;
return (args_string_percentage(value, minval, maxval, curval, cause));
}
@@ -874,6 +984,10 @@ args_string_percentage(const char *value, long long minval, long long maxval,
size_t valuelen = strlen(value);
char *copy;
+ if (valuelen == 0) {
+ *cause = xstrdup("empty");
+ return (0);
+ }
if (value[valuelen - 1] == '%') {
copy = xstrdup(value);
copy[valuelen - 1] = '\0';
@@ -904,3 +1018,74 @@ args_string_percentage(const char *value, long long minval, long long maxval,
*cause = NULL;
return (ll);
}
+
+/*
+ * Convert an argument to a number which may be a percentage, and expand
+ * formats.
+ */
+long long
+args_percentage_and_expand(struct args *args, u_char flag, long long minval,
+ long long maxval, long long curval, struct cmdq_item *item, char **cause)
+{
+ const char *value;
+ struct args_entry *entry;
+
+ if ((entry = args_find(args, flag)) == NULL) {
+ *cause = xstrdup("missing");
+ return (0);
+ }
+ if (TAILQ_EMPTY(&entry->values)) {
+ *cause = xstrdup("empty");
+ return (0);
+ }
+ value = TAILQ_LAST(&entry->values, args_values)->string;
+ return (args_string_percentage_and_expand(value, minval, maxval, curval,
+ item, cause));
+}
+
+/*
+ * Convert a string to a number which may be a percentage, and expand formats.
+ */
+long long
+args_string_percentage_and_expand(const char *value, long long minval,
+ long long maxval, long long curval, struct cmdq_item *item, char **cause)
+{
+ const char *errstr;
+ long long ll;
+ size_t valuelen = strlen(value);
+ char *copy, *f;
+
+ if (value[valuelen - 1] == '%') {
+ copy = xstrdup(value);
+ copy[valuelen - 1] = '\0';
+
+ f = format_single_from_target(item, copy);
+ ll = strtonum(f, 0, 100, &errstr);
+ free(f);
+ free(copy);
+ if (errstr != NULL) {
+ *cause = xstrdup(errstr);
+ return (0);
+ }
+ ll = (curval * ll) / 100;
+ if (ll < minval) {
+ *cause = xstrdup("too small");
+ return (0);
+ }
+ if (ll > maxval) {
+ *cause = xstrdup("too large");
+ return (0);
+ }
+ } else {
+ f = format_single_from_target(item, value);
+ ll = strtonum(f, minval, maxval, &errstr);
+ free(f);
+ if (errstr != NULL) {
+ *cause = xstrdup(errstr);
+ return (0);
+ }
+ }
+
+ *cause = NULL;
+ return (ll);
+}