options.cpp 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. if ( argumentIndex+1 < argc ) {
  78. values.push_back(argv[argumentIndex+1]);
  79. } else {
  80. values.push_back("");
  81. }
  82. return 2;
  83. }
  84. // If they didn't supply the parameters with spaces
  85. if ( argument[2] == '=' ) {
  86. values.push_back(argument.substr(3));
  87. return 1;
  88. }
  89. values.push_back(argument.substr(2));
  90. return 1;
  91. }
  92. int Options::parseStringOption( int argc, char** argv, int argumentIndex, int validIndex ) {
  93. std::string argument = argv[argumentIndex];
  94. if ( validArguments[validIndex].isFlagArgument ) {
  95. arguments.push_back( argument.substr(2) );
  96. values.push_back("");
  97. return 1;
  98. }
  99. arguments.push_back( argument.substr(2,argument.find_first_of('=')) );
  100. values.push_back(argument.substr(argument.find_first_of('=')));
  101. return 1;
  102. }
  103. int Options::validateCharOption( int argc, char** argv, int argumentIndex ) {
  104. std::string argument = argv[argumentIndex];
  105. unsigned int index = 0;
  106. while( index < validArguments.size() ) {
  107. char check = validArguments[index].cname;
  108. if ( argument.length() < 2 ) {
  109. continue;
  110. }
  111. if ( check == argument[1] && ( argument.find("=") == 2 || argument.find('=') == std::string::npos ) && argument[0] == '-' ) {
  112. return parseCharOption( argc, argv, argumentIndex, index );
  113. }
  114. index++;
  115. }
  116. throw new std::invalid_argument("Invalid argument `" + argument + "`.");
  117. return 0;
  118. }
  119. void Options::validate( int argc, char** argv ) {
  120. for ( int i=1;i<argc;) {
  121. std::string argument = argv[i];
  122. if ( argument[0] != '-' ) {
  123. floatingValues.push_back( argument );
  124. if ( floatingValues.size() > maxFloatingValues ) {
  125. throw new std::invalid_argument("Unexpected floating value `" + argument + "`. Forget to specify an option?" );
  126. }
  127. i++;
  128. continue;
  129. }
  130. if ( argument[0] == '-' && argument[1] == '-' ) {
  131. i += validateStringOption( argc, argv, i );
  132. continue;
  133. }
  134. i += validateCharOption( argc, argv, i );
  135. }
  136. }
  137. bool Options::getFloat( std::string name, char namec, float& found ) {
  138. for( unsigned int i=0;i<arguments.size();i++ ) {
  139. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  140. std::string::size_type sz;
  141. float retvar;
  142. try {
  143. retvar = std::stof(values[i],&sz);
  144. } catch ( ... ) {
  145. throw new std::invalid_argument("Unable to parse `" + arguments[i] + "`'s value `" + values[i] + "` as a float.");
  146. }
  147. if ( sz != values[i].length() ) {
  148. throw new std::invalid_argument("Unable to parse `" + arguments[i] + "`'s value `" + values[i] + "` as a float.");
  149. }
  150. found = retvar;
  151. return true;
  152. }
  153. }
  154. return false;
  155. }
  156. bool Options::getInt( std::string name, char namec, int& found ) {
  157. for( unsigned int i=0;i<arguments.size();i++ ) {
  158. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  159. if ( arguments[i].size() > 1 && arguments[i].find("=") == std::string::npos ) {
  160. throw new std::invalid_argument("Expected `=` after " + arguments[i]);
  161. }
  162. std::string::size_type sz;
  163. float retvar;
  164. try {
  165. retvar = std::stoi(values[i],&sz);
  166. } catch ( ... ) {
  167. throw new std::invalid_argument("Unable to parse " + arguments[i] + "'s value " + values[i] + " as an integer.");
  168. }
  169. if ( sz != values[i].length() ) {
  170. throw new std::invalid_argument("Unable to parse " + arguments[i] + "'s value " + values[i] + " as an integer.");
  171. }
  172. found = retvar;
  173. return true;
  174. }
  175. }
  176. return false;
  177. }
  178. bool Options::getString( std::string name, char namec, std::string& found ) {
  179. for( unsigned int i=0;i<arguments.size();i++ ) {
  180. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  181. found = values[i];
  182. return true;
  183. }
  184. }
  185. return false;
  186. }
  187. bool Options::getColor( std::string name, char namec, glm::vec4& found ) {
  188. for( unsigned int i=0;i<arguments.size();i++ ) {
  189. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  190. std::string::size_type sz;
  191. std::string value = values[i];
  192. try {
  193. found[0] = std::stof(value,&sz);
  194. value = value.substr(sz+1);
  195. found[1] = std::stof(value,&sz);
  196. value = value.substr(sz+1);
  197. found[2] = std::stof(value,&sz);
  198. if ( value.size() != sz ) {
  199. value = value.substr(sz+1);
  200. found[3] = std::stof(value,&sz);
  201. if ( value.size() != sz ) {
  202. throw "dur";
  203. }
  204. } else {
  205. found[3] = 1;
  206. }
  207. } catch ( ... ) {
  208. 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.");
  209. }
  210. return true;
  211. }
  212. }
  213. return false;
  214. }
  215. bool Options::getBool( std::string name, char namec, bool& found ) {
  216. for( unsigned int i=0;i<arguments.size();i++ ) {
  217. if ( arguments[i] == name || arguments[i] == std::string("")+namec ) {
  218. if ( values[i] != "" ) {
  219. throw new std::invalid_argument("Unexpected value `" + values[i] + "` for flag argument `" + arguments[i] + "`.");
  220. }
  221. found = true;
  222. return true;
  223. }
  224. }
  225. return false;
  226. }