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