Panda3D
programBase.cxx
1 // Filename: programBase.cxx
2 // Created by: drose (13Feb00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "programBase.h"
16 #include "wordWrapStream.h"
17 
18 #include "pnmFileTypeRegistry.h"
19 #include "indent.h"
20 #include "dSearchPath.h"
21 #include "coordinateSystem.h"
22 #include "dconfig.h"
23 #include "config_dconfig.h"
24 #include "string_utils.h"
25 #include "vector_string.h"
26 #include "configVariableInt.h"
27 #include "configVariableBool.h"
28 #include "panda_getopt_long.h"
29 #include "preprocess_argv.h"
30 #include "pandaSystem.h"
31 
32 #include <stdlib.h>
33 #include <algorithm>
34 #include <ctype.h>
35 
36 // This manifest is defined if we are running on a system (e.g. most
37 // any Unix) that allows us to determine the width of the terminal
38 // screen via an ioctl() call. It's just handy to know for formatting
39 // output nicely for the user.
40 #ifdef IOCTL_TERMINAL_WIDTH
41  #include <termios.h>
42  #ifndef TIOCGWINSZ
43  #include <sys/ioctl.h>
44  #elif __APPLE__
45  #include <sys/ioctl.h>
46  #endif // TIOCGWINSZ
47 #endif // IOCTL_TERMINAL_WIDTH
48 
49 bool ProgramBase::SortOptionsByIndex::
50 operator () (const Option *a, const Option *b) const {
51  if (a->_index_group != b->_index_group) {
52  return a->_index_group < b->_index_group;
53  }
54  return a->_sequence < b->_sequence;
55 }
56 
57 // This should be called at program termination just to make sure
58 // Notify gets properly flushed before we exit, if someone calls
59 // exit(). It's probably not necessary, but why not be phobic about
60 // it?
61 static void flush_nout() {
62  nout << flush;
63 }
64 
65 static ConfigVariableInt default_terminal_width
66 ("default-terminal-width", 72,
67  PRC_DESC("Specify the column at which to wrap output lines "
68  "from pandatool-based programs, if it cannot be determined "
69  "automatically."));
70 
71 static ConfigVariableBool use_terminal_width
72 ("use-terminal-width", true,
73  PRC_DESC("True to try to determine the terminal width automatically from "
74  "the operating system, if supported; false to use the width "
75  "specified by default-terminal-width even if the operating system "
76  "appears to report a valid width."));
77 
78 ////////////////////////////////////////////////////////////////////
79 // Function: ProgramBase::Constructor
80 // Access: Public
81 // Description:
82 ////////////////////////////////////////////////////////////////////
83 ProgramBase::
84 ProgramBase(const string &name) : _name(name) {
85  // Set up Notify to write output to our own formatted stream.
86  Notify::ptr()->set_ostream_ptr(new WordWrapStream(this), true);
87 
88  // And we'll want to be sure to flush that in all normal exit cases.
89  atexit(&flush_nout);
90 
91  _path_replace = new PathReplace;
92 
93  // If a program never adds the path store options, the default path
94  // store is PS_absolute. This is the most robust solution for
95  // programs that read files but do not need to write them.
96  _path_replace->_path_store = PS_absolute;
97  _got_path_store = false;
98  _got_path_directory = false;
99 
100  _next_sequence = 0;
101  _sorted_options = false;
102  _last_newline = false;
103  _got_terminal_width = false;
104  _got_option_indent = false;
105 
106  add_option("h", "", 100,
107  "Display this help page.",
108  &ProgramBase::handle_help_option, NULL, (void *)this);
109 
110  // It's nice to start with a blank line.
111  nout << "\r";
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: ProgramBase::Destructor
116 // Access: Public, Virtual
117 // Description:
118 ////////////////////////////////////////////////////////////////////
119 ProgramBase::
120 ~ProgramBase() {
121  // Reset Notify in case any messages get sent after our
122  // destruction--our stream is no longer valid.
123  Notify::ptr()->set_ostream_ptr(NULL, false);
124 }
125 
126 ////////////////////////////////////////////////////////////////////
127 // Function: ProgramBase::show_description
128 // Access: Public
129 // Description: Writes the program description to stderr.
130 ////////////////////////////////////////////////////////////////////
131 void ProgramBase::
133  nout << _description << "\n";
134 }
135 
136 ////////////////////////////////////////////////////////////////////
137 // Function: ProgramBase::show_usage
138 // Access: Public
139 // Description: Writes the usage line(s) to stderr.
140 ////////////////////////////////////////////////////////////////////
141 void ProgramBase::
143  nout << "\rUsage:\n";
144  Runlines::const_iterator ri;
145  string prog = " " + _program_name.get_basename_wo_extension();
146 
147  for (ri = _runlines.begin(); ri != _runlines.end(); ++ri) {
148  show_text(prog, prog.length() + 1, *ri);
149  }
150  nout << "\r";
151 }
152 
153 ////////////////////////////////////////////////////////////////////
154 // Function: ProgramBase::show_options
155 // Access: Public
156 // Description: Describes each of the available options to stderr.
157 ////////////////////////////////////////////////////////////////////
158 void ProgramBase::
160  sort_options();
161  if (!_got_option_indent) {
162  get_terminal_width();
163  _option_indent = min(15, (int)(_terminal_width * 0.25));
164  _got_option_indent = true;
165  }
166 
167  nout << "Options:\n";
168  OptionsByIndex::const_iterator oi;
169  for (oi = _options_by_index.begin(); oi != _options_by_index.end(); ++oi) {
170  const Option &opt = *(*oi);
171  string prefix = " -" + opt._option + " " + opt._parm_name;
172  show_text(prefix, _option_indent, opt._description + "\r");
173  }
174 }
175 
176 ////////////////////////////////////////////////////////////////////
177 // Function: ProgramBase::show_text
178 // Access: Public
179 // Description: Formats the indicated text and its prefix for output
180 // to stderr with the known _terminal_width.
181 ////////////////////////////////////////////////////////////////////
182 void ProgramBase::
183 show_text(const string &prefix, int indent_width, string text) {
184  get_terminal_width();
185 
186  // This is correct! It goes go to cerr, not to nout. Sending it to
187  // nout would be cyclic, since nout is redefined to map back through
188  // this function.
189  format_text(cerr, _last_newline,
190  prefix, indent_width, text, _terminal_width);
191 }
192 
193 ////////////////////////////////////////////////////////////////////
194 // Function: ProgramBase::write_man_page
195 // Access: Public
196 // Description: Generates a man page in nroff syntax based on the
197 // description and options. This is useful when
198 // creating a man page for this utility.
199 ////////////////////////////////////////////////////////////////////
200 void ProgramBase::
201 write_man_page(ostream &out) {
202  string prog = _program_name.get_basename_wo_extension();
203  out << ".\\\" Automatically generated by " << prog << " -write-man\n";
204 
205  // Format the man page title as the uppercase version of the program name,
206  // as per the UNIX manual conventions.
207  out << ".TH ";
208  string::const_iterator si;
209  for (si = _name.begin(); si != _name.end(); ++si) {
210  out << (char)toupper(*si);
211  }
212 
213  // Generate a date string for inclusion into the footer.
214  char date_str[256];
215  date_str[0] = 0;
216  time_t current_time = time(NULL);
217 
218  if (current_time != (time_t) -1) {
219  tm *today = localtime(&current_time);
220  if (today == NULL || 0 == strftime(date_str, 256, "%d %B %Y", today)) {
221  date_str[0] = 0;
222  }
223  }
224 
225  out << " 1 \"" << date_str << "\" \""
226  << PandaSystem::get_version_string() << "\" Panda3D\n";
227 
228  out << ".SH NAME\n";
229  if (_brief.empty()) {
230  out << _name << "\n";
231  } else {
232  out << _name << " \\- " << _brief << "\n";
233  }
234 
235  out << ".SH SYNOPSIS\n";
236  Runlines::const_iterator ri = _runlines.begin();
237  if (ri != _runlines.end()) {
238  out << "\\fB" << prog << "\\fR " << *ri << "\n";
239  ++ri;
240  }
241 
242  for (; ri != _runlines.end(); ++ri) {
243  out << ".br\n";
244  out << "\\fB" << prog << "\\fR " << *ri << "\n";
245  }
246 
247  out << ".SH DESCRIPTION\n";
248  string::const_iterator di;
249  char prev = 0;
250  for (di = _description.begin(); di != _description.end(); ++di) {
251  if ((*di) == '-') {
252  // We have to escape hyphens.
253  out << "\\-";
254  } else if (prev == '\n' && (*di) == '\n') {
255  // Indicate the start of a new paragraph.
256  out << ".PP\n";
257  } else {
258  out << (char)(*di);
259  }
260  prev = (*di);
261  }
262  out << "\n";
263 
264  out << ".SH OPTIONS\n";
265  sort_options();
266  OptionsByIndex::const_iterator oi;
267  for (oi = _options_by_index.begin(); oi != _options_by_index.end(); ++oi) {
268  const Option &opt = *(*oi);
269  out << ".TP\n";
270 
271  if (opt._parm_name.empty()) {
272  out << ".B \\-" << opt._option << "\n";
273  } else {
274  out << ".BI \"\\-" << opt._option << " \" \"" << opt._parm_name << "\"\n";
275  }
276  out << opt._description << "\n";
277  }
278 }
279 
280 ////////////////////////////////////////////////////////////////////
281 // Function: ProgramBase::parse_command_line
282 // Access: Public, Virtual
283 // Description: Dispatches on each of the options on the command
284 // line, and passes the remaining parameters to
285 // handle_args(). If an error on the command line is
286 // detected, will automatically call show_usage() and
287 // exit(1).
288 ////////////////////////////////////////////////////////////////////
289 void ProgramBase::
290 parse_command_line(int argc, char **argv) {
291  preprocess_argv(argc, argv);
292 
293  // Setting this variable to zero reinitializes the options parser
294  // This is only necessary for processing multiple command lines in
295  // the same program (mainly the MaxToEgg converter plugin)
296  extern int optind;
297  optind = 0;
298 
299  _program_name = Filename::from_os_specific(argv[0]);
300  int i;
301  for (i = 1; i < argc; i++) {
302  _program_args.push_back(argv[i]);
303  }
304 
305  if (_name.empty()) {
306  _name = _program_name.get_basename_wo_extension();
307  }
308 
309  // Catch a special hidden option: -write-man, which causes the tool
310  // to generate a manual page.
311  if (argc > 1 && strcmp(argv[1], "-write-man") == 0) {
312  if (argc == 2) {
313  write_man_page(cout);
314 
315  } else if (argc == 3) {
316  if (strlen(argv[2]) == 1 && argv[2][0] == '-') {
317  write_man_page(cout);
318 
319  } else {
320  pofstream man_out(argv[2], ios::out | ios::trunc);
321  if (!man_out) {
322  cerr << "Failed to open output file " << argv[2] << "!\n";
323  }
324  write_man_page(man_out);
325  man_out.close();
326  }
327  } else {
328  cerr << "Invalid number of options for -write-man!\n";
329  exit(1);
330  }
331  exit(0);
332  }
333 
334  // Build up the long options list and the short options string for
335  // getopt_long_only().
336  pvector<struct option> long_options;
337  string short_options;
338 
339  // We also need to build a temporary map of int index numbers to
340  // Option pointers. We'll pass these index numbers to GNU's
341  // getopt_long() so we can tell one option from another.
342  typedef pmap<int, const Option *> Options;
343  Options options;
344 
345  OptionsByName::const_iterator oi;
346  int next_index = 256;
347 
348  // Let's prefix the option string with "-" to tell getopt that we
349  // want it to tell us the post-option arguments, instead of trying
350  // to meddle with ARGC and ARGV (which we aren't using directly).
351  short_options = "-";
352 
353  for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) {
354  const Option &opt = (*oi).second;
355 
356  int index;
357  if (opt._option.length() == 1) {
358  // This is a "short" option; its option string consists of only
359  // one letter. Its index is the letter itself.
360  index = (int)opt._option[0];
361 
362  short_options += opt._option;
363  if (!opt._parm_name.empty()) {
364  // This option takes an argument.
365  short_options += ':';
366  }
367  } else {
368  // This is a "long" option; we'll assign it the next available
369  // index.
370  index = ++next_index;
371  }
372 
373  // Now add it to the GNU data structures.
374  struct option gopt;
375  gopt.name = (char *)opt._option.c_str();
376  gopt.has_arg = (opt._parm_name.empty()) ?
377  no_argument : required_argument;
378  gopt.flag = (int *)NULL;
379 
380  // Return an index into the _options_by_index array, offset by 256
381  // so we don't confuse it with '?'.
382  gopt.val = index;
383 
384  long_options.push_back(gopt);
385 
386  options[index] = &opt;
387  }
388 
389  // Finally, add one more structure, all zeroes, to indicate the end
390  // of the options.
391  struct option gopt;
392  memset(&gopt, 0, sizeof(gopt));
393  long_options.push_back(gopt);
394 
395  // We'll use this vector to save the non-option arguments.
396  // Generally, these will all be at the end, but with the GNU
397  // extensions, they need not be.
398  Args remaining_args;
399 
400  // Now call getopt_long() to actually parse the arguments.
401  extern char *optarg;
402  const struct option *long_opts = &long_options[0];
403 
404  int flag =
405  getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL);
406  while (flag != EOF) {
407  string arg;
408  if (optarg != NULL) {
409  arg = optarg;
410  }
411 
412  switch (flag) {
413  case '?':
414  // Invalid option or parameter.
415  show_usage();
416  exit(1);
417 
418  case '\x1':
419  // A special return value from getopt() indicating a non-option
420  // argument.
421  remaining_args.push_back(arg);
422  break;
423 
424  default:
425  {
426  // A normal option. Figure out which one it is.
427  Options::const_iterator ii;
428  ii = options.find(flag);
429  if (ii == options.end()) {
430  nout << "Internal error! Invalid option index returned.\n";
431  abort();
432  }
433 
434  const Option &opt = *(*ii).second;
435  bool okflag = true;
436  if (opt._option_function != (OptionDispatchFunction)NULL) {
437  okflag = (*opt._option_function)(opt._option, arg, opt._option_data);
438  }
439  if (opt._option_method != (OptionDispatchMethod)NULL) {
440  okflag = (*opt._option_method)(this, opt._option, arg, opt._option_data);
441  }
442  if (opt._bool_var != (bool *)NULL) {
443  (*opt._bool_var) = true;
444  }
445 
446  if (!okflag) {
447  show_usage();
448  exit(1);
449  }
450  }
451  }
452 
453  flag =
454  getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL);
455  }
456 
457  if (!handle_args(remaining_args)) {
458  show_usage();
459  exit(1);
460  }
461 
462  if (!post_command_line()) {
463  show_usage();
464  exit(1);
465  }
466 }
467 
468 ////////////////////////////////////////////////////////////////////
469 // Function: ProgramBase::get_exec_command
470 // Access: Public
471 // Description: Returns the command that invoked this program, as a
472 // shell-friendly string, suitable for pasting into the
473 // comments of output files.
474 ////////////////////////////////////////////////////////////////////
475 string ProgramBase::
477  string command;
478 
479  command = _program_name.get_basename_wo_extension();
480  Args::const_iterator ai;
481  for (ai = _program_args.begin(); ai != _program_args.end(); ++ai) {
482  const string &arg = (*ai);
483 
484  // First, check to see if the string is shell-acceptable.
485  bool legal = true;
486  string::const_iterator si;
487  for (si = arg.begin(); legal && si != arg.end(); ++si) {
488  switch (*si) {
489  case ' ':
490  case '\n':
491  case '\t':
492  case '*':
493  case '?':
494  case '\\':
495  case '(':
496  case ')':
497  case '|':
498  case '&':
499  case '<':
500  case '>':
501  case '"':
502  case ';':
503  case '$':
504  legal = false;
505  }
506  }
507 
508  if (legal) {
509  command += " " + arg;
510  } else {
511  command += " '" + arg + "'";
512  }
513  }
514 
515  return command;
516 }
517 
518 
519 ////////////////////////////////////////////////////////////////////
520 // Function: ProgramBase::handle_args
521 // Access: Protected, Virtual
522 // Description: Does something with the additional arguments on the
523 // command line (after all the -options have been
524 // parsed). Returns true if the arguments are good,
525 // false otherwise.
526 ////////////////////////////////////////////////////////////////////
527 bool ProgramBase::
528 handle_args(ProgramBase::Args &args) {
529  if (!args.empty()) {
530  nout << "Unexpected arguments on command line:\n";
531  Args::const_iterator ai;
532  for (ai = args.begin(); ai != args.end(); ++ai) {
533  nout << (*ai) << " ";
534  }
535  nout << "\r";
536  return false;
537  }
538 
539  return true;
540 }
541 
542 ////////////////////////////////////////////////////////////////////
543 // Function: ProgramBase::post_command_line
544 // Access: Protected, Virtual
545 // Description: This is called after the command line has been
546 // completely processed, and it gives the program a
547 // chance to do some last-minute processing and
548 // validation of the options and arguments. It should
549 // return true if everything is fine, false if there is
550 // an error.
551 ////////////////////////////////////////////////////////////////////
552 bool ProgramBase::
553 post_command_line() {
554  return true;
555 }
556 
557 ////////////////////////////////////////////////////////////////////
558 // Function: ProgramBase::set_program_brief
559 // Access: Protected
560 // Description: Sets a brief synopsis of the program's function.
561 // This is currently only used for generating the
562 // synopsis of the program's man page.
563 //
564 // This should be of the format:
565 // "perform operation foo on bar files"
566 ////////////////////////////////////////////////////////////////////
567 void ProgramBase::
568 set_program_brief(const string &brief) {
569  _brief = brief;
570 }
571 
572 ////////////////////////////////////////////////////////////////////
573 // Function: ProgramBase::set_program_description
574 // Access: Protected
575 // Description: Sets the description of the program that will be
576 // reported by show_usage(). The description should be
577 // one long string of text. Embedded newline characters
578 // are interpreted as paragraph breaks and printed as
579 // blank lines.
580 ////////////////////////////////////////////////////////////////////
581 void ProgramBase::
582 set_program_description(const string &description) {
583  _description = description;
584 }
585 
586 ////////////////////////////////////////////////////////////////////
587 // Function: ProgramBase::clear_runlines
588 // Access: Protected
589 // Description: Removes all of the runlines that were previously
590 // added, presumably before adding some new ones.
591 ////////////////////////////////////////////////////////////////////
592 void ProgramBase::
593 clear_runlines() {
594  _runlines.clear();
595 }
596 
597 ////////////////////////////////////////////////////////////////////
598 // Function: ProgramBase::add_runline
599 // Access: Protected
600 // Description: Adds an additional line to the list of lines that
601 // will be displayed to describe briefly how the program
602 // is to be run. Each line should be something like
603 // "[opts] arg1 arg2", that is, it does *not* include
604 // the name of the program, but it includes everything
605 // that should be printed after the name of the program.
606 //
607 // Normally there is only one runline for a given
608 // program, but it is possible to define more than one.
609 ////////////////////////////////////////////////////////////////////
610 void ProgramBase::
611 add_runline(const string &runline) {
612  _runlines.push_back(runline);
613 }
614 
615 ////////////////////////////////////////////////////////////////////
616 // Function: ProgramBase::clear_options
617 // Access: Protected
618 // Description: Removes all of the options that were previously
619 // added, presumably before adding some new ones.
620 // Normally you wouldn't want to do this unless you want
621 // to completely replace all of the options defined by
622 // base classes.
623 ////////////////////////////////////////////////////////////////////
624 void ProgramBase::
625 clear_options() {
626  _options_by_name.clear();
627 }
628 
629 ////////////////////////////////////////////////////////////////////
630 // Function: ProgramBase::add_option
631 // Access: Protected
632 // Description: Adds (or redefines) a command line option. When
633 // parse_command_line() is executed it will look for
634 // these options (followed by a hyphen) on the command
635 // line; when a particular option is found it will call
636 // the indicated option_function, supplying the provided
637 // option_data. This allows the user to define a
638 // function that does some special behavior for any
639 // given option, or to use any of a number of generic
640 // pre-defined functions to fill in data for each
641 // option.
642 //
643 // Each option may or may not take a parameter. If
644 // parm_name is nonempty, it is assumed that the option
645 // does take a parameter (and parm_name contains the
646 // name that will be printed by show_options()). This
647 // parameter will be supplied as the second parameter to
648 // the dispatch function. If parm_name is empty, it is
649 // assumed that the option does not take a parameter.
650 // There is no provision for optional parameters.
651 //
652 // The options are listed first in order by their
653 // index_group number, and then in the order that
654 // add_option() was called. This provides a mechanism
655 // for listing the options defined in derived classes
656 // before those of the base classes.
657 ////////////////////////////////////////////////////////////////////
658 void ProgramBase::
659 add_option(const string &option, const string &parm_name,
660  int index_group, const string &description,
661  OptionDispatchFunction option_function,
662  bool *bool_var, void *option_data) {
663  Option opt;
664  opt._option = option;
665  opt._parm_name = parm_name;
666  opt._index_group = index_group;
667  opt._sequence = ++_next_sequence;
668  opt._description = description;
669  opt._option_function = option_function;
670  opt._option_method = (OptionDispatchMethod)NULL;
671  opt._bool_var = bool_var;
672  opt._option_data = option_data;
673 
674  _options_by_name[option] = opt;
675  _sorted_options = false;
676 
677  if (bool_var != (bool *)NULL) {
678  (*bool_var) = false;
679  }
680 }
681 
682 ////////////////////////////////////////////////////////////////////
683 // Function: ProgramBase::add_option
684 // Access: Protected
685 // Description: This is another variant on add_option(), above,
686 // except that it receives a pointer to a "method",
687 // which is really just another static (or global)
688 // function, whose first parameter is a ProgramBase *.
689 //
690 // We can't easily add a variant that accepts a real
691 // method, because the C++ syntax for methods requires
692 // us to know exactly what class object the method is
693 // defined for, and we want to support adding pointers
694 // for methods that are defined in other classes. So we
695 // have this hacky thing, which requires the "method" to
696 // be declared static, and receive its this pointer
697 // explicitly, as the first argument.
698 ////////////////////////////////////////////////////////////////////
699 void ProgramBase::
700 add_option(const string &option, const string &parm_name,
701  int index_group, const string &description,
702  OptionDispatchMethod option_method,
703  bool *bool_var, void *option_data) {
704  Option opt;
705  opt._option = option;
706  opt._parm_name = parm_name;
707  opt._index_group = index_group;
708  opt._sequence = ++_next_sequence;
709  opt._description = description;
710  opt._option_function = (OptionDispatchFunction)NULL;
711  opt._option_method = option_method;
712  opt._bool_var = bool_var;
713  opt._option_data = option_data;
714 
715  _options_by_name[option] = opt;
716  _sorted_options = false;
717 
718  if (bool_var != (bool *)NULL) {
719  (*bool_var) = false;
720  }
721 }
722 
723 ////////////////////////////////////////////////////////////////////
724 // Function: ProgramBase::redescribe_option
725 // Access: Protected
726 // Description: Changes the description associated with a
727 // previously-defined option. Returns true if the
728 // option was changed, false if it hadn't been defined.
729 ////////////////////////////////////////////////////////////////////
730 bool ProgramBase::
731 redescribe_option(const string &option, const string &description) {
732  OptionsByName::iterator oi = _options_by_name.find(option);
733  if (oi == _options_by_name.end()) {
734  return false;
735  }
736  (*oi).second._description = description;
737  return true;
738 }
739 
740 ////////////////////////////////////////////////////////////////////
741 // Function: ProgramBase::remove_option
742 // Access: Protected
743 // Description: Removes a previously-defined option. Returns true if
744 // the option was removed, false if it hadn't existed.
745 ////////////////////////////////////////////////////////////////////
746 bool ProgramBase::
747 remove_option(const string &option) {
748  OptionsByName::iterator oi = _options_by_name.find(option);
749  if (oi == _options_by_name.end()) {
750  return false;
751  }
752  _options_by_name.erase(oi);
753  _sorted_options = false;
754  return true;
755 }
756 
757 ////////////////////////////////////////////////////////////////////
758 // Function: ProgramBase::add_path_replace_options
759 // Access: Public
760 // Description: Adds -pr etc. as valid options for this program.
761 // These are appropriate for a model converter or model
762 // reader type program, and specify how to locate
763 // possibly-invalid pathnames in the source model file.
764 ////////////////////////////////////////////////////////////////////
765 void ProgramBase::
766 add_path_replace_options() {
767  add_option
768  ("pr", "path_replace", 40,
769  "Sometimes references to other files (textures, external references) "
770  "are stored with a full path that is appropriate for some other system, "
771  "but does not exist here. This option may be used to specify how "
772  "those invalid paths map to correct paths. Generally, this is of "
773  "the form 'orig_prefix=replacement_prefix', which indicates a "
774  "particular initial sequence of characters that should be replaced "
775  "with a new sequence; e.g. '/c/home/models=/beta/fish'. "
776  "If the replacement prefix does not begin with a slash, the file "
777  "will then be searched for along the search path specified by -pp. "
778  "You may use standard filename matching characters ('*', '?', etc.) in "
779  "the original prefix, and '**' as a component by itself stands for "
780  "any number of components.\n\n"
781 
782  "This option may be repeated as necessary; each file will be tried "
783  "against each specified method, in the order in which they appear in "
784  "the command line, until the file is found. If the file is not found, "
785  "the last matching prefix is used anyway.",
786  &ProgramBase::dispatch_path_replace, NULL, _path_replace.p());
787 
788  add_option
789  ("pp", "dirname", 40,
790  "Adds the indicated directory name to the list of directories to "
791  "search for filenames referenced by the source file. This is used "
792  "only for relative paths, or for paths that are made relative by a "
793  "-pr replacement string that doesn't begin with a leading slash. "
794  "The model-path is always implicitly searched anyway.",
795  &ProgramBase::dispatch_search_path, NULL, &(_path_replace->_path));
796 }
797 
798 ////////////////////////////////////////////////////////////////////
799 // Function: ProgramBase::add_path_store_options
800 // Access: Public
801 // Description: Adds -ps etc. as valid options for this program.
802 // These are appropriate for a model converter type
803 // program, and specify how to represent filenames in
804 // the output file.
805 ////////////////////////////////////////////////////////////////////
806 void ProgramBase::
807 add_path_store_options() {
808  // If a program has path store options at all, the default path
809  // store is relative.
810  _path_replace->_path_store = PS_relative;
811 
812  add_option
813  ("ps", "path_store", 40,
814  "Specifies the way an externally referenced file is to be "
815  "represented in the resulting output file. This "
816  "assumes the named filename actually exists; "
817  "see -pr to indicate how to deal with external "
818  "references that have bad pathnames. "
819  "This option will not help you to find a missing file, but simply "
820  "controls how filenames are represented in the output.\n\n"
821 
822  "The option may be one of: rel, abs, rel_abs, strip, or keep. If "
823  "either rel or rel_abs is specified, the files are made relative to "
824  "the directory specified by -pd. The default is rel.",
825  &ProgramBase::dispatch_path_store, &_got_path_store,
826  &(_path_replace->_path_store));
827 
828  add_option
829  ("pd", "path_directory", 40,
830  "Specifies the name of a directory to make paths relative to, if "
831  "'-ps rel' or '-ps rel_abs' is specified. If this is omitted, the "
832  "directory name is taken from the name of the output file.",
833  &ProgramBase::dispatch_filename, &_got_path_directory,
834  &(_path_replace->_path_directory));
835 
836  add_option
837  ("pc", "target_directory", 40,
838  "Copies textures and other dependent files into the indicated "
839  "directory. If a relative pathname is specified, it is relative "
840  "to the directory specified with -pd, above.",
841  &ProgramBase::dispatch_filename, &(_path_replace->_copy_files),
842  &(_path_replace->_copy_into_directory));
843 }
844 
845 ////////////////////////////////////////////////////////////////////
846 // Function: ProgramBase::dispatch_none
847 // Access: Protected, Static
848 // Description: Standard dispatch function for an option that takes
849 // no parameters, and does nothing special. Typically
850 // this would be used for a boolean flag, whose presence
851 // means something and whose absence means something
852 // else. Use the bool_var parameter to add_option() to
853 // determine whether the option appears on the command
854 // line or not.
855 ////////////////////////////////////////////////////////////////////
856 bool ProgramBase::
857 dispatch_none(const string &, const string &, void *) {
858  return true;
859 }
860 
861 ////////////////////////////////////////////////////////////////////
862 // Function: ProgramBase::dispatch_true
863 // Access: Protected, Static
864 // Description: Standard dispatch function for an option that takes
865 // no parameters, and when it is present sets a bool
866 // variable to the 'true' value. This is another way to
867 // handle a boolean flag. See also dispatch_none() and
868 // dispatch_false().
869 //
870 // The data pointer is to a bool variable.
871 ////////////////////////////////////////////////////////////////////
872 bool ProgramBase::
873 dispatch_true(const string &, const string &, void *var) {
874  bool *bp = (bool *)var;
875  (*bp) = true;
876  return true;
877 }
878 
879 ////////////////////////////////////////////////////////////////////
880 // Function: ProgramBase::dispatch_false
881 // Access: Protected, Static
882 // Description: Standard dispatch function for an option that takes
883 // no parameters, and when it is present sets a bool
884 // variable to the 'false' value. This is another way to
885 // handle a boolean flag. See also dispatch_none() and
886 // dispatch_true().
887 //
888 // The data pointer is to a bool variable.
889 ////////////////////////////////////////////////////////////////////
890 bool ProgramBase::
891 dispatch_false(const string &, const string &, void *var) {
892  bool *bp = (bool *)var;
893  (*bp) = false;
894  return true;
895 }
896 
897 ////////////////////////////////////////////////////////////////////
898 // Function: ProgramBase::dispatch_count
899 // Access: Protected, Static
900 // Description: Standard dispatch function for an option that takes
901 // no parameters, but whose presence on the command line
902 // increments an integer counter for each time it
903 // appears. -v is often an option that works this way.
904 // The data pointer is to an int counter variable.
905 ////////////////////////////////////////////////////////////////////
906 bool ProgramBase::
907 dispatch_count(const string &, const string &, void *var) {
908  int *ip = (int *)var;
909  (*ip)++;
910 
911  return true;
912 }
913 
914 ////////////////////////////////////////////////////////////////////
915 // Function: ProgramBase::dispatch_int
916 // Access: Protected, Static
917 // Description: Standard dispatch function for an option that takes
918 // one parameter, which is to be interpreted as an
919 // integer. The data pointer is to an int variable.
920 ////////////////////////////////////////////////////////////////////
921 bool ProgramBase::
922 dispatch_int(const string &opt, const string &arg, void *var) {
923  int *ip = (int *)var;
924 
925  if (!string_to_int(arg, *ip)) {
926  nout << "Invalid integer parameter for -" << opt << ": "
927  << arg << "\n";
928  return false;
929  }
930 
931  return true;
932 }
933 
934 ////////////////////////////////////////////////////////////////////
935 // Function: ProgramBase::dispatch_int_pair
936 // Access: Protected, Static
937 // Description: Standard dispatch function for an option that takes
938 // a pair of integer parameters. The data pointer is to
939 // an array of two integers.
940 ////////////////////////////////////////////////////////////////////
941 bool ProgramBase::
942 dispatch_int_pair(const string &opt, const string &arg, void *var) {
943  int *ip = (int *)var;
944 
945  vector_string words;
946  tokenize(arg, words, ",");
947 
948  bool okflag = false;
949  if (words.size() == 2) {
950  okflag =
951  string_to_int(words[0], ip[0]) &&
952  string_to_int(words[1], ip[1]);
953  }
954 
955  if (!okflag) {
956  nout << "-" << opt
957  << " requires a pair of integers separated by a comma.\n";
958  return false;
959  }
960 
961  return true;
962 }
963 
964 ////////////////////////////////////////////////////////////////////
965 // Function: ProgramBase::dispatch_int_quad
966 // Access: Protected, Static
967 // Description: Standard dispatch function for an option that takes
968 // a quad of integer parameters. The data pointer is to
969 // an array of four integers.
970 ////////////////////////////////////////////////////////////////////
971 bool ProgramBase::
972 dispatch_int_quad(const string &opt, const string &arg, void *var) {
973  int *ip = (int *)var;
974 
975  vector_string words;
976  tokenize(arg, words, ",");
977 
978  bool okflag = false;
979  if (words.size() == 4) {
980  okflag =
981  string_to_int(words[0], ip[0]) &&
982  string_to_int(words[1], ip[1]) &&
983  string_to_int(words[1], ip[2]) &&
984  string_to_int(words[1], ip[3]);
985  }
986 
987  if (!okflag) {
988  nout << "-" << opt
989  << " requires a quad of integers separated by a comma.\n";
990  return false;
991  }
992 
993  return true;
994 }
995 
996 ////////////////////////////////////////////////////////////////////
997 // Function: ProgramBase::dispatch_double
998 // Access: Protected, Static
999 // Description: Standard dispatch function for an option that takes
1000 // one parameter, which is to be interpreted as a
1001 // double. The data pointer is to an double variable.
1002 ////////////////////////////////////////////////////////////////////
1003 bool ProgramBase::
1004 dispatch_double(const string &opt, const string &arg, void *var) {
1005  double *ip = (double *)var;
1006 
1007  if (!string_to_double(arg, *ip)) {
1008  nout << "Invalid numeric parameter for -" << opt << ": "
1009  << arg << "\n";
1010  return false;
1011  }
1012 
1013  return true;
1014 }
1015 
1016 ////////////////////////////////////////////////////////////////////
1017 // Function: ProgramBase::dispatch_double_pair
1018 // Access: Protected, Static
1019 // Description: Standard dispatch function for an option that takes
1020 // a pair of double parameters. The data pointer is to
1021 // an array of two doubles.
1022 ////////////////////////////////////////////////////////////////////
1023 bool ProgramBase::
1024 dispatch_double_pair(const string &opt, const string &arg, void *var) {
1025  double *ip = (double *)var;
1026 
1027  vector_string words;
1028  tokenize(arg, words, ",");
1029 
1030  bool okflag = false;
1031  if (words.size() == 2) {
1032  okflag =
1033  string_to_double(words[0], ip[0]) &&
1034  string_to_double(words[1], ip[1]);
1035  }
1036 
1037  if (!okflag) {
1038  nout << "-" << opt
1039  << " requires a pair of numbers separated by a comma.\n";
1040  return false;
1041  }
1042 
1043  return true;
1044 }
1045 
1046 ////////////////////////////////////////////////////////////////////
1047 // Function: ProgramBase::dispatch_double_triple
1048 // Access: Protected, Static
1049 // Description: Standard dispatch function for an option that takes
1050 // a triple of double parameters. The data pointer is to
1051 // an array of three doubles.
1052 ////////////////////////////////////////////////////////////////////
1053 bool ProgramBase::
1054 dispatch_double_triple(const string &opt, const string &arg, void *var) {
1055  double *ip = (double *)var;
1056 
1057  vector_string words;
1058  tokenize(arg, words, ",");
1059 
1060  bool okflag = false;
1061  if (words.size() == 3) {
1062  okflag =
1063  string_to_double(words[0], ip[0]) &&
1064  string_to_double(words[1], ip[1]) &&
1065  string_to_double(words[2], ip[2]);
1066  }
1067 
1068  if (!okflag) {
1069  nout << "-" << opt
1070  << " requires three numbers separated by commas.\n";
1071  return false;
1072  }
1073 
1074  return true;
1075 }
1076 
1077 ////////////////////////////////////////////////////////////////////
1078 // Function: ProgramBase::dispatch_double_quad
1079 // Access: Protected, Static
1080 // Description: Standard dispatch function for an option that takes
1081 // a quad of double parameters. The data pointer is to
1082 // an array of four doubles.
1083 ////////////////////////////////////////////////////////////////////
1084 bool ProgramBase::
1085 dispatch_double_quad(const string &opt, const string &arg, void *var) {
1086  double *ip = (double *)var;
1087 
1088  vector_string words;
1089  tokenize(arg, words, ",");
1090 
1091  bool okflag = false;
1092  if (words.size() == 4) {
1093  okflag =
1094  string_to_double(words[0], ip[0]) &&
1095  string_to_double(words[1], ip[1]) &&
1096  string_to_double(words[2], ip[2]) &&
1097  string_to_double(words[3], ip[3]);
1098  }
1099 
1100  if (!okflag) {
1101  nout << "-" << opt
1102  << " requires four numbers separated by commas.\n";
1103  return false;
1104  }
1105 
1106  return true;
1107 }
1108 
1109 ////////////////////////////////////////////////////////////////////
1110 // Function: ProgramBase::dispatch_color
1111 // Access: Protected, Static
1112 // Description: Standard dispatch function for an option that takes a
1113 // color, as l or l,a or r,g,b or r,g,b,a. The data
1114 // pointer is to an array of four floats, e.g. a LColor.
1115 ////////////////////////////////////////////////////////////////////
1116 bool ProgramBase::
1117 dispatch_color(const string &opt, const string &arg, void *var) {
1118  PN_stdfloat *ip = (PN_stdfloat *)var;
1119 
1120  vector_string words;
1121  tokenize(arg, words, ",");
1122 
1123  bool okflag = false;
1124  switch (words.size()) {
1125  case 4:
1126  okflag =
1127  string_to_stdfloat(words[0], ip[0]) &&
1128  string_to_stdfloat(words[1], ip[1]) &&
1129  string_to_stdfloat(words[2], ip[2]) &&
1130  string_to_stdfloat(words[3], ip[3]);
1131  break;
1132 
1133  case 3:
1134  okflag =
1135  string_to_stdfloat(words[0], ip[0]) &&
1136  string_to_stdfloat(words[1], ip[1]) &&
1137  string_to_stdfloat(words[2], ip[2]);
1138  ip[3] = 1.0;
1139  break;
1140 
1141  case 2:
1142  okflag =
1143  string_to_stdfloat(words[0], ip[0]) &&
1144  string_to_stdfloat(words[1], ip[3]);
1145  ip[1] = ip[0];
1146  ip[2] = ip[0];
1147  break;
1148 
1149  case 1:
1150  okflag =
1151  string_to_stdfloat(words[0], ip[0]);
1152  ip[1] = ip[0];
1153  ip[2] = ip[0];
1154  ip[3] = 1.0;
1155  break;
1156  }
1157 
1158  if (!okflag) {
1159  nout << "-" << opt
1160  << " requires one through four numbers separated by commas.\n";
1161  return false;
1162  }
1163 
1164  return true;
1165 }
1166 
1167 ////////////////////////////////////////////////////////////////////
1168 // Function: ProgramBase::dispatch_string
1169 // Access: Protected, Static
1170 // Description: Standard dispatch function for an option that takes
1171 // one parameter, which is to be interpreted as a
1172 // string. The data pointer is to a string variable.
1173 ////////////////////////////////////////////////////////////////////
1174 bool ProgramBase::
1175 dispatch_string(const string &, const string &arg, void *var) {
1176  string *ip = (string *)var;
1177  (*ip) = arg;
1178 
1179  return true;
1180 }
1181 
1182 ////////////////////////////////////////////////////////////////////
1183 // Function: ProgramBase::dispatch_vector_string
1184 // Access: Protected, Static
1185 // Description: Standard dispatch function for an option that takes
1186 // one parameter, which is to be interpreted as a
1187 // string. This is different from dispatch_string in
1188 // that the parameter may be repeated multiple times,
1189 // and each time the string value is appended to a
1190 // vector.
1191 //
1192 // The data pointer is to a vector_string variable.
1193 ////////////////////////////////////////////////////////////////////
1194 bool ProgramBase::
1195 dispatch_vector_string(const string &, const string &arg, void *var) {
1196  vector_string *ip = (vector_string *)var;
1197  (*ip).push_back(arg);
1198 
1199  return true;
1200 }
1201 
1202 ////////////////////////////////////////////////////////////////////
1203 // Function: ProgramBase::dispatch_vector_string_comma
1204 // Access: Protected, Static
1205 // Description: Similar to dispatch_vector_string, but a comma is
1206 // allowed to separate multiple tokens in one argument,
1207 // without having to repeat the argument for each token.
1208 //
1209 // The data pointer is to a vector_string variable.
1210 ////////////////////////////////////////////////////////////////////
1211 bool ProgramBase::
1212 dispatch_vector_string_comma(const string &, const string &arg, void *var) {
1213  vector_string *ip = (vector_string *)var;
1214 
1215  vector_string words;
1216  tokenize(arg, words, ",");
1217 
1218  vector_string::const_iterator wi;
1219  for (wi = words.begin(); wi != words.end(); ++wi) {
1220  (*ip).push_back(*wi);
1221  }
1222 
1223  return true;
1224 }
1225 
1226 ////////////////////////////////////////////////////////////////////
1227 // Function: ProgramBase::dispatch_filename
1228 // Access: Protected, Static
1229 // Description: Standard dispatch function for an option that takes
1230 // one parameter, which is to be interpreted as a
1231 // filename. The data pointer is to a Filename variable.
1232 ////////////////////////////////////////////////////////////////////
1233 bool ProgramBase::
1234 dispatch_filename(const string &opt, const string &arg, void *var) {
1235  if (arg.empty()) {
1236  nout << "-" << opt << " requires a filename parameter.\n";
1237  return false;
1238  }
1239 
1240  Filename *ip = (Filename *)var;
1241  (*ip) = Filename::from_os_specific(arg);
1242 
1243  return true;
1244 }
1245 
1246 ////////////////////////////////////////////////////////////////////
1247 // Function: ProgramBase::dispatch_search_path
1248 // Access: Protected, Static
1249 // Description: Standard dispatch function for an option that takes
1250 // one parameter, which is to be interpreted as a
1251 // single directory name to add to a search path. The
1252 // data pointer is to a DSearchPath variable. This kind
1253 // of option may appear multiple times on the command
1254 // line; each time, the new directory is appended.
1255 ////////////////////////////////////////////////////////////////////
1256 bool ProgramBase::
1257 dispatch_search_path(const string &opt, const string &arg, void *var) {
1258  if (arg.empty()) {
1259  nout << "-" << opt << " requires a search path parameter.\n";
1260  return false;
1261  }
1262 
1263  DSearchPath *ip = (DSearchPath *)var;
1265 
1266  return true;
1267 }
1268 
1269 ////////////////////////////////////////////////////////////////////
1270 // Function: ProgramBase::dispatch_coordinate_system
1271 // Access: Protected, Static
1272 // Description: Standard dispatch function for an option that takes
1273 // one parameter, which is to be interpreted as a
1274 // coordinate system string. The data pointer is to a
1275 // CoordinateSystem variable.
1276 ////////////////////////////////////////////////////////////////////
1277 bool ProgramBase::
1278 dispatch_coordinate_system(const string &opt, const string &arg, void *var) {
1279  CoordinateSystem *ip = (CoordinateSystem *)var;
1280  (*ip) = parse_coordinate_system_string(arg);
1281 
1282  if ((*ip) == CS_invalid) {
1283  nout << "Invalid coordinate system for -" << opt << ": " << arg << "\n"
1284  << "Valid coordinate system strings are any of 'y-up', 'z-up', "
1285  "'y-up-left', or 'z-up-left'.\n";
1286  return false;
1287  }
1288 
1289  return true;
1290 }
1291 
1292 ////////////////////////////////////////////////////////////////////
1293 // Function: ProgramBase::dispatch_units
1294 // Access: Protected, Static
1295 // Description: Standard dispatch function for an option that takes
1296 // one parameter, which is to be interpreted as a
1297 // unit of distance measurement. The data pointer is to
1298 // a DistanceUnit variable.
1299 ////////////////////////////////////////////////////////////////////
1300 bool ProgramBase::
1301 dispatch_units(const string &opt, const string &arg, void *var) {
1302  DistanceUnit *ip = (DistanceUnit *)var;
1303  (*ip) = string_distance_unit(arg);
1304 
1305  if ((*ip) == DU_invalid) {
1306  nout << "Invalid units for -" << opt << ": " << arg << "\n"
1307  << "Valid units are mm, cm, m, km, yd, ft, in, nmi, and mi.\n";
1308  return false;
1309  }
1310 
1311  return true;
1312 }
1313 
1314 ////////////////////////////////////////////////////////////////////
1315 // Function: ProgramBase::dispatch_image_type
1316 // Access: Protected, Static
1317 // Description: Standard dispatch function for an option that takes
1318 // one parameter, which is to indicate an image file
1319 // type, like rgb, bmp, jpg, etc. The data pointer is
1320 // to a PNMFileType pointer.
1321 ////////////////////////////////////////////////////////////////////
1322 bool ProgramBase::
1323 dispatch_image_type(const string &opt, const string &arg, void *var) {
1324  PNMFileType **ip = (PNMFileType **)var;
1325 
1327 
1328  (*ip) = reg->get_type_from_extension(arg);
1329 
1330  if ((*ip) == (PNMFileType *)NULL) {
1331  nout << "Invalid image type for -" << opt << ": " << arg << "\n"
1332  << "The following image types are known:\n";
1333  reg->write(nout, 2);
1334  return false;
1335  }
1336 
1337  return true;
1338 }
1339 
1340 ////////////////////////////////////////////////////////////////////
1341 // Function: ProgramBase::dispatch_path_replace
1342 // Access: Protected, Static
1343 // Description: Standard dispatch function for an option that takes
1344 // one parameter, which is to be interpreted as a
1345 // single component of a path replace request. The data
1346 // pointer is to a PathReplace variable.
1347 ////////////////////////////////////////////////////////////////////
1348 bool ProgramBase::
1349 dispatch_path_replace(const string &opt, const string &arg, void *var) {
1350  PathReplace *ip = (PathReplace *)var;
1351  size_t equals = arg.find('=');
1352  if (equals == string::npos) {
1353  nout << "Invalid path replacement string for -" << opt << ": " << arg << "\n"
1354  << "String should be of the form 'old-prefix=new-prefix'.\n";
1355  return false;
1356  }
1357  ip->add_pattern(arg.substr(0, equals), arg.substr(equals + 1));
1358 
1359  return true;
1360 }
1361 
1362 ////////////////////////////////////////////////////////////////////
1363 // Function: ProgramBase::dispatch_path_store
1364 // Access: Protected, Static
1365 // Description: Standard dispatch function for an option that takes
1366 // one parameter, which is to be interpreted as a
1367 // path store string. The data pointer is to a
1368 // PathStore variable.
1369 ////////////////////////////////////////////////////////////////////
1370 bool ProgramBase::
1371 dispatch_path_store(const string &opt, const string &arg, void *var) {
1372  PathStore *ip = (PathStore *)var;
1373  (*ip) = string_path_store(arg);
1374 
1375  if ((*ip) == PS_invalid) {
1376  nout << "Invalid path store for -" << opt << ": " << arg << "\n"
1377  << "Valid path store strings are any of 'rel', 'abs', "
1378  << "'rel_abs', 'strip', or 'keep'.\n";
1379  return false;
1380  }
1381 
1382  return true;
1383 }
1384 
1385 ////////////////////////////////////////////////////////////////////
1386 // Function: ProgramBase::handle_help_option
1387 // Access: Protected, Static
1388 // Description: Called when the user enters '-h', this describes how
1389 // to use the program and then exits.
1390 ////////////////////////////////////////////////////////////////////
1391 bool ProgramBase::
1392 handle_help_option(const string &, const string &, void *data) {
1393  ProgramBase *me = (ProgramBase *)data;
1394  me->show_description();
1395  me->show_usage();
1396  me->show_options();
1397  exit(0);
1398 
1399  return false;
1400 }
1401 
1402 
1403 ////////////////////////////////////////////////////////////////////
1404 // Function: ProgramBase::format_text
1405 // Access: Protected, Static
1406 // Description: Word-wraps the indicated text to the indicated output
1407 // stream. The first line is prefixed with the
1408 // indicated prefix, then tabbed over to indent_width
1409 // where the text actually begins. A newline is
1410 // inserted at or before column line_width. Each
1411 // subsequent line begins with indent_width spaces.
1412 //
1413 // An embedded newline character ('\n') forces a line
1414 // break, while an embedded carriage-return character
1415 // ('\r'), or two or more consecutive newlines, marks a
1416 // paragraph break, which is usually printed as a blank
1417 // line. Redundant newline and carriage-return
1418 // characters are generally ignored.
1419 //
1420 // The flag last_newline should be initialized to false
1421 // for the first call to format_text, and then preserved
1422 // for future calls; it tracks the state of trailing
1423 // newline characters between calls so we can correctly
1424 // identify doubled newlines.
1425 ////////////////////////////////////////////////////////////////////
1426 void ProgramBase::
1427 format_text(ostream &out, bool &last_newline,
1428  const string &prefix, int indent_width,
1429  const string &text, int line_width) {
1430  indent_width = min(indent_width, line_width - 20);
1431  int indent_amount = indent_width;
1432  bool initial_break = false;
1433 
1434  if (!prefix.empty()) {
1435  out << prefix;
1436  indent_amount = indent_width - prefix.length();
1437  if ((int)prefix.length() + 1 > indent_width) {
1438  out << "\n";
1439  initial_break = true;
1440  indent_amount = indent_width;
1441  }
1442  }
1443 
1444  size_t p = 0;
1445 
1446  // Skip any initial whitespace and newlines.
1447  while (p < text.length() && isspace(text[p])) {
1448  if (text[p] == '\r' ||
1449  (p > 0 && text[p] == '\n' && text[p - 1] == '\n') ||
1450  (p == 0 && text[p] == '\n' && last_newline)) {
1451  if (!initial_break) {
1452  // Here's an initial paragraph break, however.
1453  out << "\n";
1454  initial_break = true;
1455  }
1456  indent_amount = indent_width;
1457 
1458  } else if (text[p] == '\n') {
1459  // Largely ignore an initial newline.
1460  indent_amount = indent_width;
1461 
1462  } else if (text[p] == ' ') {
1463  // Do count up leading spaces.
1464  indent_amount++;
1465  }
1466  p++;
1467  }
1468 
1469  last_newline = (!text.empty() && text[text.length() - 1] == '\n');
1470 
1471  while (p < text.length()) {
1472  // Look for the paragraph or line break--the next newline
1473  // character, if any.
1474  size_t par = text.find_first_of("\n\r", p);
1475  bool is_paragraph_break = false;
1476  if (par == string::npos) {
1477  par = text.length();
1478  /*
1479  This shouldn't be necessary.
1480  } else {
1481  is_paragraph_break = (text[par] == '\r');
1482  */
1483  }
1484 
1485  indent(out, indent_amount);
1486 
1487  size_t eol = p + (line_width - indent_width);
1488  if (eol >= par) {
1489  // The rest of the paragraph fits completely on the line.
1490  eol = par;
1491 
1492  } else {
1493  // The paragraph doesn't fit completely on the line. Determine
1494  // the best place to break the line. Look for the last space
1495  // before the ideal eol.
1496  size_t min_eol = max((int)p, (int)eol - 25);
1497  size_t q = eol;
1498  while (q > min_eol && !isspace(text[q])) {
1499  q--;
1500  }
1501  // Now roll back to the last non-space before this one.
1502  while (q > min_eol && isspace(text[q])) {
1503  q--;
1504  }
1505 
1506  if (q != min_eol) {
1507  // Here's a good place to stop!
1508  eol = q + 1;
1509 
1510  } else {
1511  // The line cannot be broken cleanly. Just let it keep going;
1512  // don't try to wrap it.
1513  eol = par;
1514  }
1515  }
1516  out << text.substr(p, eol - p) << "\n";
1517  p = eol;
1518 
1519  // Skip additional whitespace between the lines.
1520  while (p < text.length() && isspace(text[p])) {
1521  if (text[p] == '\r' ||
1522  (p > 0 && text[p] == '\n' && text[p - 1] == '\n')) {
1523  is_paragraph_break = true;
1524  }
1525  p++;
1526  }
1527 
1528  if (eol == par && is_paragraph_break) {
1529  // Print the paragraph break as a blank line.
1530  out << "\n";
1531  if (p >= text.length()) {
1532  // If we end on a paragraph break, don't try to insert a new
1533  // one in the next pass.
1534  last_newline = false;
1535  }
1536  }
1537 
1538  indent_amount = indent_width;
1539  }
1540 }
1541 
1542 
1543 ////////////////////////////////////////////////////////////////////
1544 // Function: ProgramBase::sort_options
1545 // Access: Private
1546 // Description: Puts all the options in order by index number
1547 // (e.g. in the order they were added, within
1548 // index_groups), for output by show_options().
1549 ////////////////////////////////////////////////////////////////////
1550 void ProgramBase::
1551 sort_options() {
1552  if (!_sorted_options) {
1553  _options_by_index.clear();
1554 
1555  OptionsByName::const_iterator oi;
1556  for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) {
1557  _options_by_index.push_back(&(*oi).second);
1558  }
1559 
1560  sort(_options_by_index.begin(), _options_by_index.end(),
1561  SortOptionsByIndex());
1562  _sorted_options = true;
1563  }
1564 }
1565 
1566 ////////////////////////////////////////////////////////////////////
1567 // Function: ProgramBase::get_terminal_width
1568 // Access: Private
1569 // Description: Attempts to determine the ideal terminal width for
1570 // formatting output.
1571 ////////////////////////////////////////////////////////////////////
1572 void ProgramBase::
1573 get_terminal_width() {
1574  if (!_got_terminal_width) {
1575  _got_terminal_width = true;
1576  _got_option_indent = false;
1577 
1578 #ifdef IOCTL_TERMINAL_WIDTH
1579  if (use_terminal_width) {
1580  struct winsize size;
1581  int result = ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&size);
1582  if (result < 0 || size.ws_col < 10) {
1583  // Couldn't determine the width for some reason. Instead of
1584  // complaining, just punt.
1585  _terminal_width = default_terminal_width;
1586  } else {
1587 
1588  // Subtract 10% for the comfort margin at the edge.
1589  _terminal_width = size.ws_col - min(8, (int)(size.ws_col * 0.1));
1590  }
1591  return;
1592  }
1593 #endif // IOCTL_TERMINAL_WIDTH
1594 
1595  _terminal_width = default_terminal_width;
1596  }
1597 }
This is intended to be the base class for most general-purpose utility programs in the PANDATOOL tree...
Definition: programBase.h:37
This is our own Panda specialization on the default STL map.
Definition: pmap.h:52
static string get_version_string()
Returns the current version of Panda, expressed as a string, e.g.
Definition: pandaSystem.cxx:81
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
void show_usage()
Writes the usage line(s) to stderr.
This is a convenience class to specialize ConfigVariable as a boolean type.
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:35
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
static Notify * ptr()
Returns the pointer to the global Notify object.
Definition: notify.cxx:337
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
void show_description()
Writes the program description to stderr.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
void show_text(const string &text)
Formats the indicated text to stderr with the known _terminal_width.
Definition: programBase.I:23
void set_ostream_ptr(ostream *ostream_ptr, bool delete_later)
Changes the ostream that all subsequent Notify messages will be written to.
Definition: notify.cxx:73
string get_exec_command() const
Returns the command that invoked this program, as a shell-friendly string, suitable for pasting into ...
void show_options()
Describes each of the available options to stderr.
A special ostream that formats all of its output through ProgramBase::show_text().
PNMFileType * get_type_from_extension(const string &filename) const
Tries to determine what the PNMFileType is likely to be for a particular image file based on its exte...
string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:460
This class maintains the set of all known PNMFileTypes in the universe.
This encapsulates the user&#39;s command-line request to replace existing, incorrect pathnames to models ...
Definition: pathReplace.h:40
This is a convenience class to specialize ConfigVariable as an integer type.
This class stores a list of directories that can be searched, in order, to locate a particular file...
Definition: dSearchPath.h:32
void add_pattern(const string &orig_prefix, const string &replacement_prefix)
Adds the indicated original/replace pattern to the specification.
Definition: pathReplace.I:59
void write_man_page(ostream &out)
Generates a man page in nroff syntax based on the description and options.
void write(ostream &out, int indent_level=0) const
Writes a list of supported image file types to the indicated output stream, one per line...
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
Definition: filename.cxx:332