From 0ff2282245a87f253843bf357988d7230139888f Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 17 Aug 2011 13:39:02 -0700 Subject: [PATCH] ofp-util: New function for parsing key-value pairs. This will soon have a new user, but it's a worthwhile cleanup on its own. --- lib/ofp-parse.c | 63 +++++--------------------------------------- lib/ofp-util.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/ofp-util.h | 3 +++ 3 files changed, 78 insertions(+), 57 deletions(-) diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index b29b34a7..6ccabfef 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -495,80 +495,29 @@ parse_named_action(enum ofputil_action_code code, struct ofpbuf *b, char *arg) static void str_to_action(char *str, struct ofpbuf *b) { - bool drop = false; + char *pos, *act, *arg; int n_actions; - char *pos; pos = str; n_actions = 0; - for (;;) { - char empty_string[] = ""; - char *act, *arg; - size_t actlen; + while (ofputil_parse_key_value(&pos, &act, &arg)) { uint16_t port; int code; - pos += strspn(pos, ", \t\r\n"); - if (*pos == '\0') { - break; - } - - if (drop) { - ovs_fatal(0, "Drop actions must not be followed by other actions"); - } - - act = pos; - actlen = strcspn(pos, ":(, \t\r\n"); - if (act[actlen] == ':') { - /* The argument can be separated by a colon. */ - size_t arglen; - - arg = act + actlen + 1; - arglen = strcspn(arg, ", \t\r\n"); - pos = arg + arglen + (arg[arglen] != '\0'); - arg[arglen] = '\0'; - } else if (act[actlen] == '(') { - /* The argument can be surrounded by balanced parentheses. The - * outermost set of parentheses is removed. */ - int level = 1; - size_t arglen; - - arg = act + actlen + 1; - for (arglen = 0; level > 0; arglen++) { - switch (arg[arglen]) { - case '\0': - ovs_fatal(0, "unbalanced parentheses in argument to %s " - "action", act); - - case '(': - level++; - break; - - case ')': - level--; - break; - } - } - arg[arglen - 1] = '\0'; - pos = arg + arglen; - } else { - /* There might be no argument at all. */ - arg = empty_string; - pos = act + actlen + (act[actlen] != '\0'); - } - act[actlen] = '\0'; - code = ofputil_action_code_from_name(act); if (code >= 0) { parse_named_action(code, b, arg); } else if (!strcasecmp(act, "drop")) { /* A drop action in OpenFlow occurs by just not setting * an action. */ - drop = true; if (n_actions) { ovs_fatal(0, "Drop actions must not be preceded by other " "actions"); + } else if (ofputil_parse_key_value(&pos, &act, &arg)) { + ovs_fatal(0, "Drop actions must not be followed by other " + "actions"); } + break; } else if (!strcasecmp(act, "CONTROLLER")) { struct ofp_action_output *oao; oao = put_output_action(b, OFPP_CONTROLLER); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index c8589c67..6887217d 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -2735,3 +2735,72 @@ ofputil_actions_clone(const union ofp_action *actions, size_t n) { return n ? xmemdup(actions, n * sizeof *actions) : NULL; } + +/* Parses a key or a key-value pair from '*stringp'. + * + * On success: Stores the key into '*keyp'. Stores the value, if present, into + * '*valuep', otherwise an empty string. Advances '*stringp' past the end of + * the key-value pair, preparing it for another call. '*keyp' and '*valuep' + * are substrings of '*stringp' created by replacing some of its bytes by null + * terminators. Returns true. + * + * If '*stringp' is just white space or commas, sets '*keyp' and '*valuep' to + * NULL and returns false. */ +bool +ofputil_parse_key_value(char **stringp, char **keyp, char **valuep) +{ + char *pos, *key, *value; + size_t key_len; + + pos = *stringp; + pos += strspn(pos, ", \t\r\n"); + if (*pos == '\0') { + *keyp = *valuep = NULL; + return false; + } + + key = pos; + key_len = strcspn(pos, ":=(, \t\r\n"); + if (key[key_len] == ':' || key[key_len] == '=') { + /* The value can be separated by a colon. */ + size_t value_len; + + value = key + key_len + 1; + value_len = strcspn(value, ", \t\r\n"); + pos = value + value_len + (value[value_len] != '\0'); + value[value_len] = '\0'; + } else if (key[key_len] == '(') { + /* The value can be surrounded by balanced parentheses. The outermost + * set of parentheses is removed. */ + int level = 1; + size_t value_len; + + value = key + key_len + 1; + for (value_len = 0; level > 0; value_len++) { + switch (value[value_len]) { + case '\0': + ovs_fatal(0, "unbalanced parentheses in argument to %s", key); + + case '(': + level++; + break; + + case ')': + level--; + break; + } + } + value[value_len - 1] = '\0'; + pos = value + value_len; + } else { + /* There might be no value at all. */ + value = key + key_len; /* Will become the empty string below. */ + pos = key + key_len + (key[key_len] != '\0'); + } + key[key_len] = '\0'; + + *stringp = pos; + *keyp = key; + *valuep = value; + return true; +} diff --git a/lib/ofp-util.h b/lib/ofp-util.h index a658df11..ecd77cc4 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -547,4 +547,7 @@ int ofputil_decode_error_msg(const struct ofp_header *, size_t *payload_ofs); void ofputil_format_error(struct ds *, int error); char *ofputil_error_to_string(int error); +/* Handy utility for parsing flows and actions. */ +bool ofputil_parse_key_value(char **stringp, char **keyp, char **valuep); + #endif /* ofp-util.h */ -- 2.30.2