]>
Commit | Line | Data |
---|---|---|
12c86877 BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
5b2cb3be | 3 | Copyright (C) 2002 - 2008 PowerDNS.COM BV |
12c86877 BH |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
fd4b10f7 BH |
6 | it under the terms of the GNU General Public License version 2 as published |
7 | by the Free Software Foundation | |
12c86877 BH |
8 | |
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
06bd9ccf | 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
12c86877 | 17 | */ |
12c86877 | 18 | #include "arguments.hh" |
5b2cb3be | 19 | #include <boost/algorithm/string.hpp> |
61b26744 | 20 | #include "namespaces.hh" |
12c86877 | 21 | |
12c86877 BH |
22 | const ArgvMap::param_t::const_iterator ArgvMap::begin() |
23 | { | |
24 | return params.begin(); | |
25 | } | |
26 | ||
27 | const ArgvMap::param_t::const_iterator ArgvMap::end() | |
28 | { | |
29 | return params.end(); | |
30 | } | |
31 | ||
32 | string & ArgvMap::set(const string &var) | |
33 | { | |
34 | return params[var]; | |
35 | } | |
36 | ||
37 | bool ArgvMap::mustDo(const string &var) | |
bd11bd1d | 38 | { |
12c86877 BH |
39 | return ((*this)[var]!="no") && ((*this)[var]!="off"); |
40 | } | |
41 | ||
42 | vector<string>ArgvMap::list() | |
43 | { | |
44 | vector<string> ret; | |
45 | for(map<string,string>::const_iterator i=params.begin();i!=params.end();++i) | |
46 | ret.push_back(i->first); | |
47 | return ret; | |
48 | } | |
49 | ||
50 | string ArgvMap::getHelp(const string &item) | |
51 | { | |
52 | return helpmap[item]; | |
53 | } | |
54 | ||
55 | string & ArgvMap::set(const string &var, const string &help) | |
56 | { | |
57 | helpmap[var]=help; | |
58 | d_typeMap[var]="Parameter"; | |
59 | return set(var); | |
60 | } | |
61 | ||
62 | void ArgvMap::setCmd(const string &var, const string &help) | |
63 | { | |
64 | helpmap[var]=help; | |
65 | d_typeMap[var]="Command"; | |
66 | set(var)="no"; | |
67 | } | |
68 | ||
69 | string & ArgvMap::setSwitch(const string &var, const string &help) | |
70 | { | |
71 | helpmap[var]=help; | |
72 | d_typeMap[var]="Switch"; | |
73 | return set(var); | |
74 | } | |
75 | ||
76 | ||
12c86877 BH |
77 | bool ArgvMap::contains(const string &var, const string &val) |
78 | { | |
102eb646 BH |
79 | params_t::const_iterator param = params.find(var); |
80 | if(param == params.end() || param->second.empty()) { | |
81 | return false; | |
82 | } | |
562588a3 BH |
83 | vector<string> parts; |
84 | vector<string>::const_iterator i; | |
85 | ||
102eb646 | 86 | stringtok( parts, param->second, ", \t" ); |
562588a3 BH |
87 | for( i = parts.begin(); i != parts.end(); i++ ) { |
88 | if( *i == val ) { | |
89 | return true; | |
90 | } | |
91 | } | |
92 | ||
93 | return false; | |
12c86877 BH |
94 | } |
95 | ||
12c86877 BH |
96 | string ArgvMap::helpstring(string prefix) |
97 | { | |
98 | if(prefix=="no") | |
99 | prefix=""; | |
100 | ||
101 | string help; | |
102 | ||
103 | for(map<string,string>::const_iterator i=helpmap.begin(); | |
104 | i!=helpmap.end(); | |
105 | i++) | |
106 | { | |
107 | if(!prefix.empty() && i->first.find(prefix)) // only print items with prefix | |
4957a608 | 108 | continue; |
12c86877 BH |
109 | |
110 | help+=" --"; | |
111 | help+=i->first; | |
112 | ||
113 | string type=d_typeMap[i->first]; | |
114 | ||
115 | if(type=="Parameter") | |
4957a608 | 116 | help+="=..."; |
12c86877 | 117 | else if(type=="Switch") |
4957a608 BH |
118 | { |
119 | help+=" | --"+i->first+"=yes"; | |
120 | help+=" | --"+i->first+"=no"; | |
121 | } | |
12c86877 BH |
122 | |
123 | ||
124 | help+="\n\t"; | |
125 | help+=i->second; | |
126 | help+="\n"; | |
127 | ||
128 | } | |
129 | return help; | |
130 | } | |
131 | ||
132 | string ArgvMap::configstring() | |
133 | { | |
134 | string help; | |
135 | ||
136 | help="# Autogenerated configuration file template\n"; | |
137 | for(map<string,string>::const_iterator i=helpmap.begin(); | |
138 | i!=helpmap.end(); | |
139 | i++) | |
140 | { | |
141 | if(d_typeMap[i->first]=="Command") | |
4957a608 | 142 | continue; |
12c86877 BH |
143 | |
144 | help+="#################################\n"; | |
145 | help+="# "; | |
146 | help+=i->first; | |
147 | help+="\t"; | |
148 | help+=i->second; | |
149 | help+="\n#\n"; | |
150 | help+="# "+i->first+"="+params[i->first]+"\n\n"; | |
151 | ||
152 | } | |
153 | return help; | |
154 | } | |
155 | ||
156 | ||
157 | const string & ArgvMap::operator[](const string &arg) | |
158 | { | |
159 | if(!parmIsset(arg)) | |
160 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
161 | ||
162 | ||
163 | return params[arg]; | |
164 | } | |
165 | ||
cc2978dc BH |
166 | #ifndef WIN32 |
167 | mode_t ArgvMap::asMode(const string &arg) | |
168 | { | |
169 | mode_t mode; | |
170 | const char *cptr_orig; | |
171 | char *cptr_ret = NULL; | |
172 | ||
173 | if(!parmIsset(arg)) | |
174 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
175 | ||
176 | cptr_orig = params[arg].c_str(); | |
177 | mode = static_cast<mode_t>(strtol(cptr_orig, &cptr_ret, 8)); | |
178 | if (mode == 0 && cptr_ret == cptr_orig) | |
179 | throw ArgException("'" + arg + string("' contains invalid octal mode")); | |
180 | return mode; | |
181 | } | |
182 | ||
183 | gid_t ArgvMap::asGid(const string &arg) | |
184 | { | |
185 | gid_t gid; | |
186 | const char *cptr_orig; | |
187 | char *cptr_ret = NULL; | |
188 | ||
189 | if(!parmIsset(arg)) | |
190 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
191 | ||
192 | cptr_orig = params[arg].c_str(); | |
193 | gid = static_cast<gid_t>(strtol(cptr_orig, &cptr_ret, 0)); | |
194 | if (gid == 0 && cptr_ret == cptr_orig) { | |
195 | // try to resolve | |
196 | struct group *group = getgrnam(params[arg].c_str()); | |
197 | if (group == NULL) | |
198 | throw ArgException("'" + arg + string("' contains invalid group")); | |
199 | gid = group->gr_gid; | |
200 | } | |
201 | return gid; | |
202 | } | |
203 | ||
204 | uid_t ArgvMap::asUid(const string &arg) | |
205 | { | |
206 | uid_t uid; | |
207 | const char *cptr_orig; | |
208 | char *cptr_ret = NULL; | |
209 | ||
210 | if(!parmIsset(arg)) | |
211 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
212 | ||
213 | cptr_orig = params[arg].c_str(); | |
214 | uid = static_cast<uid_t>(strtol(cptr_orig, &cptr_ret, 0)); | |
215 | if (uid == 0 && cptr_ret == cptr_orig) { | |
216 | // try to resolve | |
217 | struct passwd *pwent = getpwnam(params[arg].c_str()); | |
218 | if (pwent == NULL) | |
219 | throw ArgException("'" + arg + string("' contains invalid group")); | |
220 | uid = pwent->pw_uid; | |
221 | } | |
222 | return uid; | |
223 | } | |
224 | #endif | |
225 | ||
12c86877 BH |
226 | int ArgvMap::asNum(const string &arg) |
227 | { | |
cc2978dc BH |
228 | int retval; |
229 | const char *cptr_orig; | |
230 | char *cptr_ret = NULL; | |
231 | ||
12c86877 BH |
232 | if(!parmIsset(arg)) |
233 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
234 | ||
cc2978dc BH |
235 | // treat empty values as zeros |
236 | if (params[arg].empty()) | |
237 | return 0; | |
238 | ||
239 | cptr_orig = params[arg].c_str(); | |
240 | retval = static_cast<int>(strtol(cptr_orig, &cptr_ret, 0)); | |
241 | if (!retval && cptr_ret == cptr_orig) | |
242 | throw ArgException("'"+arg+string("' is not valid number")); | |
243 | ||
244 | return retval; | |
245 | } | |
246 | ||
247 | bool ArgvMap::isEmpty(const string &arg) | |
248 | { | |
249 | if(!parmIsset(arg)) | |
250 | return true; | |
251 | return params[arg].empty(); | |
12c86877 BH |
252 | } |
253 | ||
254 | double ArgvMap::asDouble(const string &arg) | |
255 | { | |
cc2978dc BH |
256 | double retval; |
257 | const char *cptr_orig; | |
258 | char *cptr_ret = NULL; | |
259 | ||
12c86877 BH |
260 | if(!parmIsset(arg)) |
261 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
262 | ||
cc2978dc BH |
263 | if (params[arg].empty()) |
264 | return 0.0; | |
265 | ||
266 | cptr_orig = params[arg].c_str(); | |
267 | retval = strtod(cptr_orig, &cptr_ret); | |
268 | ||
269 | if (retval == 0 && cptr_ret == cptr_orig) | |
270 | throw ArgException("'"+arg+string("' is not valid double")); | |
271 | ||
272 | return retval; | |
12c86877 BH |
273 | } |
274 | ||
275 | ArgvMap::ArgvMap() | |
276 | { | |
277 | ||
278 | } | |
279 | ||
280 | bool ArgvMap::parmIsset(const string &var) | |
281 | { | |
282 | return (params.find(var)!=params.end()); | |
283 | } | |
284 | ||
285 | void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax) | |
286 | { | |
287 | string var, val; | |
bdf40704 | 288 | string::size_type pos; |
12c86877 BH |
289 | |
290 | if(!arg.find("--") &&(pos=arg.find("="))!=string::npos) // this is a --port=25 case | |
291 | { | |
292 | var=arg.substr(2,pos-2); | |
293 | val=arg.substr(pos+1); | |
294 | } | |
295 | else if(!arg.find("--") && (arg.find("=")==string::npos)) // this is a --daemon case | |
296 | { | |
297 | var=arg.substr(2); | |
298 | val=""; | |
299 | } | |
300 | else if(arg[0]=='-') | |
301 | { | |
302 | var=arg.substr(1); | |
303 | val=""; | |
304 | } | |
305 | else { // command | |
306 | d_cmds.push_back(arg); | |
307 | } | |
308 | ||
309 | if(var!="" && (parseOnly.empty() || var==parseOnly)) { | |
bd11bd1d BH |
310 | |
311 | pos=val.find_first_not_of(" \t"); // strip leading whitespace | |
312 | if(pos && pos!=string::npos) | |
313 | val=val.substr(pos); | |
314 | ||
50e83e03 PD |
315 | if(parmIsset(var)) |
316 | params[var]=val; | |
12c86877 BH |
317 | else |
318 | if(!lax) | |
4957a608 | 319 | throw ArgException("Trying to set unexisting parameter '"+var+"'"); |
12c86877 BH |
320 | } |
321 | } | |
322 | ||
323 | const vector<string>&ArgvMap::getCommands() | |
324 | { | |
325 | return d_cmds; | |
326 | } | |
327 | ||
328 | void ArgvMap::parse(int &argc, char **argv, bool lax) | |
329 | { | |
330 | for(int n=1;n<argc;n++) { | |
331 | parseOne(argv[n],"",lax); | |
332 | } | |
333 | } | |
334 | ||
335 | void ArgvMap::preParse(int &argc, char **argv, const string &arg) | |
336 | { | |
337 | for(int n=1;n<argc;n++) { | |
338 | string varval=argv[n]; | |
339 | if(!varval.find("--"+arg)) | |
340 | parseOne(argv[n]); | |
341 | } | |
342 | } | |
343 | ||
f64de501 | 344 | bool ArgvMap::preParseFile(const char *fname, const string &arg, const string& theDefault) |
12c86877 | 345 | { |
f64de501 | 346 | params[arg]=theDefault; |
b56ac6fd | 347 | |
12c86877 | 348 | ifstream f(fname); |
eefd15f9 | 349 | if(!f) |
12c86877 | 350 | return false; |
eefd15f9 | 351 | |
12c86877 BH |
352 | string line; |
353 | string pline; | |
bdf40704 | 354 | string::size_type pos; |
12c86877 BH |
355 | |
356 | while(getline(f,pline)) { | |
5b2cb3be BH |
357 | trim_right(pline); |
358 | ||
12c86877 BH |
359 | if(pline[pline.size()-1]=='\\') { |
360 | line+=pline.substr(0,pline.length()-1); | |
361 | continue; | |
362 | } | |
eefd15f9 | 363 | else |
12c86877 | 364 | line+=pline; |
12c86877 BH |
365 | |
366 | // strip everything after a # | |
367 | if((pos=line.find("#"))!=string::npos) | |
368 | line=line.substr(0,pos); | |
369 | ||
370 | // strip trailing spaces | |
5b2cb3be | 371 | trim_right(line); |
eefd15f9 | 372 | |
12c86877 BH |
373 | // strip leading spaces |
374 | if((pos=line.find_first_not_of(" \t\r\n"))!=string::npos) | |
375 | line=line.substr(pos); | |
eefd15f9 | 376 | |
12c86877 BH |
377 | // gpgsql-basic-query=sdfsdfs dfsdfsdf sdfsdfsfd |
378 | ||
eefd15f9 | 379 | parseOne( string("--") + line, arg ); |
12c86877 BH |
380 | line=""; |
381 | } | |
eefd15f9 | 382 | |
12c86877 BH |
383 | return true; |
384 | } | |
385 | ||
386 | ||
387 | bool ArgvMap::file(const char *fname, bool lax) | |
388 | { | |
389 | ifstream f(fname); | |
390 | if(!f) { | |
12c86877 BH |
391 | return false; |
392 | } | |
eefd15f9 | 393 | |
12c86877 BH |
394 | string line; |
395 | string pline; | |
bdf40704 | 396 | string::size_type pos; |
eefd15f9 | 397 | |
12c86877 | 398 | while(getline(f,pline)) { |
5b2cb3be | 399 | trim_right(pline); |
ccd3ed60 BH |
400 | if(pline.empty()) |
401 | continue; | |
12c86877 BH |
402 | |
403 | if(pline[pline.size()-1]=='\\') { | |
404 | line+=pline.substr(0,pline.length()-1); | |
405 | ||
406 | continue; | |
407 | } | |
eefd15f9 | 408 | else |
12c86877 BH |
409 | line+=pline; |
410 | ||
411 | // strip everything after a # | |
412 | if((pos=line.find("#"))!=string::npos) | |
413 | line=line.substr(0,pos); | |
414 | ||
415 | // strip trailing spaces | |
9ff13837 | 416 | trim(line); |
eefd15f9 BH |
417 | |
418 | parseOne(string("--")+line,"",lax); | |
12c86877 BH |
419 | line=""; |
420 | } | |
eefd15f9 | 421 | |
12c86877 BH |
422 | return true; |
423 | } |