Import Debian changes 1.23-11
[debian-dgen.git] / rc.cpp
blob72fa2340000d09e0ac7ae082839d04cb7f887d6c
1 // This parses the RC file.
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <SDL.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
10 #include "rc.h"
11 #include "pd-defs.h"
12 #include "md-phil.h"
16 // CTV names
17 char *ctv_names[NUM_CTV] = { "off", "blur", "scanline", "interlace" };
19 // The table of strings and the keysyms they map to.
20 // The order is a bit weird, since this was originally a mapping for the SVGALib
21 // scancodes, and I just added the SDL stuff on top of it.
22 struct rc_keysym {
23 char *name;
24 long keysym;
25 } keysyms[] = {
26 { "ESCAPE", PDK_ESCAPE },
27 { "1", PDK_1 },
28 { "2", PDK_2 },
29 { "3", PDK_3 },
30 { "4", PDK_4 },
31 { "5", PDK_5 },
32 { "6", PDK_6 },
33 { "7", PDK_7 },
34 { "8", PDK_8 },
35 { "9", PDK_9 },
36 { "0", PDK_0 },
37 { "-", PDK_MINUS },
38 { "=", PDK_EQUALS },
39 { "+", PDK_EQUALS },
40 { "BACKSPACE", PDK_BACKSPACE },
41 { "TAB", PDK_TAB },
42 { "Q", PDK_q },
43 { "W", PDK_w },
44 { "E", PDK_e },
45 { "R", PDK_r },
46 { "T", PDK_t },
47 { "Y", PDK_y },
48 { "U", PDK_u },
49 { "I", PDK_i },
50 { "O", PDK_o },
51 { "P", PDK_p },
52 { "[", PDK_LEFTBRACKET },
53 { "{", PDK_LEFTBRACKET },
54 { "]", PDK_RIGHTBRACKET },
55 { "}", PDK_RIGHTBRACKET },
56 { "RETURN", PDK_RETURN },
57 { "ENTER", PDK_RETURN },
58 { "A", PDK_a },
59 { "S", PDK_s },
60 { "D", PDK_d },
61 { "F", PDK_f },
62 { "G", PDK_g },
63 { "H", PDK_h },
64 { "J", PDK_j },
65 { "K", PDK_k },
66 { "L", PDK_l },
67 { ";", PDK_SEMICOLON },
68 { ":", PDK_SEMICOLON },
69 { "'", PDK_QUOTE },
70 { "\"", PDK_QUOTE },
71 { "`", PDK_BACKQUOTE },
72 { "~", PDK_BACKQUOTE },
73 { "\\", PDK_BACKSLASH },
74 { "|", PDK_BACKSLASH },
75 { "Z", PDK_z },
76 { "X", PDK_x },
77 { "C", PDK_c },
78 { "V", PDK_v },
79 { "B", PDK_b },
80 { "N", PDK_n },
81 { "M", PDK_m },
82 { ",", PDK_COMMA },
83 { "<", PDK_COMMA },
84 { ".", PDK_PERIOD },
85 { ">", PDK_PERIOD },
86 { "/", PDK_SLASH },
87 { "?", PDK_SLASH },
88 { "KP_MULTIPLY", PDK_KP_MULTIPLY },
89 { "SPACE", PDK_SPACE },
90 { "F1", PDK_F1 },
91 { "F2", PDK_F2 },
92 { "F3", PDK_F3 },
93 { "F4", PDK_F4 },
94 { "F5", PDK_F5 },
95 { "F6", PDK_F6 },
96 { "F7", PDK_F7 },
97 { "F8", PDK_F8 },
98 { "F9", PDK_F9 },
99 { "F10", PDK_F10 },
100 { "KP_7", PDK_KP7 },
101 { "KP_HOME", PDK_KP7 },
102 { "KP_8", PDK_KP8 },
103 { "KP_UP", PDK_KP8 },
104 { "KP_9", PDK_KP9 },
105 { "KP_PAGE_UP", PDK_KP9 },
106 { "KP_PAGEUP", PDK_KP9 },
107 { "KP_MINUS", PDK_KP_MINUS },
108 { "KP_4", PDK_KP4 },
109 { "KP_LEFT", PDK_KP4 },
110 { "KP_5", PDK_KP5 },
111 { "KP_6", PDK_KP6 },
112 { "KP_RIGHT", PDK_KP6 },
113 { "KP_PLUS", PDK_KP_PLUS },
114 { "KP_1", PDK_KP1 },
115 { "KP_END", PDK_KP1 },
116 { "KP_2", PDK_KP2 },
117 { "KP_DOWN", PDK_KP2 },
118 { "KP_3", PDK_KP3 },
119 { "KP_PAGE_DOWN", PDK_KP3 },
120 { "KP_PAGEDOWN", PDK_KP3 },
121 { "KP_0", PDK_KP0 },
122 { "KP_INSERT", PDK_KP0 },
123 { "KP_PERIOD", PDK_KP_PERIOD },
124 { "KP_DELETE", PDK_KP_PERIOD },
125 { "F11", PDK_F11 },
126 { "F12", PDK_F12 },
127 { "KP_ENTER", PDK_KP_ENTER },
128 { "KP_DIVIDE", PDK_KP_DIVIDE },
129 { "HOME", PDK_HOME },
130 { "UP", PDK_UP },
131 { "PAGE_UP", PDK_PAGEUP },
132 { "PAGEUP", PDK_PAGEUP },
133 { "LEFT", PDK_LEFT },
134 { "RIGHT", PDK_RIGHT },
135 { "END", PDK_END },
136 { "DOWN", PDK_DOWN },
137 { "PAGE_DOWN", PDK_PAGEDOWN },
138 { "PAGEDOWN", PDK_PAGEDOWN },
139 { "INSERT", PDK_INSERT },
140 { "DELETE", PDK_DELETE },
141 { "NUMLOCK", PDK_NUMLOCK },
142 { "NUM_LOCK", PDK_NUMLOCK },
143 { "CAPSLOCK", PDK_CAPSLOCK },
144 { "CAPS_LOCK", PDK_CAPSLOCK },
145 { "SCROLLOCK", PDK_SCROLLOCK },
146 { "SCROLL_LOCK", PDK_SCROLLOCK },
147 { "LSHIFT", PDK_LSHIFT },
148 { "SHIFT_L", PDK_LSHIFT },
149 { "RSHIFT", PDK_RSHIFT },
150 { "SHIFT_R", PDK_RSHIFT },
151 { "LCTRL", PDK_LCTRL },
152 { "CTRL_L", PDK_LCTRL },
153 { "RCTRL", PDK_RCTRL },
154 { "CTRL_R", PDK_RCTRL },
155 { "LALT", PDK_LALT },
156 { "ALT_L", PDK_LALT },
157 { "RALT", PDK_RALT },
158 { "ALT_R", PDK_RALT },
159 { "LMETA", PDK_LMETA },
160 { "META_L", PDK_LMETA },
161 { "RMETA", PDK_RMETA },
162 { "META_R", PDK_RMETA },
163 { NULL, 0 } // Terminator
164 }; // Phew! ;)
166 /* Define all the external RC variables */
167 #include "rc-vars.h"
169 long js_map_button[2][16] = {
171 MD_A_MASK, MD_C_MASK, MD_A_MASK,
172 MD_B_MASK, MD_Y_MASK, MD_Z_MASK,
173 MD_X_MASK, MD_X_MASK, MD_START_MASK,
174 MD_MODE_MASK, 0, 0, 0, 0, 0, 0
177 MD_A_MASK, MD_C_MASK, MD_A_MASK,
178 MD_B_MASK, MD_Y_MASK, MD_Z_MASK,
179 MD_X_MASK, MD_X_MASK, MD_START_MASK,
180 MD_MODE_MASK, 0, 0, 0, 0, 0, 0
184 /* Parse a keysym.
185 * If the string matches one of the strings in the keysym table above,
186 * return the keysym, otherwise -1. */
187 static long keysym(const char *code)
189 struct rc_keysym *s = keysyms;
190 long r = 0;
192 // Check for modifier prefixes shift-, ctrl-, alt-, meta-
193 for(;;) {
194 if(!strncasecmp("shift-", code, 6)) {
195 r |= KEYSYM_MOD_SHIFT;
196 code += 6;
197 continue;
199 if(!strncasecmp("ctrl-", code, 5)) {
200 r |= KEYSYM_MOD_CTRL;
201 code += 5;
202 continue;
204 if(!strncasecmp("alt-", code, 4)) {
205 r |= KEYSYM_MOD_ALT;
206 code += 4;
207 continue;
209 if(!strncasecmp("meta-", code, 5)) {
210 r |= KEYSYM_MOD_META;
211 code += 5;
212 continue;
214 break;
217 do {
218 if(!strcasecmp(s->name, code)) return r |= s->keysym;
219 } while ((++s)->name);
220 /* No match */
221 return -1;
224 /* Parse a boolean value.
225 * If the string is "yes" or "true", return 1.
226 * If the string is "no" or "false", return 0.
227 * Otherwise, just return atoi(value). */
228 static long boolean(const char *value)
230 if(!strcasecmp(value, "yes") || !strcasecmp(value, "true"))
231 return 1;
232 if(!strcasecmp(value, "no") || !strcasecmp(value, "false"))
233 return 0;
234 return atoi(value);
237 // Made GCC happy about unused things when we don't want a joystick. :) [PKH]
238 // Cheesy hack to set joystick mappings from the RC file. [PKH]
239 static long jsmap(const char *value) {
240 if(!strcasecmp(value, "mode"))
241 snprintf((char*)value, 2, "%c", 'm');
242 if(!strcasecmp(value, "start"))
243 snprintf((char*)value, 2, "%c", 's');
244 switch(*value) {
245 case 'A':
246 case 'a':
247 return(MD_A_MASK);
248 break;
249 case 'B':
250 case 'b':
251 return(MD_B_MASK);
252 break;
253 case 'C':
254 case 'c':
255 return(MD_C_MASK);
256 break;
257 case 'X':
258 case 'x':
259 return(MD_X_MASK);
260 break;
261 case 'Y':
262 case 'y':
263 return(MD_Y_MASK);
264 break;
265 case 'Z':
266 case 'z':
267 return(MD_Z_MASK);
268 break;
269 case 'M':
270 case 'm':
271 return(MD_MODE_MASK);
272 break;
273 case 'S':
274 case 's':
275 return(MD_START_MASK);
276 break;
277 default:
278 return(0);
282 /* Parse the CTV type. As new CTV filters get submitted expect this to grow ;)
283 * Current values are:
284 * off - No CTV
285 * blur - blur bitmap (from DirectX DGen), by Dave <dave@dtmnt.com>
286 * scanline - attenuates every other line, looks cool! by Phillip K. Hornung <redx@pknet.com>
288 static long ctv(const char *value)
290 for(int i = 0; i < NUM_CTV; ++i)
291 if(!strcasecmp(value, ctv_names[i])) return i;
292 return -1;
295 static long number(const char *value)
297 return atoi(value);
300 /* This is a table of all the RC options, the variables they affect, and the
301 * functions to parse their values. */
302 struct rc_field {
303 char *fieldname;
304 long (*parser)(const char*);
305 long *variable;
306 } rc_fields[] = {
307 { "key_pad1_up", keysym, &pad1_up },
308 { "key_pad1_down", keysym, &pad1_down },
309 { "key_pad1_left", keysym, &pad1_left },
310 { "key_pad1_right", keysym, &pad1_right },
311 { "key_pad1_a", keysym, &pad1_a },
312 { "key_pad1_b", keysym, &pad1_b },
313 { "key_pad1_c", keysym, &pad1_c },
314 { "key_pad1_x", keysym, &pad1_x },
315 { "key_pad1_y", keysym, &pad1_y },
316 { "key_pad1_z", keysym, &pad1_z },
317 { "key_pad1_mode", keysym, &pad1_mode },
318 { "key_pad1_start", keysym, &pad1_start },
319 { "key_pad2_up", keysym, &pad2_up },
320 { "key_pad2_down", keysym, &pad2_down },
321 { "key_pad2_left", keysym, &pad2_left },
322 { "key_pad2_right", keysym, &pad2_right },
323 { "key_pad2_a", keysym, &pad2_a },
324 { "key_pad2_b", keysym, &pad2_b },
325 { "key_pad2_c", keysym, &pad2_c },
326 { "key_pad2_x", keysym, &pad2_x },
327 { "key_pad2_y", keysym, &pad2_y },
328 { "key_pad2_z", keysym, &pad2_z },
329 { "key_pad2_mode", keysym, &pad2_mode },
330 { "key_pad2_start", keysym, &pad2_start },
331 { "key_fix_checksum", keysym, &dgen_fix_checksum },
332 { "key_quit", keysym, &dgen_quit },
333 { "key_splitscreen_toggle", keysym, &dgen_splitscreen_toggle },
334 { "key_craptv_toggle", keysym, &dgen_craptv_toggle },
335 { "key_screenshot", keysym, &dgen_screenshot },
336 { "key_reset", keysym, &dgen_reset },
337 { "key_slot_0", keysym, &dgen_slot_0 },
338 { "key_slot_1", keysym, &dgen_slot_1 },
339 { "key_slot_2", keysym, &dgen_slot_2 },
340 { "key_slot_3", keysym, &dgen_slot_3 },
341 { "key_slot_4", keysym, &dgen_slot_4 },
342 { "key_slot_5", keysym, &dgen_slot_5 },
343 { "key_slot_6", keysym, &dgen_slot_6 },
344 { "key_slot_7", keysym, &dgen_slot_7 },
345 { "key_slot_8", keysym, &dgen_slot_8 },
346 { "key_slot_9", keysym, &dgen_slot_9 },
347 { "key_save", keysym, &dgen_save },
348 { "key_load", keysym, &dgen_load },
349 { "key_cpu_toggle", keysym, &dgen_cpu_toggle },
350 { "key_stop", keysym, &dgen_stop },
351 { "key_fullscreen_toggle", keysym, &dgen_fullscreen_toggle },
352 { "bool_splitscreen_startup", boolean, &dgen_splitscreen_startup },
353 { "bool_autoload", boolean, &dgen_autoload },
354 { "bool_autosave", boolean, &dgen_autosave },
355 { "bool_frameskip", boolean, &dgen_frameskip },
356 { "bool_show_carthead", boolean, &dgen_show_carthead },
357 { "ctv_craptv_startup", ctv, &dgen_craptv },
358 { "bool_sound", boolean, &dgen_sound },
359 { "int_soundrate", number, &dgen_soundrate },
360 { "bool_16bit", boolean, &dgen_16bit },
361 { "int_soundsegs", number, &dgen_soundsegs },
362 { "int_nice", number, &dgen_nice },
363 { "bool_fullscreen", boolean, &dgen_fullscreen },
364 { "int_scale", number, &dgen_scale },
365 { "bool_opengl", boolean, &dgen_opengl },
366 { "int_opengl_width", number, &dgen_opengl_width },
367 { "int_opengl_height", number, &dgen_opengl_height },
368 { "bool_joystick", boolean, &dgen_joystick },
369 { "joypad1_b0", jsmap, &js_map_button[0][0] },
370 { "joypad1_b1", jsmap, &js_map_button[0][1] },
371 { "joypad1_b2", jsmap, &js_map_button[0][2] },
372 { "joypad1_b3", jsmap, &js_map_button[0][3] },
373 { "joypad1_b4", jsmap, &js_map_button[0][4] },
374 { "joypad1_b5", jsmap, &js_map_button[0][5] },
375 { "joypad1_b6", jsmap, &js_map_button[0][6] },
376 { "joypad1_b7", jsmap, &js_map_button[0][7] },
377 { "joypad1_b8", jsmap, &js_map_button[0][8] },
378 { "joypad1_b9", jsmap, &js_map_button[0][9] },
379 { "joypad1_b10", jsmap, &js_map_button[0][10] },
380 { "joypad1_b11", jsmap, &js_map_button[0][11] },
381 { "joypad1_b12", jsmap, &js_map_button[0][12] },
382 { "joypad1_b13", jsmap, &js_map_button[0][13] },
383 { "joypad1_b14", jsmap, &js_map_button[0][14] },
384 { "joypad1_b15", jsmap, &js_map_button[0][15] },
385 { "joypad2_b0", jsmap, &js_map_button[1][0] },
386 { "joypad2_b1", jsmap, &js_map_button[1][1] },
387 { "joypad2_b2", jsmap, &js_map_button[1][2] },
388 { "joypad2_b3", jsmap, &js_map_button[1][3] },
389 { "joypad2_b4", jsmap, &js_map_button[1][4] },
390 { "joypad2_b5", jsmap, &js_map_button[1][5] },
391 { "joypad2_b6", jsmap, &js_map_button[1][6] },
392 { "joypad2_b7", jsmap, &js_map_button[1][7] },
393 { "joypad2_b8", jsmap, &js_map_button[1][8] },
394 { "joypad2_b9", jsmap, &js_map_button[1][9] },
395 { "joypad2_b10", jsmap, &js_map_button[1][10] },
396 { "joypad2_b11", jsmap, &js_map_button[1][11] },
397 { "joypad2_b12", jsmap, &js_map_button[1][12] },
398 { "joypad2_b13", jsmap, &js_map_button[1][13] },
399 { "joypad2_b14", jsmap, &js_map_button[1][14] },
400 { "joypad2_b15", jsmap, &js_map_button[1][15] },
401 { NULL, NULL, NULL } // Terminator
404 /* Parse the rc file */
405 void parse_rc(const char *file)
407 FILE *rc;
408 char temp[1024] = "", line[2048] = "", field[1024] = "", value[1024] = "";
409 /* If the filename is NULL, use default of $HOME/.dgen/dgenrc */
410 if(!file)
412 strncat(temp, getenv("HOME"), 1023);
413 strncat(temp, "/.dgen/dgenrc", 1023 - strlen(temp));
414 file = temp;
416 /* Open the file. If it's "-", open standard input instead. */
417 rc = fopen(file, "r");
419 if(!rc)
421 fprintf(stderr, "rc: Couldn't open rc file %s, trying to create\n", file);
422 strncat(field, getenv("HOME"), 1023);
423 strncat(field, "/.dgen", 1023 - strlen(field));
424 mkdir(field, 0777); /* Create the .dgen directory */
425 rc = fopen(file, "w");
426 if(!rc)
428 fprintf(stderr, "rc: Couldn't create rc file %s!\n", file);
429 return;
431 fclose(rc);
432 fopen(file, "r");
433 return;
435 while(fgets(line, 2047, rc))
437 struct rc_field *s;
438 s = rc_fields;
439 /* If it starts with hash (#) or is blank, we have a comment */
440 if(*line == '#' || *line == '\0' || *line == '\n') continue;
441 /* Each line is in the format field=value */
442 sscanf(line, " %s = %s", field, value);
443 /* Check field against all supported fields */
444 do {
445 if(!strcasecmp(s->fieldname, field))
447 int potential;
448 potential = (*(s->parser))(value);
449 /* If we got a bad value, discard and warn user */
450 if(potential == -1)
451 fprintf(stderr, "rc: Invalid RC value for %s: %s\n", field, value);
452 else
453 *(s->variable) = potential;
454 break;
456 } while((++s)->fieldname);
457 // If we reached the end of the table, bad field, bad line
458 if(!s->fieldname) fprintf(stderr, "rc: Invalid RC line: %s", line);
460 fclose(rc);
461 return;