1(import [mpd.ffi [*]] ctypes)
2(require [hy.contrib.walk [let]])
3
4(setv libmpdserver (ctypes.CDLL "libmpdserver.so"))
5(setv parse libmpdserver.mpd_parse)
6(setv parse.restype (ctypes.POINTER MPDCmd))
7(setv freecmd libmpdserver.mpd_free_command)
8
9(defclass Range [object]
10 (defn --init-- [self start &optional end]
11 (setv self.start start)
12 (setv self.end end))
13
14 (defn infinite? [self]
15 (not self.end))
16
17 (defn to-range [self]
18 (if (self.infinite?)
19 (raise (ValueError "Range has infinite length"))
20 (range self.start self.end))))
21
22(defclass Command [object]
23 (defn --init-- [self cmd]
24 (setv self.name (.decode cmd.name))
25 (let [args (self.argv-list cmd.argc cmd.argv)]
26 (setv self.args (list (map self.convert-argument args)))))
27
28 (defn list? [self]
29 (or (= self.name "command_list_begin")
30 (= self.name "command_list_ok_begin")))
31
32 (defn argv-list [self argc argv]
33 (lfor
34 idx (range argc)
35 (. (get argv idx) contents)))
36
37 (defn convert-argument [self arg]
38 (let [t arg.type v arg.v]
39 (cond
40 [(= t MPDVal.INT) v.ival]
41 [(= t MPDVal.UINT) v.uval]
42 [(= t MPDVal.STR) (v.sval.decode)]
43 [(= t MPDVal.FLOAT) v.fval]
44 [(= t MPDVal.BOOL) v.bval]
45 [(= t MPDVal.RANGE)
46 (Range v.rval.start
47 (if (= -1 v.rval.end) None v.rval.end))]
48 [(= t MPDVal.CMD)
49 (Command v.cmdval.contents)]
50 [(= t MPDVal.EXPR)
51 (raise (NotImplementedError "Expression not implemented yet"))]
52 [True (raise (TypeError (+ "unknown type " (string t))))]))))
53
54(defn parse-command [string]
55 (setv inptr (ctypes.c_char_p))
56 (setv inptr.value (string.encode))
57 (let [outptr (parse inptr)]
58 (if (bool outptr)
59 (let [cmd (Command outptr.contents)]
60 (freecmd outptr)
61 cmd)
62 (raise (ValueError "not a valid MPD command")))))