programBase.cxx 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  1. // Filename: programBase.cxx
  2. // Created by: drose (13Feb00)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. #include "programBase.h"
  6. #include "wordWrapStream.h"
  7. #include <pystub.h>
  8. // Since programBase.cxx includes pystub.h, no program that links with
  9. // progbase needs to do so. No Python code should attempt to link
  10. // with libprogbase.so.
  11. #include <indent.h>
  12. #include <dSearchPath.h>
  13. #include <coordinateSystem.h>
  14. #include <dconfig.h>
  15. #include <config_dconfig.h>
  16. #include <stdlib.h>
  17. #include <algorithm>
  18. #include <ctype.h>
  19. // If our system getopt() doesn't come with getopt_long_only(), then use
  20. // the GNU flavor that we've got in tool for this purpose.
  21. #ifndef HAVE_GETOPT_LONG_ONLY
  22. #include <gnu_getopt.h>
  23. #else
  24. #include <getopt.h>
  25. #endif
  26. // This manifest is defined if we are running on a system (e.g. most
  27. // any Unix) that allows us to determine the width of the terminal
  28. // screen via an ioctl() call. It's just handy to know for formatting
  29. // output nicely for the user.
  30. #ifdef IOCTL_TERMINAL_WIDTH
  31. #include <termios.h>
  32. #ifndef TIOCGWINSZ
  33. #include <sys/ioctl.h>
  34. #endif // TIOCGWINSZ
  35. #endif // IOCTL_TERMINAL_WIDTH
  36. bool ProgramBase::SortOptionsByIndex::
  37. operator () (const Option *a, const Option *b) const {
  38. if (a->_index_group != b->_index_group) {
  39. return a->_index_group < b->_index_group;
  40. }
  41. return a->_sequence < b->_sequence;
  42. }
  43. // This should be called at program termination just to make sure
  44. // Notify gets properly flushed before we exit, if someone calls
  45. // exit(). It's probably not necessary, but why not be phobic about
  46. // it?
  47. static void flush_nout() {
  48. nout << flush;
  49. }
  50. ////////////////////////////////////////////////////////////////////
  51. // Function: ProgramBase::Constructor
  52. // Access: Public
  53. // Description:
  54. ////////////////////////////////////////////////////////////////////
  55. ProgramBase::
  56. ProgramBase() {
  57. // A call to pystub() to force libpystub.so to be linked in.
  58. pystub();
  59. // Set up Notify to write output to our own formatted stream.
  60. Notify::ptr()->set_ostream_ptr(new WordWrapStream(this), true);
  61. // And we'll want to be sure to flush that in all normal exit cases.
  62. atexit(&flush_nout);
  63. _next_sequence = 0;
  64. _sorted_options = false;
  65. _last_newline = false;
  66. _got_terminal_width = false;
  67. _got_option_indent = false;
  68. add_option("h", "", 100,
  69. "Display this help page.",
  70. &ProgramBase::handle_help_option);
  71. // Should we report DConfig's debugging information?
  72. if (dconfig_cat.is_debug()) {
  73. dconfig_cat.debug()
  74. << "DConfig took " << Config::get_total_time_config_init()
  75. << " CPU seconds initializing, and "
  76. << Config::get_total_time_external_init()
  77. << " CPU seconds calling external initialization routines.\n";
  78. dconfig_cat.debug()
  79. << "ConfigTable::GetSym() was called "
  80. << Config::get_total_num_get() << " times.\n";
  81. }
  82. // It's nice to start with a blank line.
  83. nout << "\r";
  84. }
  85. ////////////////////////////////////////////////////////////////////
  86. // Function: ProgramBase::Destructor
  87. // Access: Public, Virtual
  88. // Description:
  89. ////////////////////////////////////////////////////////////////////
  90. ProgramBase::
  91. ~ProgramBase() {
  92. // Reset Notify in case any messages get sent after our
  93. // destruction--our stream is no longer valid.
  94. Notify::ptr()->set_ostream_ptr(NULL, false);
  95. }
  96. ////////////////////////////////////////////////////////////////////
  97. // Function: ProgramBase::show_description
  98. // Access: Public
  99. // Description: Writes the program description to stderr.
  100. ////////////////////////////////////////////////////////////////////
  101. void ProgramBase::
  102. show_description() {
  103. nout << _description << "\n";
  104. }
  105. ////////////////////////////////////////////////////////////////////
  106. // Function: ProgramBase::show_usage
  107. // Access: Public
  108. // Description: Writes the usage line(s) to stderr.
  109. ////////////////////////////////////////////////////////////////////
  110. void ProgramBase::
  111. show_usage() {
  112. nout << "\rUsage:\n";
  113. Runlines::const_iterator ri;
  114. string prog = " " +_program_name.get_basename();
  115. for (ri = _runlines.begin(); ri != _runlines.end(); ++ri) {
  116. show_text(prog, prog.length() + 1, *ri);
  117. }
  118. nout << "\r";
  119. }
  120. ////////////////////////////////////////////////////////////////////
  121. // Function: ProgramBase::show_options
  122. // Access: Public
  123. // Description: Describes each of the available options to stderr.
  124. ////////////////////////////////////////////////////////////////////
  125. void ProgramBase::
  126. show_options() {
  127. sort_options();
  128. if (!_got_option_indent) {
  129. get_terminal_width();
  130. _option_indent = min(15, (int)(_terminal_width * 0.25));
  131. _got_option_indent = true;
  132. }
  133. nout << "Options:\n";
  134. OptionsByIndex::const_iterator oi;
  135. for (oi = _options_by_index.begin(); oi != _options_by_index.end(); ++oi) {
  136. const Option &opt = *(*oi);
  137. string prefix = " -" + opt._option + " " + opt._parm_name;
  138. show_text(prefix, _option_indent, opt._description + "\r");
  139. }
  140. }
  141. ////////////////////////////////////////////////////////////////////
  142. // Function: ProgramBase::show_text
  143. // Access: Public
  144. // Description: Formats the indicated text and its prefix for output
  145. // to stderr with the known _terminal_width.
  146. ////////////////////////////////////////////////////////////////////
  147. void ProgramBase::
  148. show_text(const string &prefix, int indent_width, string text) {
  149. get_terminal_width();
  150. // This is correct! It goes go to cerr, not to nout. Sending it to
  151. // nout would be cyclic, since nout is redefined to map back through
  152. // this function.
  153. format_text(cerr, _last_newline,
  154. prefix, indent_width, text, _terminal_width);
  155. }
  156. ////////////////////////////////////////////////////////////////////
  157. // Function: ProgramBase::parse_command_line
  158. // Access: Public, Virtual
  159. // Description: Dispatches on each of the options on the command
  160. // line, and passes the remaining parameters to
  161. // handle_args(). If an error on the command line is
  162. // detected, will automatically call show_usage() and
  163. // exit(1).
  164. ////////////////////////////////////////////////////////////////////
  165. void ProgramBase::
  166. parse_command_line(int argc, char *argv[]) {
  167. _program_name = argv[0];
  168. int i;
  169. for (i = 1; i < argc; i++) {
  170. _program_args.push_back(argv[i]);
  171. }
  172. // Build up the long options list and the short options string for
  173. // getopt_long_only().
  174. vector<struct option> long_options;
  175. string short_options;
  176. // We also need to build a temporary map of int index numbers to
  177. // Option pointers. We'll pass these index numbers to GNU's
  178. // getopt_long() so we can tell one option from another.
  179. typedef map<int, const Option *> Options;
  180. Options options;
  181. OptionsByName::const_iterator oi;
  182. int next_index = 256;
  183. // Let's prefix the option string with "-" to tell GNU getopt that
  184. // we want it to tell us the post-option arguments, instead of
  185. // trying to meddle with ARGC and ARGV (which we aren't using
  186. // directly).
  187. short_options = "-";
  188. for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) {
  189. const Option &opt = (*oi).second;
  190. int index;
  191. if (opt._option.length() == 1) {
  192. // This is a "short" option; its option string consists of only
  193. // one letter. Its index is the letter itself.
  194. index = (int)opt._option[0];
  195. short_options += opt._option;
  196. if (!opt._parm_name.empty()) {
  197. // This option takes an argument.
  198. short_options += ':';
  199. }
  200. } else {
  201. // This is a "long" option; we'll assign it the next available
  202. // index.
  203. index = ++next_index;
  204. }
  205. // Now add it to the GNU data structures.
  206. struct option gopt;
  207. gopt.name = (char *)opt._option.c_str();
  208. gopt.has_arg = (opt._parm_name.empty()) ?
  209. no_argument : required_argument;
  210. gopt.flag = (int *)NULL;
  211. // Return an index into the _options_by_index array, offset by 256
  212. // so we don't confuse it with '?'.
  213. gopt.val = index;
  214. long_options.push_back(gopt);
  215. options[index] = &opt;
  216. }
  217. // Finally, add one more structure, all zeroes, to indicate the end
  218. // of the options.
  219. struct option gopt;
  220. memset(&gopt, 0, sizeof(gopt));
  221. long_options.push_back(gopt);
  222. // We'll use this vector to save the non-option arguments.
  223. // Generally, these will all be at the end, but with the GNU
  224. // extensions, they need not be.
  225. Args remaining_args;
  226. // Now call getopt_long() to actually parse the arguments.
  227. extern char *optarg;
  228. const struct option *long_opts = &long_options[0];
  229. int flag =
  230. getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL);
  231. while (flag != EOF) {
  232. string arg;
  233. if (optarg != NULL) {
  234. arg = optarg;
  235. }
  236. switch (flag) {
  237. case '?':
  238. // Invalid option or parameter.
  239. show_usage();
  240. exit(1);
  241. case '\x1':
  242. // A special return value from getopt() indicating a non-option
  243. // argument.
  244. remaining_args.push_back(arg);
  245. break;
  246. default:
  247. {
  248. // A normal option. Figure out which one it is.
  249. Options::const_iterator ii;
  250. ii = options.find(flag);
  251. if (ii == options.end()) {
  252. nout << "Internal error! Invalid option index returned.\n";
  253. abort();
  254. }
  255. const Option &opt = *(*ii).second;
  256. bool okflag = true;
  257. if (opt._option_function != (OptionDispatch)NULL) {
  258. okflag = (this->*opt._option_function)(opt._option, arg,
  259. opt._option_data);
  260. }
  261. if (opt._bool_var != (bool *)NULL) {
  262. (*opt._bool_var) = true;
  263. }
  264. if (!okflag) {
  265. show_usage();
  266. exit(1);
  267. }
  268. }
  269. }
  270. flag =
  271. getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL);
  272. }
  273. if (!handle_args(remaining_args)) {
  274. show_usage();
  275. exit(1);
  276. }
  277. if (!post_command_line()) {
  278. show_usage();
  279. exit(1);
  280. }
  281. }
  282. ////////////////////////////////////////////////////////////////////
  283. // Function: ProgramBase::handle_args
  284. // Access: Protected, Virtual
  285. // Description: Does something with the additional arguments on the
  286. // command line (after all the -options have been
  287. // parsed). Returns true if the arguments are good,
  288. // false otherwise.
  289. ////////////////////////////////////////////////////////////////////
  290. bool ProgramBase::
  291. handle_args(ProgramBase::Args &args) {
  292. if (!args.empty()) {
  293. nout << "Unexpected arguments on command line:\n";
  294. copy(args.begin(), args.end(), ostream_iterator<string>(nout, " "));
  295. nout << "\r";
  296. return false;
  297. }
  298. return true;
  299. }
  300. ////////////////////////////////////////////////////////////////////
  301. // Function: ProgramBase::post_command_line
  302. // Access: Protected, Virtual
  303. // Description: This is called after the command line has been
  304. // completely processed, and it gives the program a
  305. // chance to do some last-minute processing and
  306. // validation of the options and arguments. It should
  307. // return true if everything is fine, false if there is
  308. // an error.
  309. ////////////////////////////////////////////////////////////////////
  310. bool ProgramBase::
  311. post_command_line() {
  312. return true;
  313. }
  314. ////////////////////////////////////////////////////////////////////
  315. // Function: ProgramBase::set_program_description
  316. // Access: Protected
  317. // Description: Sets the description of the program that will be
  318. // reported by show_usage(). The description should be
  319. // one long string of text. Embedded newline characters
  320. // are interpreted as paragraph breaks and printed as
  321. // blank lines.
  322. ////////////////////////////////////////////////////////////////////
  323. void ProgramBase::
  324. set_program_description(const string &description) {
  325. _description = description;
  326. }
  327. ////////////////////////////////////////////////////////////////////
  328. // Function: ProgramBase::clear_runlines
  329. // Access: Protected
  330. // Description: Removes all of the runlines that were previously
  331. // added, presumably before adding some new ones.
  332. ////////////////////////////////////////////////////////////////////
  333. void ProgramBase::
  334. clear_runlines() {
  335. _runlines.clear();
  336. }
  337. ////////////////////////////////////////////////////////////////////
  338. // Function: ProgramBase::add_runline
  339. // Access: Protected
  340. // Description: Adds an additional line to the list of lines that
  341. // will be displayed to describe briefly how the program
  342. // is to be run. Each line should be something like
  343. // "[opts] arg1 arg2", that is, it does *not* include
  344. // the name of the program, but it includes everything
  345. // that should be printed after the name of the program.
  346. //
  347. // Normally there is only one runline for a given
  348. // program, but it is possible to define more than one.
  349. ////////////////////////////////////////////////////////////////////
  350. void ProgramBase::
  351. add_runline(const string &runline) {
  352. _runlines.push_back(runline);
  353. }
  354. ////////////////////////////////////////////////////////////////////
  355. // Function: ProgramBase::clear_options
  356. // Access: Protected
  357. // Description: Removes all of the options that were previously
  358. // added, presumably before adding some new ones.
  359. // Normally you wouldn't want to do this unless you want
  360. // to completely replace all of the options defined by
  361. // base classes.
  362. ////////////////////////////////////////////////////////////////////
  363. void ProgramBase::
  364. clear_options() {
  365. _options_by_name.clear();
  366. }
  367. ////////////////////////////////////////////////////////////////////
  368. // Function: ProgramBase::add_option
  369. // Access: Protected
  370. // Description: Adds (or redefines) a command line option. When
  371. // parse_command_line() is executed it will look for
  372. // these options (followed by a hyphen) on the command
  373. // line; when a particular option is found it will call
  374. // the indicated option_function, supplying the provided
  375. // option_data. This allows the user to define a
  376. // function that does some special behavior for any
  377. // given option, or to use any of a number of generic
  378. // pre-defined functions to fill in data for each
  379. // option.
  380. //
  381. // Each option may or may not take a parameter. If
  382. // parm_name is nonempty, it is assumed that the option
  383. // does take a parameter (and parm_name contains the
  384. // name that will be printed by show_options()). This
  385. // parameter will be supplied as the second parameter to
  386. // the dispatch function. If parm_name is empty, it is
  387. // assumed that the option does not take a parameter.
  388. // There is no provision for optional parameters.
  389. //
  390. // The options are listed first in order by their
  391. // index_group number, and then in the order that
  392. // add_option() was called. This provides a mechanism
  393. // for listing the options defined in derived classes
  394. // before those of the base classes.
  395. ////////////////////////////////////////////////////////////////////
  396. void ProgramBase::
  397. add_option(const string &option, const string &parm_name,
  398. int index_group, const string &description,
  399. OptionDispatch option_function,
  400. bool *bool_var, void *option_data) {
  401. Option opt;
  402. opt._option = option;
  403. opt._parm_name = parm_name;
  404. opt._index_group = index_group;
  405. opt._sequence = ++_next_sequence;
  406. opt._description = description;
  407. opt._option_function = option_function;
  408. opt._bool_var = bool_var;
  409. opt._option_data = option_data;
  410. _options_by_name[option] = opt;
  411. _sorted_options = false;
  412. if (bool_var != (bool *)NULL) {
  413. (*bool_var) = false;
  414. }
  415. }
  416. ////////////////////////////////////////////////////////////////////
  417. // Function: ProgramBase::redescribe_option
  418. // Access: Protected
  419. // Description: Changes the description associated with a
  420. // previously-defined option. Returns true if the
  421. // option was changed, false if it hadn't been defined.
  422. ////////////////////////////////////////////////////////////////////
  423. bool ProgramBase::
  424. redescribe_option(const string &option, const string &description) {
  425. OptionsByName::iterator oi = _options_by_name.find(option);
  426. if (oi == _options_by_name.end()) {
  427. return false;
  428. }
  429. (*oi).second._description = description;
  430. return true;
  431. }
  432. ////////////////////////////////////////////////////////////////////
  433. // Function: ProgramBase::remove_option
  434. // Access: Protected
  435. // Description: Removes a previously-defined option. Returns true if
  436. // the option was removed, false if it hadn't existed.
  437. ////////////////////////////////////////////////////////////////////
  438. bool ProgramBase::
  439. remove_option(const string &option) {
  440. OptionsByName::iterator oi = _options_by_name.find(option);
  441. if (oi == _options_by_name.end()) {
  442. return false;
  443. }
  444. _options_by_name.erase(oi);
  445. _sorted_options = false;
  446. return true;
  447. }
  448. ////////////////////////////////////////////////////////////////////
  449. // Function: ProgramBase::dispatch_none
  450. // Access: Protected
  451. // Description: Standard dispatch function for an option that takes
  452. // no parameters, and does nothing special. Typically
  453. // this would be used for a boolean flag, whose presence
  454. // means something and whose absence means something
  455. // else. Use the bool_var parameter to add_option() to
  456. // determine whether the option appears on the command
  457. // line or not.
  458. ////////////////////////////////////////////////////////////////////
  459. bool ProgramBase::
  460. dispatch_none(const string &, const string &, void *) {
  461. return true;
  462. }
  463. ////////////////////////////////////////////////////////////////////
  464. // Function: ProgramBase::dispatch_count
  465. // Access: Protected
  466. // Description: Standard dispatch function for an option that takes
  467. // no parameters, but whose presence on the command line
  468. // increments an integer counter for each time it
  469. // appears. -v is often an option that works this way.
  470. // The data pointer is to an int counter variable.
  471. ////////////////////////////////////////////////////////////////////
  472. bool ProgramBase::
  473. dispatch_count(const string &, const string &, void *var) {
  474. int *ip = (int *)var;
  475. (*ip)++;
  476. return true;
  477. }
  478. ////////////////////////////////////////////////////////////////////
  479. // Function: ProgramBase::dispatch_int
  480. // Access: Protected
  481. // Description: Standard dispatch function for an option that takes
  482. // one parameter, which is to be interpreted as an
  483. // integer. The data pointer is to an int variable.
  484. ////////////////////////////////////////////////////////////////////
  485. bool ProgramBase::
  486. dispatch_int(const string &opt, const string &arg, void *var) {
  487. if (arg.empty()) {
  488. nout << "-" << opt << " requires an integer parameter.\n";
  489. return false;
  490. }
  491. int *ip = (int *)var;
  492. const char *arg_str = arg.c_str();
  493. char *endptr;
  494. (*ip) = strtol(arg_str, &endptr, 0);
  495. if (*endptr != '\0') {
  496. nout << "Invalid integer parameter for -" << opt << ": "
  497. << arg << "\n";
  498. return false;
  499. }
  500. return true;
  501. }
  502. ////////////////////////////////////////////////////////////////////
  503. // Function: ProgramBase::dispatch_int_pair
  504. // Access: Protected
  505. // Description: Standard dispatch function for an option that takes
  506. // a pair of integer parameters. The data pointer is to
  507. // an array of two integers.
  508. ////////////////////////////////////////////////////////////////////
  509. bool ProgramBase::
  510. dispatch_int_pair(const string &opt, const string &arg, void *var) {
  511. if (arg.empty()) {
  512. nout << "-" << opt
  513. << " requires an pair of integers separated by a comma.\n";
  514. return false;
  515. }
  516. size_t comma = arg.find(',');
  517. if (comma == string::npos) {
  518. nout << "-" << opt
  519. << " requires an pair of integers separated by a comma.\n";
  520. return false;
  521. }
  522. string first = arg.substr(0, comma);
  523. string second = arg.substr(comma + 1);
  524. int *ip = (int *)var;
  525. char *endptr;
  526. const char *first_str = first.c_str();
  527. ip[0] = strtol(first_str, &endptr, 0);
  528. if (*endptr != '\0') {
  529. nout << "Invalid integer parameter for -" << opt << ": "
  530. << first << "\n";
  531. return false;
  532. }
  533. const char *second_str = second.c_str();
  534. ip[1] = strtol(second_str, &endptr, 0);
  535. if (*endptr != '\0') {
  536. nout << "Invalid integer parameter for -" << opt << ": "
  537. << second << "\n";
  538. return false;
  539. }
  540. return true;
  541. }
  542. ////////////////////////////////////////////////////////////////////
  543. // Function: ProgramBase::dispatch_double
  544. // Access: Protected
  545. // Description: Standard dispatch function for an option that takes
  546. // one parameter, which is to be interpreted as a
  547. // double. The data pointer is to an double variable.
  548. ////////////////////////////////////////////////////////////////////
  549. bool ProgramBase::
  550. dispatch_double(const string &opt, const string &arg, void *var) {
  551. if (arg.empty()) {
  552. nout << "-" << opt << " requires a floating-point parameter.\n";
  553. return false;
  554. }
  555. double *ip = (double *)var;
  556. const char *arg_str = arg.c_str();
  557. char *endptr;
  558. (*ip) = strtod(arg_str, &endptr);
  559. if (*endptr != '\0') {
  560. nout << "Invalid floating-point parameter for -" << opt << ": "
  561. << arg << "\n";
  562. return false;
  563. }
  564. return true;
  565. }
  566. ////////////////////////////////////////////////////////////////////
  567. // Function: ProgramBase::dispatch_string
  568. // Access: Protected
  569. // Description: Standard dispatch function for an option that takes
  570. // one parameter, which is to be interpreted as a
  571. // string. The data pointer is to a string variable.
  572. ////////////////////////////////////////////////////////////////////
  573. bool ProgramBase::
  574. dispatch_string(const string &, const string &arg, void *var) {
  575. string *ip = (string *)var;
  576. (*ip) = arg;
  577. return true;
  578. }
  579. ////////////////////////////////////////////////////////////////////
  580. // Function: ProgramBase::dispatch_filename
  581. // Access: Protected
  582. // Description: Standard dispatch function for an option that takes
  583. // one parameter, which is to be interpreted as a
  584. // filename. The data pointer is to a Filename variable.
  585. ////////////////////////////////////////////////////////////////////
  586. bool ProgramBase::
  587. dispatch_filename(const string &opt, const string &arg, void *var) {
  588. if (arg.empty()) {
  589. nout << "-" << opt << " requires a filename parameter.\n";
  590. return false;
  591. }
  592. Filename *ip = (Filename *)var;
  593. (*ip) = arg;
  594. return true;
  595. }
  596. ////////////////////////////////////////////////////////////////////
  597. // Function: ProgramBase::dispatch_search_path
  598. // Access: Protected
  599. // Description: Standard dispatch function for an option that takes
  600. // one parameter, which is to be interpreted as a
  601. // colon-delimited search path. The data pointer is to
  602. // a DSearchPath variable. This kind of option may
  603. // appear multiple times on the command line; each time,
  604. // the new search paths are appended.
  605. ////////////////////////////////////////////////////////////////////
  606. bool ProgramBase::
  607. dispatch_search_path(const string &opt, const string &arg, void *var) {
  608. if (arg.empty()) {
  609. nout << "-" << opt << " requires a search path parameter.\n";
  610. return false;
  611. }
  612. DSearchPath *ip = (DSearchPath *)var;
  613. ip->append_path(arg);
  614. return true;
  615. }
  616. ////////////////////////////////////////////////////////////////////
  617. // Function: ProgramBase::dispatch_coordinate_system
  618. // Access: Protected
  619. // Description: Standard dispatch function for an option that takes
  620. // one parameter, which is to be interpreted as a
  621. // coordinate system string. The data pointer is to a
  622. // CoordinateSystem variable.
  623. ////////////////////////////////////////////////////////////////////
  624. bool ProgramBase::
  625. dispatch_coordinate_system(const string &opt, const string &arg, void *var) {
  626. CoordinateSystem *ip = (CoordinateSystem *)var;
  627. (*ip) = parse_coordinate_system_string(arg);
  628. if ((*ip) == CS_invalid) {
  629. nout << "Invalid coordinate system for -" << opt << ": " << arg << "\n"
  630. << "Valid coordinate system strings are any of 'y-up', 'z-up', "
  631. "'y-up-left', or 'z-up-left'.\n";
  632. return false;
  633. }
  634. return true;
  635. }
  636. ////////////////////////////////////////////////////////////////////
  637. // Function: ProgramBase::handle_help_option
  638. // Access: Protected
  639. // Description: Called when the user enters '-h', this describes how
  640. // to use the program and then exits.
  641. ////////////////////////////////////////////////////////////////////
  642. bool ProgramBase::
  643. handle_help_option(const string &, const string &, void *) {
  644. show_description();
  645. show_usage();
  646. show_options();
  647. exit(0);
  648. return false;
  649. }
  650. ////////////////////////////////////////////////////////////////////
  651. // Function: ProgramBase::format_text
  652. // Access: Protected, Static
  653. // Description: Word-wraps the indicated text to the indicated output
  654. // stream. The first line is prefixed with the
  655. // indicated prefix, then tabbed over to indent_width
  656. // where the text actually begins. A newline is
  657. // inserted at or before column line_width. Each
  658. // subsequent line begins with indent_width spaces.
  659. //
  660. // An embedded newline character ('\n') forces a line
  661. // break, while an embedded carriage-return character
  662. // ('\r'), or two or more consecutive newlines, marks a
  663. // paragraph break, which is usually printed as a blank
  664. // line. Redundant newline and carriage-return
  665. // characters are generally ignored.
  666. //
  667. // The flag last_newline should be initialized to false
  668. // for the first call to format_text, and then preserved
  669. // for future calls; it tracks the state of trailing
  670. // newline characters between calls so we can correctly
  671. // identify doubled newlines.
  672. ////////////////////////////////////////////////////////////////////
  673. void ProgramBase::
  674. format_text(ostream &out, bool &last_newline,
  675. const string &prefix, int indent_width,
  676. const string &text, int line_width) {
  677. indent_width = min(indent_width, line_width - 20);
  678. int indent_amount = indent_width;
  679. bool initial_break = false;
  680. if (!prefix.empty()) {
  681. out << prefix;
  682. indent_amount = indent_width - prefix.length();
  683. if ((int)prefix.length() + 1 > indent_width) {
  684. out << "\n";
  685. initial_break = true;
  686. indent_amount = indent_width;
  687. }
  688. }
  689. size_t p = 0;
  690. // Skip any initial whitespace and newlines.
  691. while (p < text.length() && isspace(text[p])) {
  692. if (text[p] == '\r' ||
  693. (p > 0 && text[p] == '\n' && text[p - 1] == '\n') ||
  694. (p == 0 && text[p] == '\n' && last_newline)) {
  695. if (!initial_break) {
  696. // Here's an initial paragraph break, however.
  697. out << "\n";
  698. initial_break = true;
  699. }
  700. indent_amount = indent_width;
  701. } else if (text[p] == '\n') {
  702. // Largely ignore an initial newline.
  703. indent_amount = indent_width;
  704. } else if (text[p] == ' ') {
  705. // Do count up leading spaces.
  706. indent_amount++;
  707. }
  708. p++;
  709. }
  710. last_newline = (!text.empty() && text[text.length() - 1] == '\n');
  711. while (p < text.length()) {
  712. // Look for the paragraph or line break--the next newline
  713. // character, if any.
  714. size_t par = text.find_first_of("\n\r", p);
  715. bool is_paragraph_break = false;
  716. if (par == string::npos) {
  717. par = text.length();
  718. /*
  719. This shouldn't be necessary.
  720. } else {
  721. is_paragraph_break = (text[par] == '\r');
  722. */
  723. }
  724. indent(out, indent_amount);
  725. size_t eol = p + (line_width - indent_width);
  726. if (eol >= par) {
  727. // The rest of the paragraph fits completely on the line.
  728. eol = par;
  729. } else {
  730. // The paragraph doesn't fit completely on the line. Determine
  731. // the best place to break the line. Look for the last space
  732. // before the ideal eol.
  733. size_t min_eol = max((int)p, (int)eol - 25);
  734. size_t q = eol;
  735. while (q > min_eol && !isspace(text[q])) {
  736. q--;
  737. }
  738. // Now roll back to the last non-space before this one.
  739. while (q > min_eol && isspace(text[q])) {
  740. q--;
  741. }
  742. if (q != min_eol) {
  743. // Here's a good place to stop!
  744. eol = q + 1;
  745. } else {
  746. // The line cannot be broken cleanly. Just let it keep going;
  747. // don't try to wrap it.
  748. eol = par;
  749. }
  750. }
  751. out << text.substr(p, eol - p) << "\n";
  752. p = eol;
  753. // Skip additional whitespace between the lines.
  754. while (p < text.length() && isspace(text[p])) {
  755. if (text[p] == '\r' ||
  756. (p > 0 && text[p] == '\n' && text[p - 1] == '\n')) {
  757. is_paragraph_break = true;
  758. }
  759. p++;
  760. }
  761. if (eol == par && is_paragraph_break) {
  762. // Print the paragraph break as a blank line.
  763. out << "\n";
  764. if (p >= text.length()) {
  765. // If we end on a paragraph break, don't try to insert a new
  766. // one in the next pass.
  767. last_newline = false;
  768. }
  769. }
  770. indent_amount = indent_width;
  771. }
  772. }
  773. ////////////////////////////////////////////////////////////////////
  774. // Function: ProgramBase::sort_options
  775. // Access: Private
  776. // Description: Puts all the options in order by index number
  777. // (e.g. in the order they were added, within
  778. // index_groups), for output by show_options().
  779. ////////////////////////////////////////////////////////////////////
  780. void ProgramBase::
  781. sort_options() {
  782. if (!_sorted_options) {
  783. _options_by_index.clear();
  784. OptionsByName::const_iterator oi;
  785. for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) {
  786. _options_by_index.push_back(&(*oi).second);
  787. }
  788. sort(_options_by_index.begin(), _options_by_index.end(),
  789. SortOptionsByIndex());
  790. _sorted_options = true;
  791. }
  792. }
  793. ////////////////////////////////////////////////////////////////////
  794. // Function: ProgramBase::get_terminal_width
  795. // Access: Private
  796. // Description: Attempts to determine the ideal terminal width for
  797. // formatting output.
  798. ////////////////////////////////////////////////////////////////////
  799. void ProgramBase::
  800. get_terminal_width() {
  801. if (!_got_terminal_width) {
  802. #ifdef IOCTL_TERMINAL_WIDTH
  803. struct winsize size;
  804. int result = ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&size);
  805. if (result < 0) {
  806. // Couldn't determine the width for some reason. Instead of
  807. // complaining, just punt.
  808. _terminal_width = 72;
  809. } else {
  810. // Subtract 10% for the comfort margin at the edge.
  811. _terminal_width = size.ws_col - min(8, (int)(size.ws_col * 0.1));
  812. }
  813. #else // IOCTL_TERMINAL_WIDTH
  814. _terminal_width = 72;
  815. #endif // IOCTL_TERMINAL_WIDTH
  816. _got_terminal_width = true;
  817. _got_option_indent = false;
  818. }
  819. }