1 /* sdb - MIT - Copyright 2011-2020 - pancake */
2 
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <stdlib.h>
7 #include <fcntl.h>
8 #include <ctype.h>
9 #include "sdb.h"
10 
11 typedef struct {
12 	char *buf;
13 	int len;
14 	int size;
15 } StrBuf;
16 
strbuf_new(void)17 static StrBuf* strbuf_new(void) {
18 	return calloc (sizeof (StrBuf), 1);
19 }
20 
21 #define NEWLINE_AFTER_QUERY 1
22 
strbuf_append(StrBuf * sb,const char * str,const int nl)23 static StrBuf* strbuf_append(StrBuf *sb, const char *str, const int nl) {
24 	if (!sb || !str || nl < 0) {
25 		return sb;
26 	}
27 	int len = strlen (str);
28 	if ((sb->len + len + 2) >= sb->size) {
29 		int newsize = sb->size + len + 256;
30 		char *b = realloc (sb->buf, newsize);
31 		/// TODO perform free and force all callers to update the ref?
32 		if (!b) {
33 			return NULL;
34 		}
35 		sb->buf = b;
36 		sb->size = newsize;
37 	}
38 	if (sb->buf && str) {
39 		memcpy (sb->buf + sb->len, str, len);
40 		sb->len += len;
41 	}
42 #if NEWLINE_AFTER_QUERY
43 	if (sb->buf && nl) {
44 		sb->buf[sb->len++] = '\n';
45 		len++;
46 	}
47 #endif
48 	if (sb->buf) {
49 		sb->buf[sb->len] = 0;
50 	}
51 	return sb;
52 }
53 
strbuf_free(StrBuf * sb)54 static StrBuf *strbuf_free(StrBuf *sb) {
55 	free (sb->buf);
56 	free (sb);
57 	return NULL;
58 }
59 
sdb_queryf(Sdb * s,const char * fmt,...)60 SDB_API int sdb_queryf (Sdb *s, const char *fmt, ...) {
61         char string[4096];
62         int ret;
63         va_list ap;
64         va_start (ap, fmt);
65         vsnprintf (string, sizeof (string), fmt, ap);
66         ret = sdb_query (s, string);
67         va_end (ap);
68         return ret;
69 }
70 
sdb_querysf(Sdb * s,char * buf,size_t buflen,const char * fmt,...)71 SDB_API char *sdb_querysf(Sdb *s, char *buf, size_t buflen, const char *fmt, ...) {
72         char string[4096];
73         char *ret;
74         va_list ap;
75         va_start (ap, fmt);
76         vsnprintf (string, sizeof (string), fmt, ap);
77         ret = sdb_querys (s, buf, buflen, string);
78         va_end (ap);
79         return ret;
80 }
81 
82 // TODO: Reimplement as a function with optimized concat
83 #define out_concat(x) if (x&&*x) { \
84 	strbuf_append (out, x, 1); \
85 }
86 
87 typedef struct {
88 	StrBuf *out;
89 	int encode;
90 	char *root;
91 } ForeachListUser;
92 
foreach_list_cb(void * user,const char * k,const char * v)93 static bool foreach_list_cb(void *user, const char *k, const char *v) {
94 	ForeachListUser *rlu = user;
95 	char *line, *root;
96 	int rlen, klen, vlen;
97 	ut8 *v2 = NULL;
98 	if (!rlu) {
99 		return false;
100 	}
101 	root = rlu->root;
102 	klen = strlen (k);
103 	if (rlu->encode) {
104 		v2 = sdb_decode (v, NULL);
105 		if (v2) {
106 			v = (const char *)v2;
107 		}
108 	}
109 	vlen = strlen (v);
110 	if (root) {
111 		rlen = strlen (root);
112 		line = malloc (klen + vlen + rlen + 3);
113 		if (!line) {
114 			free (v2);
115 			return false;
116 		}
117 		memcpy (line, root, rlen);
118 		line[rlen]='/'; /*append the '/' at the end of the namespace */
119 		memcpy (line + rlen + 1, k, klen);
120 		line[rlen + klen + 1] = '=';
121 		memcpy (line + rlen + klen + 2, v, vlen + 1);
122 	} else {
123 		line = malloc (klen + vlen + 2);
124 		if (!line) {
125 			free (v2);
126 			return false;
127 		}
128 		memcpy (line, k, klen);
129 		line[klen] = '=';
130 		memcpy (line + klen + 1, v, vlen + 1);
131 	}
132 	strbuf_append (rlu->out, line, 1);
133 	free (v2);
134 	free (line);
135 	return true;
136 }
137 
walk_namespace(StrBuf * sb,char * root,int left,char * p,SdbNs * ns,int encode)138 static void walk_namespace (StrBuf *sb, char *root, int left, char *p, SdbNs *ns, int encode) {
139 	int len;
140 	SdbListIter *it;
141 	char *_out, *out = sb->buf;
142 	SdbNs *n;
143 	ForeachListUser user = { sb, encode, root };
144 	char *roote = root + strlen (root);
145 	if (!ns->sdb) {
146 		return;
147 	}
148 	/*Pick all key=value in the local ns*/
149 	sdb_foreach (ns->sdb, foreach_list_cb, &user);
150 
151 	/*Pick "sub"-ns*/
152 	ls_foreach (ns->sdb->ns, it, n) {
153 		len = strlen (n->name);
154 		p[0] = '/';
155 		if (len + 2 < left) {
156 			memcpy (p + 1, n->name, len + 1);
157 			left -= len + 2;
158 		}
159 		_out = out;
160 		walk_namespace (sb, root, left,
161 			roote + len + 1, n, encode);
162 		out = _out;
163 	}
164 }
165 
sdb_querys(Sdb * r,char * buf,size_t len,const char * _cmd)166 SDB_API char *sdb_querys (Sdb *r, char *buf, size_t len, const char *_cmd) {
167 	int i, d, ok, w, alength, bufset = 0, is_ref = 0, encode = 0;
168 	const char *p, *q, *val = NULL;
169 	char *eq, *tmp, *json, *next, *quot, *slash, *res,
170 		*cmd, *newcmd = NULL, *original_cmd = NULL;
171 	StrBuf *out;
172 	Sdb *s = r;
173 	ut64 n;
174 	if (!s || (!_cmd && !buf)) {
175 		return NULL;
176 	}
177 	out = strbuf_new ();
178 	if ((int)len < 1 || !buf) {
179 		bufset = 1;
180 		buf = malloc ((len = 64));
181 		if (!buf) {
182 			strbuf_free (out);
183 			return NULL;
184 		}
185 	}
186 	if (_cmd) {
187 		cmd = original_cmd = strdup (_cmd);
188 		if (!cmd) {
189 			free (out);
190 			if (bufset) {
191 				free (buf);
192 			}
193 			return NULL;
194 		}
195 	} else {
196 		cmd = buf;
197 	}
198 	// if cmd is null, we take buf as cmd
199 	next = NULL;
200 repeat:
201 	/* skip spaces */
202 	while (*cmd && (*cmd == ' ' || *cmd == '\t')) {
203 		cmd++;
204 	}
205 	s = r;
206 	p = cmd;
207 	eq = NULL;
208 	encode = 0;
209 	is_ref = 0;
210 	quot = NULL;
211 	json = NULL;
212 	if (*p == '#') {
213 		p++;
214 		next = strchr (p, ';');
215 		if (next) {
216 			*next = 0;
217 		}
218 		out_concat (sdb_fmt ("0x%08x\n", sdb_hash (p)));
219 		if (next) {
220 			*next = ';';
221 		}
222 		goto runNext;
223 	} else
224 	if (*p == '%') {
225 		encode = 1;
226 		cmd++;
227 		p++;
228 	}
229 	if (next) *next = ';';
230 	eq = strchr (p, '=');
231 	if (eq) {
232 		d = 1;
233 		*eq++ = 0;
234 		if (*eq == '$') {
235 			next = strchr (eq + 1, ';');
236 			if (next) *next = 0;
237 			val = sdb_const_get (s, eq + 1, 0);
238 			if (!val) {
239 				eprintf ("No value for '%s'\n", eq + 1);
240 				goto fail;
241 			}
242 			if (next) *next = ';';
243 			is_ref = 1; // protect readonly buffer from being processed
244 		} else {
245 			val = eq;
246 		}
247 	} else {
248 		val = NULL;
249 		d = 0;
250 	}
251 	if (!is_ref) {
252 		next = strchr (val? val: cmd, ';');
253 	}
254 	//if (!val) val = eq;
255 	if (!is_ref && val && *val == '"') {
256 		val++;
257 		// TODO: escape \" too
258 		quot = (char*)val;
259 next_quote:
260 		quot = strchr (quot, '"');
261 		if (quot) {
262 			if (*(quot - 1) == '\\') {
263 				memmove (quot - 1, quot, strlen (quot) + 1);
264 				goto next_quote;
265 			}
266 			*quot++ = 0; // crash on read only mem!!
267 		} else {
268 			eprintf ("Missing quote\n");
269 			*eq++ = 0;
270 			out = strbuf_free (out);
271 			goto fail;
272 		}
273 		next = strchr (quot, ';');
274 	} else {
275 		quot = NULL;
276 	}
277 	if (next) {
278 		*next = 0;
279 	}
280 	slash = strchr (cmd, '/');
281 	while (slash) {
282 		*slash = 0;
283 		s = sdb_ns (s, cmd, eq? 1: 0);
284 		if (!s) {
285 			eprintf ("Cant find namespace %s\n", cmd);
286 			out = strbuf_free (out);
287 			goto fail;
288 		}
289 		cmd = slash + 1;
290 		slash = strchr (cmd, '/');
291 	}
292 	if (*cmd=='?') {
293 		const char *val = sdb_const_get (s, cmd+1, 0);
294 		const char *type = sdb_type (val);
295 		out_concat (type);
296 	} else
297 	if (*cmd == '*') {
298 		if (!strcmp (cmd, "***")) {
299 			char root[1024]; // limit namespace length?
300 			SdbListIter *it;
301 			SdbNs *ns;
302 			ls_foreach (s->ns, it, ns) {
303 				int name_len = strlen (ns->name);
304 				if (name_len < (long)sizeof (root)) {
305 					memcpy (root, ns->name, name_len + 1);
306 					walk_namespace (out, root,
307 						sizeof (root) - name_len,
308 						root + name_len, ns, encode);
309 				} else {
310 					eprintf ("TODO: Namespace too long\n");
311 				}
312 			}
313 			goto fail;
314 		} else
315 		if (!strcmp (cmd, "**")) {
316 			SdbListIter *it;
317 			SdbNs *ns;
318 			ls_foreach (s->ns, it, ns) {
319 				out_concat (ns->name);
320 			}
321 			goto fail;
322 		} else
323 		if (!strcmp (cmd, "*")) {
324 			ForeachListUser user = { out, encode, NULL };
325 			SdbList *list = sdb_foreach_list (s, true);
326 			SdbListIter *iter;
327 			SdbKv *kv;
328 			ls_foreach (list, iter, kv) {
329 				foreach_list_cb (&user, sdbkv_key (kv), sdbkv_value (kv));
330 			}
331 			ls_free (list);
332 			goto fail;
333 		}
334 	}
335 	json = strchr (cmd, ':');
336 	if (*cmd == '[') {
337 		char *tp = strchr (cmd, ']');
338 		if (!tp) {
339 			eprintf ("Missing ']'.\n");
340 			goto fail;
341 		}
342 		*tp++ = 0;
343 		p = (const char *)tp;
344 	} else {
345 		p = cmd;
346 	}
347 	if (*cmd == '$') {
348 		free (newcmd);
349 		char *nc = sdb_get (s, cmd + 1, 0);
350 		cmd = newcmd = (nc) ? nc : strdup ("");
351 	}
352 	// cmd = val
353 	// cmd is key and val is value
354 	if (*cmd == '.') {
355 		if (s->options & SDB_OPTION_FS) {
356 			if (!sdb_query_file (s, cmd + 1)) {
357 				eprintf ("sdb: cannot open '%s'\n", cmd+1);
358 				goto fail;
359 			}
360 		} else {
361 			eprintf ("sdb: filesystem access disabled in config\n");
362 		}
363 	} else if (*cmd == '~') { // delete
364 		if (cmd[1] == '~') { // grep
365 			SdbKv *kv;
366 			SdbListIter *li;
367 			SdbList *l = sdb_foreach_match (s, cmd + 2, false);
368 			ls_foreach (l, li, kv) {
369 				strbuf_append (out, sdbkv_key (kv), 0);
370 				strbuf_append (out, "=", 0);
371 				strbuf_append (out, sdbkv_value (kv), 1);
372 			}
373 			fflush (stdout);
374 			ls_free (l);
375 		} else {
376 			d = 1;
377 			sdb_unset_like (s, cmd + 1);
378 		}
379 	} else if (*cmd == '+' || *cmd == '-') {
380 		d = 1;
381 		if (!buf) {
382 			buf = calloc (1, len);
383 			if (!buf) {
384 				goto fail;
385 			}
386 			bufset = 1;
387 		}
388 		*buf = 0;
389 		if (cmd[1]=='[') {
390 			const char *eb = strchr (cmd, ']');
391 			if (!eb) {
392 				eprintf ("Missing ']'.\n");
393 				goto fail;
394 			}
395 			int idx = sdb_atoi (cmd + 2);
396 			/* +[idx]key=n */
397 			/* -[idx]key=n */
398 			ut64 curnum = sdb_array_get_num (s,
399 				eb + 1, idx, 0);
400 			if (eq) {
401 				/* +[idx]key=n  -->  key[idx] += n */
402 				/* -[idx]key=n  -->  key[idx] -= n */
403 				st64 n = sdb_atoi (eq);
404 				if (*cmd=='+') {
405 					curnum += n;
406 				} else if (*cmd=='-') {
407 					curnum -= n;
408 				} else {
409 					// never happens
410 				}
411 				sdb_array_set_num (s, eb+1, idx, curnum, 0);
412 			} else {
413 				/* +[idx]key    -->  key[idx] + 1 */
414 				/* -[idx]key    -->  key[idx] - 1 */
415 				char *nstr, numstr[128];
416 				if (*cmd=='+') {
417 					curnum ++;
418 				} else if (*cmd=='-') {
419 					curnum --;
420 				} else {
421 					// never happens
422 				}
423 				nstr = sdb_itoa (curnum, numstr, 10);
424 				strbuf_append (out, nstr, 1);
425 			}
426 		} else if (val) {
427 			if (sdb_isnum (val)) {
428 				int op = *cmd;
429 				if (*val == '-') {
430 					if (*cmd == '-') {
431 						op = '+';
432 					} else {
433 						op = '-';
434 					}
435 					d = sdb_atoi (val + 1);
436 				} else {
437 					d = sdb_atoi (val);
438 				}
439 				if (op=='+') {
440 					sdb_num_inc (s, cmd+1, d, 0);
441 				} else {
442 					sdb_num_dec (s, cmd+1, d, 0);
443 				}
444 			} else {
445 				if (*cmd == '+') {
446 					sdb_concat (s, cmd + 1, val, 0);
447 				} else {
448 					sdb_uncat (s, cmd + 1, val, 0);
449 				}
450 			}
451 		} else {
452 			int base = sdb_num_base (sdb_const_get (s, cmd+1, 0));
453 			if (json) {
454 				base = 10; // NOTE: json is base10 only
455 				*json = 0;
456 				if (*cmd=='+') {
457 					n = sdb_json_num_inc (s, cmd + 1, json + 1, d, 0);
458 				} else {
459 					n = sdb_json_num_dec (s, cmd + 1, json + 1, d, 0);
460 				}
461 				*json = ':';
462 			} else {
463 				if (*cmd=='+') {
464 					n = sdb_num_inc (s, cmd + 1, d, 0);
465 				} else {
466 					n = sdb_num_dec (s, cmd + 1, d, 0);
467 				}
468 			}
469 			// keep base
470 			if (base == 16) {
471 				w = snprintf (buf, len - 1, "0x%"ULLFMT"x", n);
472 				if (w < 0 || (size_t)w > len) {
473 					if (bufset && len < 0xff) {
474 						free (buf);
475 						buf = malloc (len = 0xff);
476 						if (!buf) {
477 							goto fail;
478 						}
479 					}
480 					bufset = 1;
481 					snprintf (buf, 0xff, "0x%"ULLFMT"x", n);
482 				}
483 			} else {
484 				w = snprintf (buf, len-1, "%"ULLFMT"d", n);
485 				if (w < 0 || (size_t)w > len) {
486 					if (bufset && len < 0xff) {
487 						free (buf);
488 						buf = malloc (len = 0xff);
489 						if (!buf) {
490 							goto fail;
491 						}
492 					}
493 					bufset = 1;
494 					snprintf (buf, 0xff, "%"ULLFMT"d", n);
495 				}
496 			}
497 		}
498 		out_concat (buf);
499 	} else if (*cmd == '[') {
500 		// [?] - count elements of array
501 		if (cmd[1] == '?') {
502 			// if (!eq) ...
503 			alength = sdb_array_length (s, p);
504 			if (!buf) {
505 				buf = malloc (++len);
506 				if (!buf) {
507 					goto fail;
508 				}
509 				bufset = 1;
510 			}
511 			w = snprintf (buf, len, "%d", alength);
512 			if (w < 0 || (size_t)w > len) {
513 				if (bufset) {
514 					free (buf);
515 				}
516 				buf = malloc (len = 32);
517 				bufset = 1;
518 				snprintf (buf, 31, "%d", alength);
519 			}
520 			out_concat (buf);
521 		} else if (cmd[1]=='!') {
522 			if (cmd[2]=='+') {
523 				// [!+]key=aa	# add_sorted
524 				sdb_array_add_sorted (s, p, val, 0);
525 			} else {
526 				// [!]key		# sort
527 				sdb_array_sort (s, p, 0);
528 			}
529 		} else if (cmd[1]=='#') {
530 				// [#+]key=num	# add_sorted_num
531 			if (cmd[2]=='+') {
532 				// [#]key		# sort_num
533 				sdb_array_add_sorted_num (s, p, sdb_atoi (val), 0);
534 			} else {
535 				sdb_array_sort_num (s, p, 0);
536 			}
537 		} else if (cmd[1] == '+' || cmd[1] == '-') {
538 			if (cmd[1] == cmd[2]) {
539 				// stack
540 #if 0
541 				[++]foo=33 # push
542 				[++]foo    # <invalid>
543 				[--]foo    # pop
544 				[--]foo=b  # <invalid>
545 #endif
546 				if (cmd[1] == '-' && eq) {
547 					/* invalid syntax */
548 				} else if (cmd[1] == '+' && !eq) {
549 					/* invalid syntax */
550 				} else {
551 					if (eq) {
552 						sdb_array_push (s, p, val, 0);
553 					} else {
554 						char *ret = sdb_array_pop (s, p, 0);
555 						out_concat (ret);
556 						free (ret);
557 					}
558 				}
559 			} else
560 			// [+]foo        remove first element */
561 			// [+]foo=bar    ADD */
562 			// [-]foo        POP */
563 			// [-]foo=xx     REMOVE (=xx ignored) */
564 			if (!cmd[2] || cmd[2] == ']') {
565 				// insert
566 				if (eq) {
567 					if (cmd[1] == '+') {
568 						// [+]K=1
569 						sdb_array_add (s, p, val, 0);
570 					} else {
571 						// [-]K= = remove first element
572 						sdb_array_remove (s, p, val, 0);
573 					}
574 					//return NULL;
575 				} else {
576 					char *ret;
577 					if (cmd[1] == '+') {
578 						// [+]K = remove first element
579 						// XXX: this is a little strange syntax to remove an item
580 						ret = sdb_array_get (s, p, 0, 0);
581 						if (ret && *ret) {
582 							out_concat (ret);
583 						}
584 						// (+)foo :: remove first element
585 						sdb_array_delete (s, p, 0, 0);
586 					} else {
587 						// [-]K = remove last element
588 						ret = sdb_array_get (s, p, -1, 0);
589 						if (ret && *ret) {
590 							out_concat (ret);
591 						}
592 						// (-)foo :: remove last element
593 						sdb_array_delete (s, p, -1, 0);
594 					}
595 					free (ret);
596 				}
597 			} else {
598 				// get/set specific element in array
599 				i = atoi (cmd + 1);
600 				if (eq) {
601 					/* [+3]foo=bla */
602 					if (i < 0) {
603 						char *tmp = sdb_array_get (s, p, -i, NULL);
604 						if (tmp) {
605 							if (encode) {
606 								char *newtmp = (void*)sdb_decode (tmp, NULL);
607 								if (!newtmp) {
608 									goto fail;
609 								}
610 								free (tmp);
611 								tmp = newtmp;
612 							}
613 							ok = 0;
614 							out_concat (tmp);
615 							sdb_array_delete (s, p, -i, 0);
616 							free (tmp);
617 						} else goto fail;
618 					} else {
619 						if (encode) {
620 							val = sdb_encode ((const ut8*)val, -1);
621 						}
622 						ok = cmd[1]? ((cmd[1]=='+')?
623 							sdb_array_insert (s, p, i, val, 0):
624 							sdb_array_set (s, p, i, val, 0)
625 							): sdb_array_delete (s, p, i, 0);
626 						if (encode) {
627 							free ((void*)val);
628 							val = NULL;
629 						}
630 					}
631 					if (ok && buf) *buf = 0;
632 					else buf = NULL;
633 				} else {
634 					if (i==0) {
635 						/* [-b]foo */
636 						if (cmd[1]=='-') {
637 							sdb_array_remove (s, p, cmd+2, 0);
638 						} else {
639 							eprintf ("TODO: [b]foo -> get index of b key inside foo array\n");
640 						//	sdb_array_dels (s, p, cmd+1, 0);
641 						}
642 					} else if (i<0) {
643 						/* [-3]foo */
644 						char *tmp = sdb_array_get (s, p, -i, NULL);
645 						if (tmp && *tmp) {
646 							out_concat (tmp);
647 							sdb_array_delete (s, p, -i, 0);
648 						}
649 						free (tmp);
650 					} else {
651 						/* [+3]foo */
652 						char *tmp = sdb_array_get (s, p, i, NULL);
653 						if (tmp && *tmp) {
654 							out_concat (tmp);
655 						}
656 						free (tmp);
657 					}
658 				}
659 			}
660 		} else {
661 			if (eq) {
662 				/* [3]foo=bla */
663 				char *sval = (char*)val;
664 				if (encode) {
665 					sval = sdb_encode ((const ut8*)val, -1);
666 				}
667 				if (cmd[1]) {
668 					int idx = atoi (cmd+1);
669 					ok = sdb_array_set (s, p, idx, sval, 0);
670 // TODO: handle when idx > sdb_alen
671 					if (encode)
672 						free (sval);
673 				} else {
674 					if (encode) {
675 						ok = sdb_set_owned (s, p, sval, 0);
676 					} else {
677 						ok = sdb_set (s, p, sval, 0);
678 					}
679 				}
680 				if (ok && buf) {
681 					*buf = 0;
682 				}
683 			} else {
684 				/* [3]foo */
685 				const char *sval = sdb_const_get (s, p, 0);
686 				size_t wl;
687 				if (cmd[1]) {
688 					i = atoi (cmd + 1);
689 					buf = sdb_array_get (s, p, i, NULL);
690 					if (buf) {
691 						bufset = 1;
692 						len = strlen(buf) + 1;
693 					}
694 					if (encode) {
695 						char *newbuf = (void*)sdb_decode (buf, NULL);
696 						if (newbuf) {
697 							free (buf);
698 							buf = newbuf;
699 							len = strlen(buf) + 1;
700 						}
701 					}
702 					out_concat (buf);
703 				} else {
704 					if (!sval) {
705 						goto fail;
706 					}
707 					wl = strlen (sval);
708 					if (!buf || wl >= len) {
709 						buf = malloc (wl + 2);
710 						if (!buf) {
711 							free (out->buf);
712 							out->buf = NULL;
713 							goto fail;
714 						}
715 						bufset = 1;
716 						len = wl + 2;
717 					}
718 					for (i = 0; sval[i]; i++) {
719 						if (sval[i + 1]) {
720 							buf[i] = (sval[i] == SDB_RS)
721 								? '\n': sval[i];
722 						} else {
723 							buf[i] = sval[i];
724 						}
725 					}
726 					buf[i] = 0;
727 					if (encode) {
728 						char *newbuf = (void*)sdb_decode (buf, NULL);
729 						if (newbuf) {
730 							if (bufset) {
731 								free (buf);
732 							}
733 							buf = newbuf;
734 							len = strlen (buf) + 1;
735 						}
736 					}
737 					out_concat (buf);
738 				}
739 			}
740 		}
741 	} else {
742 		if (eq) {
743 			// 1 0 kvpath=value
744 			// 1 1 kvpath:jspath=value
745 			if (encode) {
746 				val = sdb_encode ((const ut8*)val, -1);
747 			}
748 			if (json > eq) {
749 				json = NULL;
750 			}
751 
752 			if (json) {
753 				*json++ = 0;
754 				ok = sdb_json_set (s, cmd, json, val, 0);
755 			} else {
756 				while (*val && isspace (*val)) {
757 					val++;
758 				}
759 				int i = strlen (cmd) - 1;
760 				while (i >= 0 && isspace (cmd[i])) {
761 					cmd[i] = '\0';
762 					i--;
763 				}
764 				ok = sdb_set (s, cmd, val, 0);
765 			}
766 			if (encode) {
767 				free ((void*)val);
768 				val = NULL;
769 			}
770 			if (ok && buf) {
771 				*buf = 0;
772 			}
773 		} else {
774 			// 0 1 kvpath:jspath
775 			// 0 0 kvpath
776 			if (json) {
777 				*json++ = 0;
778 				if (*json) {
779 					// TODO: not optimized to reuse 'buf'
780 					if ((tmp = sdb_json_get (s, cmd, json, 0))) {
781 						if (encode) {
782 							char *newtmp = (void*)sdb_decode (tmp, NULL);
783 							if (!newtmp)
784 								goto fail;
785 							free (tmp);
786 							tmp = newtmp;
787 						}
788 						out_concat (tmp);
789 						free (tmp);
790 					}
791 				} else {
792 					// kvpath:  -> show indented json
793 					char *o = sdb_json_indent (sdb_const_get (s, cmd, 0), "  ");
794 					out_concat (o);
795 					free (o);
796 				}
797 			} else {
798 				// sdbget
799 				if ((q = sdb_const_get (s, cmd, 0))) {
800 					if (encode) {
801 						q = (void*)sdb_decode (q, NULL);
802 					}
803 					out_concat (q);
804 					if (encode) {
805 						free ((void*)q);
806 					}
807 				}
808 			}
809 		}
810 	}
811 runNext:
812 	if (next) {
813 		if (bufset) {
814 			free (buf);
815 			buf = NULL;
816 			bufset = 0;
817 		}
818 		cmd = next + 1;
819 		encode = 0;
820 		goto repeat;
821 	}
822 	if (eq) {
823 		*--eq = '=';
824 	}
825 fail:
826 	if (bufset) {
827 		free (buf);
828 	}
829 	if (out) {
830 		res = out->buf;
831 		free (out);
832 	} else {
833 		res = NULL;
834 	}
835 	free (original_cmd);
836 	free (newcmd);
837 	return res;
838 }
839 
sdb_query(Sdb * s,const char * cmd)840 SDB_API int sdb_query (Sdb *s, const char *cmd) {
841 	char buf[1024], *out;
842 	int must_save = ((*cmd=='~') || strchr (cmd, '='));
843 	out = sdb_querys (s, buf, sizeof (buf) - 1, cmd);
844 	if (out) {
845 		if (*out) {
846 			puts (out);
847 		}
848 		if (out != buf) {
849 			free (out);
850 		}
851 	}
852 	return must_save;
853 }
854 
sdb_query_lines(Sdb * s,const char * cmd)855 SDB_API int sdb_query_lines (Sdb *s, const char *cmd) {
856 	char *o, *p, *op;
857 	if (!s || !cmd) {
858 		return 0;
859 	}
860 	op = strdup (cmd);
861 	if (!op) {
862 		return 0;
863 	}
864 	p = op;
865 	do {
866 		o = strchr (p, '\n');
867 		if (o) {
868 			*o = 0;
869 		}
870 		(void)sdb_query (s, p);
871 		if (o) {
872 			p = o + 1;
873 		}
874 	} while (o);
875 	free (op);
876 	return 1;
877 }
878 
slurp(const char * file)879 static char *slurp(const char *file) {
880 	int ret, fd;
881 	char *text;
882 	long sz;
883 	if (!file || !*file)
884 		return NULL;
885 	fd = open (file, O_RDONLY);
886 	if (fd == -1) {
887 		return NULL;
888 	}
889 	sz = lseek (fd, 0, SEEK_END);
890 	if (sz < 0){
891 		close (fd);
892 		return NULL;
893 	}
894 	lseek (fd, 0, SEEK_SET);
895 	text = malloc (sz + 1);
896 	if (!text) {
897 		close (fd);
898 		return NULL;
899 	}
900 	ret = read (fd, text, sz);
901 	if (ret != sz) {
902 		free (text);
903 		text = NULL;
904 	} else {
905 		text[sz] = 0;
906 	}
907 	close (fd);
908 	return text;
909 }
910 
sdb_query_file(Sdb * s,const char * file)911 SDB_API int sdb_query_file(Sdb *s, const char* file) {
912 	int ret = 0;
913 	char *txt = slurp (file);
914 	if (txt) {
915 		ret = sdb_query_lines (s, txt);
916 		free (txt);
917 	}
918 	return ret;
919 }
920