Skip to content

Commit 3d7a90a

Browse files
committed
added configfile.c and .h
1 parent a81ac4d commit 3d7a90a

3 files changed

Lines changed: 301 additions & 1 deletion

File tree

configfile.c

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
// configfile.c - handles loading and saving the configuration options
2+
#include <stdbool.h>
3+
#include <stdlib.h>
4+
#include <stdio.h>
5+
#include <string.h>
6+
#include <assert.h>
7+
#include <ctype.h>
8+
9+
#include "configfile.h"
10+
11+
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof(arr[0]))
12+
13+
enum ConfigOptionType {
14+
CONFIG_TYPE_BOOL,
15+
CONFIG_TYPE_UINT,
16+
CONFIG_TYPE_FLOAT,
17+
CONFIG_TYPE_ASPECT_RATIO,
18+
};
19+
20+
struct ConfigOption {
21+
const char *name;
22+
enum ConfigOptionType type;
23+
union {
24+
bool *boolValue;
25+
unsigned int *uintValue;
26+
float *floatValue;
27+
};
28+
const char *section;
29+
};
30+
31+
#undef X
32+
#define X(a, b) b,
33+
const char *aspect_ratio_name[] = {ASPECT_RATIOS};
34+
unsigned int aspect_ratio_factor_step = 10;
35+
36+
/*
37+
*Config options and default values
38+
*/
39+
unsigned int aspect_ratio = ASPECT_RATIOS_TYPE_STRETCHED;
40+
unsigned int aspect_ratio_factor_percent = 50;
41+
42+
static const struct ConfigOption options[] = {
43+
{.name = "aspect_ratio", .section=NULL, .type = CONFIG_TYPE_ASPECT_RATIO, .uintValue = &aspect_ratio},
44+
{.name = "aspect_ratio_factor_percent", .section=NULL, .type = CONFIG_TYPE_UINT, .uintValue = &aspect_ratio_factor_percent},
45+
};
46+
47+
// Reads an entire line from a file (excluding the newline character) and returns an allocated string
48+
// Returns NULL if no lines could be read from the file
49+
static char *read_file_line(FILE *file) {
50+
char *buffer;
51+
size_t bufferSize = 64;
52+
size_t offset = 0; // offset in buffer to write
53+
54+
buffer = malloc(bufferSize);
55+
while (1) {
56+
// Read a line from the file
57+
if (fgets(buffer + offset, bufferSize - offset, file) == NULL) {
58+
free(buffer);
59+
return NULL; // Nothing could be read.
60+
}
61+
offset = strlen(buffer);
62+
assert(offset > 0);
63+
64+
if (feof(file)) // EOF was reached
65+
break;
66+
67+
// If a newline was found, remove the trailing newline and exit
68+
if (buffer[offset - 1] == '\n') {
69+
buffer[offset - 1] = '\0';
70+
break;
71+
}
72+
73+
// If no newline or EOF was reached, then the whole line wasn't read.
74+
bufferSize *= 2; // Increase buffer size
75+
buffer = realloc(buffer, bufferSize);
76+
assert(buffer != NULL);
77+
}
78+
79+
return buffer;
80+
}
81+
82+
// Returns the position of the first non-whitespace character
83+
static char *skip_whitespace(char *str) {
84+
while (isspace(*str))
85+
str++;
86+
return str;
87+
}
88+
89+
// Returns the position of the first non-whitespace or '=' character
90+
static char *skip_whitespace_or_equal(char *str) {
91+
while (isspace(*str) || *str=='=')
92+
str++;
93+
return str;
94+
}
95+
96+
// NULL-terminates the current whitespace-delimited word, and returns a pointer to the next word
97+
static char *word_split(char *str) {
98+
// Precondition: str must not point to whitespace
99+
assert(!isspace(*str));
100+
101+
// Find either the next whitespace, '=' or end of string
102+
while (!isspace(*str) && *str != '\0' && *str != '=')
103+
str++;
104+
if (*str == '\0') // End of string
105+
return str;
106+
107+
// Terminate current word
108+
*(str++) = '\0';
109+
110+
// Skip whitespace to next word
111+
return skip_whitespace_or_equal(str);
112+
}
113+
114+
// Splits a string into words, and stores the words into the 'tokens' array
115+
// 'maxTokens' is the length of the 'tokens' array
116+
// Returns the number of tokens parsed
117+
static unsigned int tokenize_string(char *str, int maxTokens, char **tokens) {
118+
int count = 0;
119+
120+
str = skip_whitespace(str);
121+
while (str[0] != '\0' && count < maxTokens) {
122+
tokens[count] = str;
123+
str = word_split(str);
124+
count++;
125+
}
126+
return count;
127+
}
128+
129+
// Loads the config file specified by 'filepath'
130+
void configfile_load(const char *filepath) {
131+
FILE *file;
132+
char *line;
133+
unsigned int cur_line = 0;
134+
char *current_section = NULL;
135+
136+
printf("Loading configuration from '%s'\n", filepath);
137+
138+
// Open file or create it if it does not exist
139+
file = fopen(filepath, "r");
140+
if (file == NULL) {
141+
// Create a new config file and save defaults
142+
printf("Config file '%s' not found. Creating it.\n", filepath);
143+
configfile_save(filepath);
144+
return;
145+
}
146+
147+
// Go through each line in the file
148+
while ((line = read_file_line(file)) != NULL) {
149+
char *p = line;
150+
char *tokens[2];
151+
int numTokens;
152+
cur_line++;
153+
154+
// Get tokens
155+
while (isspace(*p)) p++;
156+
numTokens = tokenize_string(p, 2, tokens);
157+
158+
// Get content
159+
if (numTokens != 0) {
160+
161+
// Pass comments
162+
if(tokens[0][0]=='#') continue;
163+
164+
// Check sections - useless for now
165+
if(tokens[0][0]=='['){
166+
p=tokens[0];
167+
while(*p != '\0' && *p!=']') p++;
168+
if(*p == '\0') continue;
169+
*p=0;
170+
if(current_section) free(current_section);
171+
current_section = malloc(strlen(tokens[0])); //strlen(tokens[0])-1+1
172+
strcpy(current_section, &tokens[0][1]);
173+
printf("New Section: %s\n", current_section);
174+
continue;
175+
}
176+
177+
if (numTokens == 2) {
178+
const struct ConfigOption *option = NULL;
179+
180+
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
181+
if (strcmp(tokens[0], options[i].name) == 0) {
182+
option = &options[i];
183+
break;
184+
}
185+
}
186+
if (option == NULL){
187+
printf("Unknown option '%s'\n", tokens[0]);
188+
}
189+
else {
190+
printf("Reading option: '%s', value: '%s'\n", tokens[0], tokens[1]);
191+
switch (option->type) {
192+
case CONFIG_TYPE_BOOL:
193+
if (strcmp(tokens[1], "true") == 0)
194+
*option->boolValue = true;
195+
else if (strcmp(tokens[1], "false") == 0)
196+
*option->boolValue = false;
197+
else{
198+
printf("Unknown CONFIG_TYPE_BOOL value: '%s', using default: %s\n",
199+
tokens[1], (*option->boolValue)?"true":"false");
200+
}
201+
break;
202+
case CONFIG_TYPE_UINT:
203+
sscanf(tokens[1], "%u", option->uintValue);
204+
break;
205+
case CONFIG_TYPE_FLOAT:
206+
sscanf(tokens[1], "%f", option->floatValue);
207+
break;
208+
case CONFIG_TYPE_ASPECT_RATIO:
209+
;unsigned int cur_ar;
210+
for(cur_ar=0; cur_ar<NB_ASPECT_RATIOS_TYPES; cur_ar++){
211+
if(!strcmp(aspect_ratio_name[cur_ar], tokens[1])){
212+
*option->uintValue = cur_ar;
213+
break;
214+
}
215+
}
216+
if(cur_ar >= NB_ASPECT_RATIOS_TYPES){
217+
printf("Unknown CONFIG_TYPE_ASPECT_RATIO value: '%s', using default value: %s\n",
218+
tokens[1], aspect_ratio_name[*option->uintValue]);
219+
}
220+
break;
221+
default:
222+
printf("Unknown option type '%d'\n", option->type);
223+
break;
224+
}
225+
}
226+
}
227+
else{
228+
fprintf(stderr, "Error in line %d: wrong format\n", cur_line);
229+
}
230+
}
231+
free(line);
232+
}
233+
234+
fclose(file);
235+
}
236+
237+
// Writes the config file to 'filepath'
238+
void configfile_save(const char *filepath) {
239+
FILE *file;
240+
241+
printf("Saving configuration to '%s'\n", filepath);
242+
243+
file = fopen(filepath, "w");
244+
if (file == NULL) {
245+
// error
246+
printf("Could not save\n");
247+
return;
248+
}
249+
printf("Saved !\n");
250+
251+
for (unsigned int i = 0; i < ARRAY_LEN(options); i++) {
252+
const struct ConfigOption *option = &options[i];
253+
254+
switch (option->type) {
255+
case CONFIG_TYPE_BOOL:
256+
fprintf(file, "%s = %s\n", option->name, *option->boolValue ? "true" : "false");
257+
break;
258+
case CONFIG_TYPE_UINT:
259+
fprintf(file, "%s = %u\n", option->name, *option->uintValue);
260+
break;
261+
case CONFIG_TYPE_FLOAT:
262+
fprintf(file, "%s = %f\n", option->name, *option->floatValue);
263+
break;
264+
case CONFIG_TYPE_ASPECT_RATIO:
265+
fprintf(file, "%s = %s\n", option->name, aspect_ratio_name[*option->uintValue]);
266+
break;
267+
default:
268+
assert(0); // unknown type
269+
}
270+
}
271+
272+
fclose(file);
273+
}

