Changes
3 changed files (+195/-41)
-
-
@@ -15,6 +15,8 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>.// // SPDX-License-Identifier: GPL-3.0-only const std = @import("std"); const c = @cImport({ @cInclude("time.h"); @cInclude("sunriset.h");
-
@@ -28,16 +30,72 @@ now: c.time_t = 0,target_time: c.time_t = 0, now_delta: c_ulong = 0, target_delta: c_ulong = 0, function_report: c.OnOff = c.ONOFF_OFF, function_list: c.OnOff = c.ONOFF_OFF, function_poll: c.OnOff = c.ONOFF_OFF, function_wait: c.OnOff = c.ONOFF_OFF, utc: bool = false, debug: bool = false, report_sunrise: c.OnOff = c.ONOFF_OFF, report_sunset: c.OnOff = c.ONOFF_OFF, list_days: c_uint = c.DEFAULT_LIST, utc_bias_hours: f64 = 0, command: CommandOptions = .poll, pub const ParseArgsError = error{ UnknownArg, }; pub const ListOptions = struct { days: c_uint = 1, pub fn parseArg(self: *@This(), arg: []const u8, args: *std.process.ArgIterator) ParseArgsError!void { _ = self; _ = arg; _ = args; return ParseArgsError.UnknownArg; } }; pub const Command = enum { help, version, poll, report, wait, list, pub const ParseError = error{ UnknownCommand, }; pub fn parse(str: []const u8) ParseError!@This() { inline for (@typeInfo(@This()).@"enum".fields) |field| { if (std.mem.eql(u8, field.name, str)) { return @enumFromInt(field.value); } } return ParseError.UnknownCommand; } }; pub const CommandOptions = union(Command) { help: void, version: void, poll: void, report: void, wait: void, list: ListOptions, pub fn parseArg(self: *@This(), arg: []const u8, args: *std.process.ArgIterator) ParseArgsError!void { switch (self.*) { .help => return ParseArgsError.UnknownArg, .version => return ParseArgsError.UnknownArg, .poll => return ParseArgsError.UnknownArg, .report => return ParseArgsError.UnknownArg, .wait => return ParseArgsError.UnknownArg, .list => try self.list.parseArg(arg, args), } } }; pub fn init() @This() { var opts = @This(){};
-
@@ -48,6 +106,93 @@return opts; } const ParseState = enum { no_command, with_command, }; pub fn parseArgs(self: *@This(), args: *std.process.ArgIterator) ParseArgsError!void { state: switch (ParseState.no_command) { .no_command => { while (args.next()) |arg| { if (Command.parse(arg)) |command| { switch (command) { .version => { self.command = .version; return; }, .help => { self.command = .help; return; }, .poll => { self.command = .poll; }, .report => { self.command = .report; }, .wait => { self.command = .wait; }, .list => { self.command = .{ .list = .{} }; }, } continue :state .with_command; } else |_| {} self.parseArg(arg, args) catch |err| { std.log.err("Unknown argument: {s}", .{arg}); return err; }; } }, .with_command => { while (args.next()) |arg| { self.parseArg(arg, args) catch |err| { std.log.err("Unknown argument: {s}", .{arg}); return err; }; } }, } } fn parseArg(self: *@This(), arg: []const u8, args: *std.process.ArgIterator) ParseArgsError!void { if (std.mem.eql(u8, "-v", arg) or std.mem.eql(u8, "--version", arg)) { self.command = .version; return; } if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) { self.command = .help; return; } if (self.command.parseArg(arg, args)) |_| { return; } else |_| {} if (std.mem.eql(u8, "--debug", arg)) { self.debug = true; return; } if (std.mem.eql(u8, "--utc", arg)) { self.utc = true; return; } if (std.mem.eql(u8, "--gmt", arg)) { std.log.warn("--gmt is deprecated. Use --utc instead.", .{}); self.utc = true; return; } return ParseArgsError.UnknownArg; } pub fn toC(self: *const @This()) c.runStruct { return c.runStruct{ .latitude = self.latitude,
-
@@ -60,10 +205,10 @@ .now2000 = self.now_delta,.target2000 = self.target_delta, .functionVersion = c.ONOFF_OFF, .functionUsage = c.ONOFF_OFF, .functionReport = self.function_report, .functionList = self.function_list, .functionPoll = self.function_poll, .functionWait = self.function_wait, .functionReport = c.ONOFF_OFF, .functionList = c.ONOFF_OFF, .functionPoll = c.ONOFF_OFF, .functionWait = c.ONOFF_OFF, .utc = if (self.utc) c.ONOFF_ON else c.ONOFF_OFF, .debug = if (self.debug) c.ONOFF_ON else c.ONOFF_OFF, .reportSunrise = self.report_sunrise,
-
-
-
@@ -32,6 +32,8 @@ day = 2,night = 3, out_of_memory = 10, stdout_write_error = 11, stderr_write_error = 12, incorrect_usage = 15, pub fn code(self: ExitCode) u8 { return @intFromEnum(self);
-
@@ -95,47 +97,53 @@ std.log.err("Got no arguments, exiting.", .{});return ExitCode.generic_error.code(); }; while (args.next()) |arg| { if (std.mem.eql(u8, "-v", arg) or std.mem.eql(u8, "--version", arg)) { std.fmt.format(std.io.getStdOut().writer(), "{s}\n", .{config.version}) catch |err| { std.log.err("Unable to write to stdout: {s}", .{@errorName(err)}); return ExitCode.stdout_write_error.code(); }; opts.parseArgs(&args) catch { writeHelp(std.io.getStdErr().writer(), bin_name) catch |err| { std.log.err("Unable to write help message to stderr: {s}", .{@errorName(err)}); return ExitCode.stdout_write_error.code(); }; return ExitCode.ok.code(); } return ExitCode.incorrect_usage.code(); }; if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) { switch (opts.command) { .help => { writeHelp(std.io.getStdOut().writer(), bin_name) catch |err| { std.log.err("Unable to write help message to stdout: {s}", .{@errorName(err)}); return ExitCode.stdout_write_error.code(); }; return ExitCode.ok.code(); } }, .version => { std.fmt.format(std.io.getStdOut().writer(), "{s}\n", .{config.version}) catch |err| { std.log.err("Unable to write to stdout: {s}", .{@errorName(err)}); return ExitCode.stdout_write_error.code(); }; if (std.mem.eql(u8, "--debug", arg)) { opts.debug = true; continue; } if (std.mem.eql(u8, "--utc", arg)) { opts.utc = true; continue; } return ExitCode.ok.code(); }, .poll => { var c_opts = opts.toC(); if (std.mem.eql(u8, "--gmt", arg)) { std.log.warn("--gmt is deprecated. Use --utc instead.", .{}); opts.utc = true; continue; } return switch (c.sunpoll(&c_opts)) { c.EXIT_DAY => ExitCode.day.code(), c.EXIT_NIGHT => ExitCode.night.code(), else => ExitCode.generic_error.code(), }; }, .list => |command_opts| { _ = command_opts; std.log.err("list command is not implemented", .{}); return ExitCode.generic_error.code(); }, .report => { std.log.err("report command is not implemented", .{}); return ExitCode.generic_error.code(); }, .wait => { std.log.err("wait command is not implemented", .{}); return ExitCode.generic_error.code(); }, } var c_opts = opts.toC(); return switch (c.sunpoll(&c_opts)) { c.EXIT_DAY => ExitCode.day.code(), c.EXIT_NIGHT => ExitCode.night.code(), else => ExitCode.generic_error.code(), }; }
-
-
-
@@ -60,7 +60,8 @@ try env.put("TZ", "UTC");const debug = try std.process.Child.run(.{ .allocator = std.testing.allocator, .argv = &.{ config.new_bin, "--debug", "poll", "29.977435N", "31.132484E" }, // TODO: Put coordinate once "poll" accepts lat/lon arguments .argv = &.{ config.new_bin, "--debug", "poll" }, .env_map = &env, }); defer std.testing.allocator.free(debug.stderr);
-