00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00029
00030 #include <cxxtls/options.h>
00031 #include <stdlib.h>
00032 #include <portable_io.h>
00033 #include <algorithm>
00034 #include <ctype.h>
00035 #include <string.h>
00036
00037 using namespace std;
00038
00039 namespace cxxtls
00040 {
00041
00042
00043 ProgramOptions*
00044 ProgramOptions::
00045 global_options_=0;
00046
00047
00048 void
00049 ProgramOptions::
00050 constructor(const ProgramOptions::Descriptors& desc,
00051 int argc,
00052 const char*const* args,
00053 const char*const* environ,
00054 bool exit_on_error
00055 )
00056
00057
00058
00059 {
00060
00061
00062 if(environ)
00063 {
00064 while(*environ)
00065 {
00066 char const *p = *environ++;
00067
00068 char const *equal = (char const*)(memchr(p, '=', strlen(p)));
00069
00070 if(!equal)
00071 continue;
00072
00073 string name(p, equal);
00074
00075 string value(equal+1, equal+strlen(equal));
00076
00077 setenv(name, value);
00078
00079 }
00080 }
00081
00082 if(argc && args)
00083 {
00084 argv.push_back(*args);
00085
00086
00087 --argc;
00088 ++args;
00089
00090 while(argc)
00091 {
00092
00093
00094 if(args[0][0] == '-')
00095 {
00096
00097
00098 std::vector<Descriptor>::const_iterator f = desc.options_.begin();
00099 std::vector<Descriptor>::const_iterator l = desc.options_.end();
00100
00101
00102
00103
00104 while( f != l)
00105 {
00106 if( f->name_ == *args )
00107 {
00108 break;
00109 }
00110
00111 ++f;
00112
00113 }
00114
00115 bool single_char_parm=false;
00116
00117 if(f == l)
00118 {
00119
00120
00121
00122
00123
00124
00125
00126
00127 string tmp(args[0], args[0]+2);
00128
00129 for(f = desc.options_.begin(); f != l; ++f)
00130 if(tmp == f->name_ && f->parms_)
00131 {
00132 single_char_parm=true;
00133 break;
00134 }
00135 }
00136
00137 if(f == l)
00138 {
00139
00141
00143
00144 char buffer[2048];
00145
00146 sprintf(buffer, "program option '%s' is not recognized", *args);
00147
00148 if(exit_on_error_)
00149 {
00150 fprintf(stderr, "%s\n", buffer);
00151 exit(1);
00152 }
00153
00154 error_ = true;
00155
00156 errmsg_ = buffer;
00157
00158 return;
00159
00160 }
00161
00162
00163
00164
00165 if(single_char_parm && strlen(*args) > 2)
00166 {
00167
00168
00169
00170
00171 string name(*args, *args + 2);
00172
00173 Option *opt = get_option(name);
00174
00175 if(opt)
00176 {
00177 opt->append_value(string(*args+2, *args + strlen(*args)));
00178 }
00179 else
00180 {
00181 Option &newbie = add_option(name);
00182
00183 newbie.append_value(string(*args+2, *args + strlen(*args)));
00184 }
00185
00186 }
00187 else
00188 {
00189
00190 Option *newbie = get_option(*args);
00191
00192 if(!newbie)
00193 newbie = &add_option(*args);
00194 else
00195 {
00196
00197
00198
00199
00200 if(f->parms_ == no_values)
00201 {
00202
00203
00204 remove_option(*args);
00205
00206 --argc;
00207 ++args;
00208
00209 continue;
00210
00211 }
00212 else
00213 if(f->parms_ == one_value)
00214 {
00215
00216
00217
00218 char buffer[2048];
00219
00220 sprintf(buffer, "Multiple settings of option '%s' not allowed", *args);
00221
00222 if(exit_on_error_)
00223 {
00224 fprintf(stderr, "%s\n", buffer);
00225 exit(1);
00226 }
00227
00228 error_ = true;
00229
00230 errmsg_ = buffer;
00231
00232 return;
00233 }
00234
00235 }
00236
00237 if(f->parms_ && argc)
00238 {
00239 --argc;
00240 ++args;
00241
00242 newbie->append_value(*args);
00243 }
00244 }
00245 }
00246 else
00247 {
00248 argv.push_back(*args);
00249 }
00250
00251 --argc;
00252 ++args;
00253 }
00254 }
00255 }
00256
00257 ProgramOptions::Option&
00258 ProgramOptions::
00259 add_option(string const &name)
00260 {
00261 Option* p = new Option(name);
00262
00263 options_.insert( std::pair<string, Option*>(name, p) );
00264
00265 return *p;
00266 }
00267
00268
00269 void
00270 ProgramOptions::
00271 Descriptors::
00272 add_option(string const &name, int parms)
00273 {
00274 options_.push_back(Descriptor(name, parms));
00275 }
00276
00277 void
00278 ProgramOptions::
00279 setenv(string const &name, string const &value)
00280 {
00281 environ_.insert( std::pair<string,string> (name, value) );
00282 }
00283
00284 ProgramOptions::EnvVar
00285 ProgramOptions::
00286 getenv(string const &name) const
00287 {
00288 std::map<string,string>::const_iterator e;
00289
00290 e = environ_.find(name);
00291
00292 if(e == environ_.end())
00293 return EnvVar(name);
00294
00295 return EnvVar(name, e->second);
00296
00297 }
00298
00299 ProgramOptions::
00300 ~ProgramOptions()
00301 {
00302
00303
00304
00305 while(options_.begin() != options_.end())
00306 {
00307 Options::iterator i = options_.begin();
00308
00309 Option* tmp = i->second;
00310
00311 options_.erase(i);
00312
00313 delete tmp;
00314
00315 }
00316
00317 }
00318
00319 void
00320 ProgramOptions::Option::
00321 append_value(string const &value)
00322 {
00323 values_.push_back(value);
00324
00325 }
00326
00327
00328 ProgramOptions::Option::
00329 Option(string const &name)
00330 : name_(name),
00331 set_(true)
00332 {
00333 }
00334
00335
00336 ProgramOptions::Option::
00337 Option()
00338 : name_("not set"),
00339 set_(false)
00340 {
00341 }
00342
00343 string
00344 ProgramOptions::Option::
00345 value() const
00346 {
00347 string rv;
00348
00349 if(values_.size() != 0)
00350 {
00351 vector<string>::const_iterator f = values_.begin();
00352 vector<string>::const_iterator l = values_.end();
00353
00354 static string comma(",");
00355
00356 do
00357 {
00358 rv += *f;
00359
00360 ++f;
00361
00362 if(f != l)
00363 {
00364 rv += comma;
00365 }
00366
00367 }
00368 while(f != l);
00369
00370
00371 }
00372
00373 return rv;
00374 }
00375
00376 ProgramOptions::Option*
00377 ProgramOptions::
00378 get_option(string const &name)
00379 {
00380 Options::const_iterator f = options_.find(name);
00381
00382 if(f == options_.end())
00383 return 0;
00384
00385 return f->second;
00386 }
00387
00388 void
00389 ProgramOptions::
00390 remove_option(string const &name)
00391 {
00392 Options::iterator f = options_.find(name);
00393
00394 if(f != options_.end())
00395 options_.erase(f);
00396 }
00397
00398 ProgramOptions::Option
00399 ProgramOptions::
00400 null_option_;
00401
00402
00403 ProgramOptions::Option const&
00404 ProgramOptions::
00405 option(string const &name) const
00406 {
00407 ProgramOptions* me = (ProgramOptions*)(this);
00408
00409 Option* rv = me->get_option(name);
00410
00411 if(!rv)
00412 return null_option_;
00413
00414 return *rv;
00415
00416 }
00417
00418
00419 ProgramOptions::
00420 ProgramOptions(string text_desc,
00421 int argc,
00422 const char*const* args,
00423 const char*const* environ,
00424 bool exit_on_error
00425 )
00426 : exit_on_error_(exit_on_error),
00427 error_(false)
00428 {
00429
00430
00431
00432
00433 string::iterator nc = text_desc.begin();
00434 string::iterator lc = text_desc.end();
00435
00436 ProgramOptions::Descriptors desc;
00437
00438 string option_name;
00439
00440 while(nc != lc)
00441 {
00442 char c = *nc++;
00443
00444 int values=-1;
00445
00446 if(c == ',')
00447 values=no_values;
00448 else
00449 if(c == ':')
00450 values=one_value;
00451 else
00452 if(c == ';')
00453 values=many_values;
00454 else
00455 option_name += c;
00456
00457 if(values >= 0)
00458 {
00459
00460
00461 if(option_name.size())
00462 desc.add_option(option_name, values);
00463
00464 option_name.resize(0);
00465
00466 }
00467
00468 }
00469
00470 if(option_name.size() && option_name[0] == '-')
00471 {
00472
00473
00474 desc.add_option(option_name, no_values);
00475
00476 }
00477
00478 constructor(desc, argc, args, environ, exit_on_error);
00479
00480 }
00481
00482 string
00483 ProgramOptions::
00484 expand(string const &in) const
00485 {
00486 string rv;
00487
00488 size_t offset=0;
00489
00490 size_t in_size = in.size();
00491
00492 while(offset < in_size)
00493 {
00494 string::const_iterator start = in.begin() + offset;
00495 string::const_iterator end = in.end();
00496 string::const_iterator dollar = find(start, end, '$');
00497
00498 if(dollar == end)
00499 {
00500
00501
00502 rv.append(start, end);
00503 return rv;
00504
00505 }
00506 else
00507 {
00508
00509
00510 rv.append(start, dollar);
00511
00512 ++dollar;
00513
00514 if(dollar == end)
00515 return rv;
00516
00517 char c = *dollar;
00518
00519 if(c >= '0' && c < '9')
00520 {
00521
00522
00523 ++dollar;
00524
00525 c -= '0';
00526
00527
00528
00529 if( size_t(c) < argv.size())
00530 {
00531 rv += argv[c];
00532 }
00533
00534 }
00535 else
00536 {
00537
00538
00539 string varname;
00540
00541 while(dollar < end &&
00542 ( isalnum(*dollar) || *dollar == '_')
00543 )
00544 {
00545
00546 varname += *dollar++;
00547
00548 }
00549
00550 string value = getenv(varname);
00551
00552 rv += value;
00553
00554 char const *varname_ptr = varname.c_str();
00555 char const *value_ptr = value.c_str();
00556
00557 if(value_ptr == varname_ptr)
00558 varname_ptr = value_ptr;
00559
00560 }
00561
00562 offset = dollar - in.begin();
00563
00564 }
00565 }
00566
00567 return rv;
00568
00569 }
00570
00571 }