Skip to content

Instantly share code, notes, and snippets.

@xor-gate
Last active January 17, 2024 11:17
Show Gist options
  • Save xor-gate/e627f3578444688573a9f2d719deec93 to your computer and use it in GitHub Desktop.
Save xor-gate/e627f3578444688573a9f2d719deec93 to your computer and use it in GitHub Desktop.
ini-parser-xmacros
#include "ConfigFormat.h"
#include <string.h>
const struct ConfigFormatField *ConfigFormatGetFieldByName(const struct ConfigFormat *Format, const char *Name, void *Structure)
{
static struct ConfigFormatField Field;
for (size_t n = 0; n < Format->num_members; n++) {
if (strcmp(Name, Format->names[n]) != 0) {
continue;
}
Field.offset = Format->offsets[n];
Field.size = Format->sizes[n];
Field.type = Format->types[n];
Field.name = Format->names[n];
Field.value = Structure+Field.offset;
return &Field;
}
return NULL;
}
#ifndef CONFIG_FORMAT_H__
#define CONFIG_FORMAT_H__
#include <stdlib.h>
enum ConfigFormatFieldTypes
{
CONFIG_FORMAT_FIELD_TYPE_U32,
CONFIG_FORMAT_FIELD_TYPE_STR
};
struct ConfigFormat {
char const *struct_name;
size_t num_members;
size_t struct_size;
size_t packed_size;
size_t *offsets;
size_t *sizes;
enum ConfigFormatFieldTypes *types;
char const **names;
};
struct ConfigFormatField {
size_t offset;
size_t size;
enum ConfigFormatFieldTypes type;
const char *name;
void *value;
};
const struct ConfigFormatField *ConfigFormatGetFieldByName(const struct ConfigFormat *Format, const char *Name, void *Structure);
#endif // CONFIG_FORMAT_H__
// Original from https://natecraun.net/articles/struct-iteration-through-abuse-of-the-c-preprocessor.html
#include <stdint.h>
#include "ConfigFormat.h"
/* Error Checking */
#ifndef CONFIG_STRUCT_NAME
#error "Did not define CONFIG_STRUCT_NAME before including ConfigFormat.h"
#endif
#ifndef CONFIG_STRUCT_FIELDS
#error "Did not define CONFIG_STRUCT_FIELDS before including ConfigFormat.h"
#endif
#define STR_NOEXPAND(A) #A
#define STR(A) STR_NOEXPAND(A)
#define CAT_NOEXPAND(A, B) A ## B
#define CAT(A, B) CAT_NOEXPAND(A, B)
struct CONFIG_STRUCT_NAME {
#define X(L, R) L R;
CONFIG_STRUCT_FIELDS
#undef X
};
static const struct ConfigFormat CAT(CONFIG_STRUCT_NAME, Format) = {
.struct_name = STR(CONFIG_STRUCT_NAME),
.num_members = (
#define X(L, R) 1 +
CONFIG_STRUCT_FIELDS
#undef X
0),
.struct_size = sizeof(struct CONFIG_STRUCT_NAME),
.packed_size = (
#define X(L, R) sizeof(L) +
CONFIG_STRUCT_FIELDS
#undef X
0),
.offsets = (size_t[]){
#define X(L, R) offsetof(struct CONFIG_STRUCT_NAME, R),
CONFIG_STRUCT_FIELDS
#undef X
},
.sizes = (size_t []){
#define X(L, R) sizeof(L),
CONFIG_STRUCT_FIELDS
#undef X
},
.types = (enum ConfigFormatFieldTypes []){
#define X(L, R) CONFIG_FORMAT_FIELD_TYPE_U32,
CONFIG_STRUCT_FIELDS
#undef X
},
.names = (char const *[]){
#define X(L, R) #R,
CONFIG_STRUCT_FIELDS
#undef X
},
};
#undef CONFIG_STRUCT_FIELDS
#undef CONFIG_STRUCT_NAME
#undef STR_NOEXPAND
#undef STR
#undef CAT_NOEXPAND
#undef CAT
#include "ConfigIni.h"
#include "ConfigFormat.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define CONFIG_INI_MAX_KEY_LEN 64
#define CONFIG_INI_MAX_VALUE_LEN 128
static void ConfigIniParseKeyValue(void *Structure, const struct ConfigFormat *Format, const char *Key, const char *Value)
{
const struct ConfigFormatField *Field = ConfigFormatGetFieldByName(Format, Key, Structure);
printf("Parsed key=\"%s\", value=\"%s\"\n", Key, Value);
if (!Field) {
return;
}
printf("Found matching field in struct\n");
}
void ConfigIniParse(void *Structure, const struct ConfigFormat *Format, const char *Data)
{
const char *Line = Data;
while (*Line) {
char Key[CONFIG_INI_MAX_KEY_LEN];
char Value[CONFIG_INI_MAX_VALUE_LEN];
size_t i = 0;
// Parse Key
while (*Line && *Line != '=') {
if (i < CONFIG_INI_MAX_KEY_LEN - 1) {
Key[i++] = *Line;
}
Line++;
}
Key[i] = '\0';
if (*Line == '=') {
i = 0;
Line++; // Move past '='
// Parse Value
while (*Line && *Line != '\n') {
if (i < CONFIG_INI_MAX_VALUE_LEN - 1) {
Value[i++] = *Line;
}
Line++;
}
Value[i] = '\0';
ConfigIniParseKeyValue(Structure, Format, Key, Value);
}
// Move to the next Line
while (*Line && *Line != '\n') {
Line++;
}
if (*Line == '\n') {
Line++; // Move past '\n'
}
}
}
#ifndef CONFIG_INI_H__
#define CONFIG_INI_H__
#include "ConfigFormat.h"
void ConfigIniParse(void *Structure, const struct ConfigFormat *Format, const char *Data);
#endif // CONFIG_INI_H__
#ifndef CONFIG_STRUCTS_H__
#define CONFIG_STRUCTS_H__
#define CONFIG_STRUCT_NAME ConfigCamera
#define CONFIG_STRUCT_FIELDS \
X(uint32_t, Version)
#include "ConfigFormatGen.h"
#endif // CONFIG_STRUCTS_H__
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "ConfigFormat.h"
#include "ConfigStructs.h"
#include "ConfigIni.h"
void
print_buffer(unsigned char *buffer, size_t size)
{
for (size_t j = 0; j < size; j++) {
printf(" %02x", buffer[j]);
}
}
size_t
struct_pack(struct ConfigFormat *fmt, void *structure, unsigned char *buffer)
{
size_t pos = 0;
for (size_t i = 0; i < fmt->num_members; i++) {
memcpy(buffer+pos, ((unsigned char*)structure)+fmt->offsets[i], fmt->sizes[i]);
pos += fmt->sizes[i];
}
return pos;
}
size_t
struct_unpack(struct ConfigFormat *fmt, unsigned char *buffer, void *structure)
{
size_t pos = 0;
for (size_t i = 0; i < fmt->num_members; i++) {
memcpy(((unsigned char*)structure)+fmt->offsets[i], buffer+pos, fmt->sizes[i]);
pos += fmt->sizes[i];
}
return pos;
}
void
struct_print(struct ConfigFormat *fmt, void *structure)
{
printf("%s:\n", fmt->struct_name);
for (size_t i = 0; i < fmt->num_members; i++) {
printf("\t%s: %zu %zu =", fmt->names[i], fmt->offsets[i], fmt->sizes[i]);
print_buffer(((unsigned char*)structure)+fmt->offsets[i], fmt->sizes[i]);
printf("\n");
}
}
int
main(void)
{
const char *Data = "Version=2";
struct ConfigCamera cc = {.Version = 1};
struct_print(&ConfigCameraFormat, &cc);
ConfigIniParse(&cc, &ConfigCameraFormat, Data);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment