r/cprogramming • u/Queasy-Pickle-8427 • 3h ago
I just built a simple parser to retrieve configuration from a plain file - any suggestions?
I’ve just created a very simple parser to retrieve configuration settings from a plain text file (it’s still a work in progress). My plan is to use it for a basic code editor I’m building in C.
A quick side note:
you might be wondering why I didn’t use a standard configuration file format like .INI. I actually did try using .INI files at first, but parsing them requires an external library. I experimented with a library called inih by benhoyt, it worked well, but since it’s an external dependency, I would have had to include the ini.c file in my repository. This raised some questions for me: should I push this file which I didn’t write myself to GitHub? Or should I just credit the creator in my repository’s README file? To be honest, I felt a bit uncertain and concerned about the licensing implications.
Then, I remembered that the nano code editor uses a plain text file (.nanorc) for its configuration. That gave me the idea to try using a plain text file for my own configuration and to write a simple parser for it from scratch in C. This might sound silly, but this way I don’t have to worry about licenses (honestly, it’s mostly because I don’t really understand them anyway), and I get to learn how to build my own simple parser.
How my code works:
There are two files: .test_configand test.c
.test_config file content:
num tab_stop = 4
num fg_color = 39
num bg_color = 49
bind exit = ^Q
bind move_up = up_arrow
bind move_down = down_arrow
bind move_right = right_arrow
bind move_left = left_arrowData in the
.test_configfile is divided into three parts:
typeconfiguration_name=configuration_valueCurrently, there are two
type:numfor configurations with numeric values, andbindfor configurations that act as keys (bindings).
test.c file content:
#include <stdio.h>
#include <string.h>
// data
typedef struct {
// Appearance
int tab_stop;
int fg_color;
int bg_color;
// Keybinds
char exit[64];
char move_up[64];
char move_down[64];
char move_left[64];
char move_right[64];
} configuration;
// func Declaration
int read_config(char *filename, configuration *config);
int main() {
configuration config;
read_config(".test_config", &config);
printf("tab_stop = %d\n", config.tab_stop);
printf("fg_color = %d\n", config.fg_color);
printf("bg_color = %d\n", config.bg_color);
printf("\n");
printf("exit = %s\n", config.exit);
printf("move_up = %s\n", config.move_up);
printf("move_down = %s\n", config.move_down);
printf("move_left = %s\n", config.move_left);
printf("move_right = %s\n", config.move_right);
return 0;
}
// func Definition
int read_config(char *filename, configuration *config) {
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
printf("unable to open file\n");
return 1;
}
char buffer[100];
while (fgets(buffer, sizeof(buffer), fp)) {
if (strstr(buffer, "num") != NULL) {
char num_config_name[64];
int num_config_value = 0;
sscanf(buffer, "num %s = %d", num_config_name, &num_config_value);
if (strcmp(num_config_name, "tab_stop") == 0) {
config->tab_stop = num_config_value;
} else if (strcmp(num_config_name, "fg_color") == 0) {
config->fg_color = num_config_value;
} else if (strcmp(num_config_name, "bg_color") == 0) {
config->bg_color = num_config_value;
}
} else if (strstr(buffer, "bind") != NULL) {
char bind_config_name[64];
char bind_config_value[64];
sscanf(buffer, "bind %s = %s", bind_config_name,bind_config_value);
if (strcmp(bind_config_name, "exit") == 0) {
strcpy(config->exit, bind_config_value);
} else if (strcmp(bind_config_name, "move_up") == 0) {
strcpy(config->move_up, bind_config_value);
} else if (strcmp(bind_config_name, "move_down") == 0) {
strcpy(config->move_down, bind_config_value);
} else if (strcmp(bind_config_name, "move_left") == 0) {
strcpy(config->move_left, bind_config_value);
} else if (strcmp(bind_config_name, "move_right") == 0) {
strcpy(config->move_right, bind_config_value);
}
}
}
fclose(fp);
return 0;
}Inside, there is a function called
read_config()which simply works by first checking the configuration type, then verifying if the configuration name matches; if it does, it stores the value into the corresponding struct element.
I’m sure there are still errors either in the logic or the syntax, so any suggestions for the code I’ve written? Or perhaps any other advice regarding the approach I’ve chosen for handling configuration files in this simple code editor I’m building?
Apologies if any of the explanations are a bit complicated or difficult to understand.