options.cpp 9.3KB

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