diff --git a/src/main/lkt.c b/src/main/lkt.c index 94114a9475e01a9b5a7c1da0275c6280a22b2a30..cbf08f2c7a2ac04778a4557dfbc88b4068d3dd2d 100644 --- a/src/main/lkt.c +++ b/src/main/lkt.c @@ -25,26 +25,28 @@ #include <stdarg.h> #include <limits.h> -#define LKT_KEY_VALUE_SEP ": \n\t\0" -#define STR_MATCH(str1, str2) (! strcasecmp(str1, str2)) -#define STR_NMATCH(str1, str2, n) (! strncasecmp(str1, str2, n)) +#define LKT_KEY_VALUE_SEP ": \n\t\0" +#define STR_MATCH(str1, str2) (! strcasecmp(str1, str2)) +#define STR_NMATCH(str1, str2, n) (! strncasecmp(str1, str2, n)) +#define fail_if(cond, msg) if (cond) { LOG_ERROR("%s", msg); exit(EXIT_FAILURE); } +#define fail(msg) { LOG_ERROR("%s", msg); exit(EXIT_FAILURE); } +#define lkt_send_and_exit(buffer, len) exit(write_socket(lkt_connect(), buffer, len)) +#define write_socket(sock, buff, len) (fwrite(buff, sizeof(char), len, sock) != len) -static noreturn inline void -fail(const char *message) -{ - LOG_ERROR("%s", message); - exit(EXIT_FAILURE); +#define exit_with_status(sock, buff) { \ + fail_if(read_socket(sock, buff, 2) == 0, "ACK"); \ + fail_if(buff[0] != 'O' && buff[1] != 'K', "ACK"); \ + exit(EXIT_SUCCESS); \ } /* Type definition. */ typedef struct { - const char *host; /* Serveur host, may be resolved. */ - const char *port; /* Serveur port. */ - const char *pwd; /* The password for the user. */ - const char **argv; /* Pointer to the argv from the main - function. */ - int argc; /* Argument count of the args. */ + const char *host; /* Serveur host, may be resolved. */ + const char *port; /* Serveur port. */ + const char *pwd; /* The password for the user. */ + const char **argv; /* Pointer to the argv from the main function. */ + int argc; /* Argument count of the args. */ } args_t; /* Global variables. */ @@ -61,7 +63,6 @@ lkt_valid_type(const char *type) { return (STR_MATCH(type, "all") || STR_MATCH(type, "any") || - STR_MATCH(type, "a") || STR_MATCH(type, "id") || STR_MATCH(type, "title") || STR_MATCH(type, "type") || @@ -78,31 +79,15 @@ static int read_socket(FILE *sock, char *buff, size_t max_len) { size_t i, len; - for (i = 0; i < max_len; ++i) { len = fread(buff + i, sizeof(char), 1, sock); if (buff[i] == '\n' || len != 1) - goto end; + return i; } - -end: return i; } -static inline int -write_socket(FILE *sock, const char *buff, size_t len) -{ - int ret = 1; - - if (fwrite(buff, sizeof(char), len, sock) != len) - goto end; - - ret = 0; -end: - return ret; -} - static int write_socket_format(FILE *sock, const char *format, ...) { @@ -169,12 +154,6 @@ lkt_connect(void) return sock; } -static noreturn inline void -lkt_send_and_exit(const char *buffer, size_t len) -{ - exit(write_socket(lkt_connect(), buffer, len)); -} - static char * lkt_skip_key(char *buffer) { @@ -186,42 +165,18 @@ lkt_skip_key(char *buffer) /* Functions implementing options. */ -noreturn void -queue_clear__(struct lkt_cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the clear command takes no arguments"); - static const char cmd__[] = "clear\nclose\n"; - lkt_send_and_exit(cmd__, sizeof(cmd__)); -} - -noreturn void -queue_crop__(struct lkt_cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the crop command takes no arguments"); - static const char cmd__[] = "crop\nclose\n"; - lkt_send_and_exit(cmd__, sizeof(cmd__)); -} - - -noreturn void -next__(struct lkt_cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the next command takes no arguments"); - static const char cmd__[] = "next\nclose\n"; - lkt_send_and_exit(cmd__, sizeof(cmd__)); /* In bytes. */ -} - -noreturn void -prev__(struct lkt_cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the previous command takes no arguments"); - static const char cmd__[] = "previous\nclose\n"; - lkt_send_and_exit(cmd__, sizeof(cmd__)); /* In bytes. */ -} +#define just_send(func, msg) /* Just send a simple string functions */ \ + noreturn void func (struct lkt_cmd_args *args) { \ + fail_if(args->argc, "This command takes no arguments"); \ + lkt_send_and_exit(msg, sizeof(msg)); \ + } +just_send(queue_clear__, "clear\nclose\n") +just_send(queue_crop__, "crop\nclose\n") +just_send(next__, "next\nclose\n") +just_send(prev__, "previous\nclose\n") +just_send(stop__, "stop\nclose\n") +just_send(shuffle__, "shuffle\nplay\nclose\n") +#undef just_send noreturn void simple_send_with_password__(const char *cmd) @@ -285,15 +240,6 @@ update__(struct lkt_cmd_args *args) rescan_or_update__(args, "update"); } -noreturn void -stop__(struct lkt_cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the stop command takes no arguments"); - static const char cmd__[] = "stop\nclose\n"; - lkt_send_and_exit(cmd__, sizeof(cmd__)); /* In bytes. */ -} - noreturn void play__(struct lkt_cmd_args *args) { @@ -314,7 +260,7 @@ play__(struct lkt_cmd_args *args) FILE *sock = lkt_connect(); if (write_socket(sock, status__, sizeof(status__))) /* In bytes. */ - goto error; + exit(EXIT_FAILURE); for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); @@ -336,12 +282,9 @@ play__(struct lkt_cmd_args *args) else lkt_send_and_exit(cmd_pause__, sizeof(cmd_pause__)); /* In bytes. */ - goto error; + exit(EXIT_FAILURE); } } - -error: - exit(EXIT_FAILURE); } noreturn void @@ -374,7 +317,7 @@ current__(struct lkt_cmd_args *args) FILE *sock = lkt_connect(); if (write_socket(sock, current_song__, sizeof(current_song__))) /* In bytes. */ - goto error; + exit(EXIT_FAILURE); assert(mem = calloc(6 * LKT_MESSAGE_MAX, sizeof(char))); assert(memset(mem, 0, 6 * LKT_MESSAGE_MAX * sizeof(char))); @@ -389,35 +332,35 @@ current__(struct lkt_cmd_args *args) for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) - goto error; + exit(EXIT_FAILURE); const size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); char *value = lkt_skip_key(buff); const size_t value_size = strcspn(value, "\n\0") * sizeof(char); - if (! strncasecmp("title", buff, len)) + if (STR_NMATCH("title", buff, len)) assert(memcpy(title, value, value_size)); - if (! strncasecmp("author", buff, len)) + if (STR_NMATCH("author", buff, len)) assert(memcpy(author, value, value_size)); - if (! strncasecmp("source", buff, len)) + if (STR_NMATCH("source", buff, len)) assert(memcpy(source, value, value_size)); - if (!strncasecmp("type", buff, len)) + if (STR_NMATCH("type", buff, len)) assert(memcpy(type, value, value_size)); - if (!strncasecmp("language", buff, len)) + if (STR_NMATCH("language", buff, len)) assert(memcpy(language, value, value_size)); - if (!strncasecmp("category", buff, len)) + if (STR_NMATCH("category", buff, len)) assert(memcpy(category, value, value_size)); /* At this point every key has been parsed. */ - if (! strncmp(buff, "OK", 2)) + if (STR_NMATCH(buff, "OK", 2)) goto ok; - else if (! strncmp(buff, "ACK", 3)) - goto error; + else if (STR_NMATCH(buff, "ACK", 3)) + exit(EXIT_FAILURE); } ok: @@ -429,8 +372,6 @@ ok: category, source, type, title, author); exit(EXIT_SUCCESS); -error: - exit(EXIT_FAILURE); } noreturn void @@ -449,7 +390,6 @@ queue_pop__(struct lkt_cmd_args *args) goto error; #define assign_int(str, var) if (! strncmp(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } - for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) @@ -459,11 +399,12 @@ queue_pop__(struct lkt_cmd_args *args) assign_int("songid", songid) /* At this point every key has been parsed. */ - if (! strncmp(buff, "OK", 2)) + if (STR_NMATCH(buff, "OK", 2)) break; - else if (! strncmp(buff, "ACK", 3)) + else if (STR_NMATCH(buff, "ACK", 3)) goto error; } +#undef assign_int fclose(sock); sock = lkt_connect(); @@ -498,9 +439,8 @@ status__(struct lkt_cmd_args *args) if (write_socket(sock, status_str__, strlen(status_str__))) goto error; -#define assign_flag(str, f) if (! strncmp(buff, str, len) && (atoi(lkt_skip_key(buff)) == 1)) { flags[it++] = f; continue; } -#define assign_int(str, var) if (! strncmp(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } - +#define assign_flag(str, f) if (STR_NMATCH(buff, str, len) && (atoi(lkt_skip_key(buff)) == 1)) { flags[it++] = f; continue; } +#define assign_int(str, var) if (STR_NMATCH(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) @@ -508,7 +448,7 @@ status__(struct lkt_cmd_args *args) size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); - if (! strncmp(buff, "state", len)) { + if (STR_NMATCH(buff, "state", len)) { char *it = lkt_skip_key(buff); play = ! strncmp(it, "play", 4); stopped = ! strncmp(it, "stop", 4); @@ -526,11 +466,13 @@ status__(struct lkt_cmd_args *args) assign_int("playlistlength", plt_len) /* At this point every key has been parsed. */ - if (! strncmp(buff, "OK", 2)) + if (STR_NMATCH(buff, "OK", 2)) goto print; - else if (! strncmp(buff, "ACK", 3)) + else if (STR_NMATCH(buff, "ACK", 3)) goto error; } +#undef assign_flag +#undef assign_int print: fclose(sock); @@ -551,16 +493,6 @@ error: exit(ret); } -noreturn void -shuffle__(struct lkt_cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the shuffle command takes no arguments"); - - static const char *const shuffle_str__ = "shuffle\nplay\nclose\n"; - lkt_send_and_exit(shuffle_str__, strlen(shuffle_str__)); -} - noreturn void queue_delete__(struct lkt_cmd_args *args) { @@ -575,23 +507,16 @@ queue_delete__(struct lkt_cmd_args *args) sscanf(args->argv[0], "%d", &dumy); if (dumy != 0) { write_socket_format(sock, cmd_id__, dumy); - goto check; + exit_with_status(sock, buff); } fail("Invalid argument"); - -check: - assert(read_socket(sock, buff, 2) > 0); - if (buff[0] == 'O' && buff[1] == 'K') - exit(EXIT_SUCCESS); - else - exit(EXIT_FAILURE); } noreturn void queue_add__(struct lkt_cmd_args *args) { - char buff[LKT_MESSAGE_MAX]; + char buff[3]; int i; if (args->argc < 1) @@ -614,24 +539,13 @@ queue_add__(struct lkt_cmd_args *args) /* Here we have `i == argc - 1`. */ write_socket(sock, args->argv[i], strlen(args->argv[i])); write_socket(sock, "\n", sizeof(char)); - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - assert(read_socket(sock, buff, LKT_MESSAGE_MAX - 1) > 0); - - if (! strncmp(buff, "OK", 2)) - exit(EXIT_SUCCESS); - - else if (! strncmp(buff, "ACK", 3)) - exit(EXIT_FAILURE); - } + exit_with_status(sock, buff); } noreturn void queue_seek__(struct lkt_cmd_args *args) { - if (args->argc != 1) - fail("The seek command needs one argument: queue seek <id>"); + fail_if(args->argc != 1, "The seek command needs one argument: queue seek <id>"); char *endptr, buf[3]; long id = strtol(args->argv[0], &endptr, 0); @@ -646,8 +560,7 @@ queue_seek__(struct lkt_cmd_args *args) FILE *sock = lkt_connect(); write_socket_format(sock, "playid %ld\n", id); - read_socket(sock, buf, 2); - exit(!strncmp(buf, "OK", 2)); + exit_with_status(sock, buf); } noreturn void @@ -693,9 +606,9 @@ redo: } } - if (! strncmp(buff, "OK", 2)) + if (STR_NMATCH(buff, "OK", 2)) exit(EXIT_SUCCESS); - else if (! strncmp(buff, "ACK", 3)) + else if (STR_NMATCH(buff, "ACK", 3)) exit(EXIT_FAILURE); fprintf(stdout, "%s", buff); @@ -731,7 +644,6 @@ queue_list__(struct lkt_cmd_args *args) fail("Communication error"); #define assign_int(str, var) if (! strncmp(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } - for (;;) { memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); if (read_socket(sock, buff, LKT_MESSAGE_MAX - 1) <= 0) @@ -741,11 +653,12 @@ queue_list__(struct lkt_cmd_args *args) assign_int("song", song_index); /* At this point every key has been parsed. */ - if (! strncmp(buff, "OK", 2)) + if (STR_NMATCH(buff, "OK", 2)) break; - else if (! strncmp(buff, "ACK", 3)) + else if (STR_NMATCH(buff, "ACK", 3)) exit(EXIT_FAILURE); } +#undef assign_int fclose(sock); /* Get the content of the queue. */ @@ -768,11 +681,8 @@ plt_add__(struct lkt_cmd_args *args) char buff[2]; FILE *sock = lkt_connect(); - if (args->argc < 3) - fail("Invalid argument, need at least three arguments: plt add <plt> <query>"); - - if (!lkt_valid_type(args->argv[1])) - fail("Invalid argument, type for the query is invalid"); + fail_if(args->argc < 3, "Invalid argument, need at least three arguments: plt add <plt> <query>"); + fail_if(!lkt_valid_type(args->argv[1]), "Invalid argument, type for the query is invalid"); write_socket(sock, "playlistadd ", strlen("playlistadd ")); write_socket(sock, args->argv[0], strlen(args->argv[0])); @@ -788,12 +698,7 @@ plt_add__(struct lkt_cmd_args *args) /* Here we have `i == argc - 1`. */ write_socket(sock, args->argv[i], strlen(args->argv[i])); write_socket(sock, "\n", sizeof(char)); - - assert(read_socket(sock, buff, 2) > 0); - if (buff[0] == 'O' && buff[1] == 'K') - exit(EXIT_SUCCESS); - else - exit(EXIT_FAILURE); + exit_with_status(sock, buff); } noreturn void @@ -803,8 +708,7 @@ plt_delete__(struct lkt_cmd_args *args) char buff[2]; int i; - if (args->argc < 1) - fail("Invalid argument, need at least two arguments: plt delete <plt> <id>"); + fail_if(args->argc < 1, "Invalid argument"); write_socket(sock, "playlistdelete ", strlen("playlistdelete ")); write_socket(sock, args->argv[0], strlen(args->argv[0])); @@ -818,19 +722,13 @@ plt_delete__(struct lkt_cmd_args *args) /* Here we have `i == argc - 1`. */ write_socket(sock, args->argv[i], strlen(args->argv[i])); write_socket(sock, "\n", sizeof(char)); - - assert(read_socket(sock, buff, 2) > 0); - if (buff[0] == 'O' && buff[1] == 'K') - exit(EXIT_SUCCESS); - else - exit(EXIT_FAILURE); + exit_with_status(sock, buff); } noreturn void plt_destroy__(struct lkt_cmd_args *args) { - if (args->argc != 1) - fail("Invalid argument, you may only specify the name of the playlist to delete: plt destroy <plt>"); + fail_if(args->argc != 1, "Invalid argument"); FILE *sock = lkt_connect(); char buff[2]; @@ -839,19 +737,13 @@ plt_destroy__(struct lkt_cmd_args *args) write_socket(sock, "rm ", 3 * sizeof(char)); write_socket(sock, name, strlen(name)); write_socket(sock, "\n", sizeof(char)); - - assert(read_socket(sock, buff, 2) > 0); - if (buff[0] == 'O' && buff[1] == 'K') - exit(EXIT_SUCCESS); - else - exit(EXIT_FAILURE); + exit_with_status(sock, buff); } noreturn void plt_create__(struct lkt_cmd_args *args) { - if (args->argc != 1) - fail("Invalid argument, you may only specify the name of the playlist to create: plt create <plt>"); + fail_if(args->argc != 1, "Invalid argument"); FILE *sock = lkt_connect(); char buff[2]; @@ -860,12 +752,7 @@ plt_create__(struct lkt_cmd_args *args) write_socket(sock, "playlistadd ", strlen("playlistadd ")); write_socket(sock, name, strlen(name)); write_socket(sock, "\n", sizeof(char)); - - assert(read_socket(sock, buff, 2) > 0); - if (buff[0] == 'O' && buff[1] == 'K') - exit(EXIT_SUCCESS); - else - exit(EXIT_FAILURE); + exit_with_status(sock, buff); } /* Search functions. */ @@ -873,11 +760,8 @@ plt_create__(struct lkt_cmd_args *args) noreturn void search_with_cmd__(struct lkt_cmd_args *args, const char *cmd) { - if (args->argc < 2) - fail("Invalid number of arguments, need at least a valid query: search <action> <plt when action == plt> <query>"); - - if (!lkt_valid_type(args->argv[0])) - fail("Invalid type for the query"); + fail_if(args->argc < 2, "Invalid number of arguments"); + fail_if(!lkt_valid_type(args->argv[0]), "Invalid type for the query"); char buff[LKT_MESSAGE_MAX]; int continuation = 0, i; @@ -894,57 +778,30 @@ redo: memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); assert(read_socket(sock, buff, LKT_MESSAGE_MAX - 1) > 0); - if (! strncmp(buff, "continue:", strlen("continue:"))) { + if (STR_NMATCH(buff, "continue:", strlen("continue:"))) { continuation = atoi(lkt_skip_key(buff)); fclose(sock); goto redo; } - if (! strncmp(buff, "OK", 2)) + if (STR_NMATCH(buff, "OK", 2)) exit(EXIT_SUCCESS); - else if (! strncmp(buff, "ACK", 3)) + else if (STR_NMATCH(buff, "ACK", 3)) exit(EXIT_FAILURE); fprintf(stdout, "%s", buff); } } -noreturn void -search_get__(struct lkt_cmd_args *args) -{ - search_with_cmd__(args, "search"); -} - -noreturn void -search_add__(struct lkt_cmd_args *args) -{ - search_with_cmd__(args, "searchadd"); -} - -noreturn void -search_insert__(struct lkt_cmd_args *args) -{ - UNUSED(args); - fail("Not implemented"); -} - -noreturn void -search_plt__(struct lkt_cmd_args *args) -{ - search_with_cmd__(args, "listplaylist"); -} - -noreturn void -search_count__(struct lkt_cmd_args *args) -{ - search_with_cmd__(args, "count"); -} - -noreturn void -search_queue__(struct lkt_cmd_args *args) -{ - search_with_cmd__(args, "playlistfind"); -} +#define search_with_cmd(func, cmd) /* I don't want to write always the same things */ \ + noreturn void func (struct lkt_cmd_args *args) { search_with_cmd__(args, #cmd); } +search_with_cmd(search_get__, search) +search_with_cmd(search_add__, searchadd) +search_with_cmd(search_insert__, __insert) +search_with_cmd(search_plt__, listplaylist) +search_with_cmd(search_count__, count) +search_with_cmd(search_queue__, playlistfind) +#undef search_with_cmd /* Parsing stuff. */ @@ -986,41 +843,23 @@ static struct lkt_cmd_opt options_admin[] = { LKT_OPT_NULL, }; -noreturn void -admin__(struct lkt_cmd_args *args) -{ - if (args->argc == 0) - fail("Invalid argument, you must specify a sub command for the admin command"); - - lkt_cmd_parse(options_admin, args->argc, args->argv); -} +#define sub_command(name) /* Create sub-commands here */ \ + noreturn void name ## __(struct lkt_cmd_args *args) { \ + fail_if(!args->argc, "Invalid command, specify a sub command for " #name); \ + lkt_cmd_parse(options_ ## name, args->argc, args->argv); \ + } +sub_command(search) +sub_command(plt) +sub_command(admin) noreturn void queue__(struct lkt_cmd_args *args) { if (args->argc == 0) queue_list__(args); - lkt_cmd_parse(options_queue, args->argc, args->argv); } - -noreturn void -search__(struct lkt_cmd_args *args) -{ - if (args->argc == 0) - fail("Invalid argument, you must specify a sub command for the search command"); - - lkt_cmd_parse(options_search, args->argc, args->argv); -} - -noreturn void -plt__(struct lkt_cmd_args *args) -{ - if (args->argc == 0) - fail("Invalid argument, you must specify a sub command for the playlist command"); - - lkt_cmd_parse(options_plt, args->argc, args->argv); -} +#undef sub_command static struct lkt_cmd_opt options_[] = { { .name = "current", .call = current__ },