intial commit

This commit is contained in:
wes
2025-12-01 12:36:35 -05:00
commit 39bbae4e73
12 changed files with 309574 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
const std = @import("std");
const c = @cImport({
@cInclude("sqlite3.h");
});
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Get command line args
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len < 2) {
std.debug.print("Usage: {s} <path-to-kobo-database.sqlite>\n", .{args[0]});
std.debug.print("Example: {s} /mnt/kobo/.kobo/KoboReader.sqlite\n", .{args[0]});
return error.MissingArgument;
}
const db_path = args[1];
// Open database
var db: ?*c.sqlite3 = null;
const rc = c.sqlite3_open(db_path.ptr, &db);
if (rc != c.SQLITE_OK) {
std.debug.print("Failed to open database: {s}\n", .{c.sqlite3_errmsg(db)});
return error.DatabaseOpenFailed;
}
defer _ = c.sqlite3_close(db);
// Prepare query to get highlights
const query =
\\SELECT
\\ Text,
\\ Annotation,
\\ DateCreated,
\\ ContentID
\\FROM Bookmark
\\WHERE Text IS NOT NULL
\\ORDER BY DateCreated DESC;
;
var stmt: ?*c.sqlite3_stmt = null;
if (c.sqlite3_prepare_v2(db, query.ptr, @intCast(query.len), &stmt, null) != c.SQLITE_OK) {
std.debug.print("Failed to prepare statement: {s}\n", .{c.sqlite3_errmsg(db)});
return error.QueryPrepareFailed;
}
defer _ = c.sqlite3_finalize(stmt);
// Set up buffered stdout writer
const stdout_file = std.fs.File{ .handle = std.posix.STDOUT_FILENO };
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = stdout_file.writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
var count: usize = 0;
// Execute query and print results
while (c.sqlite3_step(stmt) == c.SQLITE_ROW) {
count += 1;
// Get the text (highlight)
const text_ptr = c.sqlite3_column_text(stmt, 0);
const text = if (text_ptr != null)
std.mem.span(@as([*:0]const u8, @ptrCast(text_ptr)))
else
"";
// Get annotation (user's note, may be NULL)
const annotation_ptr = c.sqlite3_column_text(stmt, 1);
const annotation = if (annotation_ptr != null)
std.mem.span(@as([*:0]const u8, @ptrCast(annotation_ptr)))
else
null;
// Get date
const date_ptr = c.sqlite3_column_text(stmt, 2);
const date = if (date_ptr != null)
std.mem.span(@as([*:0]const u8, @ptrCast(date_ptr)))
else
"unknown";
// Get content ID (book identifier)
const content_ptr = c.sqlite3_column_text(stmt, 3);
const content_id = if (content_ptr != null)
std.mem.span(@as([*:0]const u8, @ptrCast(content_ptr)))
else
"unknown";
// Print formatted output
try stdout.print("\n========== Highlight #{d} ==========\n", .{count});
try stdout.print("Date: {s}\n", .{date});
try stdout.print("Book: {s}\n", .{content_id});
try stdout.print("\n{s}\n", .{text});
if (annotation) |note| {
if (note.len > 0) {
try stdout.print("\nNote: {s}\n", .{note});
}
}
try stdout.print("===================================\n", .{});
}
try stdout.print("\nTotal highlights extracted: {d}\n", .{count});
try stdout_writer.interface.flush();
}
+23
View File
@@ -0,0 +1,23 @@
//! By convention, root.zig is the root source file when making a library.
const std = @import("std");
pub fn bufferedPrint() !void {
// Stdout is for the actual output of your application, for example if you
// are implementing gzip, then only the compressed bytes should be sent to
// stdout, not any debugging messages.
var stdout_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
try stdout.print("Run `zig build test` to run the tests.\n", .{});
try stdout.flush(); // Don't forget to flush!
}
pub fn add(a: i32, b: i32) i32 {
return a + b;
}
test "basic add functionality" {
try std.testing.expect(add(3, 7) == 10);
}