+// Advances buf while reading a positive int, terminated by [^0-9]
+// buf is left pointing at first [^0-9]
+// If digits are found, the parsed number is written to *out and 0 is returned.
+// Otherwise *buf and *out are left unchanged, and non-zero is returned.
+int
+parse_next_int(char **buf, int* out) {
+ int ret = 0, mul = 1;
+ if(!*buf) {
+ return 1;
+ }
+ // make sure *buf starts -?[0-9]
+ if(**buf == '-') {
+ mul = -1;
+ if((*buf)[1] < '0' || (*buf)[1] > '9') {
+ return 2;
+ }
+ *buf += 1;
+ } else {
+ if(**buf < '0' || **buf > '9') {
+ return 2;
+ }
+ }
+ while(**buf >= '0' && **buf <= '9') {
+ ret *= 10;
+ ret += **buf - '0';
+ *buf += 1;
+ }
+ *out = ret * mul;
+
+ return 0;
+}
+
+// returns 1 on success. return 0 causes usage message
+int
+parse_joystick_opts(char *arg) {
+ char *arg_was = arg;
+ static char* bad_arg = "Error: invalid argument to -j/--joystick.";
+
+ // argument is required
+ if(arg == NULL) {
+ puts(bad_arg);
+ return 0;
+ }
+
+ // read x axis
+ if(parse_next_int(&arg, &opt_joystick_x_axis)) {
+ puts(bad_arg);
+ return 0;
+ }
+
+ // skip comma
+ if(*arg != ',') {
+ puts(bad_arg);
+ return 0;
+ }
+ arg += 1;
+
+ // read y axis
+ if(parse_next_int(&arg, &opt_joystick_y_axis)) {
+ puts(bad_arg);
+ return 0;
+ }
+
+ // optionally joystick number
+ if(*arg == ',') {
+ arg += 1; // skip comma
+ if(parse_next_int(&arg, &opt_joystick_number)) {
+ puts(bad_arg);
+ return 0;
+ }
+ opt_joystick_enabled = 1;
+ }
+
+ // end with a comma or end of string
+ if(*arg != 0 && *arg != ',') {
+ puts(bad_arg);
+ return 0;
+ }
+
+ // mark arg as consumed (so it won't be parsed as a commandline switch)
+ arg_was[0] = 0;
+
+ // return success
+ return 1;
+}