configfile.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#ifndef CONFIGFILE_H
2+
#define CONFIGFILE_H
3+
4+
#include <stdbool.h>
5+
6+
7+
///------ Definition of the different aspect ratios
8+
#define ASPECT_RATIOS \
9+
X(ASPECT_RATIOS_TYPE_MANUAL, "ZOOMED") \
10+
X(ASPECT_RATIOS_TYPE_STRETCHED, "STRETCHED") \
11+
X(ASPECT_RATIOS_TYPE_CROPPED, "CROPPED") \
12+
X(ASPECT_RATIOS_TYPE_SCALED, "SCALED") \
13+
X(NB_ASPECT_RATIOS_TYPES, "")
14+
15+
////------ Enumeration of the different aspect ratios ------
16+
#undef X
17+
#define X(a, b) a,
18+
typedef enum {ASPECT_RATIOS} ENUM_ASPECT_RATIOS_TYPES;
19+
20+
extern unsigned int aspect_ratio;
21+
extern unsigned int aspect_ratio_factor_percent;
22+
extern const char * aspect_ratio_name[];
23+
extern unsigned int aspect_ratio_factor_step;
24+
25+
void configfile_load(const char *filename);
26+
void configfile_save(const char *filename);
27+
28+
#endif

main.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ static char *quick_save_file_extension = "quicksave";
103103
char *mRomName = NULL;
104104
char *mRomPath = NULL;
105105
char *quick_save_file = NULL;
106-
char *console_name;
107106
char *cfg_file_default = NULL;
108107
char *cfg_file_rom = NULL;
109108
static char *cfg_file_default_name = "default_config";

0 commit comments

Comments
 (0)