Better way of working out any flag.

This commit is contained in:
Nicholas Marriott
2026-06-30 18:48:58 +01:00
parent 36273fde4f
commit fefb926291
3 changed files with 117 additions and 44 deletions

View File

@@ -69,40 +69,23 @@ static void client_dispatch_attached(struct imsg *);
static void client_dispatch_wait(struct imsg *); static void client_dispatch_wait(struct imsg *);
static const char *client_exit_message(void); static const char *client_exit_message(void);
static int /* Does any command have a flag? */
client_next_has_flag(int argc, char **argv, int flag)
{
struct args_value *values = args_from_vector(argc, argv);
struct cmd *cmd;
char *cause;
int result = 0;
cmd = cmd_parse(values, argc, NULL, 0, 0, &cause);
if (cmd == NULL)
free(cause);
else {
if (cmd_get_entry(cmd)->flags & flag)
result = 1;
cmd_free(cmd);
}
args_free_values(values, argc);
free(values);
return (result);
}
static int static int
client_command_has_flag(int argc, char **argv, int flag) client_command_has_flag(int argc, char **argv, int flag)
{ {
int start = 0, i; struct args_value *values;
struct cmd_parse_tree *tree;
int found;
for (i = 0; i <= argc; i++) { values = args_from_vector(argc, argv);
if (i != argc && strcmp(argv[i], ";") != 0) tree = cmd_parse_from_arguments(values, argc);
continue; found = cmd_parse_any_have(tree, flag);
if (i != start && client_next_has_flag(i - start, argv + start, flag))
return (1); cmd_parse_free(tree);
start = i + 1; args_free_values(values, argc);
} free(values);
return (0);
return (found);
} }
/* /*

View File

@@ -1115,10 +1115,6 @@ cmd_parse_print_command(char **buf, struct cmd_parse_node *cmd, u_int depth)
} }
} }
/*
* Emit a line break before a body line, or a space when printing on one
* line.
*/
static void static void
cmd_parse_print_break(char **buf, u_int depth, int oneline) cmd_parse_print_break(char **buf, u_int depth, int oneline)
{ {
@@ -1130,12 +1126,6 @@ cmd_parse_print_break(char **buf, u_int depth, int oneline)
} }
} }
/*
* An %if that shares a sequence with other commands must be printed on one
* line, because only an inline %if reparses in that position; such an %if
* always has single-sequence branch bodies, so this is lossless. An %if that
* is alone in its sequence is printed over multiple lines.
*/
static void static void
cmd_parse_print_if(char **buf, struct cmd_parse_node *node, u_int depth, cmd_parse_print_if(char **buf, struct cmd_parse_node *node, u_int depth,
int oneline) int oneline)
@@ -1208,11 +1198,15 @@ static void
cmd_parse_print_sequence(char **buf, struct cmd_parse_node *seq, u_int depth) cmd_parse_print_sequence(char **buf, struct cmd_parse_node *seq, u_int depth)
{ {
struct cmd_parse_node *child; struct cmd_parse_node *child;
int first = 1, oneline; int first = 1, oneline = 0;
/* More than one item in a sequence forces everything onto one line. */ if (TAILQ_NEXT(TAILQ_FIRST(&seq->children), entry) != NULL) {
oneline = (TAILQ_FIRST(&seq->children) != /*
TAILQ_LAST(&seq->children, cmd_parse_nodes)); * If there is more than one item in a sequence, force
* everything on to one line.
*/
oneline = 1;
}
TAILQ_FOREACH(child, &seq->children, entry) { TAILQ_FOREACH(child, &seq->children, entry) {
if (!first) if (!first)
@@ -1240,6 +1234,101 @@ cmd_parse_print(struct cmd_parse_tree *tree)
return (buf); return (buf);
} }
static char *
cmd_parse_make_string(struct cmd_parse_node *node)
{
struct cmd_parse_node *child;
char *s = NULL, *new;
if (node->type != CMD_PARSE_STRING)
return (NULL);
TAILQ_FOREACH(child, &node->children, entry) {
if (child->type != CMD_PARSE_TEXT) {
free(s);
return (NULL);
}
if (s == NULL)
s = xstrdup(child->value);
else {
xasprintf(&new, "%s%s", s, child->value);
free(s);
s = new;
}
}
if (s == NULL)
s = xstrdup("");
return (s);
}
static int
cmd_parse_command_any_have(struct cmd_parse_node *node, int flag)
{
struct cmd_parse_node *child;
struct args_value *values = NULL;
struct cmd *cmd;
char *cause = NULL;
u_int count = 0;
int found = 0;
if (node->type != CMD_PARSE_COMMAND)
return (0);
TAILQ_FOREACH(child, &node->children, entry) {
values = xreallocarray(values, count + 1, sizeof *values);
memset(&values[count], 0, sizeof values[count]);
switch (child->type) {
case CMD_PARSE_STRING:
values[count].type = ARGS_STRING;
values[count].string = cmd_parse_make_string(child);
if (values[count].string == NULL)
goto out;
break;
case CMD_PARSE_COMMANDS:
values[count].type = ARGS_COMMANDS;
values[count].cmd = cmd_parse_from_node(child);
break;
default:
fatalx("unexpected node type in command");
}
count++;
}
cmd = cmd_parse(values, count, NULL, node->line, 0, &cause);
if (cmd == NULL)
free(cause);
else {
if (cmd_get_entry(cmd)->flags & flag)
found = 1;
cmd_free(cmd);
}
out:
args_free_values(values, count);
free(values);
return (found);
}
int
cmd_parse_any_have(struct cmd_parse_tree *tree, int flag)
{
struct cmd_parse_node *seq, *node;
TAILQ_FOREACH(seq, &tree->root->children, entry) {
if (seq->type != CMD_PARSE_SEQUENCE)
continue;
TAILQ_FOREACH(node, &seq->children, entry) {
if (node->type != CMD_PARSE_COMMAND)
continue;
if (cmd_parse_command_any_have(node, flag))
return (1);
}
}
return (0);
}
static void printflike(1, 2) static void printflike(1, 2)
yyerror(const char *fmt, ...) yyerror(const char *fmt, ...)
{ {

View File

@@ -81,6 +81,7 @@ struct cmd_parse_tree *cmd_parse_from_string(const char *,
struct cmd_parse_tree *cmd_parse_from_node(struct cmd_parse_node *); struct cmd_parse_tree *cmd_parse_from_node(struct cmd_parse_node *);
struct cmd_parse_tree *cmd_parse_from_arguments(struct args_value *, u_int); struct cmd_parse_tree *cmd_parse_from_arguments(struct args_value *, u_int);
struct cmd_parse_tree *cmd_parse_add_ref(struct cmd_parse_tree *); struct cmd_parse_tree *cmd_parse_add_ref(struct cmd_parse_tree *);
int cmd_parse_any_have(struct cmd_parse_tree *, int);
void cmd_parse_free(struct cmd_parse_tree *); void cmd_parse_free(struct cmd_parse_tree *);
struct cmd_parse_node *cmd_parse_root(struct cmd_parse_tree *); struct cmd_parse_node *cmd_parse_root(struct cmd_parse_tree *);
char *cmd_parse_print(struct cmd_parse_tree *); char *cmd_parse_print(struct cmd_parse_tree *);