december-adventure-2024/src/main.zig

112 lines
3.6 KiB
Zig
Raw Normal View History

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});
}
}