1#include <assert.h>
2#include <err.h>
3#include <stddef.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "mpdserver.h"
9
10static void format_cmd(int, mpd_command_t *);
11
12static char *
13format_op(mpd_operation_t op)
14{
15 switch (op) {
16 case MPD_OP_NONE:
17 return "";
18 case MPD_OP_EQUAL:
19 return "==";
20 case MPD_OP_NEQUAL:
21 return "!=";
22 case MPD_OP_CONTAINS:
23 return "contains";
24 case MPD_OP_MATCH:
25 return "=~";
26 case MPD_OP_NMATCH:
27 return "!~";
28 default:
29 assert(0);
30 }
31}
32
33static char *
34format_val(mpd_val_t val)
35{
36 switch (val) {
37 case MPD_VAL_INT:
38 return "int";
39 case MPD_VAL_UINT:
40 return "uint";
41 case MPD_VAL_STR:
42 return "str";
43 case MPD_VAL_FLOAT:
44 return "float";
45 case MPD_VAL_BOOL:
46 return "bool";
47 case MPD_VAL_RANGE:
48 return "range";
49 case MPD_VAL_EXPR:
50 return "expr";
51 case MPD_VAL_CMD:
52 return "cmd";
53 default:
54 assert(0);
55 return NULL;
56 }
57}
58
59static void
60format_expr(int ident, mpd_expression_t *expr)
61{
62 printf("%*sname: %s\n", ident, "", expr->name);
63 printf("%*soperation: %s\n", ident, "", format_op(expr->op));
64
65 printf("%*sargument: ", ident, "");
66 if (!strcmp(expr->name, "AND") || !strcmp(expr->name, "NOT")) {
67 printf("\n");
68 format_expr(ident + 2, expr->o1.expr);
69 } else {
70 printf("%s\n", expr->o1.str);
71 }
72
73 if (expr->next) {
74 printf("%*snext:\n", ident, "");
75 format_expr(ident + 2, expr->next);
76 }
77}
78
79static void
80format_arg(int ident, mpd_argument_t *arg)
81{
82 switch (arg->type) {
83 case MPD_VAL_INT:
84 printf("%d\n", arg->v.ival);
85 break;
86 case MPD_VAL_UINT:
87 printf("%u\n", arg->v.uval);
88 break;
89 case MPD_VAL_STR:
90 printf("%s\n", arg->v.sval);
91 break;
92 case MPD_VAL_FLOAT:
93 printf("%.1f\n", arg->v.fval);
94 break;
95 case MPD_VAL_BOOL:
96 printf("%s\n", (arg->v.bval) ? "true" : "false");
97 break;
98 case MPD_VAL_RANGE:
99 printf("%zu:%zd\n", arg->v.rval.start, arg->v.rval.end);
100 break;
101 case MPD_VAL_EXPR:
102 printf("\n");
103 format_expr(ident + 2, arg->v.eval);
104 break;
105 case MPD_VAL_CMD:
106 printf("\n");
107 format_cmd(ident + 2, arg->v.cmdval);
108 break;
109 default:
110 errx(EXIT_FAILURE, "unsupported type: %u\n", arg->type);
111 break;
112 }
113}
114
115static void
116format_cmd(int ident, mpd_command_t *cmd)
117{
118 size_t i;
119 mpd_argument_t *arg;
120
121 printf("%*sname: %s\n", ident, "", cmd->name);
122 if (!cmd->argc)
123 printf("%*sargv: []\n", ident, "");
124 else
125 printf("%*sargv:\n", ident, "");
126
127 ident += 2;
128 for (i = 0; i < cmd->argc; i++) {
129 arg = cmd->argv[i];
130
131 printf("%*s- type: %s\n", ident, "", format_val(arg->type));
132 ident += 2;
133
134 printf("%*svalue: ", ident, "");
135 format_arg(ident, arg);
136
137 ident -= 2;
138 }
139}
140
141static bool
142is_lststart(char *str)
143{
144 return !strcmp(str, "command_list_begin\n") ||
145 !(strcmp(str, "command_list_ok_begin\n"));
146}
147
148static bool
149is_lstend(char *str)
150{
151 return !strcmp(str, "command_list_end\n");
152}
153
154static char *
155read_command(FILE *stream)
156{
157 size_t nlen;
158 static size_t llen;
159 static char *line, *result;
160
161 while (getline(&line, &llen, stream) != -1) {
162 if (!result) {
163 if (!(result = strdup(line)))
164 err(EXIT_FAILURE, "strdup failed");
165
166 if (is_lststart(line))
167 continue;
168 else
169 break;
170 }
171
172 nlen = strlen(result) + strlen(line) + 1;
173 if (!(result = realloc(result, nlen)))
174 err(EXIT_FAILURE, "realloc failed");
175 strncpy(&result[strlen(result)], line, nlen - strlen(result));
176
177 if (is_lstend(line))
178 break;
179 }
180
181 free(line);
182 if (ferror(stdin))
183 err(EXIT_FAILURE, "ferror failed");
184
185 return result;
186}
187
188int
189main(void)
190{
191 int ret;
192 char *input;
193 mpd_command_t *cmd;
194
195 input = read_command(stdin); /* NULL if empty */
196 if (!(cmd = mpd_parse((input) ? input : ""))) {
197 ret = EXIT_FAILURE;
198 goto exit;
199 }
200
201 format_cmd(0, cmd);
202 mpd_free_command(cmd);
203
204 ret = EXIT_SUCCESS;
205exit:
206 free(input);
207 return ret;
208}