Skip to content

Commit f318ce8

Browse files
committed
added configfile.c and .h, handling config files
1 parent 005e050 commit f318ce8

File tree

9 files changed

+353
-27
lines changed

9 files changed

+353
-27
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ endif
140140
ifeq "$(USE_FRONTEND)" "1"
141141

142142
# common
143-
OBJS += platform/common/main.o platform/common/emu.o \
143+
OBJS += platform/common/main.o platform/common/configfile.o platform/common/emu.o \
144144
platform/common/menu_pico.o platform/common/config_file.o
145145

146146
# libpicofe

platform/common/configfile.c

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

platform/common/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

platform/common/emu.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "emu.h"
2424
#include "input_pico.h"
2525
#include "menu_pico.h"
26+
#include "configfile.h"
2627
#include "config_file.h"
2728

2829
#include <pico/pico_int.h>
@@ -1261,6 +1262,9 @@ static void run_events_ui(unsigned int which)
12611262
if (fp == NULL) {
12621263
printf("Failed to run command %s\n", shell_cmd);
12631264
}
1265+
1266+
// Save config file
1267+
configfile_save(cfg_file_rom);
12641268
}
12651269
if (which & PEV_AR_FACT_DOWN)
12661270
{
@@ -1284,6 +1288,9 @@ static void run_events_ui(unsigned int which)
12841288
fp = popen(shell_cmd, "r");
12851289
if (fp == NULL) {
12861290
printf("Failed to run command %s\n", shell_cmd);
1291+
1292+
// Save config file
1293+
configfile_save(cfg_file_rom);
12871294
}
12881295

12891296
}
@@ -1309,6 +1316,9 @@ static void run_events_ui(unsigned int which)
13091316
if (fp == NULL) {
13101317
printf("Failed to run command %s\n", shell_cmd);
13111318
}
1319+
1320+
// Save config file
1321+
configfile_save(cfg_file_rom);
13121322
}
13131323
if (which & (PEV_SSLOT_PREV|PEV_SSLOT_NEXT))
13141324
{

platform/common/emu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ extern char *prog_name;
9393
extern char *mRomName;
9494
extern char *mRomPath;
9595
extern char *quick_save_file;
96+
extern char *cfg_file_rom;
9697

9798
#define PICO_PEN_ADJUST_X 4
9899
#define PICO_PEN_ADJUST_Y 2

0 commit comments

Comments
 (0)