options.cpp 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #include "options.hpp"
  2. Options::Options( int argc, char** argv ) {
  3. validArguments.push_back( Argument( "bordersize", 'b', false ) );
  4. validArguments.push_back( Argument( "padding", 'p', false ) );
  5. validArguments.push_back( Argument( "color", 'c', false ) );
  6. validArguments.push_back( Argument( "shader", 'r', false ) );
  7. validArguments.push_back( Argument( "highlight", 'h', true ) );
  8. validArguments.push_back( Argument( "format", 'f', false ) );
  9. validArguments.push_back( Argument( "tolerance", 't', false ) );
  10. validArguments.push_back( Argument( "nodecorations", 'n', false ) );
  11. validArguments.push_back( Argument( "nokeyboard", 'k', true ) );
  12. validArguments.push_back( Argument( "help", 'h', true ) );
  13. validArguments.push_back( Argument( "xdisplay", 'x', false ) );
  14. validArguments.push_back( Argument( "version", 'v', true ) );
  15. validArguments.push_back( Argument( "quiet", 'q', true ) );
  16. validate( argc, argv );
  17. }
  18. int Options::validateStringOption( int argc, char** argv, int argumentIndex ) {
  19. std::string argument = argv[argumentIndex];
  20. unsigned int index = 0;
  21. while( index < validArguments.size() ) {
  22. Argument& check = validArguments[index];
  23. for( unsigned int i=0;i<check.name.length();i++ ) {
  24. if ( check.name[i] != argument[i+2] ) {
  25. break;
  26. }
  27. if ( i == check.name.length()-1 ) {
  28. if ( !check.isFlagArgument && argument.find("=") == std::string::npos ) {
  29. throw new std::invalid_argument("Expected `=` after " + arguments[i]);
  30. }
  31. if ( check.isFlagArgument && i+3 != argument.length() ) {
  32. throw new std::invalid_argument("Trailing characters on flag " + argument );
  33. }
  34. return parseStringOption( argc, argv, argumentIndex, index );
  35. }
  36. }
  37. index++;
  38. }
  39. throw new std::invalid_argument("Invalid argument " + argument);
  40. return 0;
  41. }
  42. int Options::parseCharOption( int argc, char** argv, int argumentIndex, int validIndex ) {
  43. std::string argument = argv[argumentIndex];
  44. Argument& check = validArguments[validIndex];
  45. // If we're a flag, we take no arguments, nor do we allow = signs or whatever.
  46. if ( check.isFlagArgument ) {
  47. if ( argument != std::string()+"-"+check.cname ) {
  48. for( int o=1;o<argument.length();o++ ) {
  49. bool isValid = false;
  50. for( int i=0;i<validArguments.size()&&!isValid;i++ ) {
  51. if ( argument[o] == check.cname ) {
  52. if ( check.isFlagArgument ) {
  53. isValid = true;
  54. arguments.push_back( std::string()+check.cname );
  55. values.push_back("");
  56. break;
  57. } else {
  58. throw new std::invalid_argument( std::string()+"Truncating non-flag arguments is not allowed. Split this up: `" + argument + "`." );
  59. }
  60. }
  61. }
  62. if (!isValid) {
  63. throw new std::invalid_argument( std::string()+"Unexpected characters around flag `" + argument + "`." );
  64. }
  65. }
  66. return 1;
  67. } else {
  68. arguments.push_back( std::string()+argument[1] );
  69. values.push_back("");
  70. return 1;
  71. }
  72. }
  73. arguments.push_back( std::string()+argument[1] );
  74. // If they supplied the parameters with spaces
  75. if ( argument == std::string()+"-"+check.cname ) {
  76. values.push_back(argv[argumentIndex+1]);
  77. return 2;
  78. }
  79. // If they didn't supply the parameters with spaces
  80. if ( argument[2] == '=' ) {
  81. values.push_back(argument.substr(3));
  82. return 1;
  83. }
  84. values.push_back(argument.substr(2));
  85. return 1;
  86. }
  87. int Options::parseStringOption( int argc, char** argv, int argumentIndex, int validIndex ) {
  88. std::string argument = argv[argumentIndex];
  89. if ( validArguments[validIndex].isFlagArgument ) {
  90. arguments.push_back( argument.substr(2) );
  91. values.push_back("");
  92. return 1;
  93. }
  94. arguments.push_back( argument.substr(2,argument.find_first_of('=')) );
  95. values.push_back(argument.substr(argument.find_first_of('=')));
  96. return 1;
  97. }
  98. int Options::validateCharOption( int argc, char** argv, int argumentIndex ) {
  99. std::string argument = argv[argumentIndex];
  100. unsigned int index = 0;
  101. while( index < validArguments.size() ) {
  102. char check = validArguments[index].cname;
  103. if ( argument.length() < 2 ) {
  104. continue;
  105. }
  106. if ( check == argument[1] && ( argument.find("=") == 2 || argument.find('=') == std::string::npos ) && argument[0] == '-' ) {
  107. return parseCharOption( argc, argv, argumentIndex, index );
  108. }
  109. index++;
  110. }
  111. throw new std::invalid_argument("Invalid argument `" + argument + "`.");
  112. return 0;
  113. }
  114. void Options::validate( int argc, char** argv ) {
  115. for ( int i=1;i<argc;) {
  116. std::string argument = argv[i];
  117. if ( argument[0] != '-' ) {
  118. floatingValues.push_back( argument );
  119. if ( floatingValues.size() > maxFloatingValues ) {
  120. throw new std::invalid_argument("Unexpected floating value `" + argument + "`. Forget to specify an option?" );
  121. }
  122. i++;
  123. continue;
  124. }
  125. if ( argument[0] == '-' && argument[1] == '-' ) {
  126. i += validateStringOption( argc, argv, i );
  127. continue;
  128. }
  129. i += validateCharOption( argc, argv, i );
  130. }
  131. }
  132. bool Options::getFloat( std::string name, char namec, float& found ) {
  133. for( unsigned int i=0;i<arguments.size();i++ ) {
  134. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  135. std::string::size_type sz;
  136. float retvar;
  137. try {
  138. retvar = std::stof(values[i],&sz);
  139. } catch ( ... ) {
  140. throw new std::invalid_argument("Unable to parse `" + arguments[i] + "`'s value `" + values[i] + "` as a float.");
  141. }
  142. if ( sz != values[i].length() ) {
  143. throw new std::invalid_argument("Unable to parse `" + arguments[i] + "`'s value `" + values[i] + "` as a float.");
  144. }
  145. found = retvar;
  146. return true;
  147. }
  148. }
  149. return false;
  150. }
  151. bool Options::getInt( std::string name, char namec, int& found ) {
  152. for( unsigned int i=0;i<arguments.size();i++ ) {
  153. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  154. if ( arguments[i].size() > 1 && arguments[i].find("=") == std::string::npos ) {
  155. throw new std::invalid_argument("Expected `=` after " + arguments[i]);
  156. }
  157. std::string::size_type sz;
  158. float retvar;
  159. try {
  160. retvar = std::stoi(values[i],&sz);
  161. } catch ( ... ) {
  162. throw new std::invalid_argument("Unable to parse " + arguments[i] + "'s value " + values[i] + " as an integer.");
  163. }
  164. if ( sz != values[i].length() ) {
  165. throw new std::invalid_argument("Unable to parse " + arguments[i] + "'s value " + values[i] + " as an integer.");
  166. }
  167. found = retvar;
  168. return true;
  169. }
  170. }
  171. return false;
  172. }
  173. bool Options::getString( std::string name, char namec, std::string& found ) {
  174. for( unsigned int i=0;i<arguments.size();i++ ) {
  175. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  176. found = values[i];
  177. return true;
  178. }
  179. }
  180. return false;
  181. }
  182. bool Options::getColor( std::string name, char namec, glm::vec4& found ) {
  183. for( unsigned int i=0;i<arguments.size();i++ ) {
  184. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  185. std::string::size_type sz;
  186. std::string value = values[i];
  187. try {
  188. found[0] = std::stof(value,&sz);
  189. value = value.substr(sz+1);
  190. found[1] = std::stof(value,&sz);
  191. value = value.substr(sz+1);
  192. found[2] = std::stof(value,&sz);
  193. if ( value.size() != sz ) {
  194. value = value.substr(sz+1);
  195. found[3] = std::stof(value,&sz);
  196. if ( value.size() != sz ) {
  197. throw "dur";
  198. }
  199. } else {
  200. found[3] = 1;
  201. }
  202. } catch ( ... ) {
  203. throw new std::invalid_argument("Unable to parse `" + arguments[i] + "`'s value `" + values[i] + "` as a color. Should be in the format r,g,b or r,g,b,a. Like 1,1,1,1.");
  204. }
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210. bool Options::getBool( std::string name, char namec, bool& found ) {
  211. for( unsigned int i=0;i<arguments.size();i++ ) {
  212. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  213. if ( values[i] != "" ) {
  214. throw new std::invalid_argument("Unexpected value `" + values[i] + "` for flag argument `" + arguments[i] + "`.");
  215. }
  216. found = true;
  217. return true;
  218. }
  219. }
  220. return false;
  221. }