commit c84a54bb008e5e273d33af4a94b65d64c7a18ddb
parent 82f6feeb9cbe041f52f369f323189f7b6c8d0049
Author: ssnf <ssnf@ssnf.xyz>
Date: Sat, 12 Jul 2025 11:34:24 +0000
add libsdb documentation
Diffstat:
2 files changed, 281 insertions(+), 0 deletions(-)
diff --git a/man/man3/INDEX b/man/man3/INDEX
@@ -1189,6 +1189,19 @@ sdbr_val sdbr.3
sdbr_zero sdbr.3
vsdbr_join sdbr.3
sdbr sdbr.3
+sdb_add sdb.3
+sdb_Bopen sdb.3
+sdb_close sdb.3
+sdb_edit sdb.3
+sdb_flush sdb.3
+sdb_n sdb.3
+sdb_next sdb.3
+sdb_open sdb.3
+sdb_openf sdb.3
+sdb_query sdb.3
+sdb_remove sdb.3
+sdb_rewind sdb.3
+sdb sdb.3
Str str.3
Strn str.3
Straddc str.3
diff --git a/man/man3/sdb.3 b/man/man3/sdb.3
@@ -0,0 +1,268 @@
+.TH SDB 3
+.SH NAME
+sdb_add, sdb_Bopen, sdb_close, sdb_edit, sdb_flush, sdb_n, sdb_next, sdb_open, sdb_openf, sdb_query, sdb_remove, sdb_rewind \- simple database
+.SH SYNOPSIS
+.B #include <u.h>
+.br
+.B #include <libc.h>
+.br
+.B #include <bio.h>
+.br
+.B #include <str.h>
+.br
+.B #include <vec.h>
+.br
+.B #include <sdbr.h>
+.br
+.B #include <sdb.h>
+.PP
+.ft L
+.nf
+.ta \w'\fL 'u +\w'\fLString 'u
+typedef struct {
+ String ln;
+ Sdbr *r;
+ Biobuf *b;
+ ulong n;
+} Sdb;
+.fi
+.PP
+.ta \w'\fLvoid 'u
+.B
+void sdb_add(Sdb *db, Sdbr r)
+.PP
+.B
+void sdb_Bopen(Sdb *db, Biobuf *b)
+.PP
+.B
+void sdb_close(Sdb *db)
+.PP
+.B
+void sdb_edit(Sdb *db, Sdbr q, Sdbr r)
+.PP
+.B
+void sdb_flush(Sdb *db)
+.PP
+.B
+ulong sdb_n(Sdb db)
+.PP
+.B
+int sdb_next(Sdb *db)
+.PP
+.B
+void sdb_open(Sdb *db, char *file)
+.PP
+.B
+void sdb_openf(Sdb *db, char *fmt, ...)
+.PP
+.B
+int sdb_query(Sdb *db, Sdbr q)
+.PP
+.B
+void sdb_remove(Sdb *db)
+.PP
+.B
+void sdb_rewind(Sdb *db)
+.SH DESCRIPTION
+These functions provide a simple database system for storing and querying
+collections of records using the same format as Plan 9's network database (ndb).
+An
+.B Sdb
+database contains a vector of
+.B Sdbr
+records, a current line buffer, a
+.B Biobuf
+for I/O, and a current record position.
+While ndb supports importing multiple database files,
+sdb operates on a single file or input stream.
+.PP
+.I Sdb_open
+opens a database file
+.I file
+for reading.
+If
+.I file
+is nil or empty, it reads from standard input.
+.PP
+.I Sdb_openf
+opens a database file using a formatted filename created with
+.I fmt
+and additional arguments.
+.PP
+.I Sdb_Bopen
+initializes a database using an existing
+.I Biobuf
+.IR b .
+.PP
+.I Sdb_close
+closes the database and frees all associated resources.
+.PP
+.I Sdb_n
+returns the number of records currently loaded in the database.
+.PP
+.I Sdb_next
+advances to the next record in the database.
+If records are already loaded, it moves to the next loaded record.
+Otherwise, it reads the next record from the input.
+It returns the number of attributes in the record, or 0 if no more records.
+Records are parsed from the input where each record consists of
+attribute=value pairs separated by whitespace.
+Multi-line records are supported with continuation lines starting with whitespace.
+Comments starting with '#' are ignored.
+.PP
+.I Sdb_rewind
+resets the current record position to the beginning of the loaded records.
+.PP
+.I Sdb_add
+adds record
+.I r
+to the database and sets the current position to the newly added record.
+.PP
+.I Sdb_query
+searches the database for records matching query
+.IR q .
+It returns 1 if a matching record is found and sets the current position to that record,
+or 0 if no match is found.
+The search starts from the current position and continues through all records,
+loading new records from input as needed.
+.PP
+.I Sdb_edit
+finds all records matching query
+.I q
+and applies edits from record
+.I r
+to each matching record.
+If no matching record is found, it adds query
+.I q
+as a new record.
+.PP
+.I Sdb_remove
+removes the current record from the database.
+.PP
+.I Sdb_flush
+reads all remaining records from the input and prints all records
+in the database to standard output.
+.SH EXAMPLES
+.PP
+Reading and querying a database:
+.IP
+.EX
+Sdb db;
+Sdbr q;
+
+sdb_open(&db, "users.db");
+sdbr_init(&q);
+sdbr_add(&q, Str("type"), Str("admin"));
+if(sdb_query(&db, q))
+ sdbr_print(db.r[db.n]);
+sdbr_close(&q);
+sdb_close(&db);
+.EE
+.PP
+Adding records to a database:
+.IP
+.EX
+Sdb db;
+Sdbr r;
+
+sdb_open(&db, "");
+sdbr_init(&r);
+sdbr_add(&r, Str("name"), Str("Alice"));
+sdbr_add(&r, Str("role"), Str("user"));
+sdb_add(&db, r);
+sdb_flush(&db);
+sdbr_close(&r);
+sdb_close(&db);
+.EE
+.PP
+Iterating through all records:
+.IP
+.EX
+Sdb db;
+
+sdb_open(&db, "data.db");
+while(sdb_next(&db))
+ sdbr_print(db.r[db.n]);
+sdb_close(&db);
+.EE
+.PP
+Editing records:
+.IP
+.EX
+Sdb db;
+Sdbr q, r;
+
+sdb_open(&db, "users.db");
+sdbr_init(&q);
+sdbr_init(&r);
+sdbr_add(&q, Str("name"), Str("Bob"));
+sdbr_add(&r, Str("status"), Str("active"));
+sdb_edit(&db, q, r);
+sdb_flush(&db);
+sdbr_close(&q);
+sdbr_close(&r);
+sdb_close(&db);
+.EE
+.PP
+Log analysis with range queries:
+.IP
+.EX
+Sdb db;
+Sdbr q;
+String s;
+
+sdb_open(&db, "access.log");
+sdbr_init(&q);
+sdbr_str2r(&q, "level=error "
+ "timestamp=>=2024-01-15T14:00:00");
+while(sdb_query(&db, q)) {
+ s = sdbr_val(db.r[db.n], "component");
+ if(sdbr_match("*auth*", s.s))
+ print("AUTH ERROR: %s\en",
+ sdbr_val(db.r[db.n], "message").s);
+ if(!sdb_next(&db))
+ break;
+}
+sdbr_close(&q);
+sdb_close(&db);
+.EE
+.PP
+Server monitoring with negation:
+.IP
+.EX
+Sdb db;
+Sdbr q;
+String s;
+
+sdb_open(&db, "servers.db");
+sdbr_init(&q);
+sdbr_str2r(&q, "type=server !status=maintenance "
+ "location=datacenter1");
+while(sdb_query(&db, q)) {
+ s = sdbr_val(db.r[db.n], "hostname");
+ print("Active server: %s\en", s.s);
+ if(!sdb_next(&db))
+ break;
+}
+sdbr_close(&q);
+sdb_close(&db);
+.EE
+.SH SOURCE
+.B \*9/src/libsdb
+.SH SEE ALSO
+.MR ndb (1) ,
+.MR ndb (3) ,
+.MR ndb (7) ,
+.MR sdb (1) ,
+.MR sdbr (3) ,
+.MR bio (3) ,
+.MR str (3) ,
+.MR vec (3)
+.SH DIAGNOSTICS
+Functions call
+.I sysfatal
+if file operations fail.
+.SH BUGS
+.I Sdb_flush
+only prints to standard output, so you cannot directly write to a database file.
+But maybe that's good!