Extend runscript to allow file with content like:
"/prog1 prm1; /prog2 prm2"

Tests are included.

Signed-off-by: Justin Cinkelj <justin.cink...@xlab.si>
---
 core/commands.cc      |  39 ++++++++----
 tests/tst-commands.cc | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 195 insertions(+), 12 deletions(-)

diff --git a/core/commands.cc b/core/commands.cc
index ebcac89..90fd1f2 100644
--- a/core/commands.cc
+++ b/core/commands.cc
@@ -85,16 +85,23 @@ parse_command_line_min(const std::string line, bool &ok)
 
 /*
 If cmd starts with "runcript file", read content of file and
-update cmd with the content.
+return vector of all programs to be run.
+File can contain multiple commands per line.
 ok flag is set to false on parse error, and left unchanged otherwise.
+
+If cmd doesn't start with runscript, then vector with size 0 is returned.
 */
-void runscript_expand(std::vector<std::string>& cmd, bool &ok)
+std::vector<std::vector<std::string>> runscript_expand(const 
std::vector<std::string>& cmd, bool &ok)
 {
+    std::vector<std::vector<std::string> > result;
     if (cmd[0] == "runscript") {
-        if (cmd.size()<2) {
-            puts("Failed expanding runscript - filename missing.");
+        /*
+        The cmd vector ends with additional ";" or "\0" element.
+        */
+        if (cmd.size() != 3 && cmd[2].c_str()[0] != 0x00) {
+            puts("Failed expanding runscript - filename missing or extra 
parameters present.");
             ok = false;
-            return;
+            return result;
         }
         auto fn = cmd[1];
 
@@ -102,24 +109,22 @@ void runscript_expand(std::vector<std::string>& cmd, bool 
&ok)
         std::string line;
         // only first line up to \n is used.
         getline(in, line);
-        std::vector<std::vector<std::string> > result;
         bool ok2;
         result = parse_command_line_min(line, ok2);
         debug("runscript expand fn='%s' line='%s'\n", fn.c_str(), 
line.c_str());
         if (ok2 == false) {
             printf("Failed expanding runscript file='%s' line='%s'.\n", 
fn.c_str(), line.c_str());
+            result.clear();
             ok = false;
         }
-        else {
-            cmd = result[0];
-        }
     }
+    return result;
 }
 
 std::vector<std::vector<std::string>>
 parse_command_line(const std::string line,  bool &ok)
 {
-    std::vector<std::vector<std::string> > result;
+    std::vector<std::vector<std::string> > result, result2;
     result = parse_command_line_min(line, ok);
 
     /*
@@ -127,8 +132,18 @@ parse_command_line(const std::string line,  bool &ok)
     execute from the given file.
     */
     std::vector<std::vector<std::string>>::iterator cmd_iter;
-    for (cmd_iter=result.begin(); ok && cmd_iter!=result.end(); cmd_iter++) {
-        runscript_expand(*cmd_iter, ok);
+    for (cmd_iter=result.begin(); ok && cmd_iter!=result.end(); ) {
+        result2 = runscript_expand(*cmd_iter, ok);
+        if (result2.size() > 0) {
+            cmd_iter = result.erase(cmd_iter);
+            int pos;
+            pos = cmd_iter - result.begin();
+            result.insert(cmd_iter, result2.begin(), result2.end());
+            cmd_iter = result.begin() + pos + result2.size();
+        }
+        else {
+            cmd_iter++;
+        }
     }
 
     return result;
diff --git a/tests/tst-commands.cc b/tests/tst-commands.cc
index c6fb3a5..3b8c1c9 100644
--- a/tests/tst-commands.cc
+++ b/tests/tst-commands.cc
@@ -353,6 +353,168 @@ static bool test_runscript_multiple_with_args_quotes()
     return true;
 }
 
+static bool test_runscript_multiple_commands_per_line()
+{
+    std::ofstream of1("/myscript", std::ios::out | std::ios::binary);
+    of1 << "/prog1; /prog2";
+    of1.close();
+
+    std::vector<std::vector<std::string> > result;
+    std::vector<std::string> cmd = { "/prog1", "/prog2" };
+    bool ok;
+
+    result = osv::parse_command_line(
+        std::string("runscript \"/myscript\""),
+        ok);
+
+    if (!ok) {
+        return false;
+    }
+
+    if (result.size() != 2) {
+        return false;
+    }
+
+    if (result[0].size() != 2) {
+        return false;
+    }
+
+    if (result[1].size() != 2) {
+        return false;
+    }
+
+    for (size_t i = 0; i < result.size(); i++) {
+        if (result[i][0] != cmd[i]) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool test_runscript_multiple_commands_per_line_with_args()
+{
+    std::ofstream of1("/myscript", std::ios::out | std::ios::binary);
+    of1 << "/prog1 pp1a ; /prog2 pp2a pp2b";
+    of1.close();
+
+    std::vector<std::vector<std::string> > result;
+    std::vector<std::string> cmd = { "/prog1", "/prog2" };
+    bool ok;
+
+    result = osv::parse_command_line(
+        std::string("runscript \"/myscript\""),
+        ok);
+
+    if (!ok) {
+        return false;
+    }
+
+    if (result.size() != 2) {
+        return false;
+    }
+
+    if (result[0].size() != 3) {
+        return false;
+    }
+
+    if (result[1].size() != 4) {
+        return false;
+    }
+
+    for (size_t i = 0; i < result.size(); i++) {
+        if (result[i][0] != cmd[i]) {
+            return false;
+        }
+    }
+
+    if (result[0][1] != std::string("pp1a")) {
+        return false;
+    }
+
+    if (result[1][1] != std::string("pp2a")) {
+        return false;
+    }
+    if (result[1][2] != std::string("pp2b")) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool test_runscript_multiple_commands_per_line_with_args_quotes()
+{
+    std::ofstream of1("/myscript", std::ios::out | std::ios::binary);
+    of1 << "/prog1 pp1a ; /prog2 pp2a pp2b; /prog3 pp3a \"pp3b1 pp3b2\" 
\"pp3c1;pp3c2\" \"pp3d\" \" ;; --onx -fon;x \\t\"; ";
+    of1.close();
+
+    std::vector<std::vector<std::string> > result;
+    std::vector<std::string> cmd = { "/prog1", "/prog2", "/prog3" };
+    bool ok;
+
+    result = osv::parse_command_line(
+        std::string("runscript \"/myscript\""),
+        ok);
+
+    if (!ok) {
+        return false;
+    }
+
+    if (result.size() != 3) {
+        return false;
+    }
+
+    if (result[0].size() != 3) {
+        return false;
+    }
+
+    if (result[1].size() != 4) {
+        return false;
+    }
+
+    if (result[2].size() != 7) {
+        return false;
+    }
+
+    for (size_t i = 0; i < result.size(); i++) {
+        if (result[i][0] != cmd[i]) {
+            return false;
+        }
+    }
+
+    if (result[0][1] != std::string("pp1a")) {
+        return false;
+    }
+
+    if (result[1][1] != std::string("pp2a")) {
+        return false;
+    }
+    if (result[1][2] != std::string("pp2b")) {
+        return false;
+    }
+
+    if (result[2][1] != std::string("pp3a")) {
+        return false;
+    }
+    if (result[2][2] != std::string("pp3b1 pp3b2")) {
+        return false;
+    }
+    if (result[2][3] != std::string("pp3c1;pp3c2")) {
+        return false;
+    }
+    if (result[2][4] != std::string("pp3d")) {
+        return false;
+    }
+    if (result[2][5] != std::string(" ;; --onx -fon;x \t")) {
+        return false;
+    }
+    if (result[2][6] != std::string(";")) {
+        return false;
+    }
+
+    return true;
+}
+
 int main(int argc, char *argv[])
 {
     report(test_parse_simplest(), "simplest command line");
@@ -369,6 +531,12 @@ int main(int argc, char *argv[])
            "cpiod upload and haproxy launch");
     report(test_runscript_multiple_with_args_quotes(),
            "runscript multiple with args and quotes");
+    report(test_runscript_multiple_commands_per_line(),
+           "runscript multiple commands per line");
+    report(test_runscript_multiple_commands_per_line_with_args(),
+           "runscript multiple commands per line with args");
+    report(test_runscript_multiple_commands_per_line_with_args_quotes(),
+           "runscript multiple commands per line with args and quotes");
     printf("SUMMARY: %d tests, %d failures\n", tests, fails);
     return 0;
 }
-- 
2.5.5

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to