Changeset 76
- Timestamp:
- 01/11/07 06:45:53 (2 years ago)
- Files:
-
- misc/optparse.d (modified) (15 diffs)
- misc/opttest.d (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
misc/optparse.d
r75 r76 25 25 module optparse; 26 26 27 import std.stdio : writefln ;28 import std.string : split, find ;29 import std.c.stdlib : exit, EXIT_FAILURE ;27 import std.stdio : writefln, writef; 28 import std.string : split, find, toupper; 29 import std.c.stdlib : exit, EXIT_FAILURE, EXIT_SUCCESS; 30 30 import std.conv : toInt, ConvError; 31 import std.path : getName, getBaseName; 31 32 32 33 /* … … 169 170 Action action; 170 171 ArgType type; 171 char[] name ;172 char[] name, argname; 172 173 char[] const_value; 173 174 OptionCallbackArg callback; 174 175 OptionCallbackInt int_callback; 175 176 OptionCallback void_callback; 177 char[] helptext; 176 178 this( 177 179 char[][] shorts, char[][] longs, ArgType type, 178 180 Action act, char[] name, char[] const_value, 179 181 OptionCallbackArg dga, OptionCallback dg, 180 OptionCallbackInt dgi 182 OptionCallbackInt dgi, 183 char[] help 181 184 ) { 182 185 this.shortopts = shorts; … … 185 188 this.type = type; 186 189 this.name = name; 190 this.argname = toupper(name); 191 this.helptext = help; 187 192 188 193 // Perform sanity checks. … … 217 222 this.void_callback = dg; 218 223 } 224 char[] toString() { 225 int optCount = this.shortopts.length + this.longopts.length; 226 char[] result; 227 bool printed_arg = false; 228 foreach(i, opt; this.shortopts ~ this.longopts) { 229 result ~= opt; 230 if (i < optCount-1) { 231 result ~= ", "; 232 } else if (this.hasArg()) { 233 result ~= "=" ~ toupper(this.argname); 234 } 235 } 236 return result; 237 } 219 238 // Does whatever this option is supposed to do. 220 void perform_action(Option s results, char[] arg) {239 void perform_action(OptionParser parser, Options results, char[] arg) { 221 240 int i; 222 241 if (this.type == ArgType.Integer) { … … 257 276 break; 258 277 case Action.Help: 259 writefln("<Print useful help info here.>"); 278 parser.help_text(); 279 exit(EXIT_SUCCESS); 260 280 break; 261 281 } … … 263 283 bool hasArg() { 264 284 return this.type != ArgType.None; 285 } 286 Option help(char[] help) { 287 this.helptext = help; 288 return this; 289 } 290 Option argName(char[] argname) { 291 this.argname = argname; 292 return this; 265 293 } 266 294 // Returns true if the passed option string matches this option. … … 290 318 } 291 319 320 private void delegate(char[]) error_callback; 321 void set_error_callback(void delegate(char[]) dg) { 322 error_callback = dg; 323 } 324 292 325 void unknown_opt_error(char[] opt) { 293 326 error("Unknown argument '"~opt~"'"); … … 297 330 } 298 331 void error(char[] err) { 299 writefln(err); 332 if (error_callback !is null) { 333 error_callback(err); 334 } else { 335 writefln(err); 336 } 300 337 exit(EXIT_FAILURE); 301 338 } 302 339 303 340 class OptionParser { 341 OptionCallbackArg leftover_cb; 304 342 Option[] options; 305 343 char[] name, desc, argdesc; 344 345 this(char[] desc="") { 346 this.name = ""; 347 this.desc = desc; 348 this.argdesc = "[options] args..."; 349 } 350 351 void help_text() { 352 int optWidth; 353 char[][] optStrs; 354 // Calculate the maximum width of the option lists. 355 foreach(i, opt; options) { 356 optStrs ~= opt.toString(); 357 if (optStrs[i].length > optWidth) { 358 optWidth = optStrs[i].length; 359 } 360 } 361 writefln("Usage: %s %s", this.name, this.argdesc); 362 if (this.desc !is null && this.desc != "") writefln(this.desc); 363 writefln("\nOptions:"); 364 foreach(i, opt; options) { 365 // The commented-out code is a great idea I'll do properly later. 366 //if (opt.helptext.length + optWidth + 3 > 80) { 367 // writefln(" %s\n\t%s", optStrs[i], opt.helptext); 368 //} else { 369 writefln(" %-*s %s", optWidth, optStrs[i], opt.helptext); 370 //} 371 } 372 } 373 306 374 // Checks the passed arg against all the options in the parser. 307 375 // Returns null if no match is found. … … 314 382 return null; 315 383 } 384 char[] get_program_name(char[] path) { 385 char[] result; 386 version(Windows) { 387 assert(path[$-4 .. $] == ".exe"); 388 result = path[0 .. $-4]; 389 } 390 return getBaseName(result); 391 } 316 392 Options parse_args(char[][] args) { 393 this.name = get_program_name(args[0]); 317 394 args = args[1 .. $]; 318 395 Options options = new Options; … … 343 420 for (int i=0; i<args.length; ++i) { 344 421 opt = args[i]; 345 if (opt.startswith("--")) { 422 // -- ends the option list, the remainder is dumped into args 423 if (opt == "--") { 424 options.args ~= args[i+1 .. $]; 425 i = args.length; 426 } else if (opt.startswith("--")) { 346 427 idx = find(opt, '='); 347 428 if (idx != -1) { … … 363 444 arg = null; 364 445 } 365 match.perform_action( options, arg);446 match.perform_action(this, options, arg); 366 447 } else if (opt.startswith("-")) { 367 448 if (opt.length >= 2) { … … 383 464 } else { 384 465 arg = opt[j+2 .. $]; 385 match.perform_action( options, arg);466 match.perform_action(this, options, arg); 386 467 break; 387 468 } … … 389 470 arg = null; 390 471 } 391 match.perform_action( options, arg);472 match.perform_action(this, options, arg); 392 473 } 393 474 } 394 475 } else { 395 options.args ~= opt; 476 if (this.leftover_cb is null) { 477 options.args ~= opt; 478 } else { 479 this.leftover_cb(opt); 480 } 396 481 } 397 482 } … … 399 484 } 400 485 401 // options action name type const_value dga dgv dgi 402 void add_option(char[][] options ...) { 403 add_option(options, Action.Store, null, defaultType(Action.Store), null, null, null, null); 404 } 405 void add_option(char[][] options, char[] name) { 406 add_option(options, Action.Store, name, defaultType(Action.Store), null, null, null, null); 407 } 408 void add_option(char[][] options, Action action) { 409 add_option(options, action, null, defaultType(action), null, null, null, null); 410 } 411 void add_option(char[][] options, ArgType type) { 412 add_option(options, Action.Store, null, type, null, null, null, null); 413 } 414 void add_option(char[][] options, Action action, ArgType type) { 415 add_option(options, action, null, type, null, null, null, null); 416 } 417 void add_option(char[][] options, char[] name, Action action) { 418 add_option(options, action, name, defaultType(action), null, null, null, null); 419 } 420 void add_option(char[][] options, char[] name, Action action, ArgType type) { 421 add_option(options, action, name, type, null, null, null, null); 422 } 423 void add_option(char[][] options, Action action, char[] const_value) { 424 add_option(options, action, null, defaultType(action), const_value, null, null, null); 425 } 426 void add_option(char[][] options, char[] name, char[] const_value) { 427 add_option(options, Action.StoreConst, name, defaultType(Action.Store), const_value, null, null, null); 428 } 429 void add_option(char[][] options, char[] name, Action action, char[] const_value) { 430 add_option(options, action, name, defaultType(action), const_value, null, null, null); 431 } 432 void add_option(char[][] options, OptionCallbackArg dg) { 433 add_option(options, Action.Callback, null, defaultType(Action.Callback), null, dg, null, null); 434 } 435 void add_option(char[][] options, OptionCallback dg) { 436 add_option(options, Action.Callback, null, ArgType.None, null, null, dg, null); 437 } 438 void add_option(char[][] options, OptionCallbackInt dg) { 439 add_option(options, Action.Callback, null, ArgType.Integer, null, null, null, dg); 486 void leftover_callback(OptionCallbackArg dg) { 487 this.leftover_cb = dg; 488 } 489 Option add_option(Option option) { 490 this.options ~= option; 491 return option; 492 } 493 // options action name type const_value dga dgv dgi help 494 Option add_option(char[][] options ...) { 495 return add_option(options, Action.Store, null, defaultType(Action.Store), null, null, null, null, null); 496 } 497 Option add_option(char[][] options, char[] name) { 498 return add_option(options, Action.Store, name, defaultType(Action.Store), null, null, null, null, null); 499 } 500 Option add_option(char[][] options, Action action) { 501 return add_option(options, action, null, defaultType(action), null, null, null, null, null); 502 } 503 Option add_option(char[][] options, ArgType type) { 504 return add_option(options, Action.Store, null, type, null, null, null, null, null); 505 } 506 Option add_option(char[][] options, Action action, ArgType type) { 507 return add_option(options, action, null, type, null, null, null, null, null); 508 } 509 Option add_option(char[][] options, char[] name, Action action) { 510 return add_option(options, action, name, defaultType(action), null, null, null, null, null); 511 } 512 Option add_option(char[][] options, char[] name, Action action, ArgType type) { 513 return add_option(options, action, name, type, null, null, null, null, null); 514 } 515 Option add_option(char[][] options, Action action, char[] const_value) { 516 return add_option(options, action, null, defaultType(action), const_value, null, null, null, null); 517 } 518 Option add_option(char[][] options, char[] name, char[] const_value) { 519 return add_option(options, Action.StoreConst, name, defaultType(Action.Store), const_value, null, null, null, null); 520 } 521 Option add_option(char[][] options, char[] name, Action action, char[] const_value) { 522 return add_option(options, action, name, defaultType(action), const_value, null, null, null, null); 523 } 524 Option add_option(char[][] options, OptionCallbackArg dg) { 525 return add_option(options, Action.Callback, null, defaultType(Action.Callback), null, dg, null, null, null); 526 } 527 Option add_option(char[][] options, OptionCallback dg) { 528 return add_option(options, Action.Callback, null, ArgType.None, null, null, dg, null, null); 529 } 530 Option add_option(char[][] options, OptionCallbackInt dg) { 531 return add_option(options, Action.Callback, null, ArgType.Integer, null, null, null, dg, null); 440 532 } 441 533 // Although users certainly /can/ call this, all those overloads are there 442 534 // for a reason. 443 voidadd_option(535 Option add_option( 444 536 char[][] options, 445 537 Action action, char[] name, ArgType type, char[] const_value, 446 538 OptionCallbackArg callback, OptionCallback vcall, 447 OptionCallbackInt icall 539 OptionCallbackInt icall, 540 char[] help 448 541 ) { 449 542 char[][] shortopts; 450 543 char[][] longopts; 544 Option option; 451 545 foreach (opt; options) { 452 546 if (opt.length < 2) { … … 471 565 if (longopts.length > 0) 472 566 name = longopts[0][2 .. $]; 567 else if (shortopts.length > 0) 568 name = shortopts[0][1 .. 2]; 473 569 else 474 name = shortopts[0][1 .. 2]; 475 } 476 this.options ~= new Option(shortopts, longopts, type, action, name, const_value, callback, vcall, icall); 477 } 478 } 479 570 throw new OptionError( 571 "No options provided to add_option!" 572 ); 573 } 574 option = new Option(shortopts, longopts, type, action, name, const_value, callback, vcall, icall, help); 575 this.options ~= option; 576 return option; 577 } 578 } 579 misc/opttest.d
r75 r76 9 9 writefln("value: ", options.value("value")); 10 10 writefln("number list: ", options.value_list("list")); 11 foreach (a; options.args) { 12 writefln("arg: ", a); 13 } 11 writefln("args: ", options.args); 14 12 } 15 13 16 14 int main(char[][] args) { 17 auto parser = new OptionParser ;18 parser.add_option("-f", "--file") ;19 parser.add_option(["-I", "--import"], "importPath", Action.Append) ;15 auto parser = new OptionParser("A test suite for optparser."); 16 parser.add_option("-f", "--file").help("Stores a single argument."); 17 parser.add_option(["-I", "--import"], "importPath", Action.Append).help("Adds arguments to a list."); 20 18 parser.add_option(["-c", "--callback"], { 21 19 writefln("callback encountered"); 22 }) ;20 }).help("Calls a callback."); 23 21 parser.add_option(["-n", "--number"], (int i) { 24 22 writefln("number callback: %d * 2 = %d", i, i*2); 25 }); 26 parser.add_option(["-V", "--value"], ArgType.Integer); 27 parser.add_option(["-l", "--list"], Action.Append, ArgType.Integer); 28 parser.add_option(["-v", "--verbose"], Action.Count); 23 }).help("Calls a callback with a number."); 24 parser.add_option(["-V", "--value"], ArgType.Integer).help("Stores a single number").argName("NUMBER"); 25 parser.add_option(["-l", "--list"], Action.Append, ArgType.Integer).help("Adds numbers to a list.").argName("NUMBER"); 26 parser.add_option(["-v", "--verbose"], Action.Count).help("Counts the number of times this option appears."); 27 parser.add_option(["-h", "--help"], Action.Help).help("Displays a help message."); 29 28 auto options = parser.parse_args(args); 30 29
