plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

commit 66bf45d4e933e7d6d91f612cc4bb560ca24a8692
parent d10fbc3951057e3979ff7ee30989c222800e43ef
Author: ssnf <ssnf@ssnf.xyz>
Date:   Sun, 31 Aug 2025 15:37:53 +0000

sdb documentation and fixes

Diffstat:
Mman/man7/sdb.7 | 77+++++++++++++++++++++++------------------------------------------------------
Msrc/cmd/sdb/json2sdb.c | 2--
Msrc/cmd/sdb/sdbrval.c | 8+++++++-
Msrc/libsdbr/sdbr_escape.c | 6++----
Msrc/libsdbr/sdbr_match.c | 18++++++++++++++----
Msrc/libsdbr/sdbr_str2r.c | 8+++-----
Msrc/libsdbr/std.h | 6++++++
7 files changed, 55 insertions(+), 70 deletions(-)

diff --git a/man/man7/sdb.7 b/man/man7/sdb.7 @@ -2,57 +2,39 @@ .SH NAME sdb \- simple database format .SH DESCRIPTION -The simple database (sdb) format is a text-based database format -that is 100% backward compatible with Plan 9's network database (ndb) format. -Database files contain records with attribute=value pairs, -with records separated by blank lines. +The simple database (sdb) format is Plan 9's network database +.MR ndb (7) +format with arbitrary-length strings for general-purpose use. .PP -Each record consists of one or more lines. -The first line contains space-separated attribute=value pairs. -Continuation lines begin with whitespace (spaces or tabs) and -contain additional attribute=value pairs for the same record. -.PP -Within a line, attribute=value pairs are separated by spaces or tabs. -The attribute name and value are separated by an equals sign (=). -Attribute names cannot contain equals signs or whitespace. +Database files consist of multi-line records made up of tuples of the +form attr=value. +Attributes are any sequence of non-whitespace characters exluding = and #. +Tuples with no value can omit the =. +Within a record, tuples are separated by whitespace, and lines starting +with whitespace continue the current record. .PP Values can be quoted with double quotes to include spaces. When values are quoted, the following escape sequences are recognized: -\e0 (null), \ef (form feed), \en (newline), \er (carriage return), -\et (tab), \ev (vertical tab), \e" (quote), and \e\e (backslash). +\e0 (null), \et (tab), \en (newline), \er (carriage return), +\e" (quote), and \e\e (backslash). All other bytes, including those with values above 127, can be stored directly. -SDB fully supports binary data. -.PP -When values are not quoted, tabs cannot appear in values as they -are field separators. To include a tab in a value, quote the value -and use \et. +This allows sdb to fully support binary data. .PP -Comments begin with # and extend to the end of the line. -Comments can appear on their own line or after attribute=value pairs. +Comments begin with # and extend to the end of the line, except when # +appears inside a quoted value. .SH PATTERN MATCHING -Several sdb tools support pattern matching for attribute values. +Several sdb tools support pattern matching for attributes and values. The pattern language includes: .TP .B * Wildcard that matches zero or more characters. -However, a pattern consisting of a single * matches one or more characters. -.TP -.B > -.PD 0 -.TP -.B >= -.TP -.B < +A trailing * in a pattern matches one or more characters. .TP -.B <= -.PD +.B >, >=, < and <= Comparison operators for lexicographic string comparison. .TP .B \e* Literal asterisk (escaped with backslash). -.PP -When a * is followed by a literal character, it finds the first occurrence -of that character in the remaining string and continues matching from there. .SH EXAMPLES A simple database of network services: .IP @@ -70,30 +52,18 @@ service=ssh port=22 protocol=tcp Using special characters in values: .IP .EX -# Tab-separated data -data=raw value="one\ttwo\tthree" +data=raw value="one\ettwo\etthree" -# Multi-line text message="First line\enSecond line\enThird line" -# Path with spaces file="/home/user/My Documents/report.txt" -# Binary data with null bytes and high-bit characters -signature="GIF89a\0\0ÿÿ" -checksum="Á¢£¤¥¦§¨©" +signature="GIF89a\e0\e0ÿÿ" + checksum=Á¢£¤¥¦§¨© .EE .SH SEE ALSO -.MR ndb (1) , -.MR ndb (7) , .MR sdb (1) , .MR sdb (3) , -.MR sdbr (3) -.SH NOTES -The sdb format is designed to be both human-readable and -suitable for processing with standard Unix text tools. -Single-line record format enables easy sorting and filtering -with tools like -.MR sort (1) -and -.MR grep (1) . -\ No newline at end of file +.MR sdbr (3) , +.MR ndb (7) , + diff --git a/src/cmd/sdb/json2sdb.c b/src/cmd/sdb/json2sdb.c @@ -68,11 +68,9 @@ Ufmt(Fmt *fmt) case '+': fmtprint(fmt, "\\x2b"); break; case '=': fmtprint(fmt, "\\x3d"); break; case '\\': fmtprint(fmt, "\\\\"); break; - case '\f': fmtprint(fmt, "\\f"); break; case '\n': fmtprint(fmt, "\\n"); break; case '\r': fmtprint(fmt, "\\r"); break; case '\t': fmtprint(fmt, "\\t"); break; - case '\v': fmtprint(fmt, "\\v"); break; default: fmtrune(fmt, *s); } } diff --git a/src/cmd/sdb/sdbrval.c b/src/cmd/sdb/sdbrval.c @@ -5,6 +5,7 @@ static void print_col(Sdbr*, char*); static String val; static String ln; +static int hasdata; static char *fmt = "%.0s%s"; static void (*print_fn)(Sdbr*, char*) = print_col; static char* (*escapefn)(String*, String) = sdbr_escape; @@ -46,6 +47,8 @@ print_col(Sdbr *r, char *attr) } escapefn(&val, r->val[n]); Strprint(&ln, fmt, r->attr[n].s, val.s); + if (val.n) + hasdata = 1; } static void @@ -60,6 +63,8 @@ print_match(Sdbr *r, char *attr) Straddc(&ln, '\t'); escapefn(&val, r->val[i]); Strprint(&ln, fmt, r->attr[i].s, val.s); + if (val.n) + hasdata = 1; } } @@ -97,10 +102,11 @@ main(int argc, char *argv[]) sdb_open(&db, nil); for (;sdb_next(&db);) { r = db.r + db.n; + hasdata = 0; Strzero(&ln); for (n = 0; n < argc; ++n) print_fn(r, argv[n]); - if (ln.n) + if (hasdata) print("%s\n", ln.s); } exits(0); diff --git a/src/libsdbr/sdbr_escape.c b/src/libsdbr/sdbr_escape.c @@ -12,7 +12,7 @@ sdbr_escape(String *s, String val) e = 1; else for (i = 0; i < val.n; ++i) { c = val.s[i]; - if (c == '\0' || isspace(c)) { + if (c == '\0' || ISWHITE(c)) { e = 1; break; } @@ -21,11 +21,9 @@ sdbr_escape(String *s, String val) c = val.s[i]; switch (c) { case '\0': c = '0'; break; - case '\f': c = 'f'; break; + case '\t': c = 't'; break; case '\n': c = 'n'; break; case '\r': c = 'r'; break; - case '\t': c = 't'; break; - case '\v': c = 'v'; break; case '"': case '\\': if (e) diff --git a/src/libsdbr/sdbr_match.c b/src/libsdbr/sdbr_match.c @@ -4,6 +4,7 @@ char sdbr_match(char *k, char *v) { size_t l, n; + char *t; if (!k) sysfatal("sdbr_match: nil key"); @@ -22,11 +23,20 @@ sdbr_match(char *k, char *v) } for (;*k;) { if (*k == '*') { - if (!*++k) + for (;*++k == '*';); + if (!*k) return 1; - if (k[strcspn(k, "*\\")]) { - v = strchr(v, *k); - return v == NULL ? 0 : sdbr_match(k, v); + n = strcspn(k, "*\\"); + if (k[n]) { + t = strdup(k); + t[n] = '\0'; + v = strstr(v, t); + if (v) { + v += n; + k += n; + } + free(t); + return !v ? 0 : sdbr_match(k, v); } l = strlen(k); n = strlen(v); diff --git a/src/libsdbr/sdbr_str2r.c b/src/libsdbr/sdbr_str2r.c @@ -5,9 +5,9 @@ parsetuple(char *p, Sdbr *r) { char *k, *v, *q; - for (;isspace(*p); ++p); + for (;ISWHITE(*p); ++p); k = p; - for (;*p && !isspace(*p) && *p != '='; ++p) + for (;*p && !ISWHITE(*p) && *p != '='; ++p) if (*p == '#') *p-- = '\0'; if (!*p || *p != '=') { @@ -18,7 +18,7 @@ parsetuple(char *p, Sdbr *r) *p++ = '\0'; if (*p != '"') { v = p; - for (;*p && !isspace(*p); ++p) + for (;*p && !ISWHITE(*p); ++p) if (*p == '#') *p-- = '\0'; if (v != p) @@ -33,11 +33,9 @@ parsetuple(char *p, Sdbr *r) switch (*(q + 1)) { case '\\': ++q; break; case '0': *++q = '\0'; break; - case 'f': *++q = '\f'; break; case 'n': *++q = '\n'; break; case 'r': *++q = '\r'; break; case 't': *++q = '\t'; break; - case 'v': *++q = '\v'; break; case '"': *++q = '"'; break; } *p++ = *q; diff --git a/src/libsdbr/std.h b/src/libsdbr/std.h @@ -5,3 +5,9 @@ #include <str.h> #include <sdbr.h> +#define ISWHITE(x) (\ + (x) == ' '\ + || (x) == '\t'\ + || (x) == '\n'\ + || (x) == '\r'\ +)