00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "programBase.h"
00020 #include "wordWrapStream.h"
00021
00022 #include "pystub.h"
00023
00024
00025
00026
00027 #include "pnmFileTypeRegistry.h"
00028 #include "indent.h"
00029 #include "dSearchPath.h"
00030 #include "coordinateSystem.h"
00031 #include "dconfig.h"
00032 #include "config_dconfig.h"
00033 #include "string_utils.h"
00034
00035 #include <stdlib.h>
00036 #include <algorithm>
00037 #include <ctype.h>
00038
00039
00040
00041 #ifndef HAVE_GETOPT_LONG_ONLY
00042 #include <gnu_getopt.h>
00043 #else
00044 #include <getopt.h>
00045 #endif
00046
00047
00048
00049
00050
00051 #ifdef IOCTL_TERMINAL_WIDTH
00052 #include <termios.h>
00053 #ifndef TIOCGWINSZ
00054 #include <sys/ioctl.h>
00055 #endif // TIOCGWINSZ
00056 #endif // IOCTL_TERMINAL_WIDTH
00057
00058 bool ProgramBase::SortOptionsByIndex::
00059 operator () (const Option *a, const Option *b) const {
00060 if (a->_index_group != b->_index_group) {
00061 return a->_index_group < b->_index_group;
00062 }
00063 return a->_sequence < b->_sequence;
00064 }
00065
00066
00067
00068
00069
00070 static void flush_nout() {
00071 nout << flush;
00072 }
00073
00074
00075
00076
00077
00078
00079 ProgramBase::
00080 ProgramBase() {
00081
00082 pystub();
00083
00084
00085 Notify::ptr()->set_ostream_ptr(new WordWrapStream(this), true);
00086
00087
00088 atexit(&flush_nout);
00089
00090 _path_replace = new PathReplace;
00091
00092
00093
00094
00095 _path_replace->_path_store = PS_absolute;
00096 _got_path_store = false;
00097 _got_path_directory = false;
00098
00099 _next_sequence = 0;
00100 _sorted_options = false;
00101 _last_newline = false;
00102 _got_terminal_width = false;
00103 _got_option_indent = false;
00104
00105 add_option("h", "", 100,
00106 "Display this help page.",
00107 &ProgramBase::handle_help_option, NULL, (void *)this);
00108
00109
00110 if (dconfig_cat.is_debug()) {
00111 dconfig_cat.debug()
00112 << "DConfig took " << Config::get_total_time_config_init()
00113 << " CPU seconds initializing, and "
00114 << Config::get_total_time_external_init()
00115 << " CPU seconds calling external initialization routines.\n";
00116 dconfig_cat.debug()
00117 << "ConfigTable::GetSym() was called "
00118 << Config::get_total_num_get() << " times.\n";
00119 }
00120
00121
00122 nout << "\r";
00123 }
00124
00125
00126
00127
00128
00129
00130 ProgramBase::
00131 ~ProgramBase() {
00132
00133
00134 Notify::ptr()->set_ostream_ptr(NULL, false);
00135 }
00136
00137
00138
00139
00140
00141
00142 void ProgramBase::
00143 show_description() {
00144 nout << _description << "\n";
00145 }
00146
00147
00148
00149
00150
00151
00152 void ProgramBase::
00153 show_usage() {
00154 nout << "\rUsage:\n";
00155 Runlines::const_iterator ri;
00156 string prog = " " +_program_name.get_basename_wo_extension();
00157
00158 for (ri = _runlines.begin(); ri != _runlines.end(); ++ri) {
00159 show_text(prog, prog.length() + 1, *ri);
00160 }
00161 nout << "\r";
00162 }
00163
00164
00165
00166
00167
00168
00169 void ProgramBase::
00170 show_options() {
00171 sort_options();
00172 if (!_got_option_indent) {
00173 get_terminal_width();
00174 _option_indent = min(15, (int)(_terminal_width * 0.25));
00175 _got_option_indent = true;
00176 }
00177
00178 nout << "Options:\n";
00179 OptionsByIndex::const_iterator oi;
00180 for (oi = _options_by_index.begin(); oi != _options_by_index.end(); ++oi) {
00181 const Option &opt = *(*oi);
00182 string prefix = " -" + opt._option + " " + opt._parm_name;
00183 show_text(prefix, _option_indent, opt._description + "\r");
00184 }
00185 }
00186
00187
00188
00189
00190
00191
00192
00193 void ProgramBase::
00194 show_text(const string &prefix, int indent_width, string text) {
00195 get_terminal_width();
00196
00197
00198
00199
00200 format_text(cerr, _last_newline,
00201 prefix, indent_width, text, _terminal_width);
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 void ProgramBase::
00214 parse_command_line(int argc, char *argv[]) {
00215 _program_name = Filename::from_os_specific(argv[0]);
00216 int i;
00217 for (i = 1; i < argc; i++) {
00218 _program_args.push_back(argv[i]);
00219 }
00220
00221
00222
00223 pvector<struct option> long_options;
00224 string short_options;
00225
00226
00227
00228
00229 typedef pmap<int, const Option *> Options;
00230 Options options;
00231
00232 OptionsByName::const_iterator oi;
00233 int next_index = 256;
00234
00235
00236
00237
00238
00239 short_options = "-";
00240
00241 for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) {
00242 const Option &opt = (*oi).second;
00243
00244 int index;
00245 if (opt._option.length() == 1) {
00246
00247
00248 index = (int)opt._option[0];
00249
00250 short_options += opt._option;
00251 if (!opt._parm_name.empty()) {
00252
00253 short_options += ':';
00254 }
00255 } else {
00256
00257
00258 index = ++next_index;
00259 }
00260
00261
00262 struct option gopt;
00263 gopt.name = (char *)opt._option.c_str();
00264 gopt.has_arg = (opt._parm_name.empty()) ?
00265 no_argument : required_argument;
00266 gopt.flag = (int *)NULL;
00267
00268
00269
00270 gopt.val = index;
00271
00272 long_options.push_back(gopt);
00273
00274 options[index] = &opt;
00275 }
00276
00277
00278
00279 struct option gopt;
00280 memset(&gopt, 0, sizeof(gopt));
00281 long_options.push_back(gopt);
00282
00283
00284
00285
00286 Args remaining_args;
00287
00288
00289 extern char *optarg;
00290 const struct option *long_opts = &long_options[0];
00291
00292 int flag =
00293 getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL);
00294 while (flag != EOF) {
00295 string arg;
00296 if (optarg != NULL) {
00297 arg = optarg;
00298 }
00299
00300 switch (flag) {
00301 case '?':
00302
00303 show_usage();
00304 exit(1);
00305
00306 case '\x1':
00307
00308
00309 remaining_args.push_back(arg);
00310 break;
00311
00312 default:
00313 {
00314
00315 Options::const_iterator ii;
00316 ii = options.find(flag);
00317 if (ii == options.end()) {
00318 nout << "Internal error! Invalid option index returned.\n";
00319 abort();
00320 }
00321
00322 const Option &opt = *(*ii).second;
00323 bool okflag = true;
00324 if (opt._option_function != (OptionDispatchFunction)NULL) {
00325 okflag = (*opt._option_function)(opt._option, arg, opt._option_data);
00326 }
00327 if (opt._option_method != (OptionDispatchMethod)NULL) {
00328 okflag = (*opt._option_method)(this, opt._option, arg, opt._option_data);
00329 }
00330 if (opt._bool_var != (bool *)NULL) {
00331 (*opt._bool_var) = true;
00332 }
00333
00334 if (!okflag) {
00335 show_usage();
00336 exit(1);
00337 }
00338 }
00339 }
00340
00341 flag =
00342 getopt_long_only(argc, argv, short_options.c_str(), long_opts, NULL);
00343 }
00344
00345 if (!handle_args(remaining_args)) {
00346 show_usage();
00347 exit(1);
00348 }
00349
00350 if (!post_command_line()) {
00351 show_usage();
00352 exit(1);
00353 }
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363 string ProgramBase::
00364 get_exec_command() const {
00365 string command;
00366
00367 command = _program_name.get_basename_wo_extension();
00368 Args::const_iterator ai;
00369 for (ai = _program_args.begin(); ai != _program_args.end(); ++ai) {
00370 const string &arg = (*ai);
00371
00372
00373 bool legal = true;
00374 string::const_iterator si;
00375 for (si = arg.begin(); legal && si != arg.end(); ++si) {
00376 switch (*si) {
00377 case ' ':
00378 case '\n':
00379 case '\t':
00380 case '*':
00381 case '?':
00382 case '\\':
00383 case '(':
00384 case ')':
00385 case '|':
00386 case '&':
00387 case '<':
00388 case '>':
00389 case '"':
00390 case ';':
00391 case '$':
00392 legal = false;
00393 }
00394 }
00395
00396 if (legal) {
00397 command += " " + arg;
00398 } else {
00399 command += " '" + arg + "'";
00400 }
00401 }
00402
00403 return command;
00404 }
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 bool ProgramBase::
00416 handle_args(ProgramBase::Args &args) {
00417 if (!args.empty()) {
00418 nout << "Unexpected arguments on command line:\n";
00419 Args::const_iterator ai;
00420 for (ai = args.begin(); ai != args.end(); ++ai) {
00421 nout << (*ai) << " ";
00422 }
00423 nout << "\r";
00424 return false;
00425 }
00426
00427 return true;
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 bool ProgramBase::
00441 post_command_line() {
00442 return true;
00443 }
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 void ProgramBase::
00455 set_program_description(const string &description) {
00456 _description = description;
00457 }
00458
00459
00460
00461
00462
00463
00464
00465 void ProgramBase::
00466 clear_runlines() {
00467 _runlines.clear();
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 void ProgramBase::
00484 add_runline(const string &runline) {
00485 _runlines.push_back(runline);
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497 void ProgramBase::
00498 clear_options() {
00499 _options_by_name.clear();
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 void ProgramBase::
00532 add_option(const string &option, const string &parm_name,
00533 int index_group, const string &description,
00534 OptionDispatchFunction option_function,
00535 bool *bool_var, void *option_data) {
00536 Option opt;
00537 opt._option = option;
00538 opt._parm_name = parm_name;
00539 opt._index_group = index_group;
00540 opt._sequence = ++_next_sequence;
00541 opt._description = description;
00542 opt._option_function = option_function;
00543 opt._option_method = (OptionDispatchMethod)NULL;
00544 opt._bool_var = bool_var;
00545 opt._option_data = option_data;
00546
00547 _options_by_name[option] = opt;
00548 _sorted_options = false;
00549
00550 if (bool_var != (bool *)NULL) {
00551 (*bool_var) = false;
00552 }
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 void ProgramBase::
00573 add_option(const string &option, const string &parm_name,
00574 int index_group, const string &description,
00575 OptionDispatchMethod option_method,
00576 bool *bool_var, void *option_data) {
00577 Option opt;
00578 opt._option = option;
00579 opt._parm_name = parm_name;
00580 opt._index_group = index_group;
00581 opt._sequence = ++_next_sequence;
00582 opt._description = description;
00583 opt._option_function = (OptionDispatchFunction)NULL;
00584 opt._option_method = option_method;
00585 opt._bool_var = bool_var;
00586 opt._option_data = option_data;
00587
00588 _options_by_name[option] = opt;
00589 _sorted_options = false;
00590
00591 if (bool_var != (bool *)NULL) {
00592 (*bool_var) = false;
00593 }
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603 bool ProgramBase::
00604 redescribe_option(const string &option, const string &description) {
00605 OptionsByName::iterator oi = _options_by_name.find(option);
00606 if (oi == _options_by_name.end()) {
00607 return false;
00608 }
00609 (*oi).second._description = description;
00610 return true;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619 bool ProgramBase::
00620 remove_option(const string &option) {
00621 OptionsByName::iterator oi = _options_by_name.find(option);
00622 if (oi == _options_by_name.end()) {
00623 return false;
00624 }
00625 _options_by_name.erase(oi);
00626 _sorted_options = false;
00627 return true;
00628 }
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 void ProgramBase::
00639 add_path_replace_options() {
00640 add_option
00641 ("pr", "path_replace", 40,
00642 "Sometimes references to other files (textures, external references) "
00643 "are stored with a full path that is appropriate for some other system, "
00644 "but does not exist here. This option may be used to specify how "
00645 "those invalid paths map to correct paths. Generally, this is of "
00646 "the form 'orig_prefix=replacement_prefix', which indicates a "
00647 "particular initial sequence of characters that should be replaced "
00648 "with a new sequence; e.g. '/c/home/models=/beta/fish'. "
00649 "If the replacement prefix does not begin with a slash, the file "
00650 "will then be searched for along the search path specified by -pp. "
00651 "You may use standard filename matching characters ('*', '?', etc.) in "
00652 "the original prefix, and '**' as a component by itself stands for "
00653 "any number of components.\n\n"
00654
00655 "This option may be repeated as necessary; each file will be tried "
00656 "against each specified method, in the order in which they appear in "
00657 "the command line, until the file is found. If the file is not found, "
00658 "the last matching prefix is used anyway.",
00659 &ProgramBase::dispatch_path_replace, NULL, _path_replace.p());
00660
00661 add_option
00662 ("pp", "dirname", 40,
00663 "Adds the indicated directory name to the list of directories to "
00664 "search for filenames referenced by the source file. This is used "
00665 "only for relative paths, or for paths that are made relative by a "
00666 "-pr replacement string that doesn't begin with a leading slash. "
00667 "The model-path is always implicitly searched anyway.",
00668 &ProgramBase::dispatch_search_path, NULL, &(_path_replace->_path));
00669 }
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679 void ProgramBase::
00680 add_path_store_options() {
00681
00682
00683 _path_replace->_path_store = PS_relative;
00684
00685 add_option
00686 ("ps", "path_store", 40,
00687 "Specifies the way an externally referenced file is to be "
00688 "represented in the resulting output file. This "
00689 "assumes the named filename actually exists; "
00690 "see -pr to indicate how to deal with external "
00691 "references that have bad pathnames. "
00692 "This option will not help you to find a missing file, but simply "
00693 "controls how filenames are represented in the output.\n\n"
00694
00695 "The option may be one of: rel, abs, rel_abs, strip, or keep. If "
00696 "either rel or rel_abs is specified, the files are made relative to "
00697 "the directory specified by -pd. The default is rel.",
00698 &ProgramBase::dispatch_path_store, &_got_path_store,
00699 &(_path_replace->_path_store));
00700
00701 add_option
00702 ("pd", "path_directory", 40,
00703 "Specifies the name of a directory to make paths relative to, if "
00704 "'-ps rel' or '-ps rel_abs' is specified. If this is omitted, the "
00705 "directory name is taken from the name of the output file.",
00706 &ProgramBase::dispatch_filename, &_got_path_directory,
00707 &(_path_replace->_path_directory));
00708 }
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721 bool ProgramBase::
00722 dispatch_none(const string &, const string &, void *) {
00723 return true;
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737 bool ProgramBase::
00738 dispatch_true(const string &, const string &, void *var) {
00739 bool *bp = (bool *)var;
00740 (*bp) = true;
00741 return true;
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755 bool ProgramBase::
00756 dispatch_false(const string &, const string &, void *var) {
00757 bool *bp = (bool *)var;
00758 (*bp) = false;
00759 return true;
00760 }
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771 bool ProgramBase::
00772 dispatch_count(const string &, const string &, void *var) {
00773 int *ip = (int *)var;
00774 (*ip)++;
00775
00776 return true;
00777 }
00778
00779
00780
00781
00782
00783
00784
00785
00786 bool ProgramBase::
00787 dispatch_int(const string &opt, const string &arg, void *var) {
00788 int *ip = (int *)var;
00789
00790 if (!string_to_int(arg, *ip)) {
00791 nout << "Invalid integer parameter for -" << opt << ": "
00792 << arg << "\n";
00793 return false;
00794 }
00795
00796 return true;
00797 }
00798
00799
00800
00801
00802
00803
00804
00805
00806 bool ProgramBase::
00807 dispatch_int_pair(const string &opt, const string &arg, void *var) {
00808 int *ip = (int *)var;
00809
00810 vector_string words;
00811 tokenize(arg, words, ",");
00812
00813 bool okflag = false;
00814 if (words.size() == 2) {
00815 okflag =
00816 string_to_int(words[0], ip[0]) &&
00817 string_to_int(words[1], ip[1]);
00818 }
00819
00820 if (!okflag) {
00821 nout << "-" << opt
00822 << " requires a pair of integers separated by a comma.\n";
00823 return false;
00824 }
00825
00826 return true;
00827 }
00828
00829
00830
00831
00832
00833
00834
00835
00836 bool ProgramBase::
00837 dispatch_double(const string &opt, const string &arg, void *var) {
00838 double *ip = (double *)var;
00839
00840 if (!string_to_double(arg, *ip)) {
00841 nout << "Invalid numeric parameter for -" << opt << ": "
00842 << arg << "\n";
00843 return false;
00844 }
00845
00846 return true;
00847 }
00848
00849
00850
00851
00852
00853
00854
00855
00856 bool ProgramBase::
00857 dispatch_double_pair(const string &opt, const string &arg, void *var) {
00858 double *ip = (double *)var;
00859
00860 vector_string words;
00861 tokenize(arg, words, ",");
00862
00863 bool okflag = false;
00864 if (words.size() == 2) {
00865 okflag =
00866 string_to_double(words[0], ip[0]) &&
00867 string_to_double(words[1], ip[1]);
00868 }
00869
00870 if (!okflag) {
00871 nout << "-" << opt
00872 << " requires a pair of numbers separated by a comma.\n";
00873 return false;
00874 }
00875
00876 return true;
00877 }
00878
00879
00880
00881
00882
00883
00884
00885
00886 bool ProgramBase::
00887 dispatch_double_triple(const string &opt, const string &arg, void *var) {
00888 double *ip = (double *)var;
00889
00890 vector_string words;
00891 tokenize(arg, words, ",");
00892
00893 bool okflag = false;
00894 if (words.size() == 3) {
00895 okflag =
00896 string_to_double(words[0], ip[0]) &&
00897 string_to_double(words[1], ip[1]) &&
00898 string_to_double(words[2], ip[2]);
00899 }
00900
00901 if (!okflag) {
00902 nout << "-" << opt
00903 << " requires three numbers separated by commas.\n";
00904 return false;
00905 }
00906
00907 return true;
00908 }
00909
00910
00911
00912
00913
00914
00915
00916
00917 bool ProgramBase::
00918 dispatch_double_quad(const string &opt, const string &arg, void *var) {
00919 double *ip = (double *)var;
00920
00921 vector_string words;
00922 tokenize(arg, words, ",");
00923
00924 bool okflag = false;
00925 if (words.size() == 4) {
00926 okflag =
00927 string_to_double(words[0], ip[0]) &&
00928 string_to_double(words[1], ip[1]) &&
00929 string_to_double(words[2], ip[2]) &&
00930 string_to_double(words[3], ip[3]);
00931 }
00932
00933 if (!okflag) {
00934 nout << "-" << opt
00935 << " requires four numbers separated by commas.\n";
00936 return false;
00937 }
00938
00939 return true;
00940 }
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950 bool ProgramBase::
00951 dispatch_color(const string &opt, const string &arg, void *var) {
00952 float *ip = (float *)var;
00953
00954 vector_string words;
00955 tokenize(arg, words, ",");
00956
00957 bool okflag = false;
00958 if (words.size() == 4) {
00959 okflag =
00960 string_to_float(words[0], ip[0]) &&
00961 string_to_float(words[1], ip[1]) &&
00962 string_to_float(words[2], ip[2]) &&
00963 string_to_float(words[3], ip[3]);
00964
00965 } else if (words.size() == 3) {
00966 okflag =
00967 string_to_float(words[0], ip[0]) &&
00968 string_to_float(words[1], ip[1]) &&
00969 string_to_float(words[2], ip[2]);
00970 ip[3] = 1.0;
00971 }
00972
00973 if (!okflag) {
00974 nout << "-" << opt
00975 << " requires three or four numbers separated by commas.\n";
00976 return false;
00977 }
00978
00979 return true;
00980 }
00981
00982
00983
00984
00985
00986
00987
00988
00989 bool ProgramBase::
00990 dispatch_string(const string &, const string &arg, void *var) {
00991 string *ip = (string *)var;
00992 (*ip) = arg;
00993
00994 return true;
00995 }
00996
00997
00998
00999
01000
01001
01002
01003
01004 bool ProgramBase::
01005 dispatch_filename(const string &opt, const string &arg, void *var) {
01006 if (arg.empty()) {
01007 nout << "-" << opt << " requires a filename parameter.\n";
01008 return false;
01009 }
01010
01011 Filename *ip = (Filename *)var;
01012 (*ip) = Filename::from_os_specific(arg);
01013
01014 return true;
01015 }
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027 bool ProgramBase::
01028 dispatch_search_path(const string &opt, const string &arg, void *var) {
01029 if (arg.empty()) {
01030 nout << "-" << opt << " requires a search path parameter.\n";
01031 return false;
01032 }
01033
01034 DSearchPath *ip = (DSearchPath *)var;
01035 ip->append_directory(Filename::from_os_specific(arg));
01036
01037 return true;
01038 }
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048 bool ProgramBase::
01049 dispatch_coordinate_system(const string &opt, const string &arg, void *var) {
01050 CoordinateSystem *ip = (CoordinateSystem *)var;
01051 (*ip) = parse_coordinate_system_string(arg);
01052
01053 if ((*ip) == CS_invalid) {
01054 nout << "Invalid coordinate system for -" << opt << ": " << arg << "\n"
01055 << "Valid coordinate system strings are any of 'y-up', 'z-up', "
01056 "'y-up-left', or 'z-up-left'.\n";
01057 return false;
01058 }
01059
01060 return true;
01061 }
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 bool ProgramBase::
01072 dispatch_units(const string &opt, const string &arg, void *var) {
01073 DistanceUnit *ip = (DistanceUnit *)var;
01074 (*ip) = string_distance_unit(arg);
01075
01076 if ((*ip) == DU_invalid) {
01077 nout << "Invalid units for -" << opt << ": " << arg << "\n"
01078 << "Valid units are mm, cm, m, km, yd, ft, in, nmi, and mi.\n";
01079 return false;
01080 }
01081
01082 return true;
01083 }
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093 bool ProgramBase::
01094 dispatch_image_type(const string &opt, const string &arg, void *var) {
01095 PNMFileType **ip = (PNMFileType **)var;
01096
01097 PNMFileTypeRegistry *reg = PNMFileTypeRegistry::get_ptr();
01098
01099 (*ip) = reg->get_type_from_extension(arg);
01100
01101 if ((*ip) == (PNMFileType *)NULL) {
01102 nout << "Invalid image type for -" << opt << ": " << arg << "\n"
01103 << "The following image types are known:\n";
01104 reg->write_types(nout, 2);
01105 return false;
01106 }
01107
01108 return true;
01109 }
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119 bool ProgramBase::
01120 dispatch_path_replace(const string &opt, const string &arg, void *var) {
01121 PathReplace *ip = (PathReplace *)var;
01122 size_t equals = arg.find('=');
01123 if (equals == string::npos) {
01124 nout << "Invalid path replacement string for -" << opt << ": " << arg << "\n"
01125 << "String should be of the form 'old-prefix=new-prefix'.\n";
01126 return false;
01127 }
01128 ip->add_pattern(arg.substr(0, equals), arg.substr(equals + 1));
01129
01130 return true;
01131 }
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141 bool ProgramBase::
01142 dispatch_path_store(const string &opt, const string &arg, void *var) {
01143 PathStore *ip = (PathStore *)var;
01144 (*ip) = string_path_store(arg);
01145
01146 if ((*ip) == PS_invalid) {
01147 nout << "Invalid path store for -" << opt << ": " << arg << "\n"
01148 << "Valid path store strings are any of 'rel', 'abs', "
01149 << "'rel_abs', 'strip', or 'keep'.\n";
01150 return false;
01151 }
01152
01153 return true;
01154 }
01155
01156
01157
01158
01159
01160
01161
01162 bool ProgramBase::
01163 handle_help_option(const string &, const string &, void *data) {
01164 ProgramBase *me = (ProgramBase *)data;
01165 me->show_description();
01166 me->show_usage();
01167 me->show_options();
01168 exit(0);
01169
01170 return false;
01171 }
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197 void ProgramBase::
01198 format_text(ostream &out, bool &last_newline,
01199 const string &prefix, int indent_width,
01200 const string &text, int line_width) {
01201 indent_width = min(indent_width, line_width - 20);
01202 int indent_amount = indent_width;
01203 bool initial_break = false;
01204
01205 if (!prefix.empty()) {
01206 out << prefix;
01207 indent_amount = indent_width - prefix.length();
01208 if ((int)prefix.length() + 1 > indent_width) {
01209 out << "\n";
01210 initial_break = true;
01211 indent_amount = indent_width;
01212 }
01213 }
01214
01215 size_t p = 0;
01216
01217
01218 while (p < text.length() && isspace(text[p])) {
01219 if (text[p] == '\r' ||
01220 (p > 0 && text[p] == '\n' && text[p - 1] == '\n') ||
01221 (p == 0 && text[p] == '\n' && last_newline)) {
01222 if (!initial_break) {
01223
01224 out << "\n";
01225 initial_break = true;
01226 }
01227 indent_amount = indent_width;
01228
01229 } else if (text[p] == '\n') {
01230
01231 indent_amount = indent_width;
01232
01233 } else if (text[p] == ' ') {
01234
01235 indent_amount++;
01236 }
01237 p++;
01238 }
01239
01240 last_newline = (!text.empty() && text[text.length() - 1] == '\n');
01241
01242 while (p < text.length()) {
01243
01244
01245 size_t par = text.find_first_of("\n\r", p);
01246 bool is_paragraph_break = false;
01247 if (par == string::npos) {
01248 par = text.length();
01249
01250
01251
01252
01253
01254 }
01255
01256 indent(out, indent_amount);
01257
01258 size_t eol = p + (line_width - indent_width);
01259 if (eol >= par) {
01260
01261 eol = par;
01262
01263 } else {
01264
01265
01266
01267 size_t min_eol = max((int)p, (int)eol - 25);
01268 size_t q = eol;
01269 while (q > min_eol && !isspace(text[q])) {
01270 q--;
01271 }
01272
01273 while (q > min_eol && isspace(text[q])) {
01274 q--;
01275 }
01276
01277 if (q != min_eol) {
01278
01279 eol = q + 1;
01280
01281 } else {
01282
01283
01284 eol = par;
01285 }
01286 }
01287 out << text.substr(p, eol - p) << "\n";
01288 p = eol;
01289
01290
01291 while (p < text.length() && isspace(text[p])) {
01292 if (text[p] == '\r' ||
01293 (p > 0 && text[p] == '\n' && text[p - 1] == '\n')) {
01294 is_paragraph_break = true;
01295 }
01296 p++;
01297 }
01298
01299 if (eol == par && is_paragraph_break) {
01300
01301 out << "\n";
01302 if (p >= text.length()) {
01303
01304
01305 last_newline = false;
01306 }
01307 }
01308
01309 indent_amount = indent_width;
01310 }
01311 }
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321 void ProgramBase::
01322 sort_options() {
01323 if (!_sorted_options) {
01324 _options_by_index.clear();
01325
01326 OptionsByName::const_iterator oi;
01327 for (oi = _options_by_name.begin(); oi != _options_by_name.end(); ++oi) {
01328 _options_by_index.push_back(&(*oi).second);
01329 }
01330
01331 sort(_options_by_index.begin(), _options_by_index.end(),
01332 SortOptionsByIndex());
01333 _sorted_options = true;
01334 }
01335 }
01336
01337
01338
01339
01340
01341
01342
01343 void ProgramBase::
01344 get_terminal_width() {
01345 if (!_got_terminal_width) {
01346 #ifdef IOCTL_TERMINAL_WIDTH
01347 struct winsize size;
01348 int result = ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&size);
01349 if (result < 0) {
01350
01351
01352 _terminal_width = 72;
01353 } else {
01354
01355
01356 _terminal_width = size.ws_col - min(8, (int)(size.ws_col * 0.1));
01357 }
01358 #else // IOCTL_TERMINAL_WIDTH
01359 _terminal_width = 72;
01360 #endif // IOCTL_TERMINAL_WIDTH
01361 _got_terminal_width = true;
01362 _got_option_indent = false;
01363 }
01364 }
01365