1#include <assert.h>2#include <err.h>3#include <stddef.h>4#include <stdio.h>5#include <stdlib.h>6#include <string.h>78#include "mpdserver.h"910static void format_cmd(int, mpd_command_t *);1112static 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}3233static 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}5859static void60format_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));6465 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 }7273 if (expr->next) {74 printf("%*snext:\n", ident, "");75 format_expr(ident + 2, expr->next);76 }77}7879static void80format_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}114115static void116format_cmd(int ident, mpd_command_t *cmd)117{118 size_t i;119 mpd_argument_t *arg;120121 printf("%*sname: %s\n", ident, "", cmd->name);122 if (!cmd->argc)123 printf("%*sargv: []\n", ident, "");124 else125 printf("%*sargv:\n", ident, "");126127 ident += 2;128 for (i = 0; i < cmd->argc; i++) {129 arg = cmd->argv[i];130131 printf("%*s- type: %s\n", ident, "", format_val(arg->type));132 ident += 2;133134 printf("%*svalue: ", ident, "");135 format_arg(ident, arg);136137 ident -= 2;138 }139}140141static bool142is_lststart(char *str)143{144 return !strcmp(str, "command_list_begin\n") ||145 !(strcmp(str, "command_list_ok_begin\n"));146}147148static bool149is_lstend(char *str)150{151 return !strcmp(str, "command_list_end\n");152}153154static char *155read_command(FILE *stream)156{157 size_t nlen;158 static size_t llen;159 static char *line, *result;160161 while (getline(&line, &llen, stream) != -1) {162 if (!result) {163 if (!(result = strdup(line)))164 err(EXIT_FAILURE, "strdup failed");165166 if (is_lststart(line))167 continue;168 else169 break;170 }171172 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));176177 if (is_lstend(line))178 break;179 }180181 free(line);182 if (ferror(stdin))183 err(EXIT_FAILURE, "ferror failed");184185 return result;186}187188int189main(void)190{191 int ret;192 char *input;193 mpd_command_t *cmd;194195 input = read_command(stdin); /* NULL if empty */196 if (!(cmd = mpd_parse((input) ? input : ""))) {197 ret = EXIT_FAILURE;198 goto exit;199 }200201 format_cmd(0, cmd);202 mpd_free_command(cmd);203204 ret = EXIT_SUCCESS;205exit:206 free(input);207 return ret;208}