1 /* sdb - MIT - Copyright 2011-2018 - pancake */
2 
3 #include "sdb.h"
4 #include <limits.h>
5 
6 // TODO: Push should always prepend. do not make this configurable
7 #define PUSH_PREPENDS 1
8 
9 // TODO: missing num_{inc/dec} functions
10 
Aindexof(const char * str,int idx)11 static const char *Aindexof(const char *str, int idx) {
12 	int len = 0;
13 	const char *n, *p = str;
14 	for (len = 0; ; len++) {
15 		if (len == idx) {
16 			return p;
17 		}
18 		if (!(n = strchr (p, SDB_RS))) {
19 			break;
20 		}
21 		p = n + 1;
22 	}
23 	return NULL;
24 }
25 
astrcmp(const char * a,const char * b)26 static int astrcmp(const char *a, const char *b) {
27 	register char va = *a;
28 	register char vb = *b;
29 	for (;;) {
30 		if (va == '\0' || va == SDB_RS) {
31 			if (vb == '\0' || vb == SDB_RS) {
32 				return 0;
33 			}
34 			return -1;
35 		}
36 		if (vb == '\0' || vb == SDB_RS) {
37 			return 1;
38 		}
39 		if (va != vb) {
40 			return (va > vb) ? 1 : -1;
41 		}
42 		va = *(++a);
43 		vb = *(++b);
44 	}
45 }
46 
cstring_cmp(const void * a,const void * b)47 static inline int cstring_cmp(const void *a, const void *b) {
48 	const char **va = (const char **)a;
49 	const char **vb = (const char **)b;
50 	return astrcmp (*va, *vb);
51 }
52 
int_cmp(const void * a,const void * b)53 static inline int int_cmp(const void *a, const void *b) {
54 	const ut64 va = *(const ut64 *)a;
55 	const ut64 vb = *(const ut64 *)b;
56 	if (va > vb) {
57 		return 1;
58 	}
59 	if (va < vb) {
60 		return -1;
61 	}
62 	return 0;
63 }
64 
sdb_array_get_num(Sdb * s,const char * key,int idx,ut32 * cas)65 SDB_API ut64 sdb_array_get_num(Sdb *s, const char *key, int idx, ut32 *cas) {
66 	int i;
67 	const char *n, *str = sdb_const_get (s, key, cas);
68 	if (!str || !*str) {
69 		return 0LL;
70 	}
71 	if (idx) {
72 		for (i = 0; i < idx; i++) {
73 			n = strchr (str, SDB_RS);
74 			if (!n) {
75 				return 0LL;
76 			}
77 			str = n + 1;
78 		}
79 	}
80 	return sdb_atoi (str);
81 }
82 
sdb_array_get(Sdb * s,const char * key,int idx,ut32 * cas)83 SDB_API char *sdb_array_get(Sdb *s, const char *key, int idx, ut32 *cas) {
84 	const char *str = sdb_const_get (s, key, cas);
85 	const char *p = str;
86 	char *o, *n;
87 	int i, len;
88 	if (!str || !*str) {
89 		return NULL;
90 	}
91 	if (idx < 0) {
92 		int len = sdb_alen (str);
93 		idx = -idx;
94 		if (idx > len) {
95 			return NULL;
96 		}
97 		idx = len - idx;
98 	}
99 	if (!idx) {
100 		n = strchr (str, SDB_RS);
101 		if (!n) {
102 			return strdup (str);
103 		}
104 		len = n - str;
105 		o = malloc (len + 1);
106 		if (!o) {
107 			return NULL;
108 		}
109 		memcpy (o, str, len);
110 		o[len] = 0;
111 		return o;
112 	}
113 	for (i = 0; i < idx; i++) {
114 		n = strchr (p, SDB_RS);
115 		if (!n) return NULL;
116 		p = n + 1;
117 	}
118 	n = strchr (p, SDB_RS);
119 	if (!n) {
120 		return strdup (p);
121 	}
122 	len = n - p;
123 	o = malloc (len + 1);
124 	if (o) {
125 		memcpy (o, p, len);
126 		o[len] = 0;
127 		return o;
128 	}
129 	return NULL;
130 }
131 
sdb_array_insert_num(Sdb * s,const char * key,int idx,ut64 val,ut32 cas)132 SDB_API int sdb_array_insert_num(Sdb *s, const char *key, int idx, ut64 val,
133 				  ut32 cas) {
134 	char valstr[64];
135 	return sdb_array_insert (s, key, idx,
136 				 sdb_itoa (val, valstr, SDB_NUM_BASE), cas);
137 }
138 
139 // TODO: done, but there's room for improvement
sdb_array_insert(Sdb * s,const char * key,int idx,const char * val,ut32 cas)140 SDB_API int sdb_array_insert(Sdb *s, const char *key, int idx, const char *val,
141 			      ut32 cas) {
142 	int lnstr, lstr;
143 	size_t lval;
144 	char *x, *ptr;
145 	const char *str = sdb_const_get_len (s, key, &lstr, 0);
146 	if (!str || !*str) {
147 		return sdb_set (s, key, val, cas);
148 	}
149 	lval = strlen (val);
150 	lstr--;
151 	// XXX: lstr is wrongly computed in sdb_const_get_with an off-by-one
152 	// we can optimize this by caching value len in memory . add
153 	// sdb_const_get_size()
154 	lstr = strlen (str);
155 
156 	// When removing strlen this conversion should be checked
157 	size_t lstr_tmp = lstr;
158 	if (SZT_ADD_OVFCHK (lval, lstr_tmp) || SZT_ADD_OVFCHK (lval + lstr_tmp, 2)) {
159 		return false;
160 	}
161 	x = malloc (lval + lstr_tmp + 2);
162 	if (!x) {
163 		return false;
164 	}
165 
166 	if (idx == -1) {
167 		memcpy (x, str, lstr);
168 		x[lstr] = SDB_RS;
169 		memcpy (x + lstr + 1, val, lval + 1);
170 	} else if (!idx) {
171 		memcpy (x, val, lval);
172 		x[lval] = SDB_RS;
173 		memcpy (x + lval + 1, str, lstr + 1);
174 	} else {
175 		char *nstr = malloc (lstr + 1);
176 		if (!nstr) {
177 			free (x);
178 			return false;
179 		}
180 		memcpy (nstr, str, lstr + 1);
181 		ptr = (char *)Aindexof (nstr, idx);
182 		if (ptr) {
183 			int lptr = (nstr + lstr + 1) - ptr;
184 			char *p_1 = ptr > nstr? ptr - 1: ptr;
185 			*p_1 = 0;
186 			lnstr = ptr - nstr - 1;
187 			memcpy (x, nstr, lnstr);
188 			x[lnstr] = SDB_RS;
189 			memcpy (x + lnstr + 1, val, lval);
190 			x[lnstr + lval + 1] = SDB_RS;
191 			// TODO: this strlen hurts performance
192 			memcpy (x + lval + 2 + lnstr, ptr, lptr); //strlen (ptr)+1);
193 			free (nstr);
194 		} else {
195 			// this is not efficient
196 			free (nstr);
197 			free (x);
198 			// fallback for empty buckets
199 			return sdb_array_set (s, key, idx, val, cas);
200 		}
201 	}
202 	return sdb_set_owned (s, key, x, cas);
203 }
204 
sdb_array_set_num(Sdb * s,const char * key,int idx,ut64 val,ut32 cas)205 SDB_API int sdb_array_set_num(Sdb *s, const char *key, int idx, ut64 val,
206 			       ut32 cas) {
207 	char valstr[SDB_NUM_BUFSZ];
208 	return sdb_array_set (s, key, idx, sdb_itoa (val, valstr, SDB_NUM_BASE),
209 			      cas);
210 }
211 
sdb_array_add_num(Sdb * s,const char * key,ut64 val,ut32 cas)212 SDB_API int sdb_array_add_num(Sdb *s, const char *key, ut64 val, ut32 cas) {
213 	char buf[SDB_NUM_BUFSZ];
214 	char *v = sdb_itoa (val, buf, SDB_NUM_BASE);
215 	if (!sdb_array_contains (s, key, v, NULL)) {
216 		if (val < 256) {
217 			char *v = sdb_itoa (val, buf, 10);
218 			return sdb_array_add (s, key, v, cas);
219 		}
220 	}
221 	return sdb_array_add (s, key, v, cas);
222 }
223 
224 // XXX: index should be supressed here? if its a set we shouldnt change the index
sdb_array_add(Sdb * s,const char * key,const char * val,ut32 cas)225 SDB_API int sdb_array_add(Sdb *s, const char *key, const char *val, ut32 cas) {
226 	if (sdb_array_contains (s, key, val, NULL)) {
227 		return 0;
228 	}
229 	return sdb_array_insert (s, key, -1, val, cas);
230 }
231 
sdb_array_add_sorted(Sdb * s,const char * key,const char * val,ut32 cas)232 SDB_API int sdb_array_add_sorted(Sdb *s, const char *key, const char *val, ut32 cas) {
233 	int lstr, lval, i, j;
234 	const char *str_e, *str_lp, *str_p, *str = sdb_const_get_len (s, key, &lstr, 0);
235 	char *nstr, *nstr_p, **vals;
236 	const char null = '\0';
237 	if (!str || !*str) {
238 		str = &null;
239 		lstr = 0;
240 	}
241 	str_e = str + lstr;
242 	str_lp = str_p = str;
243 	if (!val || !*val) {
244 		return 1;
245 	}
246 	lval = strlen (val);
247 	vals = sdb_fmt_array (val);
248 	for (i = 0; vals[i]; i++) {
249 		/* empty */
250 	}
251 	if (i > 1) {
252 		qsort (vals, i, sizeof (ut64*), cstring_cmp);
253 	}
254 	nstr_p = nstr = malloc (lstr + lval + 3);
255 	if (!nstr) {
256 		return 1;
257 	}
258 	for (i = 0; vals[i]; i++) {
259 		while (str_p < str_e) {
260 			if (astrcmp (vals[i], str_p) < 0) {
261 				break;
262 			}
263 			str_p = sdb_const_anext (str_p);
264 			if (!str_p) {
265 				str_p = str_e;
266 			}
267 		}
268 		memcpy (nstr_p, str_lp, str_p - str_lp);
269 		nstr_p += str_p - str_lp;
270 		if (str_p == str_e && str_lp != str_e) {
271 			*(nstr_p++) = SDB_RS;
272 		}
273 		str_lp = str_p;
274 		j = strlen (vals[i]);
275 		memcpy (nstr_p, vals[i], j);
276 		nstr_p += j;
277 		*(nstr_p++) = SDB_RS;
278 	}
279 	if (str_lp < str_e) {
280 		memcpy (nstr_p, str_lp, str_e - str_lp);
281 		nstr_p += str_e - str_lp;
282 		*(nstr_p) = '\0';
283 	} else {
284 		*(--nstr_p) = '\0';
285 	}
286 	sdb_set_owned (s, key, nstr, cas);
287 	free (vals);
288 	return 0;
289 }
290 
sdb_array_add_sorted_num(Sdb * s,const char * key,ut64 val,ut32 cas)291 SDB_API int sdb_array_add_sorted_num(Sdb *s, const char *key, ut64 val,
292 				      ut32 cas) {
293 	int i;
294 	char valstr[SDB_NUM_BUFSZ];
295 	const char *str = sdb_const_get (s, key, 0);
296 	const char *n = str;
297 	if (!str || !*str) {
298 		return sdb_set (s, key, sdb_itoa (val, valstr, SDB_NUM_BASE), cas);
299 	}
300 	for (i = 0; n; i++) {
301 		if (val <= sdb_atoi (n)) {
302 			break;
303 		}
304 		n = sdb_const_anext (n);
305 	}
306 	return sdb_array_insert_num (s, key, n? i: -1, val, cas);
307 }
308 
sdb_array_unset(Sdb * s,const char * key,int idx,ut32 cas)309 SDB_API int sdb_array_unset(Sdb *s, const char *key, int idx, ut32 cas) {
310 	return sdb_array_set (s, key, idx, "", cas);
311 }
312 
sdb_array_append(Sdb * s,const char * key,const char * val,ut32 cas)313 SDB_API bool sdb_array_append(Sdb *s, const char *key, const char *val,
314 			       ut32 cas) {
315 #if SLOW
316 	return sdb_array_set (s, key, -1, val, cas);
317 #else
318 	int str_len = 0;
319 	ut32 kas = cas;
320 	const char *str = sdb_const_get_len (s, key, &str_len, &kas);
321 	if (!val || (cas && cas != kas)) {
322 		return false;
323 	}
324 	cas = kas;
325 	if (str && *str && str_len > 0) {
326 		int val_len = strlen (val);
327 		char *newval = malloc (str_len + val_len + 2);
328 		if (!newval) {
329 			return false;
330 		}
331 		memcpy (newval, str, str_len);
332 		newval[str_len] = SDB_RS;
333 		memcpy (newval+str_len+1, val, val_len);
334 		newval[str_len+val_len+1] = 0;
335 		sdb_set_owned (s, key, newval, cas);
336 	} else {
337 		sdb_set (s, key, val, cas);
338 	}
339 	return true;
340 #endif
341 }
342 
sdb_array_append_num(Sdb * s,const char * key,ut64 val,ut32 cas)343 SDB_API bool sdb_array_append_num(Sdb *s, const char *key, ut64 val, ut32 cas) {
344 	return sdb_array_set_num (s, key, -1, val, cas);
345 }
346 
sdb_array_set(Sdb * s,const char * key,int idx,const char * val,ut32 cas)347 SDB_API int sdb_array_set(Sdb *s, const char *key, int idx, const char *val,
348 			   ut32 cas) {
349 	int lstr, lval, len;
350 	const char *usr, *str = sdb_const_get_len (s, key, &lstr, 0);
351 	char *ptr;
352 
353 	if (!str || !*str) {
354 		return sdb_set (s, key, val, cas);
355 	}
356 	// XXX: should we cache sdb_alen value inside kv?
357 	len = sdb_alen (str);
358 	lstr--;
359 	if (idx < 0 || idx == len) { // append
360 		return sdb_array_insert (s, key, -1, val, cas);
361 	}
362 	lval = strlen (val);
363 	if (idx > len) {
364 		int ret, i, ilen = idx-len;
365 		char *newkey = malloc (ilen + lval + 1);
366 		if (!newkey) {
367 			return 0;
368 		}
369 		for (i = 0; i < ilen; i++) {
370 			newkey [i] = SDB_RS;
371 		}
372 		memcpy (newkey + i, val, lval + 1);
373 		ret = sdb_array_insert (s, key, -1, newkey, cas);
374 		free (newkey);
375 		return ret;
376 	}
377 	//lstr = strlen (str);
378 	ptr = (char*)Aindexof (str, idx);
379 	if (ptr) {
380 		int diff = ptr - str;
381 		char *nstr = malloc (lstr + lval + 2);
382 		if (!nstr) {
383 			return false;
384 		}
385 		ptr = nstr + diff;
386 		//memcpy (nstr, str, lstr+1);
387 		memcpy (nstr, str, diff);
388 		memcpy (ptr, val, lval + 1);
389 		usr = Aindexof (str, idx + 1);
390 		if (usr) {
391 			ptr[lval] = SDB_RS;
392 			strcpy (ptr + lval + 1, usr);
393 		}
394 		return sdb_set_owned (s, key, nstr, 0);
395 	}
396 	return 0;
397 }
398 
sdb_array_remove_num(Sdb * s,const char * key,ut64 val,ut32 cas)399 SDB_API int sdb_array_remove_num(Sdb *s, const char *key, ut64 val, ut32 cas) {
400 	const char *n, *p, *str = sdb_const_get (s, key, 0);
401 	int idx = 0;
402 	ut64 num;
403 	if (str) {
404 		for (p = str; ; idx++) {
405 			num = sdb_atoi (p);
406 			if (num == val) {
407 				return sdb_array_delete (s, key, idx, cas);
408 			}
409 			n = strchr (p, SDB_RS);
410 			if (!n) {
411 				break;
412 			}
413 			p = n + 1;
414 		}
415 	}
416 	return 0;
417 }
418 
419 /* get array index of given value */
sdb_array_indexof(Sdb * s,const char * key,const char * val,ut32 cas)420 SDB_API int sdb_array_indexof(Sdb *s, const char *key, const char *val,
421 			       ut32 cas) {
422 	const char *str = sdb_const_get (s, key, 0);
423 	const char *n, *p = str;
424 	int i;
425 	for (i = 0; ; i++) {
426 		if (!p) {
427 			break;
428 		}
429 		if (!astrcmp (p, val)) {
430 			return i;
431 		}
432 		n = strchr (p, SDB_RS);
433 		if (!n) break;
434 		p = n + 1;
435 	}
436 	return -1;
437 }
438 
439 // previously named del_str... pair with _add
sdb_array_remove(Sdb * s,const char * key,const char * val,ut32 cas)440 SDB_API int sdb_array_remove (Sdb *s, const char *key, const char *val,
441 			      ut32 cas) {
442 	const char *str = sdb_const_get (s, key, 0);
443 	const char *n, *p = str;
444 	int idx;
445 	if (p) {
446 		for (idx = 0; ; idx++) {
447 			if (!astrcmp (p, val)) {
448 				return sdb_array_delete (s, key, idx, cas);
449 			}
450 			n = strchr (p, SDB_RS);
451 			if (!n) {
452 				break;
453 			}
454 			p = n + 1;
455 		}
456 	}
457 	return 0;
458 }
459 
sdb_array_delete(Sdb * s,const char * key,int idx,ut32 cas)460 SDB_API int sdb_array_delete(Sdb *s, const char *key, int idx, ut32 cas) {
461 	int i;
462 	char *p, *n, *str = sdb_get (s, key, 0);
463 	p = str;
464 	if (!str || !*str) {
465 		free (str);
466 		return 0;
467 	}
468 	if (idx < 0) {
469 		idx = sdb_alen (str);
470 		if (idx) idx--;
471 	}
472 	for (i = 0; i < idx; i++) {
473 		if ( (n = strchr (p, SDB_RS)) ) {
474 			p = n + 1;
475 		} else {
476 			free (str);
477 			return 0;
478 		}
479 	}
480 	n = strchr (p, SDB_RS);
481 	if (n) {
482 		memmove (p, n + 1, strlen (n));
483 	} else {
484 		if (p != str)
485 			p--; // remove tailing SDB_RS
486 		*p = 0;
487 		p[1] = 0;
488 	}
489 	sdb_set_owned (s, key, str, cas);
490 	return 1;
491 }
492 
493 // XXX Doesnt work if numbers are stored in different base
sdb_array_contains_num(Sdb * s,const char * key,ut64 num,ut32 * cas)494 SDB_API bool sdb_array_contains_num(Sdb *s, const char *key, ut64 num, ut32 *cas) {
495 	char val[SDB_NUM_BUFSZ];
496 	char *nval = sdb_itoa (num, val, SDB_NUM_BASE);
497 	return sdb_array_contains (s, key, nval, cas);
498 }
499 
sdb_array_contains(Sdb * s,const char * key,const char * val,ut32 * cas)500 SDB_API bool sdb_array_contains(Sdb *s, const char *key, const char *val, ut32 *cas) {
501 	if (!s || !key || !val) {
502 		return false;
503 	}
504 	const char *next, *ptr = sdb_const_get (s, key, cas);
505 	if (ptr && *ptr) {
506 		size_t vlen = strlen (val);
507 		while (1) {
508 			next = strchr (ptr, SDB_RS);
509 			size_t len = next ? (size_t)(next - ptr) : strlen (ptr);
510 			if (len == vlen && !memcmp (ptr, val, len)) {
511 				return true;
512 			}
513 			if (!next) {
514 				break;
515 			}
516 			ptr = next + 1;
517 		}
518 	}
519 	return false;
520 }
521 
sdb_array_size(Sdb * s,const char * key)522 SDB_API int sdb_array_size(Sdb *s, const char *key) {
523 	return sdb_alen (sdb_const_get (s, key, 0));
524 }
525 
526 // NOTE: ignore empty buckets
sdb_array_length(Sdb * s,const char * key)527 SDB_API int sdb_array_length(Sdb *s, const char *key) {
528 	return sdb_alen_ignore_empty (sdb_const_get (s, key, 0));
529 }
530 
sdb_array_push_num(Sdb * s,const char * key,ut64 num,ut32 cas)531 SDB_API int sdb_array_push_num(Sdb *s, const char *key, ut64 num, ut32 cas) {
532 	char buf[SDB_NUM_BUFSZ], *n = sdb_itoa (num, buf, SDB_NUM_BASE);
533 	return sdb_array_push (s, key, n, cas);
534 }
535 
sdb_array_push(Sdb * s,const char * key,const char * val,ut32 cas)536 SDB_API bool sdb_array_push(Sdb *s, const char *key, const char *val, ut32 cas) {
537 #if PUSH_PREPENDS
538 	return sdb_array_prepend (s, key, val, cas);
539 #else
540 	return sdb_array_append (s, key, val, cas);
541 #endif
542 }
543 
sdb_array_prepend_num(Sdb * s,const char * key,ut64 num,ut32 cas)544 SDB_API bool sdb_array_prepend_num(Sdb *s, const char *key, ut64 num, ut32 cas) {
545 	char buf[SDB_NUM_BUFSZ];
546 	char *n = sdb_itoa (num, buf, SDB_NUM_BASE);
547 	return sdb_array_push (s, key, n, cas);
548 }
549 
sdb_array_prepend(Sdb * s,const char * key,const char * val,ut32 cas)550 SDB_API bool sdb_array_prepend (Sdb *s, const char *key, const char *val, ut32 cas) {
551 	if (!s || !key || !val) {
552 		return false;
553 	}
554 	int str_len = 0;
555 	ut32 kas = cas;
556 	const char *str = sdb_const_get_len (s, key, &str_len, &kas);
557 	if (!val || (cas && cas != kas)) {
558 		return false;
559 	}
560 	cas = kas;
561 	if (str && *str) {
562 		int val_len = strlen (val);
563 		char *newval = malloc (str_len + val_len + 2);
564 		if (!newval) {
565 			return false;
566 		}
567 		memcpy (newval, val, val_len);
568 		newval[val_len] = SDB_RS;
569 		memcpy (newval + val_len + 1, str, str_len);
570 		newval[str_len + val_len + 1] = 0;
571 		// TODO: optimize this because we already have allocated and strlened everything
572 		sdb_set_owned (s, key, newval, cas);
573 	} else {
574 		sdb_set (s, key, val, cas);
575 	}
576 	return true;
577 }
578 
sdb_array_pop_num(Sdb * s,const char * key,ut32 * cas)579 SDB_API ut64 sdb_array_pop_num(Sdb *s, const char *key, ut32 *cas) {
580 	ut64 ret;
581 	char *a = sdb_array_pop (s, key, cas);
582 	if (!a) {
583 		if (cas) {
584 			*cas = UT32_MAX; // invalid
585 		}
586 		return UT64_MAX;
587 	}
588 	if (cas) {
589 		*cas = 0;
590 	}
591 	ret = sdb_atoi (a);
592 	free (a);
593 	return ret;
594 }
595 
sdb_array_pop(Sdb * s,const char * key,ut32 * cas)596 SDB_API char *sdb_array_pop(Sdb *s, const char *key, ut32 *cas) {
597 #if PUSH_PREPENDS
598 	return sdb_array_pop_head (s, key, cas);
599 #else
600 	return sdb_array_pop_tail (s, key, cas);
601 #endif
602 }
603 
sdb_array_pop_head(Sdb * s,const char * key,ut32 * cas)604 SDB_API char *sdb_array_pop_head(Sdb *s, const char *key, ut32 *cas) {
605 	// remove last element in
606 	ut32 kas;
607 	char *end, *str = sdb_get (s, key, &kas);
608 	if (!str || !*str) {
609 		free (str);
610 		return NULL;
611 	}
612 	if (cas && *cas != kas) {
613 		*cas = kas;
614 	}
615 	end = strchr (str, SDB_RS);
616 	if (end) {
617 		*end = 0;
618 		sdb_set (s, key, end + 1, 0);
619 	} else {
620 		sdb_unset (s, key, 0);
621 	}
622 	return str;
623 }
624 
sdb_array_pop_tail(Sdb * s,const char * key,ut32 * cas)625 SDB_API char *sdb_array_pop_tail(Sdb *s, const char *key, ut32 *cas) {
626 	ut32 kas;
627 	char *end, *str = sdb_get (s, key, &kas);
628 	if (!str || !*str) {
629 		free (str);
630 		return NULL;
631 	}
632 	if (cas && *cas != kas) {
633 		*cas = kas;
634 	}
635 	for (end = str + strlen (str) - 1; end > str && *end != SDB_RS; end--) {
636 		//nothing to see here
637 	}
638 	if (*end == SDB_RS) {
639 		*end++ = 0;
640 	}
641 	sdb_set_owned (s, key, str, 0);
642 	// XXX: probably wrong
643 	return strdup (end);
644 }
645 
sdb_array_sort(Sdb * s,const char * key,ut32 cas)646 SDB_API void sdb_array_sort(Sdb *s, const char *key, ut32 cas) {
647 	char *nstr, *str, **strs;
648 	int lstr, j, i;
649 	str = sdb_get_len (s, key, &lstr, 0);
650 	if (!str) {
651 		return;
652 	}
653 	if (!*str) {
654 		free (str);
655 		return;
656 	}
657 	strs = sdb_fmt_array (str);
658 	for (i = 0; strs[i]; i++) {
659 		//nothing to see here
660 	}
661 	qsort (strs, i, sizeof (char*), cstring_cmp);
662 	nstr = str;
663 	for (i = 0; strs[i]; i++) {
664 		j = strlen (strs[i]);
665 		memcpy (nstr, strs[i], j);
666 		nstr += j;
667 		*(nstr++) = SDB_RS;
668 	}
669 	if (nstr > str) {
670 		*(--nstr) = '\0';
671 	} else {
672 		*nstr = '\0';
673 	}
674 	sdb_set_owned (s, key, str, cas);
675 	free (strs);
676 }
677 
sdb_array_sort_num(Sdb * s,const char * key,ut32 cas)678 SDB_API void sdb_array_sort_num(Sdb *s, const char *key, ut32 cas) {
679 	char *ret, *nstr;
680 
681 	char *str = sdb_get (s, key, 0);
682 	if (!str) {
683 		return;
684 	}
685 	if (!*str) {
686 		free (str);
687 		return;
688 	}
689 	ut64 *nums = sdb_fmt_array_num (str);
690 	free (str);
691 	if (!nums) {
692 		return;
693 	}
694 
695 	qsort (nums + 1, (int)*nums, sizeof (ut64), int_cmp);
696 
697 	nstr = malloc (*nums + 1);
698 	if (!nstr) {
699 		free (nums);
700 		return;
701 	}
702 	memset (nstr, 'q', *nums);
703 	nstr[*nums] = '\0';
704 
705 	ret = sdb_fmt_tostr (nums + 1, nstr);
706 	sdb_set_owned (s, key, ret, cas);
707 
708 	free (nstr);
709 	free (nums);
710 	return;
711 }
712