This will soon have a new user, but it's a worthwhile cleanup on its own.
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);
{
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;
+}
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 */