1 /* sdb - MIT - Copyright 2011-2016 - pancake */
2 
3 #include "sdb.h"
4 
sdb_ns_lock(Sdb * s,int lock,int depth)5 SDB_API void sdb_ns_lock(Sdb *s, int lock, int depth) {
6 	SdbListIter *it;
7 	SdbNs *ns;
8 	s->ns_lock = lock;
9 	if (depth) { // handles -1 as infinite
10 		ls_foreach (s->ns, it, ns) {
11 			sdb_ns_lock (ns->sdb, lock, depth-1);
12 		}
13 	}
14 }
15 
in_list(SdbList * list,void * item)16 static int in_list(SdbList *list, void *item) {
17 	SdbNs *ns;
18 	SdbListIter *it;
19 	if (list && item)
20 	ls_foreach (list, it, ns) {
21 		if (item == ns) {
22 			return 1;
23 		}
24 	}
25 	return 0;
26 }
27 
ns_free(Sdb * s,SdbList * list)28 static void ns_free(Sdb *s, SdbList *list) {
29 	SdbListIter next;
30 	SdbListIter *it;
31 	int deleted;
32 	SdbNs *ns;
33 	if (!list || !s) {
34 		return;
35 	}
36 	// TODO: Implement and use ls_foreach_safe
37 	if (in_list (list, s)) {
38 		return;
39 	}
40 	ls_append (list, s);
41 	ls_foreach (s->ns, it, ns) {
42 		deleted = 0;
43 		next.n = it->n;
44 		if (!in_list (list, ns)) {
45 			ls_delete (s->ns, it); // free (it)
46 			free (ns->name);
47 			ns->name = NULL;
48 			deleted = 1;
49 			if (ns->sdb) {
50 				if (sdb_free (ns->sdb)) {
51 					ns->sdb = NULL;
52 					free (ns->name);
53 					ns->name = NULL;
54 				}
55 			}
56 			ls_append (list, ns);
57 			ls_append (list, ns->sdb);
58 			ns_free (ns->sdb, list);
59 			sdb_free (ns->sdb);
60 		}
61 		if (!deleted) {
62 			sdb_free (ns->sdb);
63 			s->ns->free = NULL;
64 			ls_delete (s->ns, it); // free (it)
65 		}
66 		free (ns);
67 		it = &next;
68 	}
69 	ls_free (s->ns);
70 	s->ns = NULL;
71 }
72 
sdb_ns_free(Sdb * s)73 SDB_API void sdb_ns_free(Sdb *s) {
74 	SdbList *list;
75 	if (!s) {
76 		return;
77 	}
78 	list = ls_new ();
79 	list->free = NULL;
80 	ns_free (s, list);
81 	ls_free (list);
82 	ls_free (s->ns);
83 	s->ns = NULL;
84 }
85 
sdb_ns_new(Sdb * s,const char * name,ut32 hash)86 static SdbNs *sdb_ns_new (Sdb *s, const char *name, ut32 hash) {
87 	char dir[SDB_MAX_PATH];
88 	SdbNs *ns;
89 	if (s->dir && *s->dir && name && *name) {
90 		int dir_len = strlen (s->dir);
91 		int name_len = strlen (name);
92 		if ((dir_len+name_len+3)>SDB_MAX_PATH) {
93 			return NULL;
94 		}
95 		memcpy (dir, s->dir, dir_len);
96 		memcpy (dir + dir_len, ".", 1);
97 		memcpy (dir + dir_len + 1, name, name_len + 1);
98 	} else {
99 		dir[0] = 0;
100 	}
101 	ns = malloc (sizeof (SdbNs));
102 	if (!ns) {
103 		return NULL;
104 	}
105 	ns->hash = hash;
106 	ns->name = name? strdup (name): NULL;
107 	//ns->sdb = sdb_new (dir, ns->name, 0);
108 	ns->sdb = sdb_new0 ();
109 	// TODO: generate path
110 
111 	if (ns->sdb) {
112 		free (ns->sdb->path);
113 		ns->sdb->path = NULL;
114 		if (*dir) {
115 			ns->sdb->path = strdup (dir);
116 		}
117 		free (ns->sdb->name);
118 		if (name && *name) {
119 			ns->sdb->name = strdup (name);
120 		}
121 	} else {
122 		free (ns->name);
123 		free (ns);
124 		ns = NULL;
125 	}
126 	return ns;
127 }
128 
sdb_ns_unset(Sdb * s,const char * name,Sdb * r)129 SDB_API bool sdb_ns_unset (Sdb *s, const char *name, Sdb *r) {
130 	SdbNs *ns;
131 	SdbListIter *it;
132 	if (s && (name || r)) {
133 		ls_foreach (s->ns, it, ns) {
134 			if (name && (!strcmp (name, ns->name))) {
135 				ls_delete (s->ns, it);
136 				return true;
137 			}
138 			if (r && ns->sdb == r) {
139 				ls_delete (s->ns, it);
140 				return true;
141 			}
142 		}
143 	}
144 	return false;
145 }
146 
sdb_ns_set(Sdb * s,const char * name,Sdb * r)147 SDB_API int sdb_ns_set(Sdb *s, const char *name, Sdb *r) {
148 	SdbNs *ns;
149 	SdbListIter *it;
150 	ut32 hash = sdb_hash (name);
151 	if (!s || !r || !name) {
152 		return 0;
153 	}
154 	ls_foreach (s->ns, it, ns) {
155 		if (ns->hash == hash) {
156 			if (ns->sdb == r) {
157 				return 0;
158 			}
159 			sdb_free (ns->sdb);
160 			r->refs++; // sdb_ref / sdb_unref //
161 			ns->sdb = r;
162 			return 1;
163 		}
164 	}
165 	if (s->ns_lock) {
166 		return 0;
167 	}
168 	ns = R_NEW (SdbNs);
169 	ns->name = strdup (name);
170 	ns->hash = hash;
171 	ns->sdb = r;
172 	r->refs++;
173 	ls_append (s->ns, ns);
174 	return 1;
175 }
176 
sdb_ns(Sdb * s,const char * name,int create)177 SDB_API Sdb *sdb_ns(Sdb *s, const char *name, int create) {
178 	SdbListIter *it;
179 	SdbNs *ns;
180 	ut32 hash;
181 	if (!s || !name || !*name) {
182 		return NULL;
183 	}
184 	hash = sdb_hash (name);
185 	ls_foreach (s->ns, it, ns) {
186 		if (ns->hash == hash) {
187 			return ns->sdb;
188 		}
189 	}
190 	if (!create) {
191 		return NULL;
192 	}
193 	if (s->ns_lock) {
194 		return NULL;
195 	}
196 	ns = sdb_ns_new (s, name, hash);
197 	if (!ns) {
198 		return NULL;
199 	}
200 	ls_append (s->ns, ns);
201 	return ns->sdb;
202 }
203 
sdb_ns_path(Sdb * s,const char * path,int create)204 SDB_API Sdb *sdb_ns_path(Sdb *s, const char *path, int create) {
205 	char *ptr, *str;
206 	char *slash;
207 
208 	if (!s || !path || !*path)
209 		return s;
210 	ptr = str = strdup (path);
211 	do {
212 		slash = strchr (ptr, '/');
213 		if (slash)
214 			*slash = 0;
215 		s = sdb_ns (s, ptr, create);
216 		if (!s) break;
217 		if (slash)
218 			ptr = slash+1;
219 	} while (slash);
220 	free (str);
221 	return s;
222 }
223 
ns_sync(Sdb * s,SdbList * list)224 static void ns_sync (Sdb *s, SdbList *list) {
225 	SdbNs *ns;
226 	SdbListIter *it;
227 	ls_foreach (s->ns, it, ns) {
228 		if (in_list (list, ns)) {
229 			continue;
230 		}
231 		ls_append (list, ns);
232 		ns_sync (ns->sdb, list);
233 		sdb_sync (ns->sdb);
234 	}
235 	sdb_sync (s);
236 }
237 
sdb_ns_sync(Sdb * s)238 SDB_API void sdb_ns_sync (Sdb *s) {
239 	SdbList *list = ls_new ();
240 	ns_sync (s, list);
241 	list->free = NULL;
242 	ls_free (list);
243 }
244