diff options
Diffstat (limited to 'src/command')
31 files changed, 604 insertions, 519 deletions
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx index 6a4b18198..bd232efda 100644 --- a/src/command/AllCommands.cxx +++ b/src/command/AllCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -35,8 +35,10 @@ #include "protocol/Result.hxx" #include "Partition.hxx" #include "client/Client.hxx" +#include "util/Macros.hxx" #include "util/Tokenizer.hxx" #include "util/Error.hxx" +#include "util/ConstBuffer.hxx" #ifdef ENABLE_SQLITE #include "StickerCommands.hxx" @@ -60,22 +62,22 @@ struct command { unsigned permission; int min; int max; - CommandResult (*handler)(Client &client, unsigned argc, char **argv); + CommandResult (*handler)(Client &client, ConstBuffer<const char *> args); }; /* don't be fooled, this is the command handler for "commands" command */ static CommandResult -handle_commands(Client &client, unsigned argc, char *argv[]); +handle_commands(Client &client, ConstBuffer<const char *> args); static CommandResult -handle_not_commands(Client &client, unsigned argc, char *argv[]); +handle_not_commands(Client &client, ConstBuffer<const char *> args); /** * The command registry. * * This array must be sorted! */ -static const struct command commands[] = { +static constexpr struct command commands[] = { { "add", PERMISSION_ADD, 1, 1, handle_add }, { "addid", PERMISSION_ADD, 1, 2, handle_addid }, { "addtagid", PERMISSION_ADD, 3, 3, handle_addtagid }, @@ -194,7 +196,7 @@ static const struct command commands[] = { { "volume", PERMISSION_CONTROL, 1, 1, handle_volume }, }; -static const unsigned num_commands = sizeof(commands) / sizeof(commands[0]); +static constexpr unsigned num_commands = ARRAY_SIZE(commands); static bool command_available(gcc_unused const Partition &partition, @@ -210,19 +212,27 @@ command_available(gcc_unused const Partition &partition, return neighbor_commands_available(partition.instance); #endif + if (strcmp(cmd->cmd, "save") == 0 || + strcmp(cmd->cmd, "rm") == 0 || + strcmp(cmd->cmd, "rename") == 0 || + strcmp(cmd->cmd, "playlistdelete") == 0 || + strcmp(cmd->cmd, "playlistmove") == 0 || + strcmp(cmd->cmd, "playlistclear") == 0 || + strcmp(cmd->cmd, "playlistadd") == 0 || + strcmp(cmd->cmd, "listplaylists") == 0) + return playlist_commands_available(); + return true; } /* don't be fooled, this is the command handler for "commands" command */ static CommandResult -handle_commands(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_commands(Client &client, gcc_unused ConstBuffer<const char *> args) { const unsigned permission = client.GetPermission(); - const struct command *cmd; for (unsigned i = 0; i < num_commands; ++i) { - cmd = &commands[i]; + const struct command *cmd = &commands[i]; if (cmd->permission == (permission & cmd->permission) && command_available(client.partition, cmd)) @@ -233,14 +243,12 @@ handle_commands(Client &client, } static CommandResult -handle_not_commands(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_not_commands(Client &client, gcc_unused ConstBuffer<const char *> args) { const unsigned permission = client.GetPermission(); - const struct command *cmd; for (unsigned i = 0; i < num_commands; ++i) { - cmd = &commands[i]; + const struct command *cmd = &commands[i]; if (cmd->permission != (permission & cmd->permission)) client_printf(client, "command: %s\n", cmd->cmd); @@ -249,7 +257,8 @@ handle_not_commands(Client &client, return CommandResult::OK; } -void command_init(void) +void +command_init() { #ifndef NDEBUG /* ensure that the command list is sorted */ @@ -258,7 +267,8 @@ void command_init(void) #endif } -void command_finish(void) +void +command_finish() { } @@ -266,13 +276,12 @@ static const struct command * command_lookup(const char *name) { unsigned a = 0, b = num_commands, i; - int cmp; /* binary search */ do { i = (a + b) / 2; - cmp = strcmp(name, commands[i].cmd); + const auto cmp = strcmp(name, commands[i].cmd); if (cmp == 0) return &commands[i]; else if (cmp < 0) @@ -286,11 +295,8 @@ command_lookup(const char *name) static bool command_check_request(const struct command *cmd, Client &client, - unsigned permission, unsigned argc, char *argv[]) + unsigned permission, ConstBuffer<const char *> args) { - const unsigned min = cmd->min + 1; - const unsigned max = cmd->max + 1; - if (cmd->permission != (permission & cmd->permission)) { command_error(client, ACK_ERROR_PERMISSION, "you don't have permission for \"%s\"", @@ -298,21 +304,24 @@ command_check_request(const struct command *cmd, Client &client, return false; } - if (min == 0) + const int min = cmd->min; + const int max = cmd->max; + + if (min < 0) return true; - if (min == max && max != argc) { + if (min == max && unsigned(max) != args.size) { command_error(client, ACK_ERROR_ARG, "wrong number of arguments for \"%s\"", - argv[0]); + cmd->cmd); return false; - } else if (argc < min) { + } else if (args.size < unsigned(min)) { command_error(client, ACK_ERROR_ARG, - "too few arguments for \"%s\"", argv[0]); + "too few arguments for \"%s\"", cmd->cmd); return false; - } else if (argc > max && max /* != 0 */ ) { + } else if (max >= 0 && args.size > unsigned(max)) { command_error(client, ACK_ERROR_ARG, - "too many arguments for \"%s\"", argv[0]); + "too many arguments for \"%s\"", cmd->cmd); return false; } else return true; @@ -320,25 +329,20 @@ command_check_request(const struct command *cmd, Client &client, static const struct command * command_checked_lookup(Client &client, unsigned permission, - unsigned argc, char *argv[]) + const char *cmd_name, ConstBuffer<const char *> args) { - const struct command *cmd; - current_command = ""; - if (argc == 0) - return nullptr; - - cmd = command_lookup(argv[0]); + const struct command *cmd = command_lookup(cmd_name); if (cmd == nullptr) { command_error(client, ACK_ERROR_UNKNOWN, - "unknown command \"%s\"", argv[0]); + "unknown command \"%s\"", cmd_name); return nullptr; } current_command = cmd->cmd; - if (!command_check_request(cmd, client, permission, argc, argv)) + if (!command_check_request(cmd, client, permission, args)) return nullptr; return cmd; @@ -348,17 +352,18 @@ CommandResult command_process(Client &client, unsigned num, char *line) { Error error; - char *argv[COMMAND_ARGV_MAX] = { nullptr }; - const struct command *cmd; - CommandResult ret = CommandResult::ERROR; command_list_num = num; /* get the command name (first word on the line) */ + /* we have to set current_command because command_error() + expects it to be set */ Tokenizer tokenizer(line); - argv[0] = tokenizer.NextWord(error); - if (argv[0] == nullptr) { + + const char *const cmd_name = current_command = + tokenizer.NextWord(error); + if (cmd_name == nullptr) { current_command = ""; if (tokenizer.IsEnd()) command_error(client, ACK_ERROR_UNKNOWN, @@ -374,38 +379,41 @@ command_process(Client &client, unsigned num, char *line) return CommandResult::FINISH; } - unsigned argc = 1; + char *argv[COMMAND_ARGV_MAX]; + ConstBuffer<const char *> args(argv, 0); /* now parse the arguments (quoted or unquoted) */ - while (argc < COMMAND_ARGV_MAX && - (argv[argc] = - tokenizer.NextParam(error)) != nullptr) - ++argc; - - /* some error checks; we have to set current_command because - command_error() expects it to be set */ - - current_command = argv[0]; - - if (argc >= COMMAND_ARGV_MAX) { - command_error(client, ACK_ERROR_ARG, "Too many arguments"); - current_command = nullptr; - return CommandResult::ERROR; - } - - if (!tokenizer.IsEnd()) { - command_error(client, ACK_ERROR_ARG, "%s", error.GetMessage()); - current_command = nullptr; - return CommandResult::ERROR; + while (true) { + if (args.size == COMMAND_ARGV_MAX) { + command_error(client, ACK_ERROR_ARG, + "Too many arguments"); + current_command = nullptr; + return CommandResult::ERROR; + } + + char *a = tokenizer.NextParam(error); + if (a == nullptr) { + if (tokenizer.IsEnd()) + break; + + command_error(client, ACK_ERROR_ARG, "%s", error.GetMessage()); + current_command = nullptr; + return CommandResult::ERROR; + } + + argv[args.size++] = a; } /* look up and invoke the command handler */ - cmd = command_checked_lookup(client, client.GetPermission(), - argc, argv); - if (cmd) - ret = cmd->handler(client, argc, argv); + const struct command *cmd = + command_checked_lookup(client, client.GetPermission(), + cmd_name, args); + + CommandResult ret = cmd + ? cmd->handler(client, args) + : CommandResult::ERROR; current_command = nullptr; command_list_num = 0; diff --git a/src/command/AllCommands.hxx b/src/command/AllCommands.hxx index b7834a8de..e3405b034 100644 --- a/src/command/AllCommands.hxx +++ b/src/command/AllCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -24,9 +24,11 @@ class Client; -void command_init(void); +void +command_init(); -void command_finish(void); +void +command_finish(); CommandResult command_process(Client &client, unsigned num, char *line); diff --git a/src/command/CommandError.cxx b/src/command/CommandError.cxx index 89085fc68..da0571295 100644 --- a/src/command/CommandError.cxx +++ b/src/command/CommandError.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/command/CommandError.hxx b/src/command/CommandError.hxx index b48baa5bf..6c42ed960 100644 --- a/src/command/CommandError.hxx +++ b/src/command/CommandError.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/command/CommandListBuilder.cxx b/src/command/CommandListBuilder.cxx index 477c246ff..e2c7f95a5 100644 --- a/src/command/CommandListBuilder.cxx +++ b/src/command/CommandListBuilder.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/command/CommandListBuilder.hxx b/src/command/CommandListBuilder.hxx index 0747c4697..d2ca9d914 100644 --- a/src/command/CommandListBuilder.hxx +++ b/src/command/CommandListBuilder.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/command/CommandResult.hxx b/src/command/CommandResult.hxx index a2e968fb6..13641ec39 100644 --- a/src/command/CommandResult.hxx +++ b/src/command/CommandResult.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx index a3ea8d0ae..66ca2c279 100644 --- a/src/command/DatabaseCommands.cxx +++ b/src/command/DatabaseCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -32,6 +32,7 @@ #include "util/Error.hxx" #include "SongFilter.hxx" #include "protocol/Result.hxx" +#include "protocol/ArgParser.hxx" #include "BulkEdit.hxx" #include <string.h> @@ -49,12 +50,10 @@ handle_listfiles_db(Client &client, const char *uri) } CommandResult -handle_lsinfo2(Client &client, unsigned argc, char *argv[]) +handle_lsinfo2(Client &client, ConstBuffer<const char *> args) { - const char *const uri = argc == 2 - ? argv[1] - /* default is root directory */ - : ""; + /* default is root directory */ + const char *const uri = args.IsEmpty() ? "" : args.front(); const DatabaseSelection selection(uri, false); @@ -66,9 +65,17 @@ handle_lsinfo2(Client &client, unsigned argc, char *argv[]) } static CommandResult -handle_match(Client &client, unsigned argc, char *argv[], bool fold_case) +handle_match(Client &client, ConstBuffer<const char *> args, bool fold_case) { - ConstBuffer<const char *> args(argv + 1, argc - 1); + unsigned window_start = 0, window_end = std::numeric_limits<int>::max(); + if (args.size >= 2 && strcmp(args[args.size - 2], "window") == 0) { + if (!check_range(client, &window_start, &window_end, + args.back())) + return CommandResult::ERROR; + + args.pop_back(); + args.pop_back(); + } SongFilter filter; if (!filter.Parse(args, fold_case)) { @@ -79,28 +86,27 @@ handle_match(Client &client, unsigned argc, char *argv[], bool fold_case) const DatabaseSelection selection("", true, &filter); Error error; - return db_selection_print(client, selection, true, false, error) + return db_selection_print(client, selection, true, false, + window_start, window_end, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_find(Client &client, unsigned argc, char *argv[]) +handle_find(Client &client, ConstBuffer<const char *> args) { - return handle_match(client, argc, argv, false); + return handle_match(client, args, false); } CommandResult -handle_search(Client &client, unsigned argc, char *argv[]) +handle_search(Client &client, ConstBuffer<const char *> args) { - return handle_match(client, argc, argv, true); + return handle_match(client, args, true); } static CommandResult -handle_match_add(Client &client, unsigned argc, char *argv[], bool fold_case) +handle_match_add(Client &client, ConstBuffer<const char *> args, bool fold_case) { - ConstBuffer<const char *> args(argv + 1, argc - 1); - SongFilter filter; if (!filter.Parse(args, fold_case)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); @@ -117,21 +123,20 @@ handle_match_add(Client &client, unsigned argc, char *argv[], bool fold_case) } CommandResult -handle_findadd(Client &client, unsigned argc, char *argv[]) +handle_findadd(Client &client, ConstBuffer<const char *> args) { - return handle_match_add(client, argc, argv, false); + return handle_match_add(client, args, false); } CommandResult -handle_searchadd(Client &client, unsigned argc, char *argv[]) +handle_searchadd(Client &client, ConstBuffer<const char *> args) { - return handle_match_add(client, argc, argv, true); + return handle_match_add(client, args, true); } CommandResult -handle_searchaddpl(Client &client, unsigned argc, char *argv[]) +handle_searchaddpl(Client &client, ConstBuffer<const char *> args) { - ConstBuffer<const char *> args(argv + 1, argc - 1); const char *playlist = args.shift(); SongFilter filter; @@ -152,10 +157,8 @@ handle_searchaddpl(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_count(Client &client, unsigned argc, char *argv[]) +handle_count(Client &client, ConstBuffer<const char *> args) { - ConstBuffer<const char *> args(argv + 1, argc - 1); - TagType group = TAG_NUM_OF_ITEM_TYPES; if (args.size >= 2 && strcmp(args[args.size - 2], "group") == 0) { const char *s = args[args.size - 1]; @@ -183,24 +186,21 @@ handle_count(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_listall(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_listall(Client &client, ConstBuffer<const char *> args) { - const char *directory = ""; - - if (argc == 2) - directory = argv[1]; + /* default is root directory */ + const char *const uri = args.IsEmpty() ? "" : args.front(); Error error; - return db_selection_print(client, DatabaseSelection(directory, true), + return db_selection_print(client, DatabaseSelection(uri, true), false, false, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_list(Client &client, unsigned argc, char *argv[]) +handle_list(Client &client, ConstBuffer<const char *> args) { - ConstBuffer<const char *> args(argv + 1, argc - 1); const char *tag_name = args.shift(); unsigned tagType = locate_parse_type(tag_name); @@ -271,15 +271,13 @@ handle_list(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_listallinfo(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_listallinfo(Client &client, ConstBuffer<const char *> args) { - const char *directory = ""; - - if (argc == 2) - directory = argv[1]; + /* default is root directory */ + const char *const uri = args.IsEmpty() ? "" : args.front(); Error error; - return db_selection_print(client, DatabaseSelection(directory, true), + return db_selection_print(client, DatabaseSelection(uri, true), true, false, error) ? CommandResult::OK : print_error(client, error); diff --git a/src/command/DatabaseCommands.hxx b/src/command/DatabaseCommands.hxx index 7abf89e0c..b731517f5 100644 --- a/src/command/DatabaseCommands.hxx +++ b/src/command/DatabaseCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,38 +23,39 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult handle_listfiles_db(Client &client, const char *uri); CommandResult -handle_lsinfo2(Client &client, unsigned argc, char *argv[]); +handle_lsinfo2(Client &client, ConstBuffer<const char *> args); CommandResult -handle_find(Client &client, unsigned argc, char *argv[]); +handle_find(Client &client, ConstBuffer<const char *> args); CommandResult -handle_findadd(Client &client, unsigned argc, char *argv[]); +handle_findadd(Client &client, ConstBuffer<const char *> args); CommandResult -handle_search(Client &client, unsigned argc, char *argv[]); +handle_search(Client &client, ConstBuffer<const char *> args); CommandResult -handle_searchadd(Client &client, unsigned argc, char *argv[]); +handle_searchadd(Client &client, ConstBuffer<const char *> args); CommandResult -handle_searchaddpl(Client &client, unsigned argc, char *argv[]); +handle_searchaddpl(Client &client, ConstBuffer<const char *> args); CommandResult -handle_count(Client &client, unsigned argc, char *argv[]); +handle_count(Client &client, ConstBuffer<const char *> args); CommandResult -handle_listall(Client &client, unsigned argc, char *argv[]); +handle_listall(Client &client, ConstBuffer<const char *> args); CommandResult -handle_list(Client &client, unsigned argc, char *argv[]); +handle_list(Client &client, ConstBuffer<const char *> args); CommandResult -handle_listallinfo(Client &client, unsigned argc, char *argv[]); +handle_listallinfo(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx index 1b6a11cf5..7673c0a2e 100644 --- a/src/command/FileCommands.cxx +++ b/src/command/FileCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@ #include "protocol/Ack.hxx" #include "protocol/Result.hxx" #include "client/Client.hxx" +#include "util/ConstBuffer.hxx" #include "util/CharUtil.hxx" #include "util/UriUtil.hxx" #include "util/Error.hxx" @@ -35,7 +36,7 @@ #include "TagFile.hxx" #include "storage/StorageInterface.hxx" #include "fs/AllocatedPath.hxx" -#include "fs/FileSystem.hxx" +#include "fs/FileInfo.hxx" #include "fs/DirectoryReader.hxx" #include "TimePrint.hxx" #include "ls.hxx" @@ -46,7 +47,7 @@ gcc_pure static bool -SkipNameFS(const char *name_fs) +SkipNameFS(PathTraitsFS::const_pointer name_fs) { return name_fs[0] == '.' && (name_fs[1] == 0 || @@ -55,9 +56,9 @@ SkipNameFS(const char *name_fs) gcc_pure static bool -skip_path(const char *name_fs) +skip_path(Path name_fs) { - return strchr(name_fs, '\n') != nullptr; + return name_fs.HasNewline(); } #if defined(WIN32) && GCC_CHECK_VERSION(4,6) @@ -89,7 +90,7 @@ handle_listfiles_local(Client &client, const char *path_utf8) while (reader.ReadEntry()) { const Path name_fs = reader.GetEntry(); - if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs.c_str())) + if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs)) continue; std::string name_utf8 = name_fs.ToUTF8(); @@ -98,20 +99,22 @@ handle_listfiles_local(Client &client, const char *path_utf8) const AllocatedPath full_fs = AllocatedPath::Build(path_fs, name_fs); - struct stat st; - if (!StatFile(full_fs, st, false)) + FileInfo fi; + if (!GetFileInfo(full_fs, fi, false)) continue; - if (S_ISREG(st.st_mode)) { + if (fi.IsRegular()) client_printf(client, "file: %s\n" "size: %" PRIu64 "\n", name_utf8.c_str(), - uint64_t(st.st_size)); - } else if (S_ISDIR(st.st_mode)) + fi.GetSize()); + else if (fi.IsDirectory()) client_printf(client, "directory: %s\n", name_utf8.c_str()); + else + continue; - time_print(client, "Last-Modified", st.st_mtime); + time_print(client, "Last-Modified", fi.GetModificationTime()); } return CommandResult::OK; @@ -201,12 +204,22 @@ read_file_comments(Client &client, const Path path_fs) } -CommandResult -handle_read_comments(Client &client, gcc_unused unsigned argc, char *argv[]) +static const char * +translate_uri(const char *uri) { - assert(argc == 2); + if (memcmp(uri, "file:///", 8) == 0) + /* drop the "file://", leave only an absolute path + (starting with a slash) */ + return uri + 7; + + return uri; +} - const char *const uri = argv[1]; +CommandResult +handle_read_comments(Client &client, ConstBuffer<const char *> args) +{ + assert(args.size == 1); + const char *const uri = translate_uri(args.front()); if (memcmp(uri, "file:///", 8) == 0) { /* read comments from arbitrary local file */ diff --git a/src/command/FileCommands.hxx b/src/command/FileCommands.hxx index 62835a82c..b5bc7b8b2 100644 --- a/src/command/FileCommands.hxx +++ b/src/command/FileCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,11 +23,12 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult handle_listfiles_local(Client &client, const char *path_utf8); CommandResult -handle_read_comments(Client &client, unsigned argc, char *argv[]); +handle_read_comments(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx index a86bdf30c..9f8f3d1d4 100644 --- a/src/command/MessageCommands.cxx +++ b/src/command/MessageCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ #include "Instance.hxx" #include "Partition.hxx" #include "protocol/Result.hxx" +#include "util/ConstBuffer.hxx" #include <set> #include <string> @@ -31,11 +32,12 @@ #include <assert.h> CommandResult -handle_subscribe(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_subscribe(Client &client, ConstBuffer<const char *> args) { - assert(argc == 2); + assert(args.size == 1); + const char *const channel_name = args[0]; - switch (client.Subscribe(argv[1])) { + switch (client.Subscribe(channel_name)) { case Client::SubscribeResult::OK: return CommandResult::OK; @@ -61,11 +63,12 @@ handle_subscribe(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_unsubscribe(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_unsubscribe(Client &client, ConstBuffer<const char *> args) { - assert(argc == 2); + assert(args.size == 1); + const char *const channel_name = args[0]; - if (client.Unsubscribe(argv[1])) + if (client.Unsubscribe(channel_name)) return CommandResult::OK; else { command_error(client, ACK_ERROR_NO_EXIST, @@ -75,10 +78,9 @@ handle_unsubscribe(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_channels(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_channels(Client &client, gcc_unused ConstBuffer<const char *> args) { - assert(argc == 1); + assert(args.IsEmpty()); std::set<std::string> channels; for (const auto &c : *client.partition.instance.client_list) @@ -93,9 +95,9 @@ handle_channels(Client &client, CommandResult handle_read_messages(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) + gcc_unused ConstBuffer<const char *> args) { - assert(argc == 1); + assert(args.IsEmpty()); while (!client.messages.empty()) { const ClientMessage &msg = client.messages.front(); @@ -109,19 +111,21 @@ handle_read_messages(Client &client, } CommandResult -handle_send_message(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_send_message(Client &client, ConstBuffer<const char *> args) { - assert(argc == 3); + assert(args.size == 2); - if (!client_message_valid_channel_name(argv[1])) { + const char *const channel_name = args[0]; + const char *const message_text = args[1]; + + if (!client_message_valid_channel_name(channel_name)) { command_error(client, ACK_ERROR_ARG, "invalid channel name"); return CommandResult::ERROR; } bool sent = false; - const ClientMessage msg(argv[1], argv[2]); + const ClientMessage msg(channel_name, message_text); for (auto &c : *client.partition.instance.client_list) if (c.PushMessage(msg)) sent = true; diff --git a/src/command/MessageCommands.hxx b/src/command/MessageCommands.hxx index ac8afe2fb..44dbfbddf 100644 --- a/src/command/MessageCommands.hxx +++ b/src/command/MessageCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,20 +23,21 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult -handle_subscribe(Client &client, unsigned argc, char *argv[]); +handle_subscribe(Client &client, ConstBuffer<const char *> args); CommandResult -handle_unsubscribe(Client &client, unsigned argc, char *argv[]); +handle_unsubscribe(Client &client, ConstBuffer<const char *> args); CommandResult -handle_channels(Client &client, unsigned argc, char *argv[]); +handle_channels(Client &client, ConstBuffer<const char *> args); CommandResult -handle_read_messages(Client &client, unsigned argc, char *argv[]); +handle_read_messages(Client &client, ConstBuffer<const char *> args); CommandResult -handle_send_message(Client &client, unsigned argc, char *argv[]); +handle_send_message(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/NeighborCommands.cxx b/src/command/NeighborCommands.cxx index 22e8adf9e..3c171bddb 100644 --- a/src/command/NeighborCommands.cxx +++ b/src/command/NeighborCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@ #include "protocol/Result.hxx" #include "neighbor/Glue.hxx" #include "neighbor/Info.hxx" +#include "util/ConstBuffer.hxx" #include <set> #include <string> @@ -38,8 +39,7 @@ neighbor_commands_available(const Instance &instance) } CommandResult -handle_listneighbors(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_listneighbors(Client &client, gcc_unused ConstBuffer<const char *> args) { const NeighborGlue *const neighbors = client.partition.instance.neighbors; diff --git a/src/command/NeighborCommands.hxx b/src/command/NeighborCommands.hxx index 7fb309aeb..c0f2a86b9 100644 --- a/src/command/NeighborCommands.hxx +++ b/src/command/NeighborCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -25,12 +25,13 @@ struct Instance; class Client; +template<typename T> struct ConstBuffer; gcc_pure bool neighbor_commands_available(const Instance &instance); CommandResult -handle_listneighbors(Client &client, unsigned argc, char *argv[]); +handle_listneighbors(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/OtherCommands.cxx b/src/command/OtherCommands.cxx index a924f77b5..9ca7567b9 100644 --- a/src/command/OtherCommands.cxx +++ b/src/command/OtherCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -37,6 +37,7 @@ #include "mixer/Volume.hxx" #include "util/UriUtil.hxx" #include "util/Error.hxx" +#include "util/ConstBuffer.hxx" #include "fs/AllocatedPath.hxx" #include "Stats.hxx" #include "Permission.hxx" @@ -68,8 +69,7 @@ print_spl_list(Client &client, const PlaylistVector &list) } CommandResult -handle_urlhandlers(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_urlhandlers(Client &client, gcc_unused ConstBuffer<const char *> args) { if (client.IsLocal()) client_puts(client, "handler: file://\n"); @@ -78,31 +78,27 @@ handle_urlhandlers(Client &client, } CommandResult -handle_decoders(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_decoders(Client &client, gcc_unused ConstBuffer<const char *> args) { decoder_list_print(client); return CommandResult::OK; } CommandResult -handle_tagtypes(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_tagtypes(Client &client, gcc_unused ConstBuffer<const char *> args) { tag_print_types(client); return CommandResult::OK; } CommandResult -handle_kill(gcc_unused Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_kill(gcc_unused Client &client, gcc_unused ConstBuffer<const char *> args) { return CommandResult::KILL; } CommandResult -handle_close(gcc_unused Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_close(gcc_unused Client &client, gcc_unused ConstBuffer<const char *> args) { return CommandResult::FINISH; } @@ -116,12 +112,10 @@ print_tag(TagType type, const char *value, void *ctx) } CommandResult -handle_listfiles(Client &client, unsigned argc, char *argv[]) +handle_listfiles(Client &client, ConstBuffer<const char *> args) { - const char *const uri = argc == 2 - ? argv[1] - /* default is root directory */ - : ""; + /* default is root directory */ + const char *const uri = args.IsEmpty() ? "" : args.front(); if (memcmp(uri, "file:///", 8) == 0) /* list local directory */ @@ -157,12 +151,10 @@ static constexpr tag_handler print_tag_handler = { }; CommandResult -handle_lsinfo(Client &client, unsigned argc, char *argv[]) +handle_lsinfo(Client &client, ConstBuffer<const char *> args) { - const char *const uri = argc == 2 - ? argv[1] - /* default is root directory */ - : ""; + /* default is root directory */ + const char *const uri = args.IsEmpty() ? "" : args.front(); if (memcmp(uri, "file:///", 8) == 0) { /* print information about an arbitrary local file */ @@ -207,7 +199,7 @@ handle_lsinfo(Client &client, unsigned argc, char *argv[]) } #ifdef ENABLE_DATABASE - CommandResult result = handle_lsinfo2(client, argc, argv); + CommandResult result = handle_lsinfo2(client, args); if (result != CommandResult::OK) return result; #endif @@ -265,14 +257,14 @@ handle_update(Client &client, Database &db, #endif static CommandResult -handle_update(Client &client, unsigned argc, char *argv[], bool discard) +handle_update(Client &client, ConstBuffer<const char *> args, bool discard) { #ifdef ENABLE_DATABASE const char *path = ""; - assert(argc <= 2); - if (argc == 2) { - path = argv[1]; + assert(args.size <= 1); + if (!args.IsEmpty()) { + path = args.front(); if (*path == 0 || strcmp(path, "/") == 0) /* backwards compatibility with MPD 0.15 */ @@ -292,8 +284,7 @@ handle_update(Client &client, unsigned argc, char *argv[], bool discard) if (db != nullptr) return handle_update(client, *db, path, discard); #else - (void)argc; - (void)argv; + (void)args; (void)discard; #endif @@ -302,24 +293,24 @@ handle_update(Client &client, unsigned argc, char *argv[], bool discard) } CommandResult -handle_update(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_update(Client &client, gcc_unused ConstBuffer<const char *> args) { - return handle_update(client, argc, argv, false); + return handle_update(client, args, false); } CommandResult -handle_rescan(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_rescan(Client &client, gcc_unused ConstBuffer<const char *> args) { - return handle_update(client, argc, argv, true); + return handle_update(client, args, true); } CommandResult -handle_setvol(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_setvol(Client &client, ConstBuffer<const char *> args) { unsigned level; bool success; - if (!check_unsigned(client, &level, argv[1])) + if (!check_unsigned(client, &level, args.front())) return CommandResult::ERROR; if (level > 100) { @@ -338,10 +329,10 @@ handle_setvol(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_volume(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_volume(Client &client, ConstBuffer<const char *> args) { int relative; - if (!check_int(client, &relative, argv[1])) + if (!check_int(client, &relative, args.front())) return CommandResult::ERROR; if (relative < -100 || relative > 100) { @@ -372,26 +363,24 @@ handle_volume(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_stats(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_stats(Client &client, gcc_unused ConstBuffer<const char *> args) { stats_print(client); return CommandResult::OK; } CommandResult -handle_ping(gcc_unused Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_ping(gcc_unused Client &client, gcc_unused ConstBuffer<const char *> args) { return CommandResult::OK; } CommandResult -handle_password(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_password(Client &client, ConstBuffer<const char *> args) { unsigned permission = 0; - if (getPermissionFromPassword(argv[1], &permission) < 0) { + if (getPermissionFromPassword(args.front(), &permission) < 0) { command_error(client, ACK_ERROR_PASSWORD, "incorrect password"); return CommandResult::ERROR; } @@ -402,8 +391,7 @@ handle_password(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_config(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_config(Client &client, gcc_unused ConstBuffer<const char *> args) { if (!client.IsLocal()) { command_error(client, ACK_ERROR_PERMISSION, @@ -423,17 +411,16 @@ handle_config(Client &client, } CommandResult -handle_idle(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_idle(Client &client, ConstBuffer<const char *> args) { unsigned flags = 0; - for (unsigned i = 1; i < argc; ++i) { - unsigned event = idle_parse_name(argv[i]); + for (const char *i : args) { + unsigned event = idle_parse_name(i); if (event == 0) { command_error(client, ACK_ERROR_ARG, "Unrecognized idle event: %s", - argv[i]); + i); return CommandResult::ERROR; } diff --git a/src/command/OtherCommands.hxx b/src/command/OtherCommands.hxx index 7cfa35dfb..c0b25dece 100644 --- a/src/command/OtherCommands.hxx +++ b/src/command/OtherCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,53 +23,54 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult -handle_urlhandlers(Client &client, unsigned argc, char *argv[]); +handle_urlhandlers(Client &client, ConstBuffer<const char *> args); CommandResult -handle_decoders(Client &client, unsigned argc, char *argv[]); +handle_decoders(Client &client, ConstBuffer<const char *> args); CommandResult -handle_tagtypes(Client &client, unsigned argc, char *argv[]); +handle_tagtypes(Client &client, ConstBuffer<const char *> args); CommandResult -handle_kill(Client &client, unsigned argc, char *argv[]); +handle_kill(Client &client, ConstBuffer<const char *> args); CommandResult -handle_close(Client &client, unsigned argc, char *argv[]); +handle_close(Client &client, ConstBuffer<const char *> args); CommandResult -handle_listfiles(Client &client, unsigned argc, char *argv[]); +handle_listfiles(Client &client, ConstBuffer<const char *> args); CommandResult -handle_lsinfo(Client &client, unsigned argc, char *argv[]); +handle_lsinfo(Client &client, ConstBuffer<const char *> args); CommandResult -handle_update(Client &client, unsigned argc, char *argv[]); +handle_update(Client &client, ConstBuffer<const char *> args); CommandResult -handle_rescan(Client &client, unsigned argc, char *argv[]); +handle_rescan(Client &client, ConstBuffer<const char *> args); CommandResult -handle_setvol(Client &client, unsigned argc, char *argv[]); +handle_setvol(Client &client, ConstBuffer<const char *> args); CommandResult -handle_volume(Client &client, unsigned argc, char *argv[]); +handle_volume(Client &client, ConstBuffer<const char *> args); CommandResult -handle_stats(Client &client, unsigned argc, char *argv[]); +handle_stats(Client &client, ConstBuffer<const char *> args); CommandResult -handle_ping(Client &client, unsigned argc, char *argv[]); +handle_ping(Client &client, ConstBuffer<const char *> args); CommandResult -handle_password(Client &client, unsigned argc, char *argv[]); +handle_password(Client &client, ConstBuffer<const char *> args); CommandResult -handle_config(Client &client, unsigned argc, char *argv[]); +handle_config(Client &client, ConstBuffer<const char *> args); CommandResult -handle_idle(Client &client, unsigned argc, char *argv[]); +handle_idle(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/OutputCommands.cxx b/src/command/OutputCommands.cxx index c69a0dd65..23eb7be5e 100644 --- a/src/command/OutputCommands.cxx +++ b/src/command/OutputCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -25,12 +25,15 @@ #include "protocol/ArgParser.hxx" #include "client/Client.hxx" #include "Partition.hxx" +#include "util/ConstBuffer.hxx" CommandResult -handle_enableoutput(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_enableoutput(Client &client, ConstBuffer<const char *> args) { + assert(args.size == 1); + unsigned device; - if (!check_unsigned(client, &device, argv[1])) + if (!check_unsigned(client, &device, args.front())) return CommandResult::ERROR; if (!audio_output_enable_index(client.partition.outputs, device)) { @@ -43,10 +46,12 @@ handle_enableoutput(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_disableoutput(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_disableoutput(Client &client, ConstBuffer<const char *> args) { + assert(args.size == 1); + unsigned device; - if (!check_unsigned(client, &device, argv[1])) + if (!check_unsigned(client, &device, args.front())) return CommandResult::ERROR; if (!audio_output_disable_index(client.partition.outputs, device)) { @@ -59,10 +64,12 @@ handle_disableoutput(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_toggleoutput(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_toggleoutput(Client &client, ConstBuffer<const char *> args) { + assert(args.size == 1); + unsigned device; - if (!check_unsigned(client, &device, argv[1])) + if (!check_unsigned(client, &device, args.front())) return CommandResult::ERROR; if (!audio_output_toggle_index(client.partition.outputs, device)) { @@ -75,9 +82,10 @@ handle_toggleoutput(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_devices(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_devices(Client &client, gcc_unused ConstBuffer<const char *> args) { + assert(args.IsEmpty()); + printAudioDevices(client, client.partition.outputs); return CommandResult::OK; diff --git a/src/command/OutputCommands.hxx b/src/command/OutputCommands.hxx index 8d6be0511..985f27416 100644 --- a/src/command/OutputCommands.hxx +++ b/src/command/OutputCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,17 +23,18 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult -handle_enableoutput(Client &client, unsigned argc, char *argv[]); +handle_enableoutput(Client &client, ConstBuffer<const char *> args); CommandResult -handle_disableoutput(Client &client, unsigned argc, char *argv[]); +handle_disableoutput(Client &client, ConstBuffer<const char *> args); CommandResult -handle_toggleoutput(Client &client, unsigned argc, char *argv[]); +handle_toggleoutput(Client &client, ConstBuffer<const char *> args); CommandResult -handle_devices(Client &client, unsigned argc, char *argv[]); +handle_devices(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx index cd7f42289..3686e7b90 100644 --- a/src/command/PlayerCommands.cxx +++ b/src/command/PlayerCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -30,6 +30,7 @@ #include "protocol/ArgParser.hxx" #include "AudioFormat.hxx" #include "ReplayGainConfig.hxx" +#include "util/ConstBuffer.hxx" #ifdef ENABLE_DATABASE #include "db/update/Service.hxx" @@ -56,22 +57,22 @@ #define COMMAND_STATUS_UPDATING_DB "updating_db" CommandResult -handle_play(Client &client, unsigned argc, char *argv[]) +handle_play(Client &client, ConstBuffer<const char *> args) { int song = -1; - if (argc == 2 && !check_int(client, &song, argv[1])) + if (!args.IsEmpty() && !check_int(client, &song, args.front())) return CommandResult::ERROR; PlaylistResult result = client.partition.PlayPosition(song); return print_playlist_result(client, result); } CommandResult -handle_playid(Client &client, unsigned argc, char *argv[]) +handle_playid(Client &client, ConstBuffer<const char *> args) { int id = -1; - if (argc == 2 && !check_int(client, &id, argv[1])) + if (!args.IsEmpty() && !check_int(client, &id, args.front())) return CommandResult::ERROR; PlaylistResult result = client.partition.PlayId(id); @@ -79,28 +80,25 @@ handle_playid(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_stop(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_stop(Client &client, gcc_unused ConstBuffer<const char *> args) { client.partition.Stop(); return CommandResult::OK; } CommandResult -handle_currentsong(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_currentsong(Client &client, gcc_unused ConstBuffer<const char *> args) { playlist_print_current(client, client.playlist); return CommandResult::OK; } CommandResult -handle_pause(Client &client, - unsigned argc, char *argv[]) +handle_pause(Client &client, ConstBuffer<const char *> args) { - if (argc == 2) { + if (!args.IsEmpty()) { bool pause_flag; - if (!check_bool(client, &pause_flag, argv[1])) + if (!check_bool(client, &pause_flag, args.front())) return CommandResult::ERROR; client.player_control.SetPause(pause_flag); @@ -111,8 +109,7 @@ handle_pause(Client &client, } CommandResult -handle_status(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_status(Client &client, gcc_unused ConstBuffer<const char *> args) { const char *state = nullptr; int song; @@ -182,6 +179,10 @@ handle_status(Client &client, player_status.elapsed_time.ToDoubleS(), player_status.bit_rate); + if (!player_status.total_time.IsNegative()) + client_printf(client, "duration: %1.3f\n", + player_status.total_time.ToDoubleS()); + if (player_status.audio_format.IsDefined()) { struct audio_format_string af_string; @@ -222,8 +223,7 @@ handle_status(Client &client, } CommandResult -handle_next(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_next(Client &client, gcc_unused ConstBuffer<const char *> args) { playlist &playlist = client.playlist; @@ -239,18 +239,17 @@ handle_next(Client &client, } CommandResult -handle_previous(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_previous(Client &client, gcc_unused ConstBuffer<const char *> args) { client.partition.PlayPrevious(); return CommandResult::OK; } CommandResult -handle_repeat(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_repeat(Client &client, ConstBuffer<const char *> args) { bool status; - if (!check_bool(client, &status, argv[1])) + if (!check_bool(client, &status, args.front())) return CommandResult::ERROR; client.partition.SetRepeat(status); @@ -258,10 +257,10 @@ handle_repeat(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_single(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_single(Client &client, ConstBuffer<const char *> args) { bool status; - if (!check_bool(client, &status, argv[1])) + if (!check_bool(client, &status, args.front())) return CommandResult::ERROR; client.partition.SetSingle(status); @@ -269,10 +268,10 @@ handle_single(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_consume(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_consume(Client &client, ConstBuffer<const char *> args) { bool status; - if (!check_bool(client, &status, argv[1])) + if (!check_bool(client, &status, args.front())) return CommandResult::ERROR; client.partition.SetConsume(status); @@ -280,10 +279,10 @@ handle_consume(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_random(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_random(Client &client, ConstBuffer<const char *> args) { bool status; - if (!check_bool(client, &status, argv[1])) + if (!check_bool(client, &status, args.front())) return CommandResult::ERROR; client.partition.SetRandom(status); @@ -292,22 +291,21 @@ handle_random(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_clearerror(gcc_unused Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_clearerror(gcc_unused Client &client, gcc_unused ConstBuffer<const char *> args) { client.player_control.ClearError(); return CommandResult::OK; } CommandResult -handle_seek(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_seek(Client &client, ConstBuffer<const char *> args) { unsigned song; SongTime seek_time; - if (!check_unsigned(client, &song, argv[1])) + if (!check_unsigned(client, &song, args[0])) return CommandResult::ERROR; - if (!ParseCommandArg(client, seek_time, argv[2])) + if (!ParseCommandArg(client, seek_time, args[1])) return CommandResult::ERROR; PlaylistResult result = @@ -316,14 +314,14 @@ handle_seek(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_seekid(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_seekid(Client &client, ConstBuffer<const char *> args) { unsigned id; SongTime seek_time; - if (!check_unsigned(client, &id, argv[1])) + if (!check_unsigned(client, &id, args[0])) return CommandResult::ERROR; - if (!ParseCommandArg(client, seek_time, argv[2])) + if (!ParseCommandArg(client, seek_time, args[1])) return CommandResult::ERROR; PlaylistResult result = @@ -332,9 +330,9 @@ handle_seekid(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_seekcur(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_seekcur(Client &client, ConstBuffer<const char *> args) { - const char *p = argv[1]; + const char *p = args.front(); bool relative = *p == '+' || *p == '-'; SignedSongTime seek_time; if (!ParseCommandArg(client, seek_time, p)) @@ -346,11 +344,11 @@ handle_seekcur(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_crossfade(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_crossfade(Client &client, ConstBuffer<const char *> args) { unsigned xfade_time; - if (!check_unsigned(client, &xfade_time, argv[1])) + if (!check_unsigned(client, &xfade_time, args.front())) return CommandResult::ERROR; client.player_control.SetCrossFade(xfade_time); @@ -358,11 +356,11 @@ handle_crossfade(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_mixrampdb(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_mixrampdb(Client &client, ConstBuffer<const char *> args) { float db; - if (!check_float(client, &db, argv[1])) + if (!check_float(client, &db, args.front())) return CommandResult::ERROR; client.player_control.SetMixRampDb(db); @@ -370,11 +368,11 @@ handle_mixrampdb(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_mixrampdelay(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_mixrampdelay(Client &client, ConstBuffer<const char *> args) { float delay_secs; - if (!check_float(client, &delay_secs, argv[1])) + if (!check_float(client, &delay_secs, args.front())) return CommandResult::ERROR; client.player_control.SetMixRampDelay(delay_secs); @@ -382,10 +380,9 @@ handle_mixrampdelay(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_replay_gain_mode(Client &client, - gcc_unused unsigned argc, char *argv[]) +handle_replay_gain_mode(Client &client, ConstBuffer<const char *> args) { - if (!replay_gain_set_mode_string(argv[1])) { + if (!replay_gain_set_mode_string(args.front())) { command_error(client, ACK_ERROR_ARG, "Unrecognized replay gain mode"); return CommandResult::ERROR; @@ -396,8 +393,7 @@ handle_replay_gain_mode(Client &client, } CommandResult -handle_replay_gain_status(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_replay_gain_status(Client &client, gcc_unused ConstBuffer<const char *> args) { client_printf(client, "replay_gain_mode: %s\n", replay_gain_get_mode_string()); diff --git a/src/command/PlayerCommands.hxx b/src/command/PlayerCommands.hxx index da7083f1e..1d7bfa366 100644 --- a/src/command/PlayerCommands.hxx +++ b/src/command/PlayerCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,68 +23,69 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult -handle_play(Client &client, unsigned argc, char *argv[]); +handle_play(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playid(Client &client, unsigned argc, char *argv[]); +handle_playid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_stop(Client &client, unsigned argc, char *argv[]); +handle_stop(Client &client, ConstBuffer<const char *> args); CommandResult -handle_currentsong(Client &client, unsigned argc, char *argv[]); +handle_currentsong(Client &client, ConstBuffer<const char *> args); CommandResult -handle_pause(Client &client, unsigned argc, char *argv[]); +handle_pause(Client &client, ConstBuffer<const char *> args); CommandResult -handle_status(Client &client, unsigned argc, char *argv[]); +handle_status(Client &client, ConstBuffer<const char *> args); CommandResult -handle_next(Client &client, unsigned argc, char *argv[]); +handle_next(Client &client, ConstBuffer<const char *> args); CommandResult -handle_previous(Client &client, unsigned argc, char *avg[]); +handle_previous(Client &client, ConstBuffer<const char *> args); CommandResult -handle_repeat(Client &client, unsigned argc, char *argv[]); +handle_repeat(Client &client, ConstBuffer<const char *> args); CommandResult -handle_single(Client &client, unsigned argc, char *argv[]); +handle_single(Client &client, ConstBuffer<const char *> args); CommandResult -handle_consume(Client &client, unsigned argc, char *argv[]); +handle_consume(Client &client, ConstBuffer<const char *> args); CommandResult -handle_random(Client &client, unsigned argc, char *argv[]); +handle_random(Client &client, ConstBuffer<const char *> args); CommandResult -handle_clearerror(Client &client, unsigned argc, char *argv[]); +handle_clearerror(Client &client, ConstBuffer<const char *> args); CommandResult -handle_seek(Client &client, unsigned argc, char *argv[]); +handle_seek(Client &client, ConstBuffer<const char *> args); CommandResult -handle_seekid(Client &client, unsigned argc, char *argv[]); +handle_seekid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_seekcur(Client &client, unsigned argc, char *argv[]); +handle_seekcur(Client &client, ConstBuffer<const char *> args); CommandResult -handle_crossfade(Client &client, unsigned argc, char *argv[]); +handle_crossfade(Client &client, ConstBuffer<const char *> args); CommandResult -handle_mixrampdb(Client &client, unsigned argc, char *argv[]); +handle_mixrampdb(Client &client, ConstBuffer<const char *> args); CommandResult -handle_mixrampdelay(Client &client, unsigned argc, char *argv[]); +handle_mixrampdelay(Client &client, ConstBuffer<const char *> args); CommandResult -handle_replay_gain_mode(Client &client, unsigned argc, char *argv[]); +handle_replay_gain_mode(Client &client, ConstBuffer<const char *> args); CommandResult -handle_replay_gain_status(Client &client, unsigned argc, char *argv[]); +handle_replay_gain_status(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx index c2b18064c..516726500 100644 --- a/src/command/PlaylistCommands.cxx +++ b/src/command/PlaylistCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -35,8 +35,17 @@ #include "protocol/ArgParser.hxx" #include "protocol/Result.hxx" #include "ls.hxx" +#include "Mapper.hxx" +#include "fs/AllocatedPath.hxx" #include "util/UriUtil.hxx" #include "util/Error.hxx" +#include "util/ConstBuffer.hxx" + +bool +playlist_commands_available() +{ + return !map_spl_path().IsNull(); +} static void print_spl_list(Client &client, const PlaylistVector &list) @@ -50,28 +59,30 @@ print_spl_list(Client &client, const PlaylistVector &list) } CommandResult -handle_save(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_save(Client &client, ConstBuffer<const char *> args) { - PlaylistResult result = spl_save_playlist(argv[1], client.playlist); - return print_playlist_result(client, result); + Error error; + return spl_save_playlist(args.front(), client.playlist, error) + ? CommandResult::OK + : print_error(client, error); } CommandResult -handle_load(Client &client, unsigned argc, char *argv[]) +handle_load(Client &client, ConstBuffer<const char *> args) { unsigned start_index, end_index; - if (argc < 3) { + if (args.size < 2) { start_index = 0; end_index = unsigned(-1); - } else if (!check_range(client, &start_index, &end_index, argv[2])) + } else if (!check_range(client, &start_index, &end_index, args[1])) return CommandResult::ERROR; const ScopeBulkEdit bulk_edit(client.partition); Error error; const SongLoader loader(client); - if (!playlist_open_into_queue(argv[1], + if (!playlist_open_into_queue(args.front(), start_index, end_index, client.playlist, client.player_control, loader, error)) @@ -81,94 +92,104 @@ handle_load(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_listplaylist(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_listplaylist(Client &client, ConstBuffer<const char *> args) { - if (playlist_file_print(client, argv[1], false)) + const char *const name = args.front(); + + if (playlist_file_print(client, name, false)) return CommandResult::OK; Error error; - return spl_print(client, argv[1], false, error) + return spl_print(client, name, false, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_listplaylistinfo(Client &client, - gcc_unused unsigned argc, char *argv[]) +handle_listplaylistinfo(Client &client, ConstBuffer<const char *> args) { - if (playlist_file_print(client, argv[1], true)) + const char *const name = args.front(); + + if (playlist_file_print(client, name, true)) return CommandResult::OK; Error error; - return spl_print(client, argv[1], true, error) + return spl_print(client, name, true, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_rm(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_rm(Client &client, ConstBuffer<const char *> args) { + const char *const name = args.front(); + Error error; - return spl_delete(argv[1], error) + return spl_delete(name, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_rename(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_rename(Client &client, ConstBuffer<const char *> args) { + const char *const old_name = args[0]; + const char *const new_name = args[1]; + Error error; - return spl_rename(argv[1], argv[2], error) + return spl_rename(old_name, new_name, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_playlistdelete(Client &client, - gcc_unused unsigned argc, char *argv[]) { - char *playlist = argv[1]; +handle_playlistdelete(Client &client, ConstBuffer<const char *> args) +{ + const char *const name = args[0]; unsigned from; - if (!check_unsigned(client, &from, argv[2])) + if (!check_unsigned(client, &from, args[1])) return CommandResult::ERROR; Error error; - return spl_remove_index(playlist, from, error) + return spl_remove_index(name, from, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_playlistmove(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_playlistmove(Client &client, ConstBuffer<const char *> args) { - char *playlist = argv[1]; + const char *const name = args.front(); unsigned from, to; - if (!check_unsigned(client, &from, argv[2])) + if (!check_unsigned(client, &from, args[1])) return CommandResult::ERROR; - if (!check_unsigned(client, &to, argv[3])) + if (!check_unsigned(client, &to, args[2])) return CommandResult::ERROR; Error error; - return spl_move_index(playlist, from, to, error) + return spl_move_index(name, from, to, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_playlistclear(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_playlistclear(Client &client, ConstBuffer<const char *> args) { + const char *const name = args.front(); + Error error; - return spl_clear(argv[1], error) + return spl_clear(name, error) ? CommandResult::OK : print_error(client, error); } CommandResult -handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_playlistadd(Client &client, ConstBuffer<const char *> args) { - char *playlist = argv[1]; - char *uri = argv[2]; + const char *const playlist = args[0]; + const char *const uri = args[1]; bool success; Error error; @@ -199,8 +220,7 @@ handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_listplaylists(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_listplaylists(Client &client, gcc_unused ConstBuffer<const char *> args) { Error error; const auto list = ListPlaylistFiles(error); diff --git a/src/command/PlaylistCommands.hxx b/src/command/PlaylistCommands.hxx index fba4e1318..5ac345e57 100644 --- a/src/command/PlaylistCommands.hxx +++ b/src/command/PlaylistCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -21,40 +21,46 @@ #define MPD_PLAYLIST_COMMANDS_HXX #include "CommandResult.hxx" +#include "Compiler.h" class Client; +template<typename T> struct ConstBuffer; + +gcc_const +bool +playlist_commands_available(); CommandResult -handle_save(Client &client, unsigned argc, char *argv[]); +handle_save(Client &client, ConstBuffer<const char *> args); CommandResult -handle_load(Client &client, unsigned argc, char *argv[]); +handle_load(Client &client, ConstBuffer<const char *> args); CommandResult -handle_listplaylist(Client &client, unsigned argc, char *argv[]); +handle_listplaylist(Client &client, ConstBuffer<const char *> args); CommandResult -handle_listplaylistinfo(Client &client, unsigned argc, char *argv[]); +handle_listplaylistinfo(Client &client, ConstBuffer<const char *> args); CommandResult -handle_rm(Client &client, unsigned argc, char *argv[]); +handle_rm(Client &client, ConstBuffer<const char *> args); CommandResult -handle_rename(Client &client, unsigned argc, char *argv[]); +handle_rename(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistdelete(Client &client, unsigned argc, char *argv[]); +handle_playlistdelete(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistmove(Client &client, unsigned argc, char *argv[]); +handle_playlistmove(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistclear(Client &client, unsigned argc, char *argv[]); +handle_playlistclear(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistadd(Client &client, unsigned argc, char *argv[]); +handle_playlistadd(Client &client, ConstBuffer<const char *> args); CommandResult -handle_listplaylists(Client &client, unsigned argc, char *argv[]); +handle_listplaylists(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx index d0b789eb1..d461170fd 100644 --- a/src/command/QueueCommands.cxx +++ b/src/command/QueueCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -43,25 +43,20 @@ #include <string.h> static const char * -translate_uri(Client &client, const char *uri) +translate_uri(const char *uri) { if (memcmp(uri, "file:///", 8) == 0) /* drop the "file://", leave only an absolute path (starting with a slash) */ return uri + 7; - if (PathTraitsUTF8::IsAbsolute(uri)) { - command_error(client, ACK_ERROR_NO_EXIST, "Malformed URI"); - return nullptr; - } - return uri; } CommandResult -handle_add(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_add(Client &client, ConstBuffer<const char *> args) { - const char *uri = argv[1]; + const char *uri = args.front(); if (memcmp(uri, "/", 2) == 0) /* this URI is malformed, but some clients are buggy and use "add /" to add the whole database, which @@ -70,9 +65,7 @@ handle_add(Client &client, gcc_unused unsigned argc, char *argv[]) here */ uri = ""; - uri = translate_uri(client, uri); - if (uri == nullptr) - return CommandResult::ERROR; + uri = translate_uri(uri); if (uri_has_scheme(uri) || PathTraitsUTF8::IsAbsolute(uri)) { const SongLoader loader(client); @@ -99,11 +92,9 @@ handle_add(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_addid(Client &client, unsigned argc, char *argv[]) +handle_addid(Client &client, ConstBuffer<const char *> args) { - const char *const uri = translate_uri(client, argv[1]); - if (uri == nullptr) - return CommandResult::ERROR; + const char *const uri = translate_uri(args.front()); const SongLoader loader(client); Error error; @@ -111,9 +102,9 @@ handle_addid(Client &client, unsigned argc, char *argv[]) if (added_id == 0) return print_error(client, error); - if (argc == 3) { + if (args.size == 2) { unsigned to; - if (!check_unsigned(client, &to, argv[2])) + if (!check_unsigned(client, &to, args[1])) return CommandResult::ERROR; PlaylistResult result = client.partition.MoveId(added_id, to); if (result != PlaylistResult::SUCCESS) { @@ -160,14 +151,14 @@ parse_time_range(const char *p, SongTime &start_r, SongTime &end_r) } CommandResult -handle_rangeid(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_rangeid(Client &client, ConstBuffer<const char *> args) { unsigned id; - if (!check_unsigned(client, &id, argv[1])) + if (!check_unsigned(client, &id, args.front())) return CommandResult::ERROR; SongTime start, end; - if (!parse_time_range(argv[2], start, end)) { + if (!parse_time_range(args[1], start, end)) { command_error(client, ACK_ERROR_ARG, "Bad range"); return CommandResult::ERROR; } @@ -182,11 +173,11 @@ handle_rangeid(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_delete(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_delete(Client &client, ConstBuffer<const char *> args) { unsigned start, end; - if (!check_range(client, &start, &end, argv[1])) + if (!check_range(client, &start, &end, args.front())) return CommandResult::ERROR; PlaylistResult result = client.partition.DeleteRange(start, end); @@ -194,11 +185,11 @@ handle_delete(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_deleteid(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_deleteid(Client &client, ConstBuffer<const char *> args) { unsigned id; - if (!check_unsigned(client, &id, argv[1])) + if (!check_unsigned(client, &id, args.front())) return CommandResult::ERROR; PlaylistResult result = client.partition.DeleteId(id); @@ -206,19 +197,17 @@ handle_deleteid(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_playlist(Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_playlist(Client &client, gcc_unused ConstBuffer<const char *> args) { playlist_print_uris(client, client.playlist); return CommandResult::OK; } CommandResult -handle_shuffle(gcc_unused Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_shuffle(gcc_unused Client &client, ConstBuffer<const char *> args) { unsigned start = 0, end = client.playlist.queue.GetLength(); - if (argc == 2 && !check_range(client, &start, &end, argv[1])) + if (args.size == 1 && !check_range(client, &start, &end, args.front())) return CommandResult::ERROR; client.partition.Shuffle(start, end); @@ -226,19 +215,18 @@ handle_shuffle(gcc_unused Client &client, } CommandResult -handle_clear(gcc_unused Client &client, - gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_clear(gcc_unused Client &client, gcc_unused ConstBuffer<const char *> args) { client.partition.ClearQueue(); return CommandResult::OK; } CommandResult -handle_plchanges(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_plchanges(Client &client, ConstBuffer<const char *> args) { uint32_t version; - if (!check_uint32(client, &version, argv[1])) + if (!check_uint32(client, &version, args.front())) return CommandResult::ERROR; playlist_print_changes_info(client, client.playlist, version); @@ -246,11 +234,11 @@ handle_plchanges(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_plchangesposid(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_plchangesposid(Client &client, ConstBuffer<const char *> args) { uint32_t version; - if (!check_uint32(client, &version, argv[1])) + if (!check_uint32(client, &version, args.front())) return CommandResult::ERROR; playlist_print_changes_position(client, client.playlist, version); @@ -258,12 +246,12 @@ handle_plchangesposid(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_playlistinfo(Client &client, unsigned argc, char *argv[]) +handle_playlistinfo(Client &client, ConstBuffer<const char *> args) { unsigned start = 0, end = std::numeric_limits<unsigned>::max(); bool ret; - if (argc == 2 && !check_range(client, &start, &end, argv[1])) + if (args.size == 1 && !check_range(client, &start, &end, args.front())) return CommandResult::ERROR; ret = playlist_print_info(client, client.playlist, start, end); @@ -275,11 +263,11 @@ handle_playlistinfo(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_playlistid(Client &client, unsigned argc, char *argv[]) +handle_playlistid(Client &client, ConstBuffer<const char *> args) { - if (argc >= 2) { + if (!args.IsEmpty()) { unsigned id; - if (!check_unsigned(client, &id, argv[1])) + if (!check_unsigned(client, &id, args.front())) return CommandResult::ERROR; bool ret = playlist_print_id(client, client.playlist, id); @@ -295,11 +283,9 @@ handle_playlistid(Client &client, unsigned argc, char *argv[]) } static CommandResult -handle_playlist_match(Client &client, unsigned argc, char *argv[], +handle_playlist_match(Client &client, ConstBuffer<const char *> args, bool fold_case) { - ConstBuffer<const char *> args(argv + 1, argc - 1); - SongFilter filter; if (!filter.Parse(args, fold_case)) { command_error(client, ACK_ERROR_ARG, "incorrect arguments"); @@ -311,35 +297,35 @@ handle_playlist_match(Client &client, unsigned argc, char *argv[], } CommandResult -handle_playlistfind(Client &client, unsigned argc, char *argv[]) +handle_playlistfind(Client &client, ConstBuffer<const char *> args) { - return handle_playlist_match(client, argc, argv, false); + return handle_playlist_match(client, args, false); } CommandResult -handle_playlistsearch(Client &client, unsigned argc, char *argv[]) +handle_playlistsearch(Client &client, ConstBuffer<const char *> args) { - return handle_playlist_match(client, argc, argv, true); + return handle_playlist_match(client, args, true); } CommandResult -handle_prio(Client &client, unsigned argc, char *argv[]) +handle_prio(Client &client, ConstBuffer<const char *> args) { + const char *const priority_string = args.shift(); unsigned priority; - if (!check_unsigned(client, &priority, argv[1])) + if (!check_unsigned(client, &priority, priority_string)) return CommandResult::ERROR; if (priority > 0xff) { command_error(client, ACK_ERROR_ARG, - "Priority out of range: %s", argv[1]); + "Priority out of range: %s", priority_string); return CommandResult::ERROR; } - for (unsigned i = 2; i < argc; ++i) { + for (const char *i : args) { unsigned start_position, end_position; - if (!check_range(client, &start_position, &end_position, - argv[i])) + if (!check_range(client, &start_position, &end_position, i)) return CommandResult::ERROR; PlaylistResult result = @@ -354,22 +340,23 @@ handle_prio(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_prioid(Client &client, unsigned argc, char *argv[]) +handle_prioid(Client &client, ConstBuffer<const char *> args) { + const char *const priority_string = args.shift(); unsigned priority; - if (!check_unsigned(client, &priority, argv[1])) + if (!check_unsigned(client, &priority, priority_string)) return CommandResult::ERROR; if (priority > 0xff) { command_error(client, ACK_ERROR_ARG, - "Priority out of range: %s", argv[1]); + "Priority out of range: %s", priority_string); return CommandResult::ERROR; } - for (unsigned i = 2; i < argc; ++i) { + for (const char *i : args) { unsigned song_id; - if (!check_unsigned(client, &song_id, argv[i])) + if (!check_unsigned(client, &song_id, i)) return CommandResult::ERROR; PlaylistResult result = @@ -382,14 +369,14 @@ handle_prioid(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_move(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_move(Client &client, ConstBuffer<const char *> args) { unsigned start, end; int to; - if (!check_range(client, &start, &end, argv[1])) + if (!check_range(client, &start, &end, args[0])) return CommandResult::ERROR; - if (!check_int(client, &to, argv[2])) + if (!check_int(client, &to, args[1])) return CommandResult::ERROR; PlaylistResult result = @@ -398,27 +385,27 @@ handle_move(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_moveid(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_moveid(Client &client, ConstBuffer<const char *> args) { unsigned id; int to; - if (!check_unsigned(client, &id, argv[1])) + if (!check_unsigned(client, &id, args[0])) return CommandResult::ERROR; - if (!check_int(client, &to, argv[2])) + if (!check_int(client, &to, args[1])) return CommandResult::ERROR; PlaylistResult result = client.partition.MoveId(id, to); return print_playlist_result(client, result); } CommandResult -handle_swap(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_swap(Client &client, ConstBuffer<const char *> args) { unsigned song1, song2; - if (!check_unsigned(client, &song1, argv[1])) + if (!check_unsigned(client, &song1, args[0])) return CommandResult::ERROR; - if (!check_unsigned(client, &song2, argv[2])) + if (!check_unsigned(client, &song2, args[1])) return CommandResult::ERROR; PlaylistResult result = @@ -427,13 +414,13 @@ handle_swap(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_swapid(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_swapid(Client &client, ConstBuffer<const char *> args) { unsigned id1, id2; - if (!check_unsigned(client, &id1, argv[1])) + if (!check_unsigned(client, &id1, args[0])) return CommandResult::ERROR; - if (!check_unsigned(client, &id2, argv[2])) + if (!check_unsigned(client, &id2, args[1])) return CommandResult::ERROR; PlaylistResult result = client.partition.SwapIds(id1, id2); diff --git a/src/command/QueueCommands.hxx b/src/command/QueueCommands.hxx index f98f7bad2..48641d2d1 100644 --- a/src/command/QueueCommands.hxx +++ b/src/command/QueueCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,65 +23,66 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult -handle_add(Client &client, unsigned argc, char *argv[]); +handle_add(Client &client, ConstBuffer<const char *> args); CommandResult -handle_addid(Client &client, unsigned argc, char *argv[]); +handle_addid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_rangeid(Client &client, unsigned argc, char *argv[]); +handle_rangeid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_delete(Client &client, unsigned argc, char *argv[]); +handle_delete(Client &client, ConstBuffer<const char *> args); CommandResult -handle_deleteid(Client &client, unsigned argc, char *argv[]); +handle_deleteid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlist(Client &client, unsigned argc, char *argv[]); +handle_playlist(Client &client, ConstBuffer<const char *> args); CommandResult -handle_shuffle(Client &client, unsigned argc, char *argv[]); +handle_shuffle(Client &client, ConstBuffer<const char *> args); CommandResult -handle_clear(Client &client, unsigned argc, char *argv[]); +handle_clear(Client &client, ConstBuffer<const char *> args); CommandResult -handle_plchanges(Client &client, unsigned argc, char *argv[]); +handle_plchanges(Client &client, ConstBuffer<const char *> args); CommandResult -handle_plchangesposid(Client &client, unsigned argc, char *argv[]); +handle_plchangesposid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistinfo(Client &client, unsigned argc, char *argv[]); +handle_playlistinfo(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistid(Client &client, unsigned argc, char *argv[]); +handle_playlistid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistfind(Client &client, unsigned argc, char *argv[]); +handle_playlistfind(Client &client, ConstBuffer<const char *> args); CommandResult -handle_playlistsearch(Client &client, unsigned argc, char *argv[]); +handle_playlistsearch(Client &client, ConstBuffer<const char *> args); CommandResult -handle_prio(Client &client, unsigned argc, char *argv[]); +handle_prio(Client &client, ConstBuffer<const char *> args); CommandResult -handle_prioid(Client &client, unsigned argc, char *argv[]); +handle_prioid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_move(Client &client, unsigned argc, char *argv[]); +handle_move(Client &client, ConstBuffer<const char *> args); CommandResult -handle_moveid(Client &client, unsigned argc, char *argv[]); +handle_moveid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_swap(Client &client, unsigned argc, char *argv[]); +handle_swap(Client &client, ConstBuffer<const char *> args); CommandResult -handle_swapid(Client &client, unsigned argc, char *argv[]); +handle_swapid(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx index 37506d51b..8979d53a4 100644 --- a/src/command/StickerCommands.cxx +++ b/src/command/StickerCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -31,6 +31,7 @@ #include "Partition.hxx" #include "Instance.hxx" #include "util/Error.hxx" +#include "util/ConstBuffer.hxx" #include <string.h> @@ -51,53 +52,64 @@ sticker_song_find_print_cb(const LightSong &song, const char *value, } static CommandResult -handle_sticker_song(Client &client, unsigned argc, char *argv[]) +handle_sticker_song(Client &client, ConstBuffer<const char *> args) { Error error; const Database *db = client.GetDatabase(error); if (db == nullptr) return print_error(client, error); + const char *const cmd = args.front(); + /* get song song_id key */ - if (argc == 5 && strcmp(argv[1], "get") == 0) { - const LightSong *song = db->GetSong(argv[3], error); + if (args.size == 4 && strcmp(cmd, "get") == 0) { + const LightSong *song = db->GetSong(args[2], error); if (song == nullptr) return print_error(client, error); - const auto value = sticker_song_get_value(*song, argv[4]); + const auto value = sticker_song_get_value(*song, args[3], + error); db->ReturnSong(song); if (value.empty()) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_NO_EXIST, "no such sticker"); return CommandResult::ERROR; } - sticker_print_value(client, argv[4], value.c_str()); + sticker_print_value(client, args[3], value.c_str()); return CommandResult::OK; /* list song song_id */ - } else if (argc == 4 && strcmp(argv[1], "list") == 0) { - const LightSong *song = db->GetSong(argv[3], error); + } else if (args.size == 3 && strcmp(cmd, "list") == 0) { + const LightSong *song = db->GetSong(args[2], error); if (song == nullptr) return print_error(client, error); - sticker *sticker = sticker_song_get(*song); + Sticker *sticker = sticker_song_get(*song, error); db->ReturnSong(song); if (sticker) { sticker_print(client, *sticker); sticker_free(sticker); - } + } else if (error.IsDefined()) + return print_error(client, error); return CommandResult::OK; /* set song song_id id key */ - } else if (argc == 6 && strcmp(argv[1], "set") == 0) { - const LightSong *song = db->GetSong(argv[3], error); + } else if (args.size == 5 && strcmp(cmd, "set") == 0) { + const LightSong *song = db->GetSong(args[2], error); if (song == nullptr) return print_error(client, error); - bool ret = sticker_song_set_value(*song, argv[4], argv[5]); + bool ret = sticker_song_set_value(*song, args[3], args[4], + error); db->ReturnSong(song); if (!ret) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_SYSTEM, "failed to set sticker value"); return CommandResult::ERROR; @@ -105,17 +117,20 @@ handle_sticker_song(Client &client, unsigned argc, char *argv[]) return CommandResult::OK; /* delete song song_id [key] */ - } else if ((argc == 4 || argc == 5) && - strcmp(argv[1], "delete") == 0) { - const LightSong *song = db->GetSong(argv[3], error); + } else if ((args.size == 3 || args.size == 4) && + strcmp(cmd, "delete") == 0) { + const LightSong *song = db->GetSong(args[2], error); if (song == nullptr) return print_error(client, error); - bool ret = argc == 4 - ? sticker_song_delete(*song) - : sticker_song_delete_value(*song, argv[4]); + bool ret = args.size == 3 + ? sticker_song_delete(*song, error) + : sticker_song_delete_value(*song, args[3], error); db->ReturnSong(song); if (!ret) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_SYSTEM, "no such sticker"); return CommandResult::ERROR; @@ -123,20 +138,48 @@ handle_sticker_song(Client &client, unsigned argc, char *argv[]) return CommandResult::OK; /* find song dir key */ - } else if (argc == 5 && strcmp(argv[1], "find") == 0) { + } else if ((args.size == 4 || args.size == 6) && + strcmp(cmd, "find") == 0) { /* "sticker find song a/directory name" */ - const char *const base_uri = argv[3]; + const char *const base_uri = args[2]; + + StickerOperator op = StickerOperator::EXISTS; + const char *value = nullptr; + + if (args.size == 6) { + /* match the value */ + + const char *op_s = args[4]; + value = args[5]; + + if (strcmp(op_s, "=") == 0) + op = StickerOperator::EQUALS; + else if (strcmp(op_s, "<") == 0) + op = StickerOperator::LESS_THAN; + else if (strcmp(op_s, ">") == 0) + op = StickerOperator::GREATER_THAN; + else { + command_error(client, ACK_ERROR_ARG, + "bad operator"); + return CommandResult::ERROR; + } + } bool success; struct sticker_song_find_data data = { client, - argv[4], + args[3], }; success = sticker_song_find(*db, base_uri, data.name, - sticker_song_find_print_cb, &data); + op, value, + sticker_song_find_print_cb, &data, + error); if (!success) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_SYSTEM, "failed to set search sticker database"); return CommandResult::ERROR; @@ -150,9 +193,9 @@ handle_sticker_song(Client &client, unsigned argc, char *argv[]) } CommandResult -handle_sticker(Client &client, unsigned argc, char *argv[]) +handle_sticker(Client &client, ConstBuffer<const char *> args) { - assert(argc >= 4); + assert(args.size >= 3); if (!sticker_enabled()) { command_error(client, ACK_ERROR_UNKNOWN, @@ -160,8 +203,8 @@ handle_sticker(Client &client, unsigned argc, char *argv[]) return CommandResult::ERROR; } - if (strcmp(argv[2], "song") == 0) - return handle_sticker_song(client, argc, argv); + if (strcmp(args[1], "song") == 0) + return handle_sticker_song(client, args); else { command_error(client, ACK_ERROR_ARG, "unknown sticker domain"); diff --git a/src/command/StickerCommands.hxx b/src/command/StickerCommands.hxx index cf46cd034..8b7a8f7bf 100644 --- a/src/command/StickerCommands.hxx +++ b/src/command/StickerCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,8 +23,9 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult -handle_sticker(Client &client, unsigned argc, char *argv[]); +handle_sticker(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/StorageCommands.cxx b/src/command/StorageCommands.cxx index ee51c573e..5bb37ae6f 100644 --- a/src/command/StorageCommands.cxx +++ b/src/command/StorageCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@ #include "protocol/Result.hxx" #include "util/UriUtil.hxx" #include "util/Error.hxx" +#include "util/ConstBuffer.hxx" #include "fs/Traits.hxx" #include "client/Client.hxx" #include "Partition.hxx" @@ -63,23 +64,23 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader, if (skip_path(name_utf8)) continue; - FileInfo info; + StorageFileInfo info; if (!reader.GetInfo(false, info, error)) continue; switch (info.type) { - case FileInfo::Type::OTHER: + case StorageFileInfo::Type::OTHER: /* ignore */ continue; - case FileInfo::Type::REGULAR: + case StorageFileInfo::Type::REGULAR: client_printf(client, "file: %s\n" "size: %" PRIu64 "\n", name_utf8, info.size); break; - case FileInfo::Type::DIRECTORY: + case StorageFileInfo::Type::DIRECTORY: client_printf(client, "directory: %s\n", name_utf8); break; } @@ -147,7 +148,7 @@ print_storage_uri(Client &client, const Storage &storage) if (uri.empty()) return; - if (PathTraitsFS::IsAbsolute(uri.c_str())) { + if (PathTraitsUTF8::IsAbsolute(uri.c_str())) { /* storage points to local directory */ if (!client.IsLocal()) @@ -167,7 +168,7 @@ print_storage_uri(Client &client, const Storage &storage) } CommandResult -handle_listmounts(Client &client, gcc_unused unsigned argc, gcc_unused char *argv[]) +handle_listmounts(Client &client, gcc_unused ConstBuffer<const char *> args) { Storage *_composite = client.partition.instance.storage; if (_composite == nullptr) { @@ -189,7 +190,7 @@ handle_listmounts(Client &client, gcc_unused unsigned argc, gcc_unused char *arg } CommandResult -handle_mount(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_mount(Client &client, ConstBuffer<const char *> args) { Storage *_composite = client.partition.instance.storage; if (_composite == nullptr) { @@ -199,8 +200,8 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[]) CompositeStorage &composite = *(CompositeStorage *)_composite; - const char *const local_uri = argv[1]; - const char *const remote_uri = argv[2]; + const char *const local_uri = args[0]; + const char *const remote_uri = args[1]; if (*local_uri == 0) { command_error(client, ACK_ERROR_ARG, "Bad mount point"); @@ -252,7 +253,7 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_unmount(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_unmount(Client &client, ConstBuffer<const char *> args) { Storage *_composite = client.partition.instance.storage; if (_composite == nullptr) { @@ -262,7 +263,7 @@ handle_unmount(Client &client, gcc_unused unsigned argc, char *argv[]) CompositeStorage &composite = *(CompositeStorage *)_composite; - const char *const local_uri = argv[1]; + const char *const local_uri = args.front(); if (*local_uri == 0) { command_error(client, ACK_ERROR_ARG, "Bad mount point"); diff --git a/src/command/StorageCommands.hxx b/src/command/StorageCommands.hxx index a3636d54a..4a96b4058 100644 --- a/src/command/StorageCommands.hxx +++ b/src/command/StorageCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -24,6 +24,7 @@ class Client; class Storage; +template<typename T> struct ConstBuffer; CommandResult handle_listfiles_storage(Client &client, Storage &storage, const char *uri); @@ -32,12 +33,12 @@ CommandResult handle_listfiles_storage(Client &client, const char *uri); CommandResult -handle_listmounts(Client &client, unsigned argc, char *argv[]); +handle_listmounts(Client &client, ConstBuffer<const char *> args); CommandResult -handle_mount(Client &client, unsigned argc, char *argv[]); +handle_mount(Client &client, ConstBuffer<const char *> args); CommandResult -handle_unmount(Client &client, unsigned argc, char *argv[]); +handle_unmount(Client &client, ConstBuffer<const char *> args); #endif diff --git a/src/command/TagCommands.cxx b/src/command/TagCommands.cxx index 2d537671c..bf5b67511 100644 --- a/src/command/TagCommands.cxx +++ b/src/command/TagCommands.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -25,15 +25,16 @@ #include "protocol/Result.hxx" #include "tag/Tag.hxx" #include "Partition.hxx" +#include "util/ConstBuffer.hxx" CommandResult -handle_addtagid(Client &client, gcc_unused unsigned argc, char *argv[]) +handle_addtagid(Client &client, ConstBuffer<const char *> args) { unsigned song_id; - if (!check_unsigned(client, &song_id, argv[1])) + if (!check_unsigned(client, &song_id, args.front())) return CommandResult::ERROR; - const char *const tag_name = argv[2]; + const char *const tag_name = args[1]; const TagType tag_type = tag_name_parse_i(tag_name); if (tag_type == TAG_NUM_OF_ITEM_TYPES) { command_error(client, ACK_ERROR_ARG, @@ -41,7 +42,7 @@ handle_addtagid(Client &client, gcc_unused unsigned argc, char *argv[]) return CommandResult::ERROR; } - const char *const value = argv[3]; + const char *const value = args[2]; Error error; if (!client.partition.playlist.AddSongIdTag(song_id, tag_type, value, @@ -52,15 +53,15 @@ handle_addtagid(Client &client, gcc_unused unsigned argc, char *argv[]) } CommandResult -handle_cleartagid(Client &client, unsigned argc, char *argv[]) +handle_cleartagid(Client &client, ConstBuffer<const char *> args) { unsigned song_id; - if (!check_unsigned(client, &song_id, argv[1])) + if (!check_unsigned(client, &song_id, args.front())) return CommandResult::ERROR; TagType tag_type = TAG_NUM_OF_ITEM_TYPES; - if (argc >= 3) { - const char *const tag_name = argv[2]; + if (args.size >= 2) { + const char *const tag_name = args[1]; tag_type = tag_name_parse_i(tag_name); if (tag_type == TAG_NUM_OF_ITEM_TYPES) { command_error(client, ACK_ERROR_ARG, diff --git a/src/command/TagCommands.hxx b/src/command/TagCommands.hxx index 748838e68..ee7c27bb9 100644 --- a/src/command/TagCommands.hxx +++ b/src/command/TagCommands.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2014 The Music Player Daemon Project + * Copyright (C) 2003-2015 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -23,11 +23,12 @@ #include "CommandResult.hxx" class Client; +template<typename T> struct ConstBuffer; CommandResult -handle_addtagid(Client &client, unsigned argc, char *argv[]); +handle_addtagid(Client &client, ConstBuffer<const char *> args); CommandResult -handle_cleartagid(Client &client, unsigned argc, char *argv[]); +handle_cleartagid(Client &client, ConstBuffer<const char *> args); #endif |