options.cpp 9.6KB

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