const std = @import("std"); const builtin = @import("builtin"); const eql = @import("std").mem.eql; const stdout = std.io.getStdOut().writer(); const stderr = std.io.getStdErr().writer(); const stdin = std.io.getStdIn().reader(); const Target = enum { Stdout, Stderr, }; pub fn write(target: Target, comptime format: []const u8, args: anytype) void { switch (target) { Target.Stdout => stdout.print(format, args) catch |err| { std.debug.panic("unable to write to output: {any}\n", .{err}); }, Target.Stderr => stderr.print(format, args) catch |err| { std.debug.panic("unable to write to output: {any}\n", .{err}); }, } } pub fn main() !void { // Read the first argument to determine the subcommand const allocator = std.heap.page_allocator; var args = std.process.argsWithAllocator(allocator) catch |err| { write(Target.Stderr, "out of memory: {any}\n", .{err}); }; defer args.deinit(); _ = args.next(); // Skip the first argument, which is the program name const firstArg = args.next() orelse { write(Target.Stderr, "no subcommand provided\n", .{}); return; }; if (eql(u8, firstArg, "list")) { listEntries(); } else if (eql(u8, firstArg, "create")) { createNewEntry() catch |err| { write(Target.Stderr, "error while creating new entry: {any}\n", .{err}); }; } else { write(Target.Stderr, "Unknown subcommand: {any}\n", .{firstArg}); } } fn createNewEntry() !void { // Open the file in append mode const file = std.fs.cwd().openFile("entries.log.gmi", .{ .mode = .read_write }) catch |err| { write(Target.Stderr, "unable to open file: {any}\n", .{err}); return; }; defer file.close(); try file.seekFromEnd(0); //const date = try std.time.Time.nowUTC().format("yyyy-MM-dd HH:mm UTC"); const es = std.time.epoch.EpochSeconds{ .secs = @intCast(std.time.timestamp()) }; const ed = std.time.epoch.EpochDay{ .day = es.getEpochDay().day }; var buf2: [256]u8 = undefined; const date = try std.fmt.bufPrint(&buf2, "## {d}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2} UTC\n", .{ ed.calculateYearDay().year, std.time.epoch.YearAndDay.calculateMonthDay(ed.calculateYearDay()).month.numeric(), std.time.epoch.YearAndDay.calculateMonthDay(ed.calculateYearDay()).day_index, es.getDaySeconds().getHoursIntoDay(), es.getDaySeconds().getMinutesIntoHour(),}); // Read the input content from STDIN and append it to the file var buf: [1024]u8 = undefined; try file.writeAll(date); while (stdin.readUntilDelimiterOrEof(&buf, '\n')) |line| { try file.writeAll(line orelse break); try file.writeAll("\n"); } else |err| { write(Target.Stderr, "error while reading from stdin: {any}\n", .{err}); return; } try file.writeAll("\n"); // Print some success message and the back link to STDOUT try stdout.print("Entry added successfully\n", .{}); try stdout.print("=> / Back to the log entries", .{}); } fn listEntries() void { const file = std.fs.cwd().openFile("entries.log.gmi", .{}) catch |err| { write(Target.Stderr, "unable to open file: {any}\n", .{err}); return; }; defer file.close(); var bufReader = std.io.bufferedReader(file.reader()); var inStream = bufReader.reader(); var buf: [1024]u8 = undefined; while (inStream.readUntilDelimiterOrEof(&buf, '\n')) |line| { write(Target.Stdout, "{s}\n", .{ line orelse break }); } else |err| { write(Target.Stderr, "error while reading the file: {!}\n", .{err}); } }