diff options
| author | Soikk | 2022-04-27 22:23:59 +0200 |
|---|---|---|
| committer | Soikk | 2022-04-27 22:23:59 +0200 |
| commit | 8a2981d9137357d4b2c86e8037e4f2ca9cea5578 (patch) | |
| tree | 8410987af957afc9ced113c521c07cba92b3d302 /storage.c | |
| download | soikk-DB-8a2981d9137357d4b2c86e8037e4f2ca9cea5578.tar.xz soikk-DB-8a2981d9137357d4b2c86e8037e4f2ca9cea5578.tar.zst | |
Initial commit
Diffstat (limited to 'storage.c')
| -rw-r--r-- | storage.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/storage.c b/storage.c new file mode 100644 index 0000000..043eeae --- /dev/null +++ b/storage.c @@ -0,0 +1,122 @@ +#include "db.h" + + + + +// Splits src into words based on a separator character (sep) and stores them in arr, and the length in len. Inspired by https://github.com/joshdk/tag/blob/master/src/dsv.c's split +void split(const char *src, char sep, char ***arr, int *len){ + int i = 0, asize = 1, ai = 0, wsize = 1, wi = 0; + char c = 0; + + (*arr) = malloc(asize*sizeof(char*)); + (*arr)[ai] = malloc(wsize*sizeof(char)); + + while((c = src[i]) != '\0'){ + // If there's a new word (new array index) reallocate the array and allocate space for it + if(wi == 0){ + char **tmp; + if((tmp = realloc((*arr), (asize+ai)*sizeof(char*))) != NULL){ + *arr = tmp; + tmp = NULL; + }else{ + fprintf(stderr, "Error reallocating array (split)"); + exit(EXIT_FAILURE); + } + (*arr)[ai] = malloc(wsize*sizeof(char)); + } + // Allocate space for a new character in a word + char *tmp; + if((tmp = realloc((*arr)[ai], (wsize+wi)*sizeof(char))) != NULL){ + strcpy(tmp, (*arr)[ai]); + (*arr)[ai] = tmp; + tmp = NULL; + }else{ + fprintf(stderr, "Error reallocating word (split)"); + exit(EXIT_FAILURE); + } + // If the character is a separator, terminate the string and increment the array index; if not, assign the character and increment the word index + if(c == sep){ + (*arr)[ai][wi] = '\0'; + wi = 0; + ++ai; + }else{ + (*arr)[ai][wi] = c; + ++wi; + } + ++i; + } + if(src[i-1] != sep){ + (*arr)[ai][wi] = '\0'; + ++ai; + } + (*arr)[ai] = NULL; + *len = ai; +} + +void swapWords(char ***arr, int a, int b){ + char *tmp = (*arr)[a]; + (*arr)[a] = (*arr)[b]; + (*arr)[b] = tmp; +} + +char *normalizeTag(char *tag){ + uint16_t l = len(tag); + char *ntag = calloc(l+1, sizeof(char)); + for(int i = 0; i < l; ++i){ + ntag[i] = tolower(tag[i]); + } + return ntag; +} + +// Adds a tag in the tags array in the row r, sorted by natural string comparison with strnatcmp +// We assume that when adding a tag all other tags are already sorted +void insertTag(row *r, char *tag){ + + tag = normalizeTag(tag); + + // Dump tags into array of strings and add tag + char **arr, **tmp; + int l; + split(r->tags, ';', &arr, &l); + if((tmp = realloc(arr, (l+1)*sizeof(char*))) != NULL){ + arr = tmp; + tmp = NULL; + }else{ + fprintf(stderr, "Error reallocating array (insertTag)"); + exit(EXIT_FAILURE); + } + arr[l] = malloc((len(tag)+1)*sizeof(char)); + strcpy(arr[l], tag); + + // Sort tag by natural string comparison, starting from the last element (the new tag) + for(int i = l; i > 0; --i){ + switch(strnatcmp(arr[i-1], arr[i])){ + case 1: + // arr[i-1] is higher than arr[i]; swap them + swapWords(&arr, i, i-1); + break; + case -1: + // arr[i-1] is lower than arr[i]; exit loop + i = 0; + break; + case 0: + // The tag already exists, no need to alter anything + free(arr); + return; + } + } + ++l; // Succesfully added new tag + + // Insert tags back into tags member of row structure with the ';' separator in between them + int g = 0; + for(int i = 0; i < l; ++i){ + int j = 0; + while(arr[i][j] != '\0'){ + r->tags[g] = arr[i][j]; + ++j; + ++g; + } + r->tags[g++] = ';'; + } + r->tags[g] = '\0'; +}
\ No newline at end of file |
