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 single? [self]
15 (= self.start self.end))
16
17 (defn infinite? [self]
18 (not self.end))
19
20 (defn to-range [self &optional max]
21 (if (.single? self)
22 (range self.start (inc self.end))
23 (if (and (self.infinite?) (is None max))
24 (raise (ValueError "Range has infinite length and no maximum supplied"))
25 (range self.start self.end)))))
26
27(defclass Command [object]
28 (defn __init__ [self cmd]
29 (setv self.name (.decode cmd.name))
30 (let [args (self.argv-list cmd.argc cmd.argv)]
31 (setv self.args (list (map self.convert-argument args)))))
32
33 (defn list? [self]
34 (or (= self.name "command_list_begin")
35 (= self.name "command_list_ok_begin")))
36
37 (defn argv-list [self argc argv]
38 (lfor
39 idx (range argc)
40 (. (get argv idx) contents)))
41
42 (defn convert-argument [self arg]
43 (let [t arg.type v arg.v]
44 (cond
45 [(= t MPDVal.INT) v.ival]
46 [(= t MPDVal.UINT) v.uval]
47 [(= t MPDVal.STR) (v.sval.decode)]
48 [(= t MPDVal.FLOAT) v.fval]
49 [(= t MPDVal.BOOL) v.bval]
50 [(= t MPDVal.RANGE)
51 (Range v.rval.start
52 (if (= -1 v.rval.end) None v.rval.end))]
53 [(= t MPDVal.CMD)
54 (Command v.cmdval.contents)]
55 [(= t MPDVal.EXPR)
56 (raise (NotImplementedError "Expression not implemented yet"))]
57 [True (raise (TypeError (+ "unknown type " (str t))))]))))
58
59(defn parse-command [string]
60 (setv inptr (ctypes.c_char_p))
61 (setv inptr.value (string.encode))
62 (let [outptr (parse inptr)]
63 (if (bool outptr)
64 (let [cmd (Command outptr.contents)]
65 (freecmd outptr)
66 cmd)
67 (raise (ValueError "not a valid MPD command")))))