Panda3D
|
00001 // Filename: programBase.cxx 00002 // Created by: drose (13Feb00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "programBase.h" 00016 #include "wordWrapStream.h" 00017 00018 #include "pnmFileTypeRegistry.h" 00019 #include "indent.h" 00020 #include "dSearchPath.h" 00021 #include "coordinateSystem.h" 00022 #include "dconfig.h" 00023 #include "config_dconfig.h" 00024 #include "string_utils.h" 00025 #include "vector_string.h" 00026 #include "configVariableInt.h" 00027 #include "configVariableBool.h" 00028 00029 #include <stdlib.h> 00030 #include <algorithm> 00031 #include <ctype.h> 00032 00033 // If our system getopt() doesn't come with getopt_long_only(), then use 00034 // the GNU flavor that we've got in tool for this purpose. 00035 #ifndef HAVE_GETOPT_LONG_ONLY 00036 #include "gnu_getopt.h" 00037 #else 00038 #include <getopt.h> 00039 #endif 00040 00041 // This manifest is defined if we are running on a system (e.g. most 00042 // any Unix) that allows us to determine the width of the terminal 00043 // screen via an ioctl() call. It's just handy to know for formatting 00044 // output nicely for the user. 00045 #ifdef IOCTL_TERMINAL_WIDTH 00046 #include <termios.h> 00047 #ifndef TIOCGWINSZ 00048 #include <sys/ioctl.h> 00049 #elif __APPLE__ 00050 #include <sys/ioctl.h> 00051 #endif // TIOCGWINSZ 00052 #endif // IOCTL_TERMINAL_WIDTH 00053 00054 bool ProgramBase::SortOptionsByIndex:: 00055 operator () (const Option *a, const Option *b) const { 00056 if (a->_index_group != b->_index_group) { 00057 return a->_index_group < b->_index_group; 00058 } 00059 return a->_sequence < b->_sequence; 00060 } 00061 00062 // This should be called at program termination just to make sure 00063 // Notify gets properly flushed before we exit, if someone calls 00064 // exit(). It's probably not necessary, but why not be phobic about 00065 // it? 00066 static void flush_nout() { 00067 nout << flush; 00068 } 00069 00070 static ConfigVariableInt default_terminal_width 00071 ("default-terminal-width", 72, 00072 PRC_DESC("Specify the column at which to wrap output lines " 00073 "from pandatool-based programs, if it cannot be determined " 00074 "automatically.")); 00075 00076 static ConfigVariableBool use_terminal_width 00077 ("use-terminal-width", true, 00078 PRC_DESC("True to try to determine the terminal width automatically from " 00079 "the operating system, if supported; false to use the width " 00080 "specified by default-terminal-width even if the operating system " 00081 "appears to report a valid width.")); 00082 00083 //////////////////////////////////////////////////////////////////// 00084 // Function: ProgramBase::Constructor 00085 // Access: Public 00086 // Description: 00087 //////////////////////////////////////////////////////////////////// 00088 ProgramBase:: 00089 ProgramBase() { 00090 // Set up Notify to write output to our own formatted stream. 00091 Notify::ptr()->set_ostream_ptr(new WordWrapStream(this), true); 00092 00093 // And we'll want to be sure to flush that in all normal exit cases. 00094 atexit(&flush_nout); 00095 00096 _path_replace = new PathReplace; 00097 00098 // If a program never adds the path store options, the default path 00099 // store is PS_absolute. This is the most robust solution for 00100 // programs that read files but do not need to write them. 00101 _path_replace->_path_store = PS_absolute; 00102 _got_path_store = false; 00103 _got_path_directory = false; 00104 00105 _next_sequence = 0; 00106 _sorted_options = false; 00107 _last_newline = false; 00108 _got_terminal_width = false; 00109 _got_option_indent = false; 00110 00111 add_option("h", "", 100, 00112 "Display this help page.", 00113 &ProgramBase::handle_help_option, NULL, (void *)this); 00114 00115 // It's nice to start with a blank line. 00116 nout << "\r"; 00117 } 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: ProgramBase::Destructor 00121 // Access: Public, Virtual 00122 // Description: 00123 //////////////////////////////////////////////////////////////////// 00124 ProgramBase:: 00125 ~ProgramBase() { 00126 // Reset Notify in case any messages get sent after our 00127 // destruction--our stream is no longer valid. 00128 Notify::ptr()->set_ostream_ptr(NULL, false); 00129 } 00130 00131 //////////////////////////////////////////////////////////////////// 00132 // Function: ProgramBase::show_description 00133 // Access: Public 00134 // Description: Writes the program description to stderr. 00135 //////////////////////////////////////////////////////////////////// 00136 void ProgramBase:: 00137 show_description() { 00138 nout << _description << "\n"; 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: ProgramBase::show_usage 00143 // Access: Public 00144 // Description: Writes the usage line(s) to stderr. 00145 //////////////////////////////////////////////////////////////////// 00146 void ProgramBase:: 00147 show_usage() { 00148 nout << "\rUsage:\n"; 00149 Runlines::const_iterator ri; 00150 string prog = " " +_program_name.get_basename_wo_extension(); 00151 00152 for (ri = _runlines.begin(); ri != _runlines.end(); ++ri) { 00153 show_text(prog, prog.length() + 1, *ri); 00154 } 00155 nout << "\r"; 00156 } 00157 00158 //////////////////////////////////////////////////////////////////// 00159 // Function: ProgramBase::show_options 00160 // Access: Public 00161 // Description: Describes each of the available options to stderr. 00162 //////////////////////////////////////////////////////////////////// 00163 void ProgramBase:: 00164 show_options() { 00165 sort_options(); 00166 if (!_got_option_indent) { 00167 get_terminal_width(); 00168 _option_indent = min(15, (int)(_terminal_width * 0.25)); 00169 _got_option_indent = true; 00170 } 00171 00172 nout << "Options:\n"; 00173 OptionsByIndex::const_iterator oi; 00174 for (oi = _options_by_index.begin(); oi != _options_by_index.end(); ++oi) { 00175 const Option &opt = *(*oi); 00176 string prefix = " -" + opt._option + " " + opt._parm_name; 00177 show_text(prefix, _option_indent, opt._description + "\r"); 00178 } 00179 } 00180 00181 //////////////////////////////////////////////////////////////////// 00182 // Function: ProgramBase::show_text 00183 // Access: Public 00184 // Description: Formats the indicated text and its prefix for output 00185 // to stderr with the known _terminal_width. 00186 //////////////////////////////////////////////////////////////////// 00187 void ProgramBase:: 00188 show_text(const string &prefix, int indent_width, string text) { 00189 get_terminal_width(); 00190 00191 // This is correct! It goes go to cerr, not to nout. Sending it to 00192 // nout would be cyclic, since nout is redefined to map back through 00193 // this function. 00194 format_text(cerr, _last_newline, 00195 prefix, indent_width, text, _terminal_width); 00196 } 00197 00198 //////////////////////////////////////////////////////////////////// 00199 // Function: ProgramBase::parse_command_line 00200 // Access: Public, Virtual 00201 // Description: Dispatches on each of the options on the command 00202 // line, and passes the remaining parameters to 00203 // handle_args(). If an error on the command line is 00204 // detected, will automatically call show_usage() and 00205 // exit(1). 00206 //////////////////////////////////////////////////////////////////// 00207 void ProgramBase:: 00208 parse_command_line(int argc, char *argv[]) { 00209 00210 00211 // Setting this variable to zero reinitializes the options parser 00212 // This is only necessary for processing multiple command lines in 00213 // the same program (mainly the MaxToEgg converter plugin) 00214 extern int optind; 00215 optind = 0; 00216 00217 00218 _program_name = Filename::from_os_specific(argv[0]); 00219 int i; 00220 for (i = 1; i < argc; i++) { 00221 _program_args.push_back(argv[i]); 00222 } 00223 00224 // Build up the long options list and the short options string for 00225 // getopt_long_only(). 00226 pvector<struct option> long_options; 00227 string short_options; 00228 00229 // We also need to build a temporary map of int index numbers to 00230 // Option pointers. We'll pass these index numbers to GNU's 00231 // getopt_long() so we can tell one option from another. 00232 typedef pmap<int, const Option *> Options; 00233 Options options; 00234 00235 OptionsByName::const_iterator oi; 00236 int next_index = 256; 00237 00238 // Let's prefix the option string with "-" to tell GNU getopt that 00239 // we want it to tell us the post-option arguments, instead of 00240 // trying to meddle with ARGC and ARGV (which we aren't using 00241 // directly). 00242 short_options = "-"; 00243 00244 for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) { 00245 const Option &opt = (*oi).second; 00246 00247 int index; 00248 if (opt._option.length() == 1) { 00249 // This is a "short" option; its option string consists of only 00250 // one letter. Its index is the letter itself. 00251 index = (int)opt._option[0]; 00252 00253 short_options += opt._option; 00254 if (!opt._parm_name.empty()) { 00255 // This option takes an argument. 00256 short_options += ':'; 00257 } 00258 } else { 00259 // This is a "long" option; we'll assign it the next available 00260 // index. 00261 index = ++next_index; 00262 } 00263 00264 // Now add it to the GNU data structures. 00265 struct option gopt; 00266 gopt.name = (char *)opt._option.c_str(); 00267 gopt.has_arg = (opt._parm_name.empty()) ? 00268 no_argument : required_argument; 00269 gopt.flag = (int *)NULL; 00270 00271 // Return an index into the _options_by_index array, offset by 256 00272 // so we don't confuse it with '?'. 00273 gopt.val = index; 00274 00275 long_options.push_back(gopt); 00276 00277 options[index] = &opt; 00278 } 00279 00280 // Finally, add one more structure, all zeroes, to indicate the end 00281 // of the options. 00282 struct option gopt; 00283 memset(&gopt, 0, sizeof(gopt)); 00284 long_options.push_back(gopt); 00285 00286 // We'll use this vector to save the non-option arguments. 00287 // Generally, these will all be at the end, but with the GNU 00288 // extensions, they need not be. 00289 Args remaining_args; 00290 00291 // Now call getopt_long() to actually parse the arguments. 00292 extern char *optarg; 00293 const struct option *long_opts = &long_options[0]; 00294 00295 int flag = 00296 getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL); 00297 while (flag != EOF) { 00298 string arg; 00299 if (optarg != NULL) { 00300 arg = optarg; 00301 } 00302 00303 switch (flag) { 00304 case '?': 00305 // Invalid option or parameter. 00306 show_usage(); 00307 exit(1); 00308 00309 case '\x1': 00310 // A special return value from getopt() indicating a non-option 00311 // argument. 00312 remaining_args.push_back(arg); 00313 break; 00314 00315 default: 00316 { 00317 // A normal option. Figure out which one it is. 00318 Options::const_iterator ii; 00319 ii = options.find(flag); 00320 if (ii == options.end()) { 00321 nout << "Internal error! Invalid option index returned.\n"; 00322 abort(); 00323 } 00324 00325 const Option &opt = *(*ii).second; 00326 bool okflag = true; 00327 if (opt._option_function != (OptionDispatchFunction)NULL) { 00328 okflag = (*opt._option_function)(opt._option, arg, opt._option_data); 00329 } 00330 if (opt._option_method != (OptionDispatchMethod)NULL) { 00331 okflag = (*opt._option_method)(this, opt._option, arg, opt._option_data); 00332 } 00333 if (opt._bool_var != (bool *)NULL) { 00334 (*opt._bool_var) = true; 00335 } 00336 00337 if (!okflag) { 00338 show_usage(); 00339 exit(1); 00340 } 00341 } 00342 } 00343 00344 flag = 00345 getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL); 00346 } 00347 00348 if (!handle_args(remaining_args)) { 00349 show_usage(); 00350 exit(1); 00351 } 00352 00353 if (!post_command_line()) { 00354 show_usage(); 00355 exit(1); 00356 } 00357 } 00358 00359 //////////////////////////////////////////////////////////////////// 00360 // Function: ProgramBase::get_exec_command 00361 // Access: Public 00362 // Description: Returns the command that invoked this program, as a 00363 // shell-friendly string, suitable for pasting into the 00364 // comments of output files. 00365 //////////////////////////////////////////////////////////////////// 00366 string ProgramBase:: 00367 get_exec_command() const { 00368 string command; 00369 00370 command = _program_name.get_basename_wo_extension(); 00371 Args::const_iterator ai; 00372 for (ai = _program_args.begin(); ai != _program_args.end(); ++ai) { 00373 const string &arg = (*ai); 00374 00375 // First, check to see if the string is shell-acceptable. 00376 bool legal = true; 00377 string::const_iterator si; 00378 for (si = arg.begin(); legal && si != arg.end(); ++si) { 00379 switch (*si) { 00380 case ' ': 00381 case '\n': 00382 case '\t': 00383 case '*': 00384 case '?': 00385 case '\\': 00386 case '(': 00387 case ')': 00388 case '|': 00389 case '&': 00390 case '<': 00391 case '>': 00392 case '"': 00393 case ';': 00394 case '$': 00395 legal = false; 00396 } 00397 } 00398 00399 if (legal) { 00400 command += " " + arg; 00401 } else { 00402 command += " '" + arg + "'"; 00403 } 00404 } 00405 00406 return command; 00407 } 00408 00409 00410 //////////////////////////////////////////////////////////////////// 00411 // Function: ProgramBase::handle_args 00412 // Access: Protected, Virtual 00413 // Description: Does something with the additional arguments on the 00414 // command line (after all the -options have been 00415 // parsed). Returns true if the arguments are good, 00416 // false otherwise. 00417 //////////////////////////////////////////////////////////////////// 00418 bool ProgramBase:: 00419 handle_args(ProgramBase::Args &args) { 00420 if (!args.empty()) { 00421 nout << "Unexpected arguments on command line:\n"; 00422 Args::const_iterator ai; 00423 for (ai = args.begin(); ai != args.end(); ++ai) { 00424 nout << (*ai) << " "; 00425 } 00426 nout << "\r"; 00427 return false; 00428 } 00429 00430 return true; 00431 } 00432 00433 //////////////////////////////////////////////////////////////////// 00434 // Function: ProgramBase::post_command_line 00435 // Access: Protected, Virtual 00436 // Description: This is called after the command line has been 00437 // completely processed, and it gives the program a 00438 // chance to do some last-minute processing and 00439 // validation of the options and arguments. It should 00440 // return true if everything is fine, false if there is 00441 // an error. 00442 //////////////////////////////////////////////////////////////////// 00443 bool ProgramBase:: 00444 post_command_line() { 00445 return true; 00446 } 00447 00448 //////////////////////////////////////////////////////////////////// 00449 // Function: ProgramBase::set_program_description 00450 // Access: Protected 00451 // Description: Sets the description of the program that will be 00452 // reported by show_usage(). The description should be 00453 // one long string of text. Embedded newline characters 00454 // are interpreted as paragraph breaks and printed as 00455 // blank lines. 00456 //////////////////////////////////////////////////////////////////// 00457 void ProgramBase:: 00458 set_program_description(const string &description) { 00459 _description = description; 00460 } 00461 00462 //////////////////////////////////////////////////////////////////// 00463 // Function: ProgramBase::clear_runlines 00464 // Access: Protected 00465 // Description: Removes all of the runlines that were previously 00466 // added, presumably before adding some new ones. 00467 //////////////////////////////////////////////////////////////////// 00468 void ProgramBase:: 00469 clear_runlines() { 00470 _runlines.clear(); 00471 } 00472 00473 //////////////////////////////////////////////////////////////////// 00474 // Function: ProgramBase::add_runline 00475 // Access: Protected 00476 // Description: Adds an additional line to the list of lines that 00477 // will be displayed to describe briefly how the program 00478 // is to be run. Each line should be something like 00479 // "[opts] arg1 arg2", that is, it does *not* include 00480 // the name of the program, but it includes everything 00481 // that should be printed after the name of the program. 00482 // 00483 // Normally there is only one runline for a given 00484 // program, but it is possible to define more than one. 00485 //////////////////////////////////////////////////////////////////// 00486 void ProgramBase:: 00487 add_runline(const string &runline) { 00488 _runlines.push_back(runline); 00489 } 00490 00491 //////////////////////////////////////////////////////////////////// 00492 // Function: ProgramBase::clear_options 00493 // Access: Protected 00494 // Description: Removes all of the options that were previously 00495 // added, presumably before adding some new ones. 00496 // Normally you wouldn't want to do this unless you want 00497 // to completely replace all of the options defined by 00498 // base classes. 00499 //////////////////////////////////////////////////////////////////// 00500 void ProgramBase:: 00501 clear_options() { 00502 _options_by_name.clear(); 00503 } 00504 00505 //////////////////////////////////////////////////////////////////// 00506 // Function: ProgramBase::add_option 00507 // Access: Protected 00508 // Description: Adds (or redefines) a command line option. When 00509 // parse_command_line() is executed it will look for 00510 // these options (followed by a hyphen) on the command 00511 // line; when a particular option is found it will call 00512 // the indicated option_function, supplying the provided 00513 // option_data. This allows the user to define a 00514 // function that does some special behavior for any 00515 // given option, or to use any of a number of generic 00516 // pre-defined functions to fill in data for each 00517 // option. 00518 // 00519 // Each option may or may not take a parameter. If 00520 // parm_name is nonempty, it is assumed that the option 00521 // does take a parameter (and parm_name contains the 00522 // name that will be printed by show_options()). This 00523 // parameter will be supplied as the second parameter to 00524 // the dispatch function. If parm_name is empty, it is 00525 // assumed that the option does not take a parameter. 00526 // There is no provision for optional parameters. 00527 // 00528 // The options are listed first in order by their 00529 // index_group number, and then in the order that 00530 // add_option() was called. This provides a mechanism 00531 // for listing the options defined in derived classes 00532 // before those of the base classes. 00533 //////////////////////////////////////////////////////////////////// 00534 void ProgramBase:: 00535 add_option(const string &option, const string &parm_name, 00536 int index_group, const string &description, 00537 OptionDispatchFunction option_function, 00538 bool *bool_var, void *option_data) { 00539 Option opt; 00540 opt._option = option; 00541 opt._parm_name = parm_name; 00542 opt._index_group = index_group; 00543 opt._sequence = ++_next_sequence; 00544 opt._description = description; 00545 opt._option_function = option_function; 00546 opt._option_method = (OptionDispatchMethod)NULL; 00547 opt._bool_var = bool_var; 00548 opt._option_data = option_data; 00549 00550 _options_by_name[option] = opt; 00551 _sorted_options = false; 00552 00553 if (bool_var != (bool *)NULL) { 00554 (*bool_var) = false; 00555 } 00556 } 00557 00558 //////////////////////////////////////////////////////////////////// 00559 // Function: ProgramBase::add_option 00560 // Access: Protected 00561 // Description: This is another variant on add_option(), above, 00562 // except that it receives a pointer to a "method", 00563 // which is really just another static (or global) 00564 // function, whose first parameter is a ProgramBase *. 00565 // 00566 // We can't easily add a variant that accepts a real 00567 // method, because the C++ syntax for methods requires 00568 // us to know exactly what class object the method is 00569 // defined for, and we want to support adding pointers 00570 // for methods that are defined in other classes. So we 00571 // have this hacky thing, which requires the "method" to 00572 // be declared static, and receive its this pointer 00573 // explicitly, as the first argument. 00574 //////////////////////////////////////////////////////////////////// 00575 void ProgramBase:: 00576 add_option(const string &option, const string &parm_name, 00577 int index_group, const string &description, 00578 OptionDispatchMethod option_method, 00579 bool *bool_var, void *option_data) { 00580 Option opt; 00581 opt._option = option; 00582 opt._parm_name = parm_name; 00583 opt._index_group = index_group; 00584 opt._sequence = ++_next_sequence; 00585 opt._description = description; 00586 opt._option_function = (OptionDispatchFunction)NULL; 00587 opt._option_method = option_method; 00588 opt._bool_var = bool_var; 00589 opt._option_data = option_data; 00590 00591 _options_by_name[option] = opt; 00592 _sorted_options = false; 00593 00594 if (bool_var != (bool *)NULL) { 00595 (*bool_var) = false; 00596 } 00597 } 00598 00599 //////////////////////////////////////////////////////////////////// 00600 // Function: ProgramBase::redescribe_option 00601 // Access: Protected 00602 // Description: Changes the description associated with a 00603 // previously-defined option. Returns true if the 00604 // option was changed, false if it hadn't been defined. 00605 //////////////////////////////////////////////////////////////////// 00606 bool ProgramBase:: 00607 redescribe_option(const string &option, const string &description) { 00608 OptionsByName::iterator oi = _options_by_name.find(option); 00609 if (oi == _options_by_name.end()) { 00610 return false; 00611 } 00612 (*oi).second._description = description; 00613 return true; 00614 } 00615 00616 //////////////////////////////////////////////////////////////////// 00617 // Function: ProgramBase::remove_option 00618 // Access: Protected 00619 // Description: Removes a previously-defined option. Returns true if 00620 // the option was removed, false if it hadn't existed. 00621 //////////////////////////////////////////////////////////////////// 00622 bool ProgramBase:: 00623 remove_option(const string &option) { 00624 OptionsByName::iterator oi = _options_by_name.find(option); 00625 if (oi == _options_by_name.end()) { 00626 return false; 00627 } 00628 _options_by_name.erase(oi); 00629 _sorted_options = false; 00630 return true; 00631 } 00632 00633 //////////////////////////////////////////////////////////////////// 00634 // Function: ProgramBase::add_path_replace_options 00635 // Access: Public 00636 // Description: Adds -pr etc. as valid options for this program. 00637 // These are appropriate for a model converter or model 00638 // reader type program, and specify how to locate 00639 // possibly-invalid pathnames in the source model file. 00640 //////////////////////////////////////////////////////////////////// 00641 void ProgramBase:: 00642 add_path_replace_options() { 00643 add_option 00644 ("pr", "path_replace", 40, 00645 "Sometimes references to other files (textures, external references) " 00646 "are stored with a full path that is appropriate for some other system, " 00647 "but does not exist here. This option may be used to specify how " 00648 "those invalid paths map to correct paths. Generally, this is of " 00649 "the form 'orig_prefix=replacement_prefix', which indicates a " 00650 "particular initial sequence of characters that should be replaced " 00651 "with a new sequence; e.g. '/c/home/models=/beta/fish'. " 00652 "If the replacement prefix does not begin with a slash, the file " 00653 "will then be searched for along the search path specified by -pp. " 00654 "You may use standard filename matching characters ('*', '?', etc.) in " 00655 "the original prefix, and '**' as a component by itself stands for " 00656 "any number of components.\n\n" 00657 00658 "This option may be repeated as necessary; each file will be tried " 00659 "against each specified method, in the order in which they appear in " 00660 "the command line, until the file is found. If the file is not found, " 00661 "the last matching prefix is used anyway.", 00662 &ProgramBase::dispatch_path_replace, NULL, _path_replace.p()); 00663 00664 add_option 00665 ("pp", "dirname", 40, 00666 "Adds the indicated directory name to the list of directories to " 00667 "search for filenames referenced by the source file. This is used " 00668 "only for relative paths, or for paths that are made relative by a " 00669 "-pr replacement string that doesn't begin with a leading slash. " 00670 "The model-path is always implicitly searched anyway.", 00671 &ProgramBase::dispatch_search_path, NULL, &(_path_replace->_path)); 00672 } 00673 00674 //////////////////////////////////////////////////////////////////// 00675 // Function: ProgramBase::add_path_store_options 00676 // Access: Public 00677 // Description: Adds -ps etc. as valid options for this program. 00678 // These are appropriate for a model converter type 00679 // program, and specify how to represent filenames in 00680 // the output file. 00681 //////////////////////////////////////////////////////////////////// 00682 void ProgramBase:: 00683 add_path_store_options() { 00684 // If a program has path store options at all, the default path 00685 // store is relative. 00686 _path_replace->_path_store = PS_relative; 00687 00688 add_option 00689 ("ps", "path_store", 40, 00690 "Specifies the way an externally referenced file is to be " 00691 "represented in the resulting output file. This " 00692 "assumes the named filename actually exists; " 00693 "see -pr to indicate how to deal with external " 00694 "references that have bad pathnames. " 00695 "This option will not help you to find a missing file, but simply " 00696 "controls how filenames are represented in the output.\n\n" 00697 00698 "The option may be one of: rel, abs, rel_abs, strip, or keep. If " 00699 "either rel or rel_abs is specified, the files are made relative to " 00700 "the directory specified by -pd. The default is rel.", 00701 &ProgramBase::dispatch_path_store, &_got_path_store, 00702 &(_path_replace->_path_store)); 00703 00704 add_option 00705 ("pd", "path_directory", 40, 00706 "Specifies the name of a directory to make paths relative to, if " 00707 "'-ps rel' or '-ps rel_abs' is specified. If this is omitted, the " 00708 "directory name is taken from the name of the output file.", 00709 &ProgramBase::dispatch_filename, &_got_path_directory, 00710 &(_path_replace->_path_directory)); 00711 } 00712 00713 //////////////////////////////////////////////////////////////////// 00714 // Function: ProgramBase::dispatch_none 00715 // Access: Protected, Static 00716 // Description: Standard dispatch function for an option that takes 00717 // no parameters, and does nothing special. Typically 00718 // this would be used for a boolean flag, whose presence 00719 // means something and whose absence means something 00720 // else. Use the bool_var parameter to add_option() to 00721 // determine whether the option appears on the command 00722 // line or not. 00723 //////////////////////////////////////////////////////////////////// 00724 bool ProgramBase:: 00725 dispatch_none(const string &, const string &, void *) { 00726 return true; 00727 } 00728 00729 //////////////////////////////////////////////////////////////////// 00730 // Function: ProgramBase::dispatch_true 00731 // Access: Protected, Static 00732 // Description: Standard dispatch function for an option that takes 00733 // no parameters, and when it is present sets a bool 00734 // variable to the 'true' value. This is another way to 00735 // handle a boolean flag. See also dispatch_none() and 00736 // dispatch_false(). 00737 // 00738 // The data pointer is to a bool variable. 00739 //////////////////////////////////////////////////////////////////// 00740 bool ProgramBase:: 00741 dispatch_true(const string &, const string &, void *var) { 00742 bool *bp = (bool *)var; 00743 (*bp) = true; 00744 return true; 00745 } 00746 00747 //////////////////////////////////////////////////////////////////// 00748 // Function: ProgramBase::dispatch_false 00749 // Access: Protected, Static 00750 // Description: Standard dispatch function for an option that takes 00751 // no parameters, and when it is present sets a bool 00752 // variable to the 'false' value. This is another way to 00753 // handle a boolean flag. See also dispatch_none() and 00754 // dispatch_true(). 00755 // 00756 // The data pointer is to a bool variable. 00757 //////////////////////////////////////////////////////////////////// 00758 bool ProgramBase:: 00759 dispatch_false(const string &, const string &, void *var) { 00760 bool *bp = (bool *)var; 00761 (*bp) = false; 00762 return true; 00763 } 00764 00765 //////////////////////////////////////////////////////////////////// 00766 // Function: ProgramBase::dispatch_count 00767 // Access: Protected, Static 00768 // Description: Standard dispatch function for an option that takes 00769 // no parameters, but whose presence on the command line 00770 // increments an integer counter for each time it 00771 // appears. -v is often an option that works this way. 00772 // The data pointer is to an int counter variable. 00773 //////////////////////////////////////////////////////////////////// 00774 bool ProgramBase:: 00775 dispatch_count(const string &, const string &, void *var) { 00776 int *ip = (int *)var; 00777 (*ip)++; 00778 00779 return true; 00780 } 00781 00782 //////////////////////////////////////////////////////////////////// 00783 // Function: ProgramBase::dispatch_int 00784 // Access: Protected, Static 00785 // Description: Standard dispatch function for an option that takes 00786 // one parameter, which is to be interpreted as an 00787 // integer. The data pointer is to an int variable. 00788 //////////////////////////////////////////////////////////////////// 00789 bool ProgramBase:: 00790 dispatch_int(const string &opt, const string &arg, void *var) { 00791 int *ip = (int *)var; 00792 00793 if (!string_to_int(arg, *ip)) { 00794 nout << "Invalid integer parameter for -" << opt << ": " 00795 << arg << "\n"; 00796 return false; 00797 } 00798 00799 return true; 00800 } 00801 00802 //////////////////////////////////////////////////////////////////// 00803 // Function: ProgramBase::dispatch_int_pair 00804 // Access: Protected, Static 00805 // Description: Standard dispatch function for an option that takes 00806 // a pair of integer parameters. The data pointer is to 00807 // an array of two integers. 00808 //////////////////////////////////////////////////////////////////// 00809 bool ProgramBase:: 00810 dispatch_int_pair(const string &opt, const string &arg, void *var) { 00811 int *ip = (int *)var; 00812 00813 vector_string words; 00814 tokenize(arg, words, ","); 00815 00816 bool okflag = false; 00817 if (words.size() == 2) { 00818 okflag = 00819 string_to_int(words[0], ip[0]) && 00820 string_to_int(words[1], ip[1]); 00821 } 00822 00823 if (!okflag) { 00824 nout << "-" << opt 00825 << " requires a pair of integers separated by a comma.\n"; 00826 return false; 00827 } 00828 00829 return true; 00830 } 00831 00832 //////////////////////////////////////////////////////////////////// 00833 // Function: ProgramBase::dispatch_double 00834 // Access: Protected, Static 00835 // Description: Standard dispatch function for an option that takes 00836 // one parameter, which is to be interpreted as a 00837 // double. The data pointer is to an double variable. 00838 //////////////////////////////////////////////////////////////////// 00839 bool ProgramBase:: 00840 dispatch_double(const string &opt, const string &arg, void *var) { 00841 double *ip = (double *)var; 00842 00843 if (!string_to_double(arg, *ip)) { 00844 nout << "Invalid numeric parameter for -" << opt << ": " 00845 << arg << "\n"; 00846 return false; 00847 } 00848 00849 return true; 00850 } 00851 00852 //////////////////////////////////////////////////////////////////// 00853 // Function: ProgramBase::dispatch_double_pair 00854 // Access: Protected, Static 00855 // Description: Standard dispatch function for an option that takes 00856 // a pair of double parameters. The data pointer is to 00857 // an array of two doubles. 00858 //////////////////////////////////////////////////////////////////// 00859 bool ProgramBase:: 00860 dispatch_double_pair(const string &opt, const string &arg, void *var) { 00861 double *ip = (double *)var; 00862 00863 vector_string words; 00864 tokenize(arg, words, ","); 00865 00866 bool okflag = false; 00867 if (words.size() == 2) { 00868 okflag = 00869 string_to_double(words[0], ip[0]) && 00870 string_to_double(words[1], ip[1]); 00871 } 00872 00873 if (!okflag) { 00874 nout << "-" << opt 00875 << " requires a pair of numbers separated by a comma.\n"; 00876 return false; 00877 } 00878 00879 return true; 00880 } 00881 00882 //////////////////////////////////////////////////////////////////// 00883 // Function: ProgramBase::dispatch_double_triple 00884 // Access: Protected, Static 00885 // Description: Standard dispatch function for an option that takes 00886 // a triple of double parameters. The data pointer is to 00887 // an array of three doubles. 00888 //////////////////////////////////////////////////////////////////// 00889 bool ProgramBase:: 00890 dispatch_double_triple(const string &opt, const string &arg, void *var) { 00891 double *ip = (double *)var; 00892 00893 vector_string words; 00894 tokenize(arg, words, ","); 00895 00896 bool okflag = false; 00897 if (words.size() == 3) { 00898 okflag = 00899 string_to_double(words[0], ip[0]) && 00900 string_to_double(words[1], ip[1]) && 00901 string_to_double(words[2], ip[2]); 00902 } 00903 00904 if (!okflag) { 00905 nout << "-" << opt 00906 << " requires three numbers separated by commas.\n"; 00907 return false; 00908 } 00909 00910 return true; 00911 } 00912 00913 //////////////////////////////////////////////////////////////////// 00914 // Function: ProgramBase::dispatch_double_quad 00915 // Access: Protected, Static 00916 // Description: Standard dispatch function for an option that takes 00917 // a quad of double parameters. The data pointer is to 00918 // an array of four doubles. 00919 //////////////////////////////////////////////////////////////////// 00920 bool ProgramBase:: 00921 dispatch_double_quad(const string &opt, const string &arg, void *var) { 00922 double *ip = (double *)var; 00923 00924 vector_string words; 00925 tokenize(arg, words, ","); 00926 00927 bool okflag = false; 00928 if (words.size() == 4) { 00929 okflag = 00930 string_to_double(words[0], ip[0]) && 00931 string_to_double(words[1], ip[1]) && 00932 string_to_double(words[2], ip[2]) && 00933 string_to_double(words[3], ip[3]); 00934 } 00935 00936 if (!okflag) { 00937 nout << "-" << opt 00938 << " requires four numbers separated by commas.\n"; 00939 return false; 00940 } 00941 00942 return true; 00943 } 00944 00945 //////////////////////////////////////////////////////////////////// 00946 // Function: ProgramBase::dispatch_color 00947 // Access: Protected, Static 00948 // Description: Standard dispatch function for an option that takes a 00949 // color, as l or l,a or r,g,b or r,g,b,a. The data 00950 // pointer is to an array of four floats, e.g. a Colorf. 00951 //////////////////////////////////////////////////////////////////// 00952 bool ProgramBase:: 00953 dispatch_color(const string &opt, const string &arg, void *var) { 00954 float *ip = (float *)var; 00955 00956 vector_string words; 00957 tokenize(arg, words, ","); 00958 00959 bool okflag = false; 00960 switch (words.size()) { 00961 case 4: 00962 okflag = 00963 string_to_float(words[0], ip[0]) && 00964 string_to_float(words[1], ip[1]) && 00965 string_to_float(words[2], ip[2]) && 00966 string_to_float(words[3], ip[3]); 00967 break; 00968 00969 case 3: 00970 okflag = 00971 string_to_float(words[0], ip[0]) && 00972 string_to_float(words[1], ip[1]) && 00973 string_to_float(words[2], ip[2]); 00974 ip[3] = 1.0; 00975 break; 00976 00977 case 2: 00978 okflag = 00979 string_to_float(words[0], ip[0]) && 00980 string_to_float(words[1], ip[3]); 00981 ip[1] = ip[0]; 00982 ip[2] = ip[0]; 00983 break; 00984 00985 case 1: 00986 okflag = 00987 string_to_float(words[0], ip[0]); 00988 ip[1] = ip[0]; 00989 ip[2] = ip[0]; 00990 ip[3] = 1.0; 00991 break; 00992 } 00993 00994 if (!okflag) { 00995 nout << "-" << opt 00996 << " requires one through four numbers separated by commas.\n"; 00997 return false; 00998 } 00999 01000 return true; 01001 } 01002 01003 //////////////////////////////////////////////////////////////////// 01004 // Function: ProgramBase::dispatch_string 01005 // Access: Protected, Static 01006 // Description: Standard dispatch function for an option that takes 01007 // one parameter, which is to be interpreted as a 01008 // string. The data pointer is to a string variable. 01009 //////////////////////////////////////////////////////////////////// 01010 bool ProgramBase:: 01011 dispatch_string(const string &, const string &arg, void *var) { 01012 string *ip = (string *)var; 01013 (*ip) = arg; 01014 01015 return true; 01016 } 01017 01018 //////////////////////////////////////////////////////////////////// 01019 // Function: ProgramBase::dispatch_vector_string 01020 // Access: Protected, Static 01021 // Description: Standard dispatch function for an option that takes 01022 // one parameter, which is to be interpreted as a 01023 // string. This is different from dispatch_string in 01024 // that the parameter may be repeated multiple times, 01025 // and each time the string value is appended to a 01026 // vector. 01027 // 01028 // The data pointer is to a vector_string variable. 01029 //////////////////////////////////////////////////////////////////// 01030 bool ProgramBase:: 01031 dispatch_vector_string(const string &, const string &arg, void *var) { 01032 vector_string *ip = (vector_string *)var; 01033 (*ip).push_back(arg); 01034 01035 return true; 01036 } 01037 01038 //////////////////////////////////////////////////////////////////// 01039 // Function: ProgramBase::dispatch_vector_string_comma 01040 // Access: Protected, Static 01041 // Description: Similar to dispatch_vector_string, but a comma is 01042 // allowed to separate multiple tokens in one argument, 01043 // without having to repeat the argument for each token. 01044 // 01045 // The data pointer is to a vector_string variable. 01046 //////////////////////////////////////////////////////////////////// 01047 bool ProgramBase:: 01048 dispatch_vector_string_comma(const string &, const string &arg, void *var) { 01049 vector_string *ip = (vector_string *)var; 01050 01051 vector_string words; 01052 tokenize(arg, words, ","); 01053 01054 vector_string::const_iterator wi; 01055 for (wi = words.begin(); wi != words.end(); ++wi) { 01056 (*ip).push_back(*wi); 01057 } 01058 01059 return true; 01060 } 01061 01062 //////////////////////////////////////////////////////////////////// 01063 // Function: ProgramBase::dispatch_filename 01064 // Access: Protected, Static 01065 // Description: Standard dispatch function for an option that takes 01066 // one parameter, which is to be interpreted as a 01067 // filename. The data pointer is to a Filename variable. 01068 //////////////////////////////////////////////////////////////////// 01069 bool ProgramBase:: 01070 dispatch_filename(const string &opt, const string &arg, void *var) { 01071 if (arg.empty()) { 01072 nout << "-" << opt << " requires a filename parameter.\n"; 01073 return false; 01074 } 01075 01076 Filename *ip = (Filename *)var; 01077 (*ip) = Filename::from_os_specific(arg); 01078 01079 return true; 01080 } 01081 01082 //////////////////////////////////////////////////////////////////// 01083 // Function: ProgramBase::dispatch_search_path 01084 // Access: Protected, Static 01085 // Description: Standard dispatch function for an option that takes 01086 // one parameter, which is to be interpreted as a 01087 // single directory name to add to a search path. The 01088 // data pointer is to a DSearchPath variable. This kind 01089 // of option may appear multiple times on the command 01090 // line; each time, the new directory is appended. 01091 //////////////////////////////////////////////////////////////////// 01092 bool ProgramBase:: 01093 dispatch_search_path(const string &opt, const string &arg, void *var) { 01094 if (arg.empty()) { 01095 nout << "-" << opt << " requires a search path parameter.\n"; 01096 return false; 01097 } 01098 01099 DSearchPath *ip = (DSearchPath *)var; 01100 ip->append_directory(Filename::from_os_specific(arg)); 01101 01102 return true; 01103 } 01104 01105 //////////////////////////////////////////////////////////////////// 01106 // Function: ProgramBase::dispatch_coordinate_system 01107 // Access: Protected, Static 01108 // Description: Standard dispatch function for an option that takes 01109 // one parameter, which is to be interpreted as a 01110 // coordinate system string. The data pointer is to a 01111 // CoordinateSystem variable. 01112 //////////////////////////////////////////////////////////////////// 01113 bool ProgramBase:: 01114 dispatch_coordinate_system(const string &opt, const string &arg, void *var) { 01115 CoordinateSystem *ip = (CoordinateSystem *)var; 01116 (*ip) = parse_coordinate_system_string(arg); 01117 01118 if ((*ip) == CS_invalid) { 01119 nout << "Invalid coordinate system for -" << opt << ": " << arg << "\n" 01120 << "Valid coordinate system strings are any of 'y-up', 'z-up', " 01121 "'y-up-left', or 'z-up-left'.\n"; 01122 return false; 01123 } 01124 01125 return true; 01126 } 01127 01128 //////////////////////////////////////////////////////////////////// 01129 // Function: ProgramBase::dispatch_units 01130 // Access: Protected, Static 01131 // Description: Standard dispatch function for an option that takes 01132 // one parameter, which is to be interpreted as a 01133 // unit of distance measurement. The data pointer is to 01134 // a DistanceUnit variable. 01135 //////////////////////////////////////////////////////////////////// 01136 bool ProgramBase:: 01137 dispatch_units(const string &opt, const string &arg, void *var) { 01138 DistanceUnit *ip = (DistanceUnit *)var; 01139 (*ip) = string_distance_unit(arg); 01140 01141 if ((*ip) == DU_invalid) { 01142 nout << "Invalid units for -" << opt << ": " << arg << "\n" 01143 << "Valid units are mm, cm, m, km, yd, ft, in, nmi, and mi.\n"; 01144 return false; 01145 } 01146 01147 return true; 01148 } 01149 01150 //////////////////////////////////////////////////////////////////// 01151 // Function: ProgramBase::dispatch_image_type 01152 // Access: Protected, Static 01153 // Description: Standard dispatch function for an option that takes 01154 // one parameter, which is to indicate an image file 01155 // type, like rgb, bmp, jpg, etc. The data pointer is 01156 // to a PNMFileType pointer. 01157 //////////////////////////////////////////////////////////////////// 01158 bool ProgramBase:: 01159 dispatch_image_type(const string &opt, const string &arg, void *var) { 01160 PNMFileType **ip = (PNMFileType **)var; 01161 01162 PNMFileTypeRegistry *reg = PNMFileTypeRegistry::get_global_ptr(); 01163 01164 (*ip) = reg->get_type_from_extension(arg); 01165 01166 if ((*ip) == (PNMFileType *)NULL) { 01167 nout << "Invalid image type for -" << opt << ": " << arg << "\n" 01168 << "The following image types are known:\n"; 01169 reg->write(nout, 2); 01170 return false; 01171 } 01172 01173 return true; 01174 } 01175 01176 //////////////////////////////////////////////////////////////////// 01177 // Function: ProgramBase::dispatch_path_replace 01178 // Access: Protected, Static 01179 // Description: Standard dispatch function for an option that takes 01180 // one parameter, which is to be interpreted as a 01181 // single component of a path replace request. The data 01182 // pointer is to a PathReplace variable. 01183 //////////////////////////////////////////////////////////////////// 01184 bool ProgramBase:: 01185 dispatch_path_replace(const string &opt, const string &arg, void *var) { 01186 PathReplace *ip = (PathReplace *)var; 01187 size_t equals = arg.find('='); 01188 if (equals == string::npos) { 01189 nout << "Invalid path replacement string for -" << opt << ": " << arg << "\n" 01190 << "String should be of the form 'old-prefix=new-prefix'.\n"; 01191 return false; 01192 } 01193 ip->add_pattern(arg.substr(0, equals), arg.substr(equals + 1)); 01194 01195 return true; 01196 } 01197 01198 //////////////////////////////////////////////////////////////////// 01199 // Function: ProgramBase::dispatch_path_store 01200 // Access: Protected, Static 01201 // Description: Standard dispatch function for an option that takes 01202 // one parameter, which is to be interpreted as a 01203 // path store string. The data pointer is to a 01204 // PathStore variable. 01205 //////////////////////////////////////////////////////////////////// 01206 bool ProgramBase:: 01207 dispatch_path_store(const string &opt, const string &arg, void *var) { 01208 PathStore *ip = (PathStore *)var; 01209 (*ip) = string_path_store(arg); 01210 01211 if ((*ip) == PS_invalid) { 01212 nout << "Invalid path store for -" << opt << ": " << arg << "\n" 01213 << "Valid path store strings are any of 'rel', 'abs', " 01214 << "'rel_abs', 'strip', or 'keep'.\n"; 01215 return false; 01216 } 01217 01218 return true; 01219 } 01220 01221 //////////////////////////////////////////////////////////////////// 01222 // Function: ProgramBase::handle_help_option 01223 // Access: Protected, Static 01224 // Description: Called when the user enters '-h', this describes how 01225 // to use the program and then exits. 01226 //////////////////////////////////////////////////////////////////// 01227 bool ProgramBase:: 01228 handle_help_option(const string &, const string &, void *data) { 01229 ProgramBase *me = (ProgramBase *)data; 01230 me->show_description(); 01231 me->show_usage(); 01232 me->show_options(); 01233 exit(0); 01234 01235 return false; 01236 } 01237 01238 01239 //////////////////////////////////////////////////////////////////// 01240 // Function: ProgramBase::format_text 01241 // Access: Protected, Static 01242 // Description: Word-wraps the indicated text to the indicated output 01243 // stream. The first line is prefixed with the 01244 // indicated prefix, then tabbed over to indent_width 01245 // where the text actually begins. A newline is 01246 // inserted at or before column line_width. Each 01247 // subsequent line begins with indent_width spaces. 01248 // 01249 // An embedded newline character ('\n') forces a line 01250 // break, while an embedded carriage-return character 01251 // ('\r'), or two or more consecutive newlines, marks a 01252 // paragraph break, which is usually printed as a blank 01253 // line. Redundant newline and carriage-return 01254 // characters are generally ignored. 01255 // 01256 // The flag last_newline should be initialized to false 01257 // for the first call to format_text, and then preserved 01258 // for future calls; it tracks the state of trailing 01259 // newline characters between calls so we can correctly 01260 // identify doubled newlines. 01261 //////////////////////////////////////////////////////////////////// 01262 void ProgramBase:: 01263 format_text(ostream &out, bool &last_newline, 01264 const string &prefix, int indent_width, 01265 const string &text, int line_width) { 01266 indent_width = min(indent_width, line_width - 20); 01267 int indent_amount = indent_width; 01268 bool initial_break = false; 01269 01270 if (!prefix.empty()) { 01271 out << prefix; 01272 indent_amount = indent_width - prefix.length(); 01273 if ((int)prefix.length() + 1 > indent_width) { 01274 out << "\n"; 01275 initial_break = true; 01276 indent_amount = indent_width; 01277 } 01278 } 01279 01280 size_t p = 0; 01281 01282 // Skip any initial whitespace and newlines. 01283 while (p < text.length() && isspace(text[p])) { 01284 if (text[p] == '\r' || 01285 (p > 0 && text[p] == '\n' && text[p - 1] == '\n') || 01286 (p == 0 && text[p] == '\n' && last_newline)) { 01287 if (!initial_break) { 01288 // Here's an initial paragraph break, however. 01289 out << "\n"; 01290 initial_break = true; 01291 } 01292 indent_amount = indent_width; 01293 01294 } else if (text[p] == '\n') { 01295 // Largely ignore an initial newline. 01296 indent_amount = indent_width; 01297 01298 } else if (text[p] == ' ') { 01299 // Do count up leading spaces. 01300 indent_amount++; 01301 } 01302 p++; 01303 } 01304 01305 last_newline = (!text.empty() && text[text.length() - 1] == '\n'); 01306 01307 while (p < text.length()) { 01308 // Look for the paragraph or line break--the next newline 01309 // character, if any. 01310 size_t par = text.find_first_of("\n\r", p); 01311 bool is_paragraph_break = false; 01312 if (par == string::npos) { 01313 par = text.length(); 01314 /* 01315 This shouldn't be necessary. 01316 } else { 01317 is_paragraph_break = (text[par] == '\r'); 01318 */ 01319 } 01320 01321 indent(out, indent_amount); 01322 01323 size_t eol = p + (line_width - indent_width); 01324 if (eol >= par) { 01325 // The rest of the paragraph fits completely on the line. 01326 eol = par; 01327 01328 } else { 01329 // The paragraph doesn't fit completely on the line. Determine 01330 // the best place to break the line. Look for the last space 01331 // before the ideal eol. 01332 size_t min_eol = max((int)p, (int)eol - 25); 01333 size_t q = eol; 01334 while (q > min_eol && !isspace(text[q])) { 01335 q--; 01336 } 01337 // Now roll back to the last non-space before this one. 01338 while (q > min_eol && isspace(text[q])) { 01339 q--; 01340 } 01341 01342 if (q != min_eol) { 01343 // Here's a good place to stop! 01344 eol = q + 1; 01345 01346 } else { 01347 // The line cannot be broken cleanly. Just let it keep going; 01348 // don't try to wrap it. 01349 eol = par; 01350 } 01351 } 01352 out << text.substr(p, eol - p) << "\n"; 01353 p = eol; 01354 01355 // Skip additional whitespace between the lines. 01356 while (p < text.length() && isspace(text[p])) { 01357 if (text[p] == '\r' || 01358 (p > 0 && text[p] == '\n' && text[p - 1] == '\n')) { 01359 is_paragraph_break = true; 01360 } 01361 p++; 01362 } 01363 01364 if (eol == par && is_paragraph_break) { 01365 // Print the paragraph break as a blank line. 01366 out << "\n"; 01367 if (p >= text.length()) { 01368 // If we end on a paragraph break, don't try to insert a new 01369 // one in the next pass. 01370 last_newline = false; 01371 } 01372 } 01373 01374 indent_amount = indent_width; 01375 } 01376 } 01377 01378 01379 //////////////////////////////////////////////////////////////////// 01380 // Function: ProgramBase::sort_options 01381 // Access: Private 01382 // Description: Puts all the options in order by index number 01383 // (e.g. in the order they were added, within 01384 // index_groups), for output by show_options(). 01385 //////////////////////////////////////////////////////////////////// 01386 void ProgramBase:: 01387 sort_options() { 01388 if (!_sorted_options) { 01389 _options_by_index.clear(); 01390 01391 OptionsByName::const_iterator oi; 01392 for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) { 01393 _options_by_index.push_back(&(*oi).second); 01394 } 01395 01396 sort(_options_by_index.begin(), _options_by_index.end(), 01397 SortOptionsByIndex()); 01398 _sorted_options = true; 01399 } 01400 } 01401 01402 //////////////////////////////////////////////////////////////////// 01403 // Function: ProgramBase::get_terminal_width 01404 // Access: Private 01405 // Description: Attempts to determine the ideal terminal width for 01406 // formatting output. 01407 //////////////////////////////////////////////////////////////////// 01408 void ProgramBase:: 01409 get_terminal_width() { 01410 if (!_got_terminal_width) { 01411 _got_terminal_width = true; 01412 _got_option_indent = false; 01413 01414 #ifdef IOCTL_TERMINAL_WIDTH 01415 if (use_terminal_width) { 01416 struct winsize size; 01417 int result = ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&size); 01418 if (result < 0 || size.ws_col < 10) { 01419 // Couldn't determine the width for some reason. Instead of 01420 // complaining, just punt. 01421 _terminal_width = default_terminal_width; 01422 } else { 01423 01424 // Subtract 10% for the comfort margin at the edge. 01425 _terminal_width = size.ws_col - min(8, (int)(size.ws_col * 0.1)); 01426 } 01427 return; 01428 } 01429 #endif // IOCTL_TERMINAL_WIDTH 01430 01431 _terminal_width = default_terminal_width; 01432 } 01433 }