commit 69cf5e2d79b53afa6774e05c3b12629bbb38fbab
parent 451499435c91584a1f9f75910aaf29914b7034f4
Author: ssnf <ssnf@ssnf.xyz>
Date: Thu, 10 Jul 2025 04:06:22 -0500
port sdb tools
Diffstat:
11 files changed, 431 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -170,6 +170,13 @@ bin/rsagen
bin/sam
bin/samterm
bin/scat
+bin/sdbedit
+bin/sdbjoin
+bin/sdbmap
+bin/sdbpretty
+bin/sdbquery
+bin/sdbrval
+bin/sdbuniq
bin/secstore
bin/secstored
bin/secuser
diff --git a/include/str.h b/include/str.h
@@ -1,3 +1,5 @@
+AUTOLIB(str)
+
#define STRSIZ 2
typedef unsigned long Posn;
diff --git a/src/cmd/sdb/mkfile b/src/cmd/sdb/mkfile
@@ -0,0 +1,17 @@
+<$PLAN9/src/mkhdr
+
+TARG=\
+ sdbedit\
+ sdbjoin\
+ sdbmap\
+ sdbpretty\
+ sdbquery\
+ sdbrval\
+ sdbuniq\
+
+HFILES=\
+ $PLAN9/include/sdbr.h\
+ $PLAN9/include/sdb.h\
+ std.h\
+
+<$PLAN9/src/mkmany
diff --git a/src/cmd/sdb/sdbedit.c b/src/cmd/sdb/sdbedit.c
@@ -0,0 +1,36 @@
+#include "std.h"
+
+static char *file;
+
+static void
+usage(void)
+{
+ fprint(2, "sdbedit: [-f file] attr0 value0 [attr1 value1]...");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Sdb db;
+ Sdbr q, r;
+
+ ARGBEGIN {
+ case 'f':
+ file = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+ if (argc < 2)
+ usage();
+ sdbr_init(&q);
+ sdbr_init(&r);
+ sdbr_add(&q, Str(argv[0]), Str(argv[1]));
+ sdbr_arg2r(&r, &argv[2]);
+ sdb_open(&db, file);
+ sdb_edit(&db, q, r);
+ sdb_flush(&db);
+ sdb_close(&db);
+ exits(0);
+}
diff --git a/src/cmd/sdb/sdbjoin.c b/src/cmd/sdb/sdbjoin.c
@@ -0,0 +1,50 @@
+#include "std.h"
+
+static char *file[2];
+
+static void
+usage(void)
+{
+ fprint(2, "sdbjoin: [-f file0] file1 [attr [val]]...\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Sdb db[2];
+ Sdbr r, *sr;
+ ulong i;
+
+ ARGBEGIN {
+ case 'f':
+ file[0] = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+ if (argc < 1)
+ usage();
+ file[1] = *argv;
+ sdbr_init(&r);
+ sdbr_add(&r, Str(""), Str(""));
+ sdbr_arg2r(&r, &argv[1]);
+ sdb_open(&db[0], file[0]);
+ sdb_open(&db[1], file[1]);
+ for (;sdb_next(&db[0]);) {
+ sr = db[0].r + db[0].n;
+ Strinsert(&r.attr[0], sr->attr[0], 0);
+ Strinsert(&r.val[0], sr->val[0], 0);
+ for (;sdb_query(&db[1], r);) {
+ vsdbr_join(&db[0].r, db[1].r[db[1].n]);
+ if (!sdb_next(&db[1]))
+ break;
+ }
+ Strzero(&r.attr[0]);
+ Strzero(&r.val[0]);
+ sdb_rewind(&db[1]);
+ }
+ for (i = 0; i < sdb_n(db[0]); ++i)
+ sdbr_print(db[0].r[i]);
+ exits(0);
+}
diff --git a/src/cmd/sdb/sdbmap.c b/src/cmd/sdb/sdbmap.c
@@ -0,0 +1,58 @@
+#include "std.h"
+
+static void usage(void);
+
+static char* file;
+static char* key;
+
+static void
+usage(void)
+{
+ fprint(2, "sdbmap: [-k attr] [-f file0] file attr0 attr1\n");
+ exits("usage");
+}
+
+void
+main(int argc, char* argv[])
+{
+ Sdb db, map;
+ Sdbr r;
+ String p;
+
+ ARGBEGIN {
+ case 'f':
+ file = EARGF(usage());
+ break;
+ case 'k':
+ key = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+ if (argc < 3)
+ usage();
+ sdb_open(&db, file);
+ sdb_open(&map, *argv++);
+ if (!key)
+ key = argv[0];
+ sdbr_init(&r);
+ for (;sdb_next(&db);) {
+ p = sdbr_val(db.r[db.n], argv[0]);
+ if (!p.s)
+ goto print;
+ sdb_rewind(&map);
+ sdbr_zero(&r);
+ sdbr_add(&r, Str(key), p);
+ if (!sdb_query(&map, r))
+ goto print;
+ p = sdbr_val(map.r[map.n], argv[1]);
+ if (!p.s)
+ goto print;
+ sdbr_zero(&r);
+ sdbr_add(&r, Str(argv[0]), p);
+ sdbr_edit(db.r + db.n, r);
+print:
+ sdbr_print(db.r[db.n]);
+ }
+ exits(0);
+}
diff --git a/src/cmd/sdb/sdbpretty.c b/src/cmd/sdb/sdbpretty.c
@@ -0,0 +1,38 @@
+#include "std.h"
+
+static char* file;
+
+static void
+usage(void)
+{
+ fprint(2, "sdbpretty: [-f file]\n");
+ exits("usage");
+}
+
+void
+main(int argc, char* argv[])
+{
+ Sdb db;
+ Sdbr r;
+ String s;
+ ulong i;
+
+ ARGBEGIN {
+ case 'f':
+ file = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+ sdb_open(&db, file);
+ Strinit(&s);
+ for (;sdb_next(&db);) {
+ r = db.r[db.n];
+ print("%s=%s\n", r.attr[0].s
+ , sdbr_escape(&s, r.val[0]));
+ for (i = 1; i < sdbr_n(r); ++i)
+ print("\t%s=%s\n", r.attr[i].s
+ , sdbr_escape(&s, r.val[i]));
+ }
+ exits(0);
+}
diff --git a/src/cmd/sdb/sdbquery.c b/src/cmd/sdb/sdbquery.c
@@ -0,0 +1,37 @@
+#include "std.h"
+
+static char *file;
+
+static void
+usage(void)
+{
+ fprint(2, "sdbquery: "
+ "[-f file] attr0 value0 [attr1 value1]...\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Sdbr q;
+ Sdb db;
+
+ ARGBEGIN {
+ case 'f':
+ file = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+ if (argc < 2)
+ usage();
+ sdbr_init(&q);
+ sdbr_arg2r(&q, argv);
+ sdb_open(&db, file);
+ for (;sdb_query(&db, q);) {
+ sdbr_print(db.r[db.n]);
+ if (!sdb_next(&db))
+ break;
+ }
+ exits(0);
+}
diff --git a/src/cmd/sdb/sdbrval.c b/src/cmd/sdb/sdbrval.c
@@ -0,0 +1,74 @@
+#include "std.h"
+
+static void print_col(Sdbr*, char*);
+
+static String val;
+static char *fmt = "%.0s%s";
+static void (*print_fn)(Sdbr*, char*) = print_col;
+
+static void
+print_col(Sdbr *r, char *attr)
+{
+ int n;
+
+ n = sdbr_attr(*r, attr);
+ if (n < 0) {
+ print(fmt, attr, "");
+ return;
+ }
+ sdbr_escape(&val, r->val[n]);
+ print(fmt, r->attr[n].s, val.s);
+}
+
+static void
+print_match(Sdbr *r, char *attr)
+{
+ ulong i;
+
+ for (i = 0; i < sdbr_n(*r); ++i) {
+ if (!sdbr_match(attr, r->attr[i].s))
+ continue;
+ sdbr_escape(&val, r->val[i]);
+ print(fmt, r->attr[i].s, val.s);
+ }
+}
+
+static void
+usage(void)
+{
+ fprint(2, "sdbrval: [-am] attr ...\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Sdb db;
+ Sdbr *r;
+ ulong n;
+
+ ARGBEGIN {
+ case 'a':
+ fmt = "%s=%s";
+ break;
+ case 'm':
+ print_fn = print_match;
+ break;
+ default:
+ usage();
+ } ARGEND;
+ if (argc < 1)
+ usage();
+ Strinit(&val);
+ sdb_open(&db, nil);
+ for (;sdb_next(&db);) {
+ r = db.r + db.n;
+ print_fn(r, argv[0]);
+ for (n = 1; n < argc; ++n) {
+ write(1, "\t", 1);
+ print_fn(r, argv[n]);
+ }
+ write(1, "\n", 1);
+ }
+ exits(0);
+}
diff --git a/src/cmd/sdb/sdbuniq.c b/src/cmd/sdb/sdbuniq.c
@@ -0,0 +1,105 @@
+#include "std.h"
+
+static char *file;
+static char *key[256];
+
+static int
+iskey(char *attr)
+{
+ ulong i;
+
+ for (i = 0; key[i]; ++i)
+ if (!strcmp(attr, key[i]))
+ return 1;
+ return 0;
+}
+
+static int
+isnew(Sdbr r0, Sdbr r1, char *attr)
+{
+ String val[2];
+
+ val[0] = sdbr_val(r0, attr);
+ val[1] = sdbr_val(r1, attr);
+ if (!val[1].s
+ || (val[0].s && !strcmp(val[0].s, val[1].s))
+ )
+ return 0;
+ return 1;
+}
+
+static void
+usage(void)
+{
+ fprint(2, "sdbuniq: [-f file] [attr]...\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Sdb db;
+ Sdbr r, cr, nr, *sr;
+ char *attr;
+ ulong i, nk;
+
+ ARGBEGIN {
+ case 'f':
+ file = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+ for (nk = 0; *argv; ++nk)
+ key[nk] = *argv++;
+ sdbr_init(&cr);
+ sdbr_init(&nr);
+ sdbr_init(&r);
+ sdb_open(&db, file);
+ sdb_next(&db);
+ sdbr_dup(&cr, db.r[db.n]);
+ sdbr_dup(&nr, db.r[db.n]);
+ for (;sdb_next(&db);) {
+ sr = db.r + db.n;
+ /* first attribute is always a key, regardless of name */
+ if (strcmp(sr->val[0].s, cr.val[0].s)) {
+ if (sdbr_n(nr) > nk + 1)
+ sdbr_print(nr);
+ sdbr_dup(&cr, *sr);
+ sdbr_dup(&nr, *sr);
+ continue;
+ }
+ /*
+ * check each key for changes and update internal
+ * current record (cr) state
+ */
+ for (i = 0; i < nk; ++i) {
+ if (!isnew(cr, *sr, key[i]))
+ continue;
+ if (sdbr_n(nr) > nk + 1)
+ sdbr_print(nr);
+ sdbr_zero(&nr);
+ sdbr_add(&nr, cr.attr[0], cr.val[0]);
+ for (i = 0; i < nk; ++i)
+ sdbr_add(&nr, Str(key[i])
+ , sdbr_val(*sr, key[i])
+ );
+ sdbr_edit(&cr, nr);
+ break;
+ }
+ for (i = 1; i < sdbr_n(*sr); ++i) {
+ attr = sr->attr[i].s;
+ if (iskey(attr) || !isnew(cr, *sr, attr))
+ continue;
+ sdbr_add(&r, Str(attr), sdbr_val(*sr, attr));
+ }
+ if (sdbr_n(r)) {
+ sdbr_edit(&cr, r);
+ sdbr_edit(&nr, r);
+ sdbr_zero(&r);
+ }
+ }
+ if (sdbr_n(nr) > nk + 1)
+ sdbr_print(nr);
+ exits(0);
+}
diff --git a/src/cmd/sdb/std.h b/src/cmd/sdb/std.h
@@ -0,0 +1,7 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <str.h>
+#include <vec.h>
+#include <sdbr.h>
+#include <sdb.h>