From e89e5374bebd6ae00098ce40511a36daa09fc77e Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 28 Jun 2010 17:20:15 -0700 Subject: [PATCH] ovs-vsctl: Prepare for more flexible database argument parsing. The wait-until command to be added in an upcoming commit needs to support !=, <, >, <=, and >= operators in addition to =, so this commit adds that infrastructure. --- lib/ovsdb-data.c | 2 +- tests/ovs-vsctl.at | 2 +- utilities/ovs-vsctl.c | 103 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 96 insertions(+), 11 deletions(-) diff --git a/lib/ovsdb-data.c b/lib/ovsdb-data.c index 39d10ede..fe7d8c40 100644 --- a/lib/ovsdb-data.c +++ b/lib/ovsdb-data.c @@ -1633,5 +1633,5 @@ error: bool ovsdb_token_is_delim(unsigned char c) { - return strchr(":=, []{}", c) != NULL; + return strchr(":=, []{}!<>", c) != NULL; } diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at index 2923649a..66c375c9 100644 --- a/tests/ovs-vsctl.at +++ b/tests/ovs-vsctl.at @@ -659,7 +659,7 @@ AT_CHECK([RUN_OVS_VSCTL([get b br0 :y=z])], [1], [], [ovs-vsctl: :y=z: missing column name ], [OVS_VSCTL_CLEANUP]) AT_CHECK([RUN_OVS_VSCTL([get b br0 datapath_id:y=z])], - [1], [], [ovs-vsctl: datapath_id:y=z: value not accepted here + [1], [], [ovs-vsctl: datapath_id:y=z: trailing garbage "=z" in argument ], [OVS_VSCTL_CLEANUP]) AT_CHECK([RUN_OVS_VSCTL([get b br0 datapath_id::])], [1], [], [ovs-vsctl: datapath_id::: trailing garbage ":" in argument diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index 4c0a2005..b7577a01 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -2104,15 +2104,65 @@ get_column(const struct vsctl_table_class *table, const char *column_name, } } +static char * +missing_operator_error(const char *arg, const char **allowed_operators, + size_t n_allowed) +{ + struct ds s; + + ds_init(&s); + ds_put_format(&s, "%s: argument does not end in ", arg); + ds_put_format(&s, "\"%s\"", allowed_operators[0]); + if (n_allowed == 2) { + ds_put_format(&s, " or \"%s\"", allowed_operators[1]); + } else if (n_allowed > 2) { + size_t i; + + for (i = 1; i < n_allowed - 1; i++) { + ds_put_format(&s, ", \"%s\"", allowed_operators[i]); + } + ds_put_format(&s, ", or \"%s\"", allowed_operators[i]); + } + ds_put_format(&s, " followed by a value."); + + return ds_steal_cstr(&s); +} + +/* Breaks 'arg' apart into a number of fields in the following order: + * + * - If 'columnp' is nonnull, the name of a column in 'table'. The column + * is stored into '*columnp'. The column name may be abbreviated. + * + * - If 'keyp' is nonnull, optionally a key string. (If both 'columnp' + * and 'keyp' are nonnull, then the column and key names are expected to + * be separated by ':'). The key is stored as a malloc()'d string into + * '*keyp', or NULL if no key is present in 'arg'. + * + * - If 'valuep' is nonnull, an operator followed by a value string. The + * allowed operators are the 'n_allowed' string in 'allowed_operators', + * or just "=" if 'n_allowed' is 0. If 'operatorp' is nonnull, then the + * operator is stored into '*operatorp' (one of the pointers from + * 'allowed_operators' is stored; nothing is malloc()'d). The value is + * stored as a malloc()'d string into '*valuep', or NULL if no value is + * present in 'arg'. + * + * At least 'columnp' or 'keyp' must be nonnull. + * + * On success, returns NULL. On failure, returned a malloc()'d string error + * message and stores NULL into all of the nonnull output arguments. */ static char * WARN_UNUSED_RESULT -parse_column_key_value(const char *arg, const struct vsctl_table_class *table, - const struct ovsdb_idl_column **columnp, - char **keyp, char **valuep) +parse_column_key_value(const char *arg, + const struct vsctl_table_class *table, + const struct ovsdb_idl_column **columnp, char **keyp, + const char **operatorp, + const char **allowed_operators, size_t n_allowed, + char **valuep) { const char *p = arg; char *error; assert(columnp || keyp); + assert(!(operatorp && !valuep)); if (keyp) { *keyp = NULL; } @@ -2157,12 +2207,43 @@ parse_column_key_value(const char *arg, const struct vsctl_table_class *table, } /* Parse value string. */ - if (*p == '=') { - if (!valuep) { - error = xasprintf("%s: value not accepted here", arg); + if (valuep) { + const char *best; + size_t best_len; + size_t i; + + if (!allowed_operators) { + static const char *equals = "="; + allowed_operators = = + n_allowed = 1; + } + + best = NULL; + best_len = 0; + for (i = 0; i < n_allowed; i++) { + const char *op = allowed_operators[i]; + size_t op_len = strlen(op); + + if (op_len > best_len && !strncmp(op, p, op_len)) { + best_len = op_len; + best = op; + } + } + if (!best) { + error = missing_operator_error(arg, allowed_operators, n_allowed); goto error; } - *valuep = xstrdup(p + 1); + + if (operatorp) { + *operatorp = best; + } + + p += best_len; + if (p[0] == '\0') { + error = missing_operator_error(arg, allowed_operators, n_allowed); + goto error; + } + *valuep = xstrdup(p); } else { if (valuep) { *valuep = NULL; @@ -2186,6 +2267,9 @@ error: if (valuep) { free(*valuep); *valuep = NULL; + if (operatorp) { + *operatorp = NULL; + } } return error; } @@ -2218,7 +2302,8 @@ cmd_get(struct vsctl_context *ctx) } die_if_error(parse_column_key_value(ctx->argv[i], table, - &column, &key_string, NULL)); + &column, &key_string, + NULL, NULL, 0, NULL)); ovsdb_idl_txn_read(row, column, &datum); if (key_string) { @@ -2320,7 +2405,7 @@ set_column(const struct vsctl_table_class *table, char *error; error = parse_column_key_value(arg, table, &column, &key_string, - &value_string); + NULL, NULL, 0, &value_string); die_if_error(error); if (!value_string) { vsctl_fatal("%s: missing value", arg); -- 2.30.2