intial commit
This commit is contained in:
+106
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user