Skip to content

Instantly share code, notes, and snippets.

@gsora
Created April 12, 2020 17:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gsora/9454855e5958f0cb83d73856ce51d3c9 to your computer and use it in GitHub Desktop.
Save gsora/9454855e5958f0cb83d73856ce51d3c9 to your computer and use it in GitHub Desktop.
extremely stupid C key-value store
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define PREAMBLE_DELIM "#preamble#"
#define PREAMBLE_DELIM_LEN 11
#define SPLIT_TOKEN "\n"
#define T PREAMBLE_DELIM"\n""a:int:1\nb:string:31\nc:bool:1\n"PREAMBLE_DELIM"\na:1234\nb:ciaociao ciao come va la vita?\n"
#define FIELD_SZ 128
#define PREAMBLE_LINE_FMT "%[^:]:%[^:]:%lli\n"
#define KEY_FMT "%[^:]:"
#define STRING_FMT "%[^:]:%[^:]"
#define INTEGER_FMT "%[^:]:%lli"
#define BOOLEAN_FMT "%[^:]:%d"
enum entry_type {
Integer = 10,
Boolean = 20,
String = 30,
};
typedef enum entry_type entry_type;
typedef struct {
char* name;
entry_type* type;
long long *length;
} preamble_token;
typedef struct {
long long length;
long long skip_lines;
preamble_token **tokens;
} preamble;
void preamble_free(preamble *p) {
long long i = 0;
for(i = 0; i < p->length; i++) {
preamble_token *pp = p->tokens[i];
free(pp->name);
free(pp->type);
free(pp->length);
free(p->tokens[i]);
}
free(p->tokens);
free(p);
}
entry_type* string_to_type(const char* ts) {
entry_type t = 0;
if (strcmp(ts, "int") == 0) {
t = Integer;
} else if (strcmp(ts, "string") == 0) {
t = String;
} else {
t = Boolean;
}
entry_type *tt = malloc(1*sizeof(entry_type));
tt = &t;
return tt;
}
preamble* parse_preamble(const char* input) {
char *data = malloc(strlen(input) * sizeof(char));
memcpy(data, input, strlen(input));
preamble *p = malloc(1*sizeof(preamble));
p->length = 0;
char* token = strtok((char *)data, SPLIT_TOKEN);
short preamble_tags = 2;
long long skip_lines = 0;
while (token != NULL) {
skip_lines++;
if (strncmp(PREAMBLE_DELIM, token, PREAMBLE_DELIM_LEN) == 0) {
preamble_tags--;
if(preamble_tags == 0) {
free(data);
p->skip_lines = skip_lines;
return p;
}
token = strtok(NULL,SPLIT_TOKEN);
continue;
} else if(preamble_tags == 2) {
printf("preamble does not start with delimiter, bailing out\n");
free(data);
return NULL;
}
if (p->length == 0) {
p->tokens = calloc(1, sizeof(preamble_token*));
} else {
p->tokens = realloc(p->tokens, p->length*sizeof(preamble_token*));
}
preamble_token *t = malloc(1*sizeof(preamble_token));
t->name = malloc(FIELD_SZ*sizeof(char));
t->type = malloc(1*sizeof(entry_type));
t->length = malloc(1*sizeof(long long));
char type_string[FIELD_SZ];
sscanf(token, PREAMBLE_LINE_FMT, t->name, type_string, t->length);
t->name = realloc(t->name, strlen(t->name)*sizeof(char));
memcpy(t->type, string_to_type(type_string), sizeof(entry_type));
p->tokens[p->length++] = t;
token = strtok(NULL, SPLIT_TOKEN);
}
if (preamble_tags != 0) {
printf("failed to process preamble, encountered %d tags\n", preamble_tags);
preamble_free(p);
free(data);
return NULL;
}
free(data);
return NULL;
}
void* get_field(const char* input, preamble* preamble, const char* key, size_t key_len) {
char *data = malloc(strlen(input) * sizeof(char));
memcpy(data, input, strlen(input));
void* buffer = NULL;
long long length = 0;
char fmt[FIELD_SZ];
long long i = 0;
for (i = 0; i < preamble->length; i++) {
preamble_token *pt = preamble->tokens[i];
if (strncmp(pt->name, key, key_len) == 0) {
switch (*pt->type) {
case Integer:
buffer = malloc(1*sizeof(long long));
strcpy(fmt, INTEGER_FMT);
length = 1;
break;
case String:
buffer = malloc(1*sizeof(pt->length));
length = *pt->length;
strcpy(fmt, STRING_FMT);
break;
case Boolean:
buffer = malloc(1*sizeof(int));
strcpy(fmt, BOOLEAN_FMT);
length = 1;
break;
default:
printf("undefined type %u\n", *pt->type);
break;
}
}
}
char* token = strtok((char *)data, SPLIT_TOKEN);
long long iter = 0;
while (token != NULL) {
if (iter++ < preamble->skip_lines) {
token = strtok(NULL, SPLIT_TOKEN);
continue;
}
char read_key[FIELD_SZ];
sscanf(token, KEY_FMT, read_key);
if(strncmp(read_key, key, key_len) == 0) {
sscanf(token, fmt, read_key, buffer);
free(data);
return buffer;
}
token = strtok(NULL, SPLIT_TOKEN);
}
free(data);
return NULL;
}
int main(void) {
char *data = T;
preamble* p = parse_preamble(data);
if (p == NULL) { return 1; }
printf("lines to skip: %lli\n", p->skip_lines);
long long i = 0;
for(i = 0; i < p->length; i++) {
preamble_token *pp = p->tokens[i];
printf("name %s, type %u, length %lli, pointer %p\n", pp->name, *pp->type, *pp->length, pp);
}
printf("getting field b\n");
char* c = (char *)get_field(data, p, "b", 1);
printf("field b: %s\n", c);
printf("getting nonexistant field\n");
char* cc = (char *)get_field(data, p, "asd", 3);
printf("nonexistant field: %s\n", cc);
preamble_free(p);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment