init: Create classes for Action and Command

This creates the concept of 'event_trigger' vs 'property_trigger'

Previously these were merged into one, such that 'on property:a=b &&
property:b=c' is triggered when properties a=b and b=c as expected,
however combinations such as 'on early-boot && boot' would trigger
during both early-boot and boot.  Similarly, 'on early-boot &&
property:a=b' would trigger on both early-boot and again when property
a equals b.

The event trigger distinction ensures that the first example fails to
parse and the second example only triggers on early-boot if
property a equals b.

This coalesces Actions with the same triggers into a single Action object

Change-Id: I8f661d96e8a2d40236f252301bfe10979d663ea6
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 460f5ac..ab0dbc3 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "action.h"
 #include "init.h"
 #include "parser.h"
 #include "init_parser.h"
@@ -38,8 +39,6 @@
 #include <cutils/list.h>
 
 static list_declare(service_list);
-static list_declare(action_list);
-static list_declare(action_queue);
 
 struct import {
     struct listnode list;
@@ -93,25 +92,7 @@
                 INFO("  socket %s %s 0%o\n", si->name, si->type, si->perm);
             }
         }
-
-        list_for_each(node, &action_list) {
-            action* act = node_to_item(node, struct action, alist);
-            INFO("on ");
-            std::string trigger_name = build_triggers_string(act);
-            INFO("%s", trigger_name.c_str());
-            INFO("\n");
-
-            struct listnode* node2;
-            list_for_each(node2, &act->commands) {
-                command* cmd = node_to_item(node2, struct command, clist);
-                INFO("  %p", cmd->func);
-                for (int n = 0; n < cmd->nargs; n++) {
-                    INFO(" %s", cmd->args[n]);
-                }
-                INFO("\n");
-            }
-            INFO("\n");
-        }
+        ActionManager::GetInstance().DumpState();
     }
 }
 
@@ -217,10 +198,10 @@
 static void parse_line_no_op(struct parse_state*, int, char**) {
 }
 
-int expand_props(const char *src, std::string *dst) {
-    const char *src_ptr = src;
+int expand_props(const std::string& src, std::string* dst) {
+    const char *src_ptr = src.c_str();
 
-    if (!src || !dst) {
+    if (!dst) {
         return -1;
     }
 
@@ -256,7 +237,7 @@
             const char* end = strchr(c, '}');
             if (!end) {
                 // failed to find closing brace, abort.
-                ERROR("unexpected end of string in '%s', looking for }\n", src);
+                ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
                 goto err;
             }
             prop_name = std::string(c, end);
@@ -269,14 +250,14 @@
         }
 
         if (prop_name.empty()) {
-            ERROR("invalid zero-length prop name in '%s'\n", src);
+            ERROR("invalid zero-length prop name in '%s'\n", src.c_str());
             goto err;
         }
 
         std::string prop_val = property_get(prop_name.c_str());
         if (prop_val.empty()) {
             ERROR("property '%s' doesn't exist while expanding '%s'\n",
-                  prop_name.c_str(), src);
+                  prop_name.c_str(), src.c_str());
             goto err;
         }
 
@@ -527,125 +508,6 @@
     }
 }
 
-void action_for_each_trigger(const char *trigger,
-                             void (*func)(struct action *act))
-{
-    struct listnode *node, *node2;
-    struct action *act;
-    struct trigger *cur_trigger;
-
-    list_for_each(node, &action_list) {
-        act = node_to_item(node, struct action, alist);
-        list_for_each(node2, &act->triggers) {
-            cur_trigger = node_to_item(node2, struct trigger, nlist);
-            if (!strcmp(cur_trigger->name, trigger)) {
-                func(act);
-            }
-        }
-    }
-}
-
-
-void queue_property_triggers(const char *name, const char *value)
-{
-    struct listnode *node, *node2;
-    struct action *act;
-    struct trigger *cur_trigger;
-    bool match;
-    int name_length;
-
-    list_for_each(node, &action_list) {
-        act = node_to_item(node, struct action, alist);
-            match = !name;
-        list_for_each(node2, &act->triggers) {
-            cur_trigger = node_to_item(node2, struct trigger, nlist);
-            if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {
-                const char *test = cur_trigger->name + strlen("property:");
-                if (!match) {
-                    name_length = strlen(name);
-                    if (!strncmp(name, test, name_length) &&
-                        test[name_length] == '=' &&
-                        (!strcmp(test + name_length + 1, value) ||
-                        !strcmp(test + name_length + 1, "*"))) {
-                        match = true;
-                        continue;
-                    }
-                } else {
-                     const char* equals = strchr(test, '=');
-                     if (equals) {
-                         int length = equals - test;
-                         if (length <= PROP_NAME_MAX) {
-                             std::string prop_name(test, length);
-                             std::string value = property_get(prop_name.c_str());
-
-                             /* does the property exist, and match the trigger value? */
-                             if (!value.empty() && (!strcmp(equals + 1, value.c_str()) ||
-                                !strcmp(equals + 1, "*"))) {
-                                 continue;
-                             }
-                         }
-                     }
-                 }
-             }
-             match = false;
-             break;
-        }
-        if (match) {
-            action_add_queue_tail(act);
-        }
-    }
-}
-
-void queue_all_property_triggers()
-{
-    queue_property_triggers(NULL, NULL);
-}
-
-void queue_builtin_action(int (*func)(int nargs, char **args), const char *name)
-{
-    action* act = (action*) calloc(1, sizeof(*act));
-    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
-    cur_trigger->name = name;
-    list_init(&act->triggers);
-    list_add_tail(&act->triggers, &cur_trigger->nlist);
-    list_init(&act->commands);
-    list_init(&act->qlist);
-
-    command* cmd = (command*) calloc(1, sizeof(*cmd));
-    cmd->func = func;
-    cmd->args[0] = const_cast<char*>(name);
-    cmd->nargs = 1;
-    list_add_tail(&act->commands, &cmd->clist);
-
-    list_add_tail(&action_list, &act->alist);
-    action_add_queue_tail(act);
-}
-
-void action_add_queue_tail(struct action *act)
-{
-    if (list_empty(&act->qlist)) {
-        list_add_tail(&action_queue, &act->qlist);
-    }
-}
-
-struct action *action_remove_queue_head(void)
-{
-    if (list_empty(&action_queue)) {
-        return 0;
-    } else {
-        struct listnode *node = list_head(&action_queue);
-        struct action *act = node_to_item(node, struct action, qlist);
-        list_remove(node);
-        list_init(node);
-        return act;
-    }
-}
-
-int action_queue_empty()
-{
-    return list_empty(&action_queue);
-}
-
 service* make_exec_oneshot_service(int nargs, char** args) {
     // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS...
     // SECLABEL can be a - to denote default
@@ -732,13 +594,10 @@
     svc->name = strdup(args[1]);
     svc->classname = "default";
     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
-    trigger* cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
     svc->args[nargs] = 0;
     svc->nargs = nargs;
-    list_init(&svc->onrestart.triggers);
-    cur_trigger->name = "onrestart";
-    list_add_tail(&svc->onrestart.triggers, &cur_trigger->nlist);
-    list_init(&svc->onrestart.commands);
+    svc->onrestart = new Action();
+    svc->onrestart->InitSingleTrigger("onrestart");
     list_add_tail(&service_list, &svc->slist);
     return svc;
 }
@@ -746,8 +605,8 @@
 static void parse_line_service(struct parse_state *state, int nargs, char **args)
 {
     struct service *svc = (service*) state->context;
-    struct command *cmd;
     int i, kw, kw_nargs;
+    std::vector<std::string> str_args;
 
     if (nargs == 0) {
         return;
@@ -840,12 +699,8 @@
                 kw_nargs > 2 ? "arguments" : "argument");
             break;
         }
-
-        cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
-        cmd->func = kw_func(kw);
-        cmd->nargs = nargs;
-        memcpy(cmd->args, args, sizeof(char*) * nargs);
-        list_add_tail(&svc->onrestart.commands, &cmd->clist);
+        str_args.assign(args, args + nargs);
+        svc->onrestart->AddCommand(kw_func(kw), str_args);
         break;
     case K_critical:
         svc->flags |= SVC_CRITICAL;
@@ -924,48 +779,22 @@
     }
 }
 
-static void *parse_action(struct parse_state *state, int nargs, char **args)
+static void *parse_action(struct parse_state* state, int nargs, char **args)
 {
-    struct trigger *cur_trigger;
-    int i;
-    if (nargs < 2) {
-        parse_error(state, "actions must have a trigger\n");
-        return 0;
+    std::string ret_err;
+    std::vector<std::string> triggers(args + 1, args + nargs);
+    Action* ret = ActionManager::GetInstance().AddNewAction(triggers, &ret_err);
+
+    if (!ret) {
+        parse_error(state, "%s\n", ret_err.c_str());
     }
 
-    action* act = (action*) calloc(1, sizeof(*act));
-    list_init(&act->triggers);
-
-    for (i = 1; i < nargs; i++) {
-        if (!(i % 2)) {
-            if (strcmp(args[i], "&&")) {
-                struct listnode *node;
-                struct listnode *node2;
-                parse_error(state, "& is the only symbol allowed to concatenate actions\n");
-                list_for_each_safe(node, node2, &act->triggers) {
-                    struct trigger *trigger = node_to_item(node, struct trigger, nlist);
-                    free(trigger);
-                }
-                free(act);
-                return 0;
-            } else
-                continue;
-        }
-        cur_trigger = (trigger*) calloc(1, sizeof(*cur_trigger));
-        cur_trigger->name = args[i];
-        list_add_tail(&act->triggers, &cur_trigger->nlist);
-    }
-
-    list_init(&act->commands);
-    list_init(&act->qlist);
-    list_add_tail(&action_list, &act->alist);
-        /* XXX add to hash */
-    return act;
+    return ret;
 }
 
 static void parse_line_action(struct parse_state* state, int nargs, char **args)
 {
-    struct action *act = (action*) state->context;
+    Action* act = (Action*) state->context;
     int kw, n;
 
     if (nargs == 0) {
@@ -984,11 +813,7 @@
             n > 2 ? "arguments" : "argument");
         return;
     }
-    command* cmd = (command*) malloc(sizeof(*cmd) + sizeof(char*) * nargs);
-    cmd->func = kw_func(kw);
-    cmd->line = state->line;
-    cmd->filename = state->filename;
-    cmd->nargs = nargs;
-    memcpy(cmd->args, args, sizeof(char*) * nargs);
-    list_add_tail(&act->commands, &cmd->clist);
+
+    std::vector<std::string> str_args(args, args + nargs);
+    act->AddCommand(kw_func(kw), str_args, state->filename, state->line);
 }