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