aboutsummaryrefslogtreecommitdiff
path: root/src/storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/storage.c')
-rw-r--r--src/storage.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/src/storage.c b/src/storage.c
new file mode 100644
index 0000000..f934c4f
--- /dev/null
+++ b/src/storage.c
@@ -0,0 +1,160 @@
+#include "db.h"
+
+
+row *newRow(const char path[MAXPATH]){
+ row *nr = malloc(sizeof(row));
+ memcpy(nr->path, path, MAXPATH);
+ memcpy(nr->tags, "\0", MAXTAGS);
+ nr->numTags = 0;
+ nr->lenTags = 0;
+
+ return nr;
+}
+
+// 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
+static void split(const char *src, char sep, char ***arr, int *len){
+ int slen = 0, ai = 0, wnum = 0, wlen = 0;
+
+ while(src[slen] != '\0'){
+ if(src[slen] == sep){
+ ++wnum;
+ }
+ ++slen;
+ }
+ if(slen != 0 && src[slen-1] != sep){
+ ++wnum;
+ }
+ ++slen;
+
+ *arr = calloc((wnum+1), sizeof(char*));
+ for(int i = 0; i < slen; ++i){
+ if(src[i] == sep || src[i] == '\0'){
+ (*arr)[ai] = calloc(wlen+1, sizeof(char));
+ for(int j = i-wlen, k = 0; j < i; ++j, ++k){
+ (*arr)[ai][k] = src[j];
+ }
+ ++ai;
+ wlen = 0;
+ }else{
+ ++wlen;
+ }
+ }
+ *len = wnum;
+}
+
+static void swapWords(char ***arr, int a, int b){
+ char *tmp = (*arr)[a];
+ (*arr)[a] = (*arr)[b];
+ (*arr)[b] = tmp;
+}
+
+static 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. Nothing is done if the tag is already in the tags
+void insertTag(row *r, char *tag){
+ int l, ltag = len(tag);
+ if(ltag == 0){
+ return;
+ }
+
+ tag = normalizeTag(tag);
+
+ // Dump tags into array of strings and add tag
+ char **arr, **tmp;
+ 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 tagnum = 0;
+ for(int i = 0; i < l; ++i){
+ int j = 0;
+ while(arr[i][j] != '\0'){
+ r->tags[tagnum] = arr[i][j];
+ ++j;
+ ++tagnum;
+ }
+ r->tags[tagnum++] = ';';
+ }
+ r->tags[tagnum] = '\0';
+ r->numTags = l;
+ r->lenTags = tagnum;
+}
+
+// Remove a tag from the tags array in the row r
+// Nothing is done if the tag isnt in the tags
+void removeTag(row *r, char *tag){
+ int l, ltag = len(tag);
+ if(ltag == 0){
+ return;
+ }
+
+ tag = normalizeTag(tag);
+
+ // Dump tags into array of strings
+ char **arr;
+ split(r->tags, ';', &arr, &l);
+
+ // Search for tag and remove it
+ for(int i = 0; i <= l; ++i){
+ if(sameStr(arr[i], tag)){
+ for(int j = i; j < l; ++j){
+ arr[j] = arr[j+1];
+ }
+ --l;
+ break;
+ }
+ }
+
+ // Insert tags back into tags member of row structure with the ';' separator in between them
+ int tagnum = 0;
+ for(int i = 0; i < l; ++i){
+ int j = 0;
+ while(arr[i][j] != '\0'){
+ r->tags[tagnum] = arr[i][j];
+ ++j;
+ ++tagnum;
+ }
+ r->tags[tagnum++] = ';';
+ }
+ r->tags[tagnum] = '\0';
+ r->numTags = l;
+ r->lenTags = tagnum;
+} \ No newline at end of file