Skip to content

Instantly share code, notes, and snippets.

@vgheo
Last active March 9, 2019 14:11
Show Gist options
  • Save vgheo/d58465b980b633c38c072e43a6478666 to your computer and use it in GitHub Desktop.
Save vgheo/d58465b980b633c38c072e43a6478666 to your computer and use it in GitHub Desktop.
db-config-mapping
/*
DB Model
table config
app code desc
app1 map.0.k1 EUR
app1 map.0.k2 EDC
app1 map.0.v X
app1 map.1.k1 RON
app1 map.1.k2 PLT
app1 map.1.v Y
*/
#include "map.h"
#include "splitStrng.h"
#define DB_CODE_SIZE 100
#define DB_DESC_SIZE 100
#define CODE_TOKEN_COUNT 3
#define CODE_DELIM "."
#define DB_KEY1 "k1"
#define DB_KEY2 "k2"
#define DB_VAL "v"
/* assuming DB_model_1.txt
@return if load ok
*/
int loadMap(Map* map) {
char code[DB_CODE_SIZE];
char desc[DB_DESC_SIZE];
/* esql...
SELECT code, desc
INTO $code, $desc
FROM config
WHERE app='app1'
AND code like 'map.%'
ORDER BY code
-- order not really needed..
*/
// for each (code, desc):
{
MapEntry* e;
// Tokeinze code
char codeTokens[CODE_TOKEN_COUNT][DB_CODE_SIZE];
int tokens=splitString(codeTokens, CODE_TOKEN_COUNT, DB_CODE_SIZE, code, CODE_DELIM);
if(tokens!=CODE_TOKEN_COUNT) {
// config error - abort
return 0;
}
// "map" = tokens[0] - unused
const char* entryIndexStr=codeTokens[1];
const char* field=codeTokens[2];
// convert index
int entryIndex;
if( sscanf(entryIndexStr,"%d", &entryIndex) !=1 ) {
return 0;
}
// ensure entry is allocated
while( ! (entryIndex < Map_size(map))) {
MapEntry * newEntry=Map_add();
if(newEntry==NULL) {
// error - required index cannot be allocated in map
return 0;
}
}
e=Map_getEntry(entryIndex);
// write field to map entry
if( strcmp(field, DB_KEY1)==0) {
MapEntry_setKey(0, desc);
} else if( strcmp(field, DB_KEY2)==0) {
MapEntry_setKey(1, desc);
} else if( strcmp(field, DB_VAL)==0) {
MapEntry_setValue(desc);
} else {
// error - invalid key field name
return 0;
}
} // end for
// if needed, could also verify that there are no null keys
}
/*
DB Model - Variant 2
table config
app code desc
app1 map.0 EUR:EDC:X
app1 map.1 RON:PLT:Y
*/
#include "splitStrng.h"
#define DB_CODE_SIZE 100
#define DB_DESC_SIZE 100
#define DB_CODE "map"
#define DB_DESC_DELIM ":"
#define DB_DESC_FIELD_COUNT 3
/**
@return if load ok
*/
int loadMap(Map* map) {
char code[DB_CODE_SIZE];
char desc[DB_DESC_SIZE];
Map_init(map);
/* esql...
SELECT code, desc
INTO $code, $desc
FROM config
WHERE app='app1'
AND code like 'map.%'
*/
// for each (code, desc):
{
// add entry
MapEntry* e = Map_add(map);
char descFields[DB_DESC_FIELD_COUNT][DB_DESC_SIZE];
int tokens=splitString(codeFields, DB_DESC_FIELD_COUNT, DB_DESC_SIZE, desc, DB_DESC_DELIM);
if(tokens!=DB_DESC_FIELD_COUNT) {
// config error - abort
return 0;
}
MapEntry_setKey(0, tokens[0]);
MapEntry_setKey(1, tokens[1]);
MapEntry_setValue(tokens[2]);
}
}
//---- map.h ------
#include <stddef.h>
#define MAX_FIELD_LEN 10
#define FIELD_SIZE (MAX_FIELD_LEN+1)
#define KEY_COUNT 2
#define MAP_SIZE=100;
typedef struct {
char key[KEY_COUNT][FIELD_SIZE];
char value[FIELD_SIZE];
} MapEntry;
typedef struct {
size_t entryCount;
MapEntry entries[MAP_SIZE];
} Map;
void MapEntry_init(MapEntry* e);
void MapEntry_setKey(MapEntry* e, size_t idx, const char* k);
void MapEntry_setValue(MapEntry* e, size_t idx, const char* v);
void Map_init(Map* map);
size_t Map_size(Map* map);
MapEntry* Map_add();
MapEntry* Map_getEntry(Map map, size_t idx);
const char* Map_get(Map* map, const char* key[]);
//-------- map.c
void MapEntry_init(MapEntry* e) {
memset(e, sizeof(MapEntry), 0);
}
void MapEntry_setKey(MapEntry* e, size_t idx, const char* k) {
strncpy(e->key[idx], desc, FIELD_SIZE)
// truncate to FIELD_LEN
e->key[idx][MAX_FIELD_LEN]=0;
}
void MapEntry_setValue(MapEntry* e, size_t idx, const char* v) {
strncpy(e->value, desc, FIELD_SIZE)
// truncate to FIELD_LEN
e->value[MAX_FIELD_LEN]=0;
}
void Map_init(Map* map) {
map->entryCount=0;
memset(map->entries, sizeof(map->entries), 0);
}
size_t Map_size(Map* map) {
return map->entryCount;
}
MapEntry* Map_add() {
if(map->entryCount<MAP_SIZE) {
map->entryCount++;
// initialize entry
MapEntry* e=&map->entries[map->entryCount-1];
MapEntry_init(e);
return e;
} else {
return NULL;
}
}
MapEntry* Map_getEntry(Map map, size_t idx) {
return (idx<map->entryCount) ? &map[idx] : NULL;
}
/**
@returns the vaue mapped to key if exists, NULL otherwise
*/
const char* Map_get(Map* map, const char* key[]) {
for( size_t idx=0; idx<map->entryCount; idx++) {
int match=1;
for(kIdx=0; kIdx<KEY_COUNT && match; kIdx++) {
match = match && strcmp(key[kIdx], map->entries[idx].key[kIdx])==0);
}
if(match) {
return map->entries[idx].value;
}
}
return NULL;
}
#include <string.h>
/**
@param tokens
@param maxTokens maximum tokens that can be stored in the tokens array
@oaram tokenSize allocated size of each element in the tokens array
@param str string to be tokenized
@param delims string with delimiter characters that define the tokenization
@return resulting token count
@note If str contains more tokens than maxTokens, only maxTokens tokens are returned.
@note If parsed tokens is longer than tokenSize, truncation will occur at tokenSize-1 maximum length.
ref: http://www.cplusplus.com/reference/cstring/strtok/
*/
int splitString(char *tokens[], size_t maxTokens, size_t tokenSize, const char* str, const char* delims) {
// copy original string into parse buffer
size_t strSize=strlen(str)+1;
char * buffer = malloc(strSize);
memcpy(buffer, str, strSize);
// parse using buffer
int idx=0;
char* newToken=strtok(buffer, delims);
while( idx < maxTokens && token!=NULL) {
strncpy(tokens[idx], newToken, tokenSize);
// ensure terminator
tokens[idx][tokenSize-1]=0;
token=strtok(NULL, delims);
idx++
}
free(buffer);
return idx
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment