8c520b8f152d561dfb904cd9bb33ac3863fd13c4
[m6w6/libmemcached] / src / bin / common / options.cpp
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "options.hpp"
17
18 void client_options::print_version() const {
19 std::cout << prog_name << " v" << prog_vers << " (libmemcached v" << LIBMEMCACHED_VERSION_STRING << ")"
20 << std::endl;
21 }
22
23 void client_options::print_help() const {
24 print_version();
25 std::cout << "\n\t" << prog_desc << "\n\n";
26 std::cout << "Usage:\n\t" << prog_name << " -[";
27 for (const auto &opt : options) {
28 if (!opt.opt.has_arg && opt.opt.val != '-') {
29 std::cout << (char) opt.opt.val;
30 }
31 }
32 std::cout << "] [-";
33 for (const auto &ext : options) {
34 if (ext.opt.has_arg) {
35 std::cout << (char) ext.opt.val;
36 if ((&ext) != &*options.rbegin())
37 std::cout << '|';
38 }
39 }
40 std::cout << " <arg>] ";
41
42 if (prog_argp) {
43 std::cout << prog_argp;
44 }
45 std::cout << "\n\nOptions:\n";
46 for (const auto &ext : options) {
47 if (ext.opt.val == '-' || !(ext.opt.val || ext.opt.name)) {
48 continue;
49 }
50 std::cout << "\t";
51 if (ext.opt.val) {
52 std::cout << "-" << (char) ext.opt.val;
53 if (ext.opt.name) {
54 std::cout << "|";
55 }
56 } else {
57 std::cout << " ";
58 }
59 if (ext.opt.name) {
60 std::cout << "--" << ext.opt.name << " ";
61 } else {
62 std::cout << " ";
63 }
64 if (ext.opt.has_arg) {
65 if (ext.opt.has_arg == optional_argument) {
66 std::cout << "[";
67 } else {
68 std::cout << "<";
69 }
70 std::cout << "arg";
71 if (ext.opt.has_arg == optional_argument) {
72 std::cout << "]";
73 } else {
74 std::cout << ">";
75 }
76 }
77 std::cout << "\n\t\t" << ext.help << "\n";
78 }
79
80 if (has("servers")) {
81 std::cout << "\nEnvironment:\n";
82 std::cout << "\tMEMCACHED_SERVERS=\n";
83 std::cout << "\t\tList of servers to use if `-s|--servers` was not provided.\n";
84 }
85 std::cout << std::endl;
86 }
87
88 bool client_options::parse(int argc, char **argv, char ***argp) {
89 /* extern */ optind = 1;
90 auto debug = has("debug") ? &get("debug") : nullptr;
91 std::string short_opts{};
92 std::vector<option> long_opts{};
93
94 short_opts.reserve(options.size() * 3);
95 long_opts.reserve(options.size() + 1);
96
97 for (const auto &ext : options) {
98 if (ext.opt.val) {
99 short_opts.push_back(ext.opt.val);
100 for (int i = 0; i < ext.opt.has_arg; ++i) {
101 short_opts.push_back(':');
102 }
103 }
104 if (ext.opt.name) {
105 long_opts.push_back(ext.opt);
106 }
107 }
108 long_opts.push_back({});
109
110 while (true) {
111 auto opt = getopt_long(argc, argv, short_opts.c_str(), long_opts.data(), nullptr);
112
113 if (debug->set && opt > 0) {
114 std::cerr << "Processing option '" << (char) opt << "' (" << opt << ")\n";
115 }
116 if (opt == '?') {
117 return false;
118 }
119 if (opt == -1) {
120 if (argp) {
121 *argp = &argv[optind];
122 }
123 return true;
124 }
125
126 auto &ext_opt = get(opt);
127
128 // grab optional argument
129 if (ext_opt.opt.has_arg == optional_argument && !optarg) {
130 auto next_arg = argv[optind];
131
132 if (next_arg && *next_arg && *next_arg != '-') {
133 optarg = next_arg;
134 ++optind;
135 }
136 }
137
138 ext_opt.set = true;
139 ext_opt.arg = optarg;
140
141 if (ext_opt.parse) {
142 if (!ext_opt.parse(*this, ext_opt)) {
143 return false;
144 }
145 }
146 }
147 }
148
149 bool client_options::apply(memcached_st *memc) {
150 #ifdef _WIN32
151 WSADATA wsaData;
152 if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
153 std::cerr << "Socket Initialization Error.\n";
154 return false;
155 }
156 #endif // _WIN32
157
158 extended_option *servers = nullptr;
159 for (auto &opt : options) {
160 if (opt.apply) {
161 // servers should be applied last, so they take up any behaviors previously set
162 if (opt.opt.val == 's' && opt.opt.name == std::string("servers")) {
163 servers = &opt;
164 continue;
165 }
166 if (!opt.apply(*this, opt, memc)) {
167 return false;
168 }
169 }
170 }
171 if (servers) {
172 if (!servers->apply(*this, *servers, memc)) {
173 return false;
174 }
175 }
176 return true;
177 }