anyoption.cpp 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. /*
  2. * AnyOption 1.3
  3. *
  4. * kishan at hackorama dot com www.hackorama.com JULY 2001
  5. *
  6. * + Acts as a common facade class for reading
  7. * command line options as well as options from
  8. * an option file with delimited type value pairs
  9. *
  10. * + Handles the POSIX style single character options ( -w )
  11. * as well as the newer GNU long options ( --width )
  12. *
  13. * + The option file assumes the traditional format of
  14. * first character based comment lines and type value
  15. * pairs with a delimiter , and flags which are not pairs
  16. *
  17. * # this is a comment
  18. * # next line is an option value pair
  19. * width : 100
  20. * # next line is a flag
  21. * noimages
  22. *
  23. * + Supports printing out Help and Usage
  24. *
  25. * + Why not just use getopt() ?
  26. *
  27. * getopt() Its a POSIX standard not part of ANSI-C.
  28. * So it may not be available on platforms like Windows.
  29. *
  30. * + Why it is so long ?
  31. *
  32. * The actual code which does command line parsing
  33. * and option file parsing are done in few methods.
  34. * Most of the extra code are for providing a flexible
  35. * common public interface to both a resource file
  36. * and command line supporting POSIX style and
  37. * GNU long option as well as mixing of both.
  38. *
  39. * + Please see "anyoption.h" for public method descriptions
  40. *
  41. */
  42. /* Updated August 2004
  43. * Fix from Michael D Peters (mpeters at sandia.gov)
  44. * to remove static local variables, allowing multiple instantiations
  45. * of the reader (for using multiple configuration files). There is
  46. * an error in the destructor when using multiple instances, so you
  47. * cannot delete your objects (it will crash), but not calling the
  48. * destructor only introduces a small memory leak, so I
  49. * have not bothered tracking it down.
  50. *
  51. * Also updated to use modern C++ style headers, rather than
  52. * deprecated iostream.h (it was causing my compiler problems)
  53. */
  54. /*
  55. * Updated September 2006
  56. * Fix from Boyan Asenov for a bug in mixing up option indexes
  57. * leading to exception when mixing different options types
  58. */
  59. #include "anyoption.h"
  60. AnyOption::AnyOption() { init(); }
  61. AnyOption::AnyOption(int maxopt) { init(maxopt, maxopt); }
  62. AnyOption::AnyOption(int maxopt, int maxcharopt) { init(maxopt, maxcharopt); }
  63. AnyOption::~AnyOption() {
  64. if (mem_allocated)
  65. cleanup();
  66. }
  67. void AnyOption::init() { init(DEFAULT_MAXOPTS, DEFAULT_MAXOPTS); }
  68. void AnyOption::init(int maxopt, int maxcharopt) {
  69. max_options = maxopt;
  70. max_char_options = maxcharopt;
  71. max_usage_lines = DEFAULT_MAXUSAGE;
  72. usage_lines = 0;
  73. argc = 0;
  74. argv = NULL;
  75. posix_style = true;
  76. verbose = false;
  77. filename = NULL;
  78. appname = NULL;
  79. option_counter = 0;
  80. optchar_counter = 0;
  81. new_argv = NULL;
  82. new_argc = 0;
  83. max_legal_args = 0;
  84. command_set = false;
  85. file_set = false;
  86. values = NULL;
  87. g_value_counter = 0;
  88. mem_allocated = false;
  89. opt_prefix_char = '-';
  90. file_delimiter_char = ':';
  91. file_comment_char = '#';
  92. equalsign = '=';
  93. comment = '#';
  94. delimiter = ':';
  95. endofline = '\n';
  96. whitespace = ' ';
  97. nullterminate = '\0';
  98. set = false;
  99. once = true;
  100. hasoptions = false;
  101. autousage = false;
  102. print_usage = false;
  103. print_help = false;
  104. strcpy(long_opt_prefix, "--");
  105. if (alloc() == false) {
  106. cout << endl << "OPTIONS ERROR : Failed allocating memory";
  107. cout << endl;
  108. cout << "Exiting." << endl;
  109. exit(0);
  110. }
  111. }
  112. bool AnyOption::alloc() {
  113. int i = 0;
  114. int size = 0;
  115. if (mem_allocated)
  116. return true;
  117. size = (max_options + 1) * sizeof(const char *);
  118. options = (const char **)malloc(size);
  119. optiontype = (int *)malloc((max_options + 1) * sizeof(int));
  120. optionindex = (int *)malloc((max_options + 1) * sizeof(int));
  121. if (options == NULL || optiontype == NULL || optionindex == NULL)
  122. return false;
  123. else
  124. mem_allocated = true;
  125. for (i = 0; i < max_options; i++) {
  126. options[i] = NULL;
  127. optiontype[i] = 0;
  128. optionindex[i] = -1;
  129. }
  130. optionchars = (char *)malloc((max_char_options + 1) * sizeof(char));
  131. optchartype = (int *)malloc((max_char_options + 1) * sizeof(int));
  132. optcharindex = (int *)malloc((max_char_options + 1) * sizeof(int));
  133. if (optionchars == NULL || optchartype == NULL || optcharindex == NULL) {
  134. mem_allocated = false;
  135. return false;
  136. }
  137. for (i = 0; i < max_char_options; i++) {
  138. optionchars[i] = '0';
  139. optchartype[i] = 0;
  140. optcharindex[i] = -1;
  141. }
  142. size = (max_usage_lines + 1) * sizeof(const char *);
  143. usage = (const char **)malloc(size);
  144. if (usage == NULL) {
  145. mem_allocated = false;
  146. return false;
  147. }
  148. for (i = 0; i < max_usage_lines; i++)
  149. usage[i] = NULL;
  150. return true;
  151. }
  152. void AnyOption::allocValues(int index, size_t length) {
  153. if (values[index] == NULL) {
  154. values[index] = (char *)malloc(length);
  155. } else {
  156. free(values[index]);
  157. values[index] = (char *)malloc(length);
  158. }
  159. }
  160. bool AnyOption::doubleOptStorage() {
  161. const char **options_saved = options;
  162. options = (const char **)realloc(options, ((2 * max_options) + 1) *
  163. sizeof(const char *));
  164. if (options == NULL) {
  165. free(options_saved);
  166. return false;
  167. }
  168. int *optiontype_saved = optiontype;
  169. optiontype =
  170. (int *)realloc(optiontype, ((2 * max_options) + 1) * sizeof(int));
  171. if (optiontype == NULL) {
  172. free(optiontype_saved);
  173. return false;
  174. }
  175. int *optionindex_saved = optionindex;
  176. optionindex =
  177. (int *)realloc(optionindex, ((2 * max_options) + 1) * sizeof(int));
  178. if (optionindex == NULL) {
  179. free(optionindex_saved);
  180. return false;
  181. }
  182. /* init new storage */
  183. for (int i = max_options; i < 2 * max_options; i++) {
  184. options[i] = NULL;
  185. optiontype[i] = 0;
  186. optionindex[i] = -1;
  187. }
  188. max_options = 2 * max_options;
  189. return true;
  190. }
  191. bool AnyOption::doubleCharStorage() {
  192. char *optionchars_saved = optionchars;
  193. optionchars =
  194. (char *)realloc(optionchars, ((2 * max_char_options) + 1) * sizeof(char));
  195. if (optionchars == NULL) {
  196. free(optionchars_saved);
  197. return false;
  198. }
  199. int *optchartype_saved = optchartype;
  200. optchartype =
  201. (int *)realloc(optchartype, ((2 * max_char_options) + 1) * sizeof(int));
  202. if (optchartype == NULL) {
  203. free(optchartype_saved);
  204. return false;
  205. }
  206. int *optcharindex_saved = optcharindex;
  207. optcharindex =
  208. (int *)realloc(optcharindex, ((2 * max_char_options) + 1) * sizeof(int));
  209. if (optcharindex == NULL) {
  210. free(optcharindex_saved);
  211. return false;
  212. }
  213. /* init new storage */
  214. for (int i = max_char_options; i < 2 * max_char_options; i++) {
  215. optionchars[i] = '0';
  216. optchartype[i] = 0;
  217. optcharindex[i] = -1;
  218. }
  219. max_char_options = 2 * max_char_options;
  220. return true;
  221. }
  222. bool AnyOption::doubleUsageStorage() {
  223. const char **usage_saved = usage;
  224. usage = (const char **)realloc(usage, ((2 * max_usage_lines) + 1) *
  225. sizeof(const char *));
  226. if (usage == NULL) {
  227. free(usage_saved);
  228. return false;
  229. }
  230. for (int i = max_usage_lines; i < 2 * max_usage_lines; i++)
  231. usage[i] = NULL;
  232. max_usage_lines = 2 * max_usage_lines;
  233. return true;
  234. }
  235. void AnyOption::cleanup() {
  236. free(options);
  237. free(optiontype);
  238. free(optionindex);
  239. free(optionchars);
  240. free(optchartype);
  241. free(optcharindex);
  242. free(usage);
  243. if (values != NULL) {
  244. for (int i = 0; i < g_value_counter; i++) {
  245. free(values[i]);
  246. values[i] = NULL;
  247. }
  248. free(values);
  249. }
  250. if (new_argv != NULL)
  251. free(new_argv);
  252. }
  253. void AnyOption::setCommandPrefixChar(char _prefix) {
  254. opt_prefix_char = _prefix;
  255. }
  256. void AnyOption::setCommandLongPrefix(const char *_prefix) {
  257. if (strlen(_prefix) > MAX_LONG_PREFIX_LENGTH) {
  258. strncpy(long_opt_prefix, _prefix, MAX_LONG_PREFIX_LENGTH);
  259. long_opt_prefix[MAX_LONG_PREFIX_LENGTH] = nullterminate;
  260. } else {
  261. strcpy(long_opt_prefix, _prefix);
  262. }
  263. }
  264. void AnyOption::setFileCommentChar(char _comment) {
  265. file_delimiter_char = _comment;
  266. }
  267. void AnyOption::setFileDelimiterChar(char _delimiter) {
  268. file_comment_char = _delimiter;
  269. }
  270. bool AnyOption::CommandSet() const { return (command_set); }
  271. bool AnyOption::FileSet() const { return (file_set); }
  272. void AnyOption::noPOSIX() { posix_style = false; }
  273. bool AnyOption::POSIX() const { return posix_style; }
  274. void AnyOption::setVerbose() { verbose = true; }
  275. void AnyOption::printVerbose() const {
  276. if (verbose)
  277. cout << endl;
  278. }
  279. void AnyOption::printVerbose(const char *msg) const {
  280. if (verbose)
  281. cout << msg;
  282. }
  283. void AnyOption::printVerbose(char *msg) const {
  284. if (verbose)
  285. cout << msg;
  286. }
  287. void AnyOption::printVerbose(char ch) const {
  288. if (verbose)
  289. cout << ch;
  290. }
  291. bool AnyOption::hasOptions() const { return hasoptions; }
  292. void AnyOption::autoUsagePrint(bool _autousage) { autousage = _autousage; }
  293. void AnyOption::useCommandArgs(int _argc, char **_argv) {
  294. argc = _argc;
  295. argv = _argv;
  296. command_set = true;
  297. appname = argv[0];
  298. if (argc > 1)
  299. hasoptions = true;
  300. }
  301. void AnyOption::useFiileName(const char *_filename) {
  302. filename = _filename;
  303. file_set = true;
  304. }
  305. /*
  306. * set methods for options
  307. */
  308. void AnyOption::setCommandOption(const char *opt) {
  309. addOption(opt, COMMAND_OPT);
  310. g_value_counter++;
  311. }
  312. void AnyOption::setCommandOption(char opt) {
  313. addOption(opt, COMMAND_OPT);
  314. g_value_counter++;
  315. }
  316. void AnyOption::setCommandOption(const char *opt, char optchar) {
  317. addOption(opt, COMMAND_OPT);
  318. addOption(optchar, COMMAND_OPT);
  319. g_value_counter++;
  320. }
  321. void AnyOption::setCommandFlag(const char *opt) {
  322. addOption(opt, COMMAND_FLAG);
  323. g_value_counter++;
  324. }
  325. void AnyOption::setCommandFlag(char opt) {
  326. addOption(opt, COMMAND_FLAG);
  327. g_value_counter++;
  328. }
  329. void AnyOption::setCommandFlag(const char *opt, char optchar) {
  330. addOption(opt, COMMAND_FLAG);
  331. addOption(optchar, COMMAND_FLAG);
  332. g_value_counter++;
  333. }
  334. void AnyOption::setFileOption(const char *opt) {
  335. addOption(opt, FILE_OPT);
  336. g_value_counter++;
  337. }
  338. void AnyOption::setFileOption(char opt) {
  339. addOption(opt, FILE_OPT);
  340. g_value_counter++;
  341. }
  342. void AnyOption::setFileOption(const char *opt, char optchar) {
  343. addOption(opt, FILE_OPT);
  344. addOption(optchar, FILE_OPT);
  345. g_value_counter++;
  346. }
  347. void AnyOption::setFileFlag(const char *opt) {
  348. addOption(opt, FILE_FLAG);
  349. g_value_counter++;
  350. }
  351. void AnyOption::setFileFlag(char opt) {
  352. addOption(opt, FILE_FLAG);
  353. g_value_counter++;
  354. }
  355. void AnyOption::setFileFlag(const char *opt, char optchar) {
  356. addOption(opt, FILE_FLAG);
  357. addOption(optchar, FILE_FLAG);
  358. g_value_counter++;
  359. }
  360. void AnyOption::setOption(const char *opt) {
  361. addOption(opt, COMMON_OPT);
  362. g_value_counter++;
  363. }
  364. void AnyOption::setOption(char opt) {
  365. addOption(opt, COMMON_OPT);
  366. g_value_counter++;
  367. }
  368. void AnyOption::setOption(const char *opt, char optchar) {
  369. addOption(opt, COMMON_OPT);
  370. addOption(optchar, COMMON_OPT);
  371. g_value_counter++;
  372. }
  373. void AnyOption::setFlag(const char *opt) {
  374. addOption(opt, COMMON_FLAG);
  375. g_value_counter++;
  376. }
  377. void AnyOption::setFlag(const char opt) {
  378. addOption(opt, COMMON_FLAG);
  379. g_value_counter++;
  380. }
  381. void AnyOption::setFlag(const char *opt, char optchar) {
  382. addOption(opt, COMMON_FLAG);
  383. addOption(optchar, COMMON_FLAG);
  384. g_value_counter++;
  385. }
  386. void AnyOption::addOption(const char *opt, int type) {
  387. if (option_counter >= max_options) {
  388. if (doubleOptStorage() == false) {
  389. addOptionError(opt);
  390. return;
  391. }
  392. }
  393. options[option_counter] = opt;
  394. optiontype[option_counter] = type;
  395. optionindex[option_counter] = g_value_counter;
  396. option_counter++;
  397. }
  398. void AnyOption::addOption(char opt, int type) {
  399. if (!POSIX()) {
  400. printVerbose("Ignoring the option character \"");
  401. printVerbose(opt);
  402. printVerbose("\" ( POSIX options are turned off )");
  403. printVerbose();
  404. return;
  405. }
  406. if (optchar_counter >= max_char_options) {
  407. if (doubleCharStorage() == false) {
  408. addOptionError(opt);
  409. return;
  410. }
  411. }
  412. optionchars[optchar_counter] = opt;
  413. optchartype[optchar_counter] = type;
  414. optcharindex[optchar_counter] = g_value_counter;
  415. optchar_counter++;
  416. }
  417. void AnyOption::addOptionError(const char *opt) const {
  418. cout << endl;
  419. cout << "OPTIONS ERROR : Failed allocating extra memory " << endl;
  420. cout << "While adding the option : \"" << opt << "\"" << endl;
  421. cout << "Exiting." << endl;
  422. cout << endl;
  423. exit(0);
  424. }
  425. void AnyOption::addOptionError(char opt) const {
  426. cout << endl;
  427. cout << "OPTIONS ERROR : Failed allocating extra memory " << endl;
  428. cout << "While adding the option: \"" << opt << "\"" << endl;
  429. cout << "Exiting." << endl;
  430. cout << endl;
  431. exit(0);
  432. }
  433. void AnyOption::processOptions() {
  434. if (!valueStoreOK())
  435. return;
  436. }
  437. void AnyOption::processCommandArgs(int max_args) {
  438. max_legal_args = max_args;
  439. processCommandArgs();
  440. }
  441. void AnyOption::processCommandArgs(int _argc, char **_argv, int max_args) {
  442. max_legal_args = max_args;
  443. processCommandArgs(_argc, _argv);
  444. }
  445. void AnyOption::processCommandArgs(int _argc, char **_argv) {
  446. useCommandArgs(_argc, _argv);
  447. processCommandArgs();
  448. }
  449. void AnyOption::processCommandArgs() {
  450. if (!(valueStoreOK() && CommandSet()))
  451. return;
  452. if (max_legal_args == 0)
  453. max_legal_args = argc;
  454. new_argv = (int *)malloc((max_legal_args + 1) * sizeof(int));
  455. for (int i = 1; i < argc; i++) { /* ignore first argv */
  456. if (argv[i][0] == long_opt_prefix[0] &&
  457. argv[i][1] == long_opt_prefix[1]) { /* long GNU option */
  458. int match_at = parseGNU(argv[i] + 2); /* skip -- */
  459. if (match_at >= 0 && i < argc - 1) /* found match */
  460. setValue(options[match_at], argv[++i]);
  461. } else if (argv[i][0] == opt_prefix_char) { /* POSIX char */
  462. if (POSIX()) {
  463. char ch = parsePOSIX(argv[i] + 1); /* skip - */
  464. if (ch != '0' && i < argc - 1) /* matching char */
  465. setValue(ch, argv[++i]);
  466. } else { /* treat it as GNU option with a - */
  467. int match_at = parseGNU(argv[i] + 1); /* skip - */
  468. if (match_at >= 0 && i < argc - 1) /* found match */
  469. setValue(options[match_at], argv[++i]);
  470. }
  471. } else { /* not option but an argument keep index */
  472. if (new_argc < max_legal_args) {
  473. new_argv[new_argc] = i;
  474. new_argc++;
  475. } else { /* ignore extra arguments */
  476. printVerbose("Ignoring extra argument: ");
  477. printVerbose(argv[i]);
  478. printVerbose();
  479. printAutoUsage();
  480. }
  481. printVerbose("Unknown command argument option : ");
  482. printVerbose(argv[i]);
  483. printVerbose();
  484. printAutoUsage();
  485. }
  486. }
  487. }
  488. char AnyOption::parsePOSIX(char *arg) {
  489. for (unsigned int i = 0; i < strlen(arg); i++) {
  490. char ch = arg[i];
  491. if (matchChar(ch)) { /* keep matching flags till an option */
  492. /*if last char argv[++i] is the value */
  493. if (i == strlen(arg) - 1) {
  494. return ch;
  495. } else { /* else the rest of arg is the value */
  496. i++; /* skip any '=' and ' ' */
  497. while (arg[i] == whitespace || arg[i] == equalsign)
  498. i++;
  499. setValue(ch, arg + i);
  500. return '0';
  501. }
  502. }
  503. }
  504. printVerbose("Unknown command argument option : ");
  505. printVerbose(arg);
  506. printVerbose();
  507. printAutoUsage();
  508. return '0';
  509. }
  510. int AnyOption::parseGNU(char *arg) {
  511. size_t split_at = 0;
  512. /* if has a '=' sign get value */
  513. for (size_t i = 0; i < strlen(arg); i++) {
  514. if (arg[i] == equalsign) {
  515. split_at = i; /* store index */
  516. i = strlen(arg); /* get out of loop */
  517. }
  518. }
  519. if (split_at > 0) { /* it is an option value pair */
  520. char *tmp = (char *)malloc((split_at + 1) * sizeof(char));
  521. for (size_t i = 0; i < split_at; i++)
  522. tmp[i] = arg[i];
  523. tmp[split_at] = '\0';
  524. if (matchOpt(tmp) >= 0) {
  525. setValue(options[matchOpt(tmp)], arg + split_at + 1);
  526. free(tmp);
  527. } else {
  528. printVerbose("Unknown command argument option : ");
  529. printVerbose(arg);
  530. printVerbose();
  531. printAutoUsage();
  532. free(tmp);
  533. return -1;
  534. }
  535. } else { /* regular options with no '=' sign */
  536. return matchOpt(arg);
  537. }
  538. return -1;
  539. }
  540. int AnyOption::matchOpt(char *opt) {
  541. for (int i = 0; i < option_counter; i++) {
  542. if (strcmp(options[i], opt) == 0) {
  543. if (optiontype[i] == COMMON_OPT ||
  544. optiontype[i] == COMMAND_OPT) { /* found option return index */
  545. return i;
  546. } else if (optiontype[i] == COMMON_FLAG ||
  547. optiontype[i] == COMMAND_FLAG) { /* found flag, set it */
  548. setFlagOn(opt);
  549. return -1;
  550. }
  551. }
  552. }
  553. printVerbose("Unknown command argument option : ");
  554. printVerbose(opt);
  555. printVerbose();
  556. printAutoUsage();
  557. return -1;
  558. }
  559. bool AnyOption::matchChar(char c) {
  560. for (int i = 0; i < optchar_counter; i++) {
  561. if (optionchars[i] == c) { /* found match */
  562. if (optchartype[i] == COMMON_OPT ||
  563. optchartype[i] ==
  564. COMMAND_OPT) { /* an option store and stop scanning */
  565. return true;
  566. } else if (optchartype[i] == COMMON_FLAG ||
  567. optchartype[i] ==
  568. COMMAND_FLAG) { /* a flag store and keep scanning */
  569. setFlagOn(c);
  570. return false;
  571. }
  572. }
  573. }
  574. printVerbose("Unknown command argument option : ");
  575. printVerbose(c);
  576. printVerbose();
  577. printAutoUsage();
  578. return false;
  579. }
  580. bool AnyOption::valueStoreOK() {
  581. if (!set) {
  582. if (g_value_counter > 0) {
  583. const int size = g_value_counter * sizeof(char *);
  584. values = (char **)malloc(size);
  585. for (int i = 0; i < g_value_counter; i++)
  586. values[i] = NULL;
  587. set = true;
  588. }
  589. }
  590. return set;
  591. }
  592. /*
  593. * public get methods
  594. */
  595. char *AnyOption::getValue(const char *option) {
  596. if (!valueStoreOK())
  597. return NULL;
  598. for (int i = 0; i < option_counter; i++) {
  599. if (strcmp(options[i], option) == 0)
  600. return values[optionindex[i]];
  601. }
  602. return NULL;
  603. }
  604. bool AnyOption::getFlag(const char *option) {
  605. if (!valueStoreOK())
  606. return false;
  607. for (int i = 0; i < option_counter; i++) {
  608. if (strcmp(options[i], option) == 0)
  609. return findFlag(values[optionindex[i]]);
  610. }
  611. return false;
  612. }
  613. char *AnyOption::getValue(char option) {
  614. if (!valueStoreOK())
  615. return NULL;
  616. for (int i = 0; i < optchar_counter; i++) {
  617. if (optionchars[i] == option)
  618. return values[optcharindex[i]];
  619. }
  620. return NULL;
  621. }
  622. bool AnyOption::getFlag(char option) {
  623. if (!valueStoreOK())
  624. return false;
  625. for (int i = 0; i < optchar_counter; i++) {
  626. if (optionchars[i] == option)
  627. return findFlag(values[optcharindex[i]]);
  628. }
  629. return false;
  630. }
  631. bool AnyOption::findFlag(char *val) {
  632. if (val == NULL)
  633. return false;
  634. if (strcmp(TRUE_FLAG, val) == 0)
  635. return true;
  636. return false;
  637. }
  638. /*
  639. * private set methods
  640. */
  641. bool AnyOption::setValue(const char *option, char *value) {
  642. if (!valueStoreOK())
  643. return false;
  644. for (int i = 0; i < option_counter; i++) {
  645. if (strcmp(options[i], option) == 0) {
  646. size_t length = (strlen(value) + 1) * sizeof(char);
  647. allocValues(optionindex[i], length);
  648. strncpy(values[optionindex[i]], value, length);
  649. return true;
  650. }
  651. }
  652. return false;
  653. }
  654. bool AnyOption::setFlagOn(const char *option) {
  655. if (!valueStoreOK())
  656. return false;
  657. for (int i = 0; i < option_counter; i++) {
  658. if (strcmp(options[i], option) == 0) {
  659. size_t length = (strlen(TRUE_FLAG) + 1) * sizeof(char);
  660. allocValues(optionindex[i], length);
  661. strncpy(values[optionindex[i]], TRUE_FLAG, length);
  662. return true;
  663. }
  664. }
  665. return false;
  666. }
  667. bool AnyOption::setValue(char option, char *value) {
  668. if (!valueStoreOK())
  669. return false;
  670. for (int i = 0; i < optchar_counter; i++) {
  671. if (optionchars[i] == option) {
  672. size_t length = (strlen(value) + 1) * sizeof(char);
  673. allocValues(optcharindex[i], length);
  674. strncpy(values[optcharindex[i]], value, length);
  675. return true;
  676. }
  677. }
  678. return false;
  679. }
  680. bool AnyOption::setFlagOn(char option) {
  681. if (!valueStoreOK())
  682. return false;
  683. for (int i = 0; i < optchar_counter; i++) {
  684. if (optionchars[i] == option) {
  685. size_t length = (strlen(TRUE_FLAG) + 1) * sizeof(char);
  686. allocValues(optcharindex[i], length);
  687. strncpy(values[optcharindex[i]], TRUE_FLAG, length);
  688. return true;
  689. }
  690. }
  691. return false;
  692. }
  693. int AnyOption::getArgc() const { return new_argc; }
  694. char *AnyOption::getArgv(int index) const {
  695. if (index < new_argc) {
  696. return (argv[new_argv[index]]);
  697. }
  698. return NULL;
  699. }
  700. /* option file sub routines */
  701. bool AnyOption::processFile() {
  702. if (!(valueStoreOK() && FileSet()))
  703. return false;
  704. return hasoptions = (consumeFile(readFile()));
  705. }
  706. bool AnyOption::processFile(const char *_filename) {
  707. useFiileName(_filename);
  708. return (processFile());
  709. }
  710. char *AnyOption::readFile() { return (readFile(filename)); }
  711. /*
  712. * read the file contents to a character buffer
  713. */
  714. char *AnyOption::readFile(const char *fname) {
  715. char *buffer;
  716. ifstream is;
  717. is.open(fname, ifstream::in);
  718. if (!is.good()) {
  719. is.close();
  720. return NULL;
  721. }
  722. is.seekg(0, ios::end);
  723. size_t length = (size_t)is.tellg();
  724. is.seekg(0, ios::beg);
  725. buffer = (char *)malloc((length + 1) * sizeof(char));
  726. is.read(buffer, length);
  727. is.close();
  728. buffer[length] = nullterminate;
  729. return buffer;
  730. }
  731. /*
  732. * scans a char* buffer for lines that does not
  733. * start with the specified comment character.
  734. */
  735. bool AnyOption::consumeFile(char *buffer) {
  736. if (buffer == NULL)
  737. return false;
  738. char *cursor = buffer; /* preserve the ptr */
  739. char *pline = NULL;
  740. int linelength = 0;
  741. bool newline = true;
  742. for (unsigned int i = 0; i < strlen(buffer); i++) {
  743. if (*cursor == endofline) { /* end of line */
  744. if (pline != NULL) /* valid line */
  745. processLine(pline, linelength);
  746. pline = NULL;
  747. newline = true;
  748. } else if (newline) { /* start of line */
  749. newline = false;
  750. if ((*cursor != comment)) { /* not a comment */
  751. pline = cursor;
  752. linelength = 0;
  753. }
  754. }
  755. cursor++; /* keep moving */
  756. linelength++;
  757. }
  758. free(buffer);
  759. return true;
  760. }
  761. /*
  762. * find a valid type value pair separated by a delimiter
  763. * character and pass it to valuePairs()
  764. * any line which is not valid will be considered a value
  765. * and will get passed on to justValue()
  766. *
  767. * assuming delimiter is ':' the behaviour will be,
  768. *
  769. * width:10 - valid pair valuePairs( width, 10 );
  770. * width : 10 - valid pair valuepairs( width, 10 );
  771. *
  772. * :::: - not valid
  773. * width - not valid
  774. * :10 - not valid
  775. * width: - not valid
  776. * :: - not valid
  777. * : - not valid
  778. *
  779. */
  780. void AnyOption::processLine(char *theline, int length) {
  781. char *pline = (char *)malloc((length + 1) * sizeof(char));
  782. for (int i = 0; i < length; i++)
  783. pline[i] = *(theline++);
  784. pline[length] = nullterminate;
  785. char *cursor = pline; /* preserve the ptr */
  786. if (*cursor == delimiter || *(cursor + length - 1) == delimiter) {
  787. justValue(pline); /* line with start/end delimiter */
  788. } else {
  789. bool found = false;
  790. for (int i = 1; i < length - 1 && !found; i++) { /* delimiter */
  791. if (*cursor == delimiter) {
  792. *(cursor - 1) = nullterminate; /* two strings */
  793. found = true;
  794. valuePairs(pline, cursor + 1);
  795. }
  796. cursor++;
  797. }
  798. cursor++;
  799. if (!found) /* not a pair */
  800. justValue(pline);
  801. }
  802. free(pline);
  803. }
  804. /*
  805. * removes trailing and preceding white spaces from a string
  806. */
  807. char *AnyOption::chomp(char *str) {
  808. while (*str == whitespace)
  809. str++;
  810. char *end = str + strlen(str) - 1;
  811. while (*end == whitespace)
  812. end--;
  813. *(end + 1) = nullterminate;
  814. return str;
  815. }
  816. void AnyOption::valuePairs(char *type, char *value) {
  817. if (strlen(chomp(type)) == 1) { /* this is a char option */
  818. for (int i = 0; i < optchar_counter; i++) {
  819. if (optionchars[i] == type[0]) { /* match */
  820. if (optchartype[i] == COMMON_OPT || optchartype[i] == FILE_OPT) {
  821. setValue(type[0], chomp(value));
  822. return;
  823. }
  824. }
  825. }
  826. }
  827. /* if no char options matched */
  828. for (int i = 0; i < option_counter; i++) {
  829. if (strcmp(options[i], type) == 0) { /* match */
  830. if (optiontype[i] == COMMON_OPT || optiontype[i] == FILE_OPT) {
  831. setValue(type, chomp(value));
  832. return;
  833. }
  834. }
  835. }
  836. printVerbose("Unknown option in resource file : ");
  837. printVerbose(type);
  838. printVerbose();
  839. }
  840. void AnyOption::justValue(char *type) {
  841. if (strlen(chomp(type)) == 1) { /* this is a char option */
  842. for (int i = 0; i < optchar_counter; i++) {
  843. if (optionchars[i] == type[0]) { /* match */
  844. if (optchartype[i] == COMMON_FLAG || optchartype[i] == FILE_FLAG) {
  845. setFlagOn(type[0]);
  846. return;
  847. }
  848. }
  849. }
  850. }
  851. /* if no char options matched */
  852. for (int i = 0; i < option_counter; i++) {
  853. if (strcmp(options[i], type) == 0) { /* match */
  854. if (optiontype[i] == COMMON_FLAG || optiontype[i] == FILE_FLAG) {
  855. setFlagOn(type);
  856. return;
  857. }
  858. }
  859. }
  860. printVerbose("Unknown option in resource file : ");
  861. printVerbose(type);
  862. printVerbose();
  863. }
  864. /*
  865. * usage and help
  866. */
  867. void AnyOption::printAutoUsage() {
  868. if (autousage)
  869. printUsage();
  870. }
  871. void AnyOption::printUsage() {
  872. if (once) {
  873. once = false;
  874. cout << endl;
  875. for (int i = 0; i < usage_lines; i++)
  876. cout << usage[i] << endl;
  877. cout << endl;
  878. }
  879. }
  880. void AnyOption::addUsage(const char *line) {
  881. if (usage_lines >= max_usage_lines) {
  882. if (doubleUsageStorage() == false) {
  883. addUsageError(line);
  884. exit(1);
  885. }
  886. }
  887. usage[usage_lines] = line;
  888. usage_lines++;
  889. }
  890. void AnyOption::addUsageError(const char *line) {
  891. cout << endl;
  892. cout << "OPTIONS ERROR : Failed allocating extra memory " << endl;
  893. cout << "While adding the usage/help : \"" << line << "\"" << endl;
  894. cout << "Exiting." << endl;
  895. cout << endl;
  896. exit(0);
  897. }