Panda3D

programBase.cxx

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