JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
joysticks: configurable, working, buttons enable
[vor.git] / args.c
1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include "args.h"
5 #include <config.h>
6 #include "vorconfig.h"
7
8 // Look and Feel
9 int opt_fullscreen;
10 int opt_sound;
11 int opt_joystick_enabled;
12 int opt_joystick_number;
13 int opt_joystick_x_axis;
14 int opt_joystick_y_axis;
15
16 int opt_autopilot;
17
18 static void
19 show_help(void)
20 {
21         puts("Dodge the rocks until you die.");
22         putchar('\n');
23         puts("  -f, --full-screen");
24         puts("  -s, --silent             No explosion sounds or music");
25         puts("  -j x,y, --joystick=x,y   set the axis numbers. defaults to 0,1");
26         puts("                           press a joystick button to activate that joystick");
27         puts("  -V, --version            Print program version");
28         puts("  -?, --help               Give this help list");
29         putchar('\n');
30         puts("Report bugs at http://jasonwoof.com/contact.html");
31 }
32
33 // Advances buf while reading a positive int, terminated by [^0-9]
34 // buf is left pointing at first [^0-9]
35 // If digits are found, the parsed number is written to *out and 0 is returned.
36 // Otherwise *buf and *out are left unchanged, and non-zero is returned.
37 int
38 parse_next_int(char **buf, int* out) {
39         int ret = 0, mul = 1;
40         if(!*buf) {
41                 return 1;
42         }
43         // make sure *buf starts -?[0-9]
44         if(**buf == '-') {
45                 mul = -1;
46                 if((*buf)[1] < '0' || (*buf)[1] > '9') {
47                         return 2;
48                 }
49                 *buf += 1;
50         } else {
51                 if(**buf < '0' || **buf > '9') {
52                         return 2;
53                 }
54         }
55         while(**buf >= '0' && **buf <= '9') {
56                 ret *= 10;
57                 ret += **buf - '0';
58                 *buf += 1;
59         }
60         *out = ret * mul;
61
62         return 0;
63 }
64
65 // returns 1 on success. return 0 causes usage message
66 int
67 parse_joystick_opts(char *arg) {
68         char *arg_was = arg;
69         static char* bad_arg = "Error: invalid argument to -j/--joystick.";
70
71         // argument is required
72         if(arg == NULL) {
73                 puts(bad_arg);
74                 return 0;
75         }
76
77         // read x axis
78         if(parse_next_int(&arg, &opt_joystick_x_axis)) {
79                 puts(bad_arg);
80                 return 0;
81         }
82
83         // skip comma
84         if(*arg != ',') {
85                 puts(bad_arg);
86                 return 0;
87         }
88         arg += 1;
89
90         // read y axis
91         if(parse_next_int(&arg, &opt_joystick_y_axis)) {
92                 puts(bad_arg);
93                 return 0;
94         }
95
96         // optionally joystick number
97         if(*arg == ',') {
98                 arg += 1; // skip comma
99                 if(parse_next_int(&arg, &opt_joystick_number)) {
100                         puts(bad_arg);
101                         return 0;
102                 }
103                 opt_joystick_enabled = 1;
104         }
105
106         // end with a comma or end of string
107         if(*arg != 0 && *arg != ',') {
108                 puts(bad_arg);
109                 return 0;
110         }
111
112         // mark arg as consumed (so it won't be parsed as a commandline switch)
113         arg_was[0] = 0;
114
115         // return success
116         return 1;
117 }
118 int
119 short_opt(char c, char *arg)
120 {
121         switch(c) {
122                 case 'f': opt_fullscreen = 1; break;
123                 case 's': opt_sound = 0; break;
124                 case 'j':
125                         return parse_joystick_opts(arg);
126                 case 'V':
127                                   printf("Variations on Rockdodger %s\n", PACKAGE_VERSION);
128                                   exit(0);
129                 case '?':
130                 case 'h': return 0;
131                 case 'a': opt_autopilot = 1; break;
132                 default: 
133                                   fprintf(stderr, "unknown option -%c\n\n", c);
134                                   return 0;
135         }
136         return 1;
137 }
138
139 int
140 parse_short_opts(const char *s, char *arg)
141 {
142         while(s[1]) if(!short_opt(*s++, NULL)) return 0;
143         return short_opt(*s, arg);
144 }
145
146 static char *long_opts[] = { "full-screen", "silent", "joystick", "version", "help", "autopilot" };
147
148 static char short_opts[] = { 'f', 's', 'j', 'V', 'h', 'a' };
149
150 int
151 parse_long_opt(const char *s, char *arg)
152 {
153         int i;
154         for(i=0; i<sizeof(short_opts); i++) {
155                 if(strcmp(s, long_opts[i]) == 0)
156                         return short_opt(short_opts[i], arg);
157         }
158         fprintf(stderr, "unknown long option --%s\n\n", s);
159         return 0;
160 }
161
162 void
163 init_opts(void)
164 {
165         opt_fullscreen = 0;
166         opt_sound = 1;
167         opt_joystick_enabled = 0; // can also be enabled by pressing one of its buttons
168         opt_joystick_number = 0;
169         opt_joystick_x_axis = 0;
170         opt_joystick_y_axis = 1;
171         opt_autopilot = 0;
172 }
173
174 int
175 parse_opts(int argc, char *argv[])
176 {
177         int i;
178         char *r;
179
180         init_opts();
181         for(i=1; i<argc; i++) {
182                 char *s, *arg;
183                 // args that are consumed as arguments to an option (such as the zero
184                 // in: -j 0) have their first byte set to null. So skip them:
185                 s = argv[i]; if(!*s) continue;
186                 if(*s++ != '-') {
187                         fputs("not an option\n\n", stderr);
188                         show_help();
189                         return 0;
190                 }
191
192                 arg = NULL;
193                 for(r=s; *r; r++) if(*r == '=') { *r = 0; arg = r+1; break; }
194
195                 if(arg == NULL && i + 1 < argc) {
196                         arg = argv[i+1];
197                         // if this is used, it's first byte will be set to null, and
198                         // it'll be skipped. See above.
199                 }
200
201                 if(*s == '-') {
202                         if(!parse_long_opt(s+1, arg)) { show_help(); return 0; }
203                 } else {
204                    if(!parse_short_opts(s, arg)) { show_help(); return 0; }
205                 }
206         }
207         return 1;
208 }