aboutsummaryrefslogtreecommitdiffstats
path: root/common/args
diff options
context:
space:
mode:
authorGravatar BanceDev 2026-02-16 16:31:54 -0500
committerGravatar BanceDev 2026-02-16 16:31:54 -0500
commitca90ebdfa8789654766c5d7969baa7afacd9ebd2 (patch)
tree9693e0c7a5af6713f4c5e39372dcf22d05844ec3 /common/args
initial commitHEADmain
Diffstat (limited to 'common/args')
-rw-r--r--common/args/args.go79
-rw-r--r--common/args/args_test.go83
2 files changed, 162 insertions, 0 deletions
diff --git a/common/args/args.go b/common/args/args.go
new file mode 100644
index 0000000..28c3b5f
--- /dev/null
+++ b/common/args/args.go
@@ -0,0 +1,79 @@
+package args
+
+import (
+ "strings"
+
+ "github.com/osm/quake/common/buffer"
+)
+
+type Arg struct {
+ Cmd string
+ Args []string
+}
+
+func Parse(input string) []Arg {
+ var arg string
+ var args []string
+ var ret []Arg
+ var inQuotes bool
+
+ for _, c := range input {
+ switch c {
+ case '\n', ';':
+ if inQuotes {
+ arg += string(c)
+ continue
+ }
+
+ if arg != "" {
+ args = append(args, strings.TrimSpace(arg))
+ }
+
+ ret = append(ret, Arg{Cmd: strings.TrimSpace(args[0]), Args: args[1:]})
+ arg = ""
+ args = []string{}
+ case ' ':
+ if inQuotes {
+ arg += string(c)
+ continue
+ }
+
+ if arg != "" {
+ args = append(args, strings.TrimSpace(arg))
+ arg = ""
+ }
+ case '"':
+ inQuotes = !inQuotes
+ arg += string(c)
+ default:
+ arg += string(c)
+ }
+ }
+
+ if arg != "" {
+ args = append(args, strings.TrimSpace(arg))
+ }
+
+ if len(args) > 0 {
+ ret = append(ret, Arg{Cmd: strings.TrimSpace(args[0]), Args: args[1:]})
+ }
+
+ return ret
+}
+
+func (s Arg) Bytes() []byte {
+ buf := buffer.New()
+
+ buf.PutBytes([]byte(s.Cmd))
+
+ if len(s.Args) > 0 {
+ buf.PutByte(byte(' '))
+ buf.PutBytes([]byte(strings.Join(s.Args, " ")))
+ }
+
+ return buf.Bytes()
+}
+
+func (s Arg) String() string {
+ return string(s.Bytes())
+}
diff --git a/common/args/args_test.go b/common/args/args_test.go
new file mode 100644
index 0000000..4f1967c
--- /dev/null
+++ b/common/args/args_test.go
@@ -0,0 +1,83 @@
+package args
+
+import (
+ "encoding/base64"
+ "reflect"
+ "testing"
+)
+
+type argsTest struct {
+ name string
+ input string
+ expected []Arg
+}
+
+var argsTests = []argsTest{
+ {
+ name: "foo bar baz",
+ input: "Zm9vIGJhciBiYXo=",
+ expected: []Arg{
+ {
+ Cmd: "foo",
+ Args: []string{"bar", "baz"},
+ },
+ },
+ },
+ {
+ name: "foo bar baz\n",
+ input: "Zm9vIGJhciBiYXoK",
+ expected: []Arg{
+ {
+ Cmd: "foo",
+ Args: []string{"bar", "baz"},
+ },
+ },
+ },
+ {
+ name: "foo \"bar baz\"",
+ input: "Zm9vICJiYXIgYmF6Ig==",
+ expected: []Arg{
+ {
+ Cmd: "foo",
+ Args: []string{"\"bar baz\""},
+ },
+ },
+ },
+ {
+ name: "foo \"bar baz\";foo bar baz\nfoo bar",
+ input: "Zm9vICJiYXIgYmF6Ijtmb28gYmFyIGJhegpmb28gYmFy",
+ expected: []Arg{
+ {
+ Cmd: "foo",
+ Args: []string{"\"bar baz\""},
+ },
+ {
+ Cmd: "foo",
+ Args: []string{"bar", "baz"},
+ },
+ {
+ Cmd: "foo",
+ Args: []string{"bar"},
+ },
+ },
+ },
+}
+
+func TestArgs(t *testing.T) {
+ for _, at := range argsTests {
+ t.Run(at.name, func(t *testing.T) {
+ input, err := base64.StdEncoding.DecodeString(at.input)
+ if err != nil {
+ t.Errorf("unable to decode input: %#v", err)
+ }
+
+ args := Parse(string(input))
+
+ if !reflect.DeepEqual(at.expected, args) {
+ t.Errorf("parsed args output didn't match")
+ t.Logf("output: %#v", args)
+ t.Logf("expected: %#v", at.expected)
+ }
+ })
+ }
+}