Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/progbase/programBase.cxx

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

Generated on Fri May 2 03:21:31 2003 for Panda-Tool by doxygen1.3