1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
#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
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;
}
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
// 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;
}
|