commit a68e6e67b160cd3a96aa2896bf73878e2e36b143 Author: Squibid Date: Wed Nov 5 13:26:29 2025 -0500 inital commit, still got some memory leaks but who cares diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a8052f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.zig-cache +zigout diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e932c9 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# ZMOTD - zig motd +Literally just a motd setter for my servers. diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..d9c3b7a --- /dev/null +++ b/build.zig @@ -0,0 +1,49 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const mod = b.addModule("zmotd", .{ + .root_source_file = b.path("src/main.zig"), + .target = target, + }); + + const exe = b.addExecutable(.{ + .name = "zmotd", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + .imports = &.{ + .{ .name = "zmotd", .module = mod }, + }, + }), + }); + + const ziglet = b.dependency("ziglet", .{ + .target = target, + .optimize = optimize, + }); + + const toml = b.dependency("toml", .{ + .target = target, + .optimize = optimize, + }); + + exe.linkLibC(); + exe.root_module.addImport("ziglet", ziglet.module("ziglet")); + b.installArtifact(exe); + + exe.root_module.addImport("toml", toml.module("toml")); + + const run_step = b.step("run", "Run the app"); + const run_cmd = b.addRunArtifact(exe); + run_step.dependOn(&run_cmd.step); + + run_cmd.step.dependOn(b.getInstallStep()); + + if (b.args) |args| { + run_cmd.addArgs(args); + } +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..825f617 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,22 @@ +.{ + .name = .zmotd, + .version = "1.0.0", + .fingerprint = 0xfe0bb503d94d9301, + .minimum_zig_version = "0.15.2", + .dependencies = .{ + .ziglet = .{ + .url = "https://codeberg.org/benteg/ziglet/archive/5366b65794d42f658da3d171eaa3321fafa2b52f.tar.gz", + .hash = "ziglet-0.1.0-QYl7SRPiAAAW4knyR898VHRmXzPcN25LK6b4tiDIkvSY", + }, + .toml = .{ + .url = "git+https://github.com/sam701/zig-toml?ref=zig-0.15#475b03c630c802f8b6bd3e239d8fc2279b4fadb8", + .hash = "toml-0.3.0-bV14BfV7AQD8DkuQI7skP8ekQTaBYKTO0MY_35Cw_EXo", + }, + }, + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + "README.md", + }, +} diff --git a/src/config.toml b/src/config.toml new file mode 100644 index 0000000..b05eb40 --- /dev/null +++ b/src/config.toml @@ -0,0 +1,7 @@ +entries = [ + { m = "hostname", f = "fig" }, + { m = "distro" }, + { m = "kernel" }, + { m = "load" }, + { m = "uptime" }, +] diff --git a/src/formatter.zig b/src/formatter.zig new file mode 100644 index 0000000..20e3bc8 --- /dev/null +++ b/src/formatter.zig @@ -0,0 +1,5 @@ +const formatter = @This(); + +name: []const u8, +/// takes an input value and returns it formatted +callback: *const fn(input: []const u8) anyerror![]const u8, diff --git a/src/formatters/fig.zig b/src/formatters/fig.zig new file mode 100644 index 0000000..0be386a --- /dev/null +++ b/src/formatters/fig.zig @@ -0,0 +1,18 @@ +const std = @import("std"); +const ziglet = @import("ziglet"); +const formatter = @import("../formatter.zig"); + +const gpa = std.heap.page_allocator; + +fn cb(input: []const u8) ![]const u8 { + const font_buffer: []const u8 = @embedFile("small.flf"); + var font = try ziglet.DefaultFont.init(gpa, font_buffer); + defer font.deinit(gpa); + const result = try font.formatter().formatText(gpa, input, .{}); + return result; +} + +pub const fig = formatter { + .name = "fig", + .callback = cb +}; diff --git a/src/formatters/init.zig b/src/formatters/init.zig new file mode 100644 index 0000000..a81a477 --- /dev/null +++ b/src/formatters/init.zig @@ -0,0 +1,5 @@ +const formatter = @import("../formatter.zig"); + +pub const formatters = [_]formatter { + @import("fig.zig").fig, +}; diff --git a/src/formatters/small.flf b/src/formatters/small.flf new file mode 100644 index 0000000..d2a2c49 --- /dev/null +++ b/src/formatters/small.flf @@ -0,0 +1,1097 @@ +flf2a$ 5 4 13 15 10 0 22415 +Small by Glenn Chappell 4/93 -- based on Standard +Includes ISO Latin-1 +figlet release 2.1 -- 12 Aug 1994 +Permission is hereby given to modify this font, as long as the +modifier's name is placed on a comment line. + +Modified by Paul Burton 12/96 to include new parameter +supported by FIGlet and FIGWin. May also be slightly modified for better use +of new full-width/kern/smush alternatives, but default output is NOT changed. + + $@ + $@ + $@ + $@ + $@@ + _ @ + | |@ + |_|@ + (_)@ + @@ + _ _ @ + ( | )@ + V V @ + $ @ + @@ + _ _ @ + _| | |_ @ + |_ . _|@ + |_ _|@ + |_|_| @@ + @ + ||_@ + (_-<@ + / _/@ + || @@ + _ __ @ + (_)/ / @ + / /_ @ + /_/(_)@ + @@ + __ @ + / _|___ @ + > _|_ _|@ + \_____| @ + @@ + _ @ + ( )@ + |/ @ + $ @ + @@ + __@ + / /@ + | | @ + | | @ + \_\@@ + __ @ + \ \ @ + | |@ + | |@ + /_/ @@ + @ + _/\_@ + > <@ + \/ @ + @@ + _ @ + _| |_ @ + |_ _|@ + |_| @ + @@ + @ + @ + _ @ + ( )@ + |/ @@ + @ + ___ @ + |___|@ + $ @ + @@ + @ + @ + _ @ + (_)@ + @@ + __@ + / /@ + / / @ + /_/ @ + @@ + __ @ + / \ @ + | () |@ + \__/ @ + @@ + _ @ + / |@ + | |@ + |_|@ + @@ + ___ @ + |_ )@ + / / @ + /___|@ + @@ + ____@ + |__ /@ + |_ \@ + |___/@ + @@ + _ _ @ + | | | @ + |_ _|@ + |_| @ + @@ + ___ @ + | __|@ + |__ \@ + |___/@ + @@ + __ @ + / / @ + / _ \@ + \___/@ + @@ + ____ @ + |__ |@ + / / @ + /_/ @ + @@ + ___ @ + ( _ )@ + / _ \@ + \___/@ + @@ + ___ @ + / _ \@ + \_, /@ + /_/ @ + @@ + _ @ + (_)@ + _ @ + (_)@ + @@ + _ @ + (_)@ + _ @ + ( )@ + |/ @@ + __@ + / /@ + < < @ + \_\@ + @@ + @ + ___ @ + |___|@ + |___|@ + @@ + __ @ + \ \ @ + > >@ + /_/ @ + @@ + ___ @ + |__ \@ + /_/@ + (_) @ + @@ + ____ @ + / __ \ @ + / / _` |@ + \ \__,_|@ + \____/ @@ + _ @ + /_\ @ + / _ \ @ + /_/ \_\@ + @@ + ___ @ + | _ )@ + | _ \@ + |___/@ + @@ + ___ @ + / __|@ + | (__ @ + \___|@ + @@ + ___ @ + | \ @ + | |) |@ + |___/ @ + @@ + ___ @ + | __|@ + | _| @ + |___|@ + @@ + ___ @ + | __|@ + | _| @ + |_| @ + @@ + ___ @ + / __|@ + | (_ |@ + \___|@ + @@ + _ _ @ + | || |@ + | __ |@ + |_||_|@ + @@ + ___ @ + |_ _|@ + | | @ + |___|@ + @@ + _ @ + _ | |@ + | || |@ + \__/ @ + @@ + _ __@ + | |/ /@ + | ' < @ + |_|\_\@ + @@ + _ @ + | | @ + | |__ @ + |____|@ + @@ + __ __ @ + | \/ |@ + | |\/| |@ + |_| |_|@ + @@ + _ _ @ + | \| |@ + | .` |@ + |_|\_|@ + @@ + ___ @ + / _ \ @ + | (_) |@ + \___/ @ + @@ + ___ @ + | _ \@ + | _/@ + |_| @ + @@ + ___ @ + / _ \ @ + | (_) |@ + \__\_\@ + @@ + ___ @ + | _ \@ + | /@ + |_|_\@ + @@ + ___ @ + / __|@ + \__ \@ + |___/@ + @@ + _____ @ + |_ _|@ + | | @ + |_| @ + @@ + _ _ @ + | | | |@ + | |_| |@ + \___/ @ + @@ + __ __@ + \ \ / /@ + \ V / @ + \_/ @ + @@ + __ __@ + \ \ / /@ + \ \/\/ / @ + \_/\_/ @ + @@ + __ __@ + \ \/ /@ + > < @ + /_/\_\@ + @@ + __ __@ + \ \ / /@ + \ V / @ + |_| @ + @@ + ____@ + |_ /@ + / / @ + /___|@ + @@ + __ @ + | _|@ + | | @ + | | @ + |__|@@ + __ @ + \ \ @ + \ \ @ + \_\@ + @@ + __ @ + |_ |@ + | |@ + | |@ + |__|@@ + /\ @ + |/\|@ + $ @ + $ @ + @@ + @ + @ + @ + ___ @ + |___|@@ + _ @ + ( )@ + \|@ + $ @ + @@ + @ + __ _ @ + / _` |@ + \__,_|@ + @@ + _ @ + | |__ @ + | '_ \@ + |_.__/@ + @@ + @ + __ @ + / _|@ + \__|@ + @@ + _ @ + __| |@ + / _` |@ + \__,_|@ + @@ + @ + ___ @ + / -_)@ + \___|@ + @@ + __ @ + / _|@ + | _|@ + |_| @ + @@ + @ + __ _ @ + / _` |@ + \__, |@ + |___/ @@ + _ @ + | |_ @ + | ' \ @ + |_||_|@ + @@ + _ @ + (_)@ + | |@ + |_|@ + @@ + _ @ + (_)@ + | |@ + _/ |@ + |__/ @@ + _ @ + | |__@ + | / /@ + |_\_\@ + @@ + _ @ + | |@ + | |@ + |_|@ + @@ + @ + _ __ @ + | ' \ @ + |_|_|_|@ + @@ + @ + _ _ @ + | ' \ @ + |_||_|@ + @@ + @ + ___ @ + / _ \@ + \___/@ + @@ + @ + _ __ @ + | '_ \@ + | .__/@ + |_| @@ + @ + __ _ @ + / _` |@ + \__, |@ + |_|@@ + @ + _ _ @ + | '_|@ + |_| @ + @@ + @ + ___@ + (_-<@ + /__/@ + @@ + _ @ + | |_ @ + | _|@ + \__|@ + @@ + @ + _ _ @ + | || |@ + \_,_|@ + @@ + @ + __ __@ + \ V /@ + \_/ @ + @@ + @ + __ __ __@ + \ V V /@ + \_/\_/ @ + @@ + @ + __ __@ + \ \ /@ + /_\_\@ + @@ + @ + _ _ @ + | || |@ + \_, |@ + |__/ @@ + @ + ___@ + |_ /@ + /__|@ + @@ + __@ + / /@ + _| | @ + | | @ + \_\@@ + _ @ + | |@ + | |@ + | |@ + |_|@@ + __ @ + \ \ @ + | |_@ + | | @ + /_/ @@ + /\/|@ + |/\/ @ + $ @ + $ @ + @@ + _ _ @ + (_)(_)@ + /--\ @ + /_/\_\@ + @@ + _ _ @ + (_)(_)@ + / __ \@ + \____/@ + @@ + _ _ @ + (_) (_)@ + | |_| |@ + \___/ @ + @@ + _ _ @ + (_)(_)@ + / _` |@ + \__,_|@ + @@ + _ _ @ + (_)_(_)@ + / _ \ @ + \___/ @ + @@ + _ _ @ + (_)(_)@ + | || |@ + \_,_|@ + @@ + ___ @ + / _ \@ + | |< <@ + | ||_/@ + |_| @@ +160 NO-BREAK SPACE + $@ + $@ + $@ + $@ + $@@ +161 INVERTED EXCLAMATION MARK + _ @ + (_)@ + | |@ + |_|@ + @@ +162 CENT SIGN + @ + || @ + / _)@ + \ _)@ + || @@ +163 POUND SIGN + __ @ + _/ _\ @ + |_ _|_ @ + (_,___|@ + @@ +164 CURRENCY SIGN + /\_/\@ + \ . /@ + / _ \@ + \/ \/@ + @@ +165 YEN SIGN + __ __ @ + \ V / @ + |__ __|@ + |__ __|@ + |_| @@ +166 BROKEN BAR + _ @ + | |@ + |_|@ + | |@ + |_|@@ +167 SECTION SIGN + __ @ + / _)@ + /\ \ @ + \ \/ @ + (__/ @@ +168 DIAERESIS + _ _ @ + (_)(_)@ + $ $ @ + $ $ @ + @@ +169 COPYRIGHT SIGN + ____ @ + / __ \ @ + / / _| \@ + \ \__| /@ + \____/ @@ +170 FEMININE ORDINAL INDICATOR + __ _ @ + / _` |@ + \__,_|@ + |____|@ + @@ +171 LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + ____@ + / / /@ + < < < @ + \_\_\@ + @@ +172 NOT SIGN + ____ @ + |__ |@ + |_|@ + $ @ + @@ +173 SOFT HYPHEN + @ + __ @ + |__|@ + $ @ + @@ +174 REGISTERED SIGN + ____ @ + / __ \ @ + / | -) \@ + \ ||\\ /@ + \____/ @@ +175 MACRON + ___ @ + |___|@ + $ @ + $ @ + @@ +176 DEGREE SIGN + _ @ + /.\@ + \_/@ + $ @ + @@ +177 PLUS-MINUS SIGN + _ @ + _| |_ @ + |_ _|@ + _|_|_ @ + |_____|@@ +178 SUPERSCRIPT TWO + __ @ + |_ )@ + /__|@ + $ @ + @@ +179 SUPERSCRIPT THREE + ___@ + |_ /@ + |__)@ + $ @ + @@ +180 ACUTE ACCENT + __@ + /_/@ + $ @ + $ @ + @@ +181 MICRO SIGN + @ + _ _ @ + | || |@ + | .,_|@ + |_| @@ +182 PILCROW SIGN + ____ @ + / |@ + \_ | |@ + |_|_|@ + @@ +183 MIDDLE DOT + @ + _ @ + (_)@ + $ @ + @@ +184 CEDILLA + @ + @ + @ + _ @ + )_)@@ +185 SUPERSCRIPT ONE + _ @ + / |@ + |_|@ + $ @ + @@ +186 MASCULINE ORDINAL INDICATOR + ___ @ + / _ \@ + \___/@ + |___|@ + @@ +187 RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + ____ @ + \ \ \ @ + > > >@ + /_/_/ @ + @@ +188 VULGAR FRACTION ONE QUARTER + _ __ @ + / |/ /__ @ + |_/ /_' |@ + /_/ |_|@ + @@ +189 VULGAR FRACTION ONE HALF + _ __ @ + / |/ /_ @ + |_/ /_ )@ + /_//__|@ + @@ +190 VULGAR FRACTION THREE QUARTERS + ___ __ @ + |_ // /__ @ + |__) /_' |@ + /_/ |_|@ + @@ +191 INVERTED QUESTION MARK + _ @ + (_) @ + / /_ @ + \___|@ + @@ +192 LATIN CAPITAL LETTER A WITH GRAVE + __ @ + \_\ @ + /--\ @ + /_/\_\@ + @@ +193 LATIN CAPITAL LETTER A WITH ACUTE + __ @ + /_/ @ + /--\ @ + /_/\_\@ + @@ +194 LATIN CAPITAL LETTER A WITH CIRCUMFLEX + /\ @ + |/\| @ + /--\ @ + /_/\_\@ + @@ +195 LATIN CAPITAL LETTER A WITH TILDE + /\/|@ + |/\/ @ + /--\ @ + /_/\_\@ + @@ +196 LATIN CAPITAL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + /--\ @ + /_/\_\@ + @@ +197 LATIN CAPITAL LETTER A WITH RING ABOVE + __ @ + (()) @ + /--\ @ + /_/\_\@ + @@ +198 LATIN CAPITAL LETTER AE + ____ @ + /, __|@ + / _ _| @ + /_/|___|@ + @@ +199 LATIN CAPITAL LETTER C WITH CEDILLA + ___ @ + / __|@ + | (__ @ + \___|@ + )_) @@ +200 LATIN CAPITAL LETTER E WITH GRAVE + __ @ + \_\@ + | -<@ + |__<@ + @@ +201 LATIN CAPITAL LETTER E WITH ACUTE + __@ + /_/@ + | -<@ + |__<@ + @@ +202 LATIN CAPITAL LETTER E WITH CIRCUMFLEX + /\ @ + |/\|@ + | -<@ + |__<@ + @@ +203 LATIN CAPITAL LETTER E WITH DIAERESIS + _ _ @ + (_)(_)@ + | -< @ + |__< @ + @@ +204 LATIN CAPITAL LETTER I WITH GRAVE + __ @ + \_\ @ + |_ _|@ + |___|@ + @@ +205 LATIN CAPITAL LETTER I WITH ACUTE + __ @ + /_/ @ + |_ _|@ + |___|@ + @@ +206 LATIN CAPITAL LETTER I WITH CIRCUMFLEX + //\ @ + |/_\|@ + |_ _|@ + |___|@ + @@ +207 LATIN CAPITAL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + |_ _| @ + |___| @ + @@ +208 LATIN CAPITAL LETTER ETH + ____ @ + | __ \ @ + |_ _|) |@ + |____/ @ + @@ +209 LATIN CAPITAL LETTER N WITH TILDE + /\/|@ + |/\/ @ + | \| |@ + |_|\_|@ + @@ +210 LATIN CAPITAL LETTER O WITH GRAVE + __ @ + \_\_ @ + / __ \@ + \____/@ + @@ +211 LATIN CAPITAL LETTER O WITH ACUTE + __ @ + _/_/ @ + / __ \@ + \____/@ + @@ +212 LATIN CAPITAL LETTER O WITH CIRCUMFLEX + /\ @ + |/\| @ + / __ \@ + \____/@ + @@ +213 LATIN CAPITAL LETTER O WITH TILDE + /\/|@ + |/\/ @ + / __ \@ + \____/@ + @@ +214 LATIN CAPITAL LETTER O WITH DIAERESIS + _ _ @ + (_)(_)@ + / __ \@ + \____/@ + @@ +215 MULTIPLICATION SIGN + @ + /\/\@ + > <@ + \/\/@ + @@ +216 LATIN CAPITAL LETTER O WITH STROKE + ____ @ + / _//\ @ + | (//) |@ + \//__/ @ + @@ +217 LATIN CAPITAL LETTER U WITH GRAVE + __ @ + _\_\_ @ + | |_| |@ + \___/ @ + @@ +218 LATIN CAPITAL LETTER U WITH ACUTE + __ @ + _/_/_ @ + | |_| |@ + \___/ @ + @@ +219 LATIN CAPITAL LETTER U WITH CIRCUMFLEX + //\ @ + |/ \| @ + | |_| |@ + \___/ @ + @@ +220 LATIN CAPITAL LETTER U WITH DIAERESIS + _ _ @ + (_) (_)@ + | |_| |@ + \___/ @ + @@ +221 LATIN CAPITAL LETTER Y WITH ACUTE + __ @ + _/_/_@ + \ V /@ + |_| @ + @@ +222 LATIN CAPITAL LETTER THORN + _ @ + | |_ @ + | -_)@ + |_| @ + @@ +223 LATIN SMALL LETTER SHARP S + ___ @ + / _ \@ + | |< <@ + | ||_/@ + |_| @@ +224 LATIN SMALL LETTER A WITH GRAVE + __ @ + \_\_ @ + / _` |@ + \__,_|@ + @@ +225 LATIN SMALL LETTER A WITH ACUTE + __ @ + _/_/ @ + / _` |@ + \__,_|@ + @@ +226 LATIN SMALL LETTER A WITH CIRCUMFLEX + /\ @ + |/\| @ + / _` |@ + \__,_|@ + @@ +227 LATIN SMALL LETTER A WITH TILDE + /\/|@ + |/\/ @ + / _` |@ + \__,_|@ + @@ +228 LATIN SMALL LETTER A WITH DIAERESIS + _ _ @ + (_)(_)@ + / _` |@ + \__,_|@ + @@ +229 LATIN SMALL LETTER A WITH RING ABOVE + __ @ + (()) @ + / _` |@ + \__,_|@ + @@ +230 LATIN SMALL LETTER AE + @ + __ ___ @ + / _` -_)@ + \__,___|@ + @@ +231 LATIN SMALL LETTER C WITH CEDILLA + @ + __ @ + / _|@ + \__|@ + )_)@@ +232 LATIN SMALL LETTER E WITH GRAVE + __ @ + \_\ @ + / -_)@ + \___|@ + @@ +233 LATIN SMALL LETTER E WITH ACUTE + __ @ + /_/ @ + / -_)@ + \___|@ + @@ +234 LATIN SMALL LETTER E WITH CIRCUMFLEX + //\ @ + |/_\|@ + / -_)@ + \___|@ + @@ +235 LATIN SMALL LETTER E WITH DIAERESIS + _ _ @ + (_)_(_)@ + / -_) @ + \___| @ + @@ +236 LATIN SMALL LETTER I WITH GRAVE + __ @ + \_\@ + | |@ + |_|@ + @@ +237 LATIN SMALL LETTER I WITH ACUTE + __@ + /_/@ + | |@ + |_|@ + @@ +238 LATIN SMALL LETTER I WITH CIRCUMFLEX + //\ @ + |/_\|@ + | | @ + |_| @ + @@ +239 LATIN SMALL LETTER I WITH DIAERESIS + _ _ @ + (_)_(_)@ + | | @ + |_| @ + @@ +240 LATIN SMALL LETTER ETH + \\/\ @ + \/\\ @ + / _` |@ + \___/ @ + @@ +241 LATIN SMALL LETTER N WITH TILDE + /\/| @ + |/\/ @ + | ' \ @ + |_||_|@ + @@ +242 LATIN SMALL LETTER O WITH GRAVE + __ @ + \_\ @ + / _ \@ + \___/@ + @@ +243 LATIN SMALL LETTER O WITH ACUTE + __ @ + /_/ @ + / _ \@ + \___/@ + @@ +244 LATIN SMALL LETTER O WITH CIRCUMFLEX + //\ @ + |/_\|@ + / _ \@ + \___/@ + @@ +245 LATIN SMALL LETTER O WITH TILDE + /\/|@ + |/\/ @ + / _ \@ + \___/@ + @@ +246 LATIN SMALL LETTER O WITH DIAERESIS + _ _ @ + (_)_(_)@ + / _ \ @ + \___/ @ + @@ +247 DIVISION SIGN + _ @ + (_) @ + |___|@ + (_) @ + @@ +248 LATIN SMALL LETTER O WITH STROKE + @ + ___ @ + / //\@ + \//_/@ + @@ +249 LATIN SMALL LETTER U WITH GRAVE + __ @ + \_\_ @ + | || |@ + \_,_|@ + @@ +250 LATIN SMALL LETTER U WITH ACUTE + __ @ + _/_/ @ + | || |@ + \_,_|@ + @@ +251 LATIN SMALL LETTER U WITH CIRCUMFLEX + /\ @ + |/\| @ + | || |@ + \_,_|@ + @@ +252 LATIN SMALL LETTER U WITH DIAERESIS + _ _ @ + (_)(_)@ + | || |@ + \_,_|@ + @@ +253 LATIN SMALL LETTER Y WITH ACUTE + __ @ + _/_/ @ + | || |@ + \_, |@ + |__/ @@ +254 LATIN SMALL LETTER THORN + _ @ + | |__ @ + | '_ \@ + | .__/@ + |_| @@ +255 LATIN SMALL LETTER Y WITH DIAERESIS + _ _ @ + (_)(_)@ + | || |@ + \_, |@ + |__/ @@ diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..e2cc808 --- /dev/null +++ b/src/main.zig @@ -0,0 +1,80 @@ +const std = @import("std"); +const toml = @import("toml"); + +const formatters = @import("formatters/init.zig"); +const formatter = @import("formatter.zig"); +const modules = @import("modules/init.zig"); +const module = @import("module.zig"); + +const gpa = std.heap.page_allocator; + +const Entry = struct { + m: []const u8, // modifier + f: ?[]const u8, // format +}; + +const Config = struct { + entries: []const Entry, +}; + +pub fn main() !void { + var parser = toml.Parser(Config).init(gpa); + defer parser.deinit(); + + var args = std.process.args(); + _ = args.next(); // skip the first argument + const config_path = args.next(); // use the second argument as the config path + + var result: ?toml.Parsed(Config) = null; + if (config_path) |c| { + result = parser.parseFile(c) catch null; + } + if (result == null) { + result = try parser.parseString(@embedFile("config.toml")); + } + defer result.?.deinit(); + + // setup the stdout printer which is setup to only print on exit + var buf: [1024]u8 = undefined; + var stdout_writer = std.fs.File.stdout().writer(&buf); + const stdout = &stdout_writer.interface; + defer stdout.flush() catch {}; + + // print out all modules in order based on the config + const config = result.?.value; + for (config.entries) |entry| { + var mod: module = undefined; + var fmt: ?formatter = null; + + // modules + for (modules.modules) |m| { + if (std.mem.eql(u8, entry.m, m.name)) { + mod = m; + break; + } + } + + // formats + if (entry.f) |format| { + for (formatters.formatters) |f| { + if (std.mem.eql(u8, format, f.name)) { + fmt = f; + break; + } + } + } + + // get the data and format if needed + const tmp = try mod.callback(); + var txt: []const u8 = tmp; + if (fmt) |f| { + txt = try f.callback(tmp); + } + + // print the module + try stdout.print("{s}{s}\n", .{ + if (fmt) |_| "" else mod.prefix, + txt, + }); + } +} diff --git a/src/module.zig b/src/module.zig new file mode 100644 index 0000000..6514bdf --- /dev/null +++ b/src/module.zig @@ -0,0 +1,7 @@ +const module = @This(); + +name: []const u8, +/// the prefix to use when displaying this module without any formatting +prefix: []const u8, +/// returns information +callback: *const fn() anyerror![]const u8, diff --git a/src/modules/distro.zig b/src/modules/distro.zig new file mode 100644 index 0000000..e6b134d --- /dev/null +++ b/src/modules/distro.zig @@ -0,0 +1,36 @@ +const std = @import("std"); +const module = @import("../module.zig"); + +const gpa = std.heap.page_allocator; + +fn cb() anyerror![]const u8 { + var file = try std.fs.openFileAbsolute("/etc/os-release", .{}); + defer file.close(); + + const contents = try file.readToEndAlloc(gpa, 1024); // read max 1024 bytes + defer gpa.free(contents); + + var lines = std.mem.splitSequence(u8, contents, "\n"); + while (lines.next()) |line| { + if (std.mem.startsWith(u8, line, "NAME=")) { + // Strip 'NAME=' and optional quotes + var name_line = line[5..]; + if (name_line.len >= 2 and name_line[0] == '"' and name_line[name_line.len - 1] == '"') { + name_line = name_line[1..name_line.len - 1]; + } + + // Allocate copy to return + const os_name = try gpa.alloc(u8, name_line.len); + std.mem.copyForwards(u8, os_name, name_line); + return os_name; + } + } + + return "Unknown OS"; +} + +pub const distro = module { + .name = "distro", + .prefix = "Distro: ", + .callback = cb +}; diff --git a/src/modules/hostname.zig b/src/modules/hostname.zig new file mode 100644 index 0000000..068d357 --- /dev/null +++ b/src/modules/hostname.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const c = @cImport({ @cInclude("unistd.h"); }); +const module = @import("../module.zig"); + +fn cb() ![]const u8 { + var file = try std.fs.openFileAbsolute("/etc/hostname", .{}); + defer file.close(); + + const max_hostname_size = c.sysconf(c._SC_HOST_NAME_MAX); + const buffer = try std.heap.page_allocator.alloc(u8, @intCast(max_hostname_size)); + const bytes_read = try file.read(buffer); + return buffer[0..bytes_read]; +} + +pub const hostname = module { + .name = "hostname", + .prefix = "Hostname: ", + .callback = cb +}; diff --git a/src/modules/init.zig b/src/modules/init.zig new file mode 100644 index 0000000..3728f6c --- /dev/null +++ b/src/modules/init.zig @@ -0,0 +1,9 @@ +const module = @import("../module.zig"); + +pub const modules = [_]module { + @import("distro.zig").distro, + @import("hostname.zig").hostname, + @import("kernel.zig").kernel, + @import("load.zig").load, + @import("uptime.zig").uptime, +}; diff --git a/src/modules/kernel.zig b/src/modules/kernel.zig new file mode 100644 index 0000000..4a56c93 --- /dev/null +++ b/src/modules/kernel.zig @@ -0,0 +1,25 @@ +const std = @import("std"); +const module = @import("../module.zig"); + +const gpa = std.heap.page_allocator; + +fn cb() ![]const u8 { + var uname_buf: std.os.linux.utsname = undefined; + _ = std.os.linux.uname(&uname_buf); + + // Find the null-terminated end of the release string + var len: usize = 0; + while (uname_buf.release[len] != 0) : (len += 1) {} + + // Allocate and copy the string + const kernel_str = try gpa.alloc(u8, len); + std.mem.copyForwards(u8, kernel_str, uname_buf.release[0..len]); + + return kernel_str; +} + +pub const kernel = module { + .name = "kernel", + .prefix = "Kernel: ", + .callback = cb +}; diff --git a/src/modules/load.zig b/src/modules/load.zig new file mode 100644 index 0000000..01b617a --- /dev/null +++ b/src/modules/load.zig @@ -0,0 +1,28 @@ +const std = @import("std"); +const c = @cImport({ @cInclude("stdlib.h"); }); +const module = @import("../module.zig"); + +const gpa = std.heap.page_allocator; + +fn cb() ![]const u8 { + const load_nr = 3; + const loads: []f64 = try gpa.alloc(f64, load_nr); + _ = c.getloadavg(loads.ptr, load_nr); + + var list = try std.ArrayList(u8).initCapacity(gpa, 4); + defer list.deinit(gpa); + var writer = list.writer(gpa); + + var i: u8 = 0; + while (i < load_nr) : (i += 1) { + try writer.print("{d:.2}{s}", .{loads[i], if (i != load_nr - 1) ", " else ""}); + } + + return list.toOwnedSlice(gpa); +} + +pub const load = module { + .name = "load", + .prefix = "Load: ", + .callback = cb +}; diff --git a/src/modules/uptime.zig b/src/modules/uptime.zig new file mode 100644 index 0000000..53db7cc --- /dev/null +++ b/src/modules/uptime.zig @@ -0,0 +1,25 @@ +const std = @import("std"); +const c = @cImport({ @cInclude("unistd.h"); }); +const utils = @import("../utils.zig"); +const module = @import("../module.zig"); + +fn cb() ![]const u8 { + var file = try std.fs.cwd().openFile("/proc/uptime", .{}); + defer file.close(); + + var buf: [64]u8 = undefined; + const bytes_read = try file.readAll(&buf); + const data = buf[0..bytes_read]; + + var tok = std.mem.tokenizeAny(u8, data, " "); + const first_tok = tok.next() orelse return error.InvalidFormat; + const uptime_seconds = try std.fmt.parseFloat(f64, first_tok); + + return try utils.secs_to_time(@intFromFloat(uptime_seconds)); +} + +pub const uptime = module { + .name = "uptime", + .prefix = "Uptime: ", + .callback = cb +}; diff --git a/src/utils.zig b/src/utils.zig new file mode 100644 index 0000000..7bcf489 --- /dev/null +++ b/src/utils.zig @@ -0,0 +1,35 @@ +const std = @import("std"); + +const gpa = std.heap.page_allocator; + +pub fn secs_to_time(secs: u64) ![]const u8 { + var list = try std.ArrayList(u8).initCapacity(gpa, 4); + defer list.deinit(gpa); + var writer = list.writer(gpa); + var seconds = secs; + + const minute = 1 * 60; + const hour = minute * 60; + const day = hour * 24; + const week = day * 7; + + const weeks = seconds / week; + seconds = seconds % week; + const days = seconds / day; + seconds = seconds % day; + const hours = seconds / hour; + seconds = seconds % hour; + const minutes = seconds / minute; + seconds = seconds % minute; + + if (weeks > 0) try writer.print("{} {s}{s}, ", .{weeks, "week", if (weeks > 1) "s" else ""}); + if (days > 0) try writer.print("{} {s}{s}, ", .{days, "day", if (days > 1) "s" else ""}); + if (hours > 0) try writer.print("{} {s}{s}, ", .{hours, "hour", if (hours > 1) "s" else ""}); + if (minutes > 0) try writer.print("{} {s}{s}", .{minutes, "minute", if (minutes > 1) "s" else ""}); + + if (weeks == 0 and days == 0 and hours == 0 and minutes == 0) { + try writer.print("{} {s}{s}", .{seconds, "second", if (seconds > 1) "s" else ""}); + } + + return try list.toOwnedSlice(gpa); +} diff --git a/zig-out/bin/zmotd b/zig-out/bin/zmotd new file mode 100755 index 0000000..e7b5d76 Binary files /dev/null and b/zig-out/bin/zmotd differ