diff --git a/src/cli.cpp b/src/cli.cpp index 7b0689c69..d2b493264 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -85,8 +85,8 @@ void cli_tool_t::help() "(c) Vitaliy Filippov, 2019+ (VNPL-1.1)\n" "\n" "USAGE:\n" - "%s ls [-l] [-p POOL] [--sort FIELD] [-r] [-n N] [ ...]\n" - " List images (only specified if passed).\n" + "%s ls [-l] [-p POOL] [--sort FIELD] [-r] [-n N] [ ...]\n" + " List images (only matching patterns if passed).\n" " -p|--pool POOL Filter images by pool ID or name\n" " -l|--long Also report allocated size and I/O statistics\n" " --del Also include delete operation statistics\n" diff --git a/src/cli_ls.cpp b/src/cli_ls.cpp index 3b441fc49..730a4e17d 100644 --- a/src/cli_ls.cpp +++ b/src/cli_ls.cpp @@ -16,6 +16,8 @@ std::string format_lat(uint64_t lat); std::string format_q(double depth); +bool stupid_glob(const std::string str, const std::string glob); + // List existing images // // Again, you can just look into etcd, but this console tool incapsulates it @@ -213,10 +215,21 @@ resume_1: json11::Json::array list; for (auto & kv: stats) { - if (!only_names.size() || only_names.find(kv.second["name"].string_value()) != only_names.end()) + if (!only_names.size()) { list.push_back(kv.second); } + else + { + for (auto glob: only_names) + { + if (stupid_glob(kv.second["name"].string_value(), glob)) + { + list.push_back(kv.second); + break; + } + } + } } if (sort_field == "name" || sort_field == "pool_name") { @@ -493,6 +506,62 @@ std::string format_q(double depth) return std::string(buf); } +struct glob_stack_t +{ + int glob_pos; + int str_pos; +}; + +// Yes I know I could do it by translating the pattern to std::regex O:-) +bool stupid_glob(const std::string str, const std::string glob) +{ + std::vector wildcards; + int pos = 0, gp = 0; + bool m; +back: + while (true) + { + if (gp >= glob.length()) + { + if (pos >= str.length()) + return true; + m = false; + } + else if (glob[gp] == '*') + { + wildcards.push_back((glob_stack_t){ .glob_pos = ++gp, .str_pos = pos }); + continue; + } + else if (glob[gp] == '?') + m = pos < str.size(); + else + { + if (glob[gp] == '\\' && gp < glob.length()-1) + gp++; + m = pos < str.size() && str[pos] == glob[gp]; + } + if (!m) + { + while (wildcards.size() > 0) + { + // Backtrack + pos = (++wildcards[wildcards.size()-1].str_pos); + if (pos > str.size()) + wildcards.pop_back(); + else + { + gp = wildcards[wildcards.size()-1].glob_pos; + goto back; + } + } + return false; + } + pos++; + gp++; + } + return true; +} + std::function cli_tool_t::start_ls(json11::Json cfg) { json11::Json::array cmd = cfg["command"].array_items();