libmpdserver

Parser combinator library for MPD client commands

git clone https://git.8pit.net/libmpdserver.git

  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}