Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,26 @@ const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "ziglets",
const exe_root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "ziglets",
.root_module = exe_root_module,
.version = std.SemanticVersion.parse("0.1.0") catch null,
});
b.installArtifact(exe); // Add test support
const exe_unit_tests = b.addTest(.{
b.installArtifact(exe);

const test_root_module = b.createModule(.{
.root_source_file = b.path("src/tests.zig"),
.target = target,
.optimize = optimize,
});
const exe_unit_tests = b.addTest(.{
.root_module = test_root_module,
});

const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

Expand Down
29 changes: 14 additions & 15 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,43 +47,42 @@ pub const commands = [_]Command{
};

fn helpHandler(_: std.mem.Allocator, _: []const []const u8) !void {
const stdout = std.io.getStdOut().writer();
try stdout.print(
const io = std.Io.Threaded.global_single_threaded.io();
var stdout_buffer: [0]u8 = undefined;
var stdout = std.Io.File.stdout().writer(io, &stdout_buffer);
try stdout.interface.print(
\\ziglets <command>
\\
\\Available commands:
\\
, .{});
for (commands) |cmd| {
// Print the command name, padded to 10 chars, and its description
try stdout.print(" {s: <12} {s}\n", .{ cmd.name, cmd.description });
try stdout.interface.print(" {s: <12} {s}\n", .{ cmd.name, cmd.description });
}
try stdout.print("\n", .{});
try stdout.interface.print("\n", .{});
}

pub fn main() !void {
pub fn main(init: std.process.Init.Minimal) !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();

var args_iter = try std.process.argsWithAllocator(arena.allocator());
var args = std.ArrayList([]const u8).init(arena.allocator());

while (true) {
const arg = args_iter.next();
if (arg == null) break;
try args.append(arg.?);
const raw_args = try std.process.Args.toSlice(init.args, arena.allocator());
const args = try arena.allocator().alloc([]const u8, raw_args.len);
for (raw_args, 0..) |arg, i| {
args[i] = arg;
}

if (args.items.len < 2) {
if (args.len < 2) {
std.debug.print("Usage: ziglets <command>\n", .{});
std.debug.print("Try 'ziglets help' for more information.\n", .{});
return error.InvalidArguments;
}

const command = args.items[1];
const command = args[1];
for (commands) |cmd| {
if (std.mem.eql(u8, command, cmd.name)) {
try cmd.handler(arena.allocator(), args.items[2..]);
try cmd.handler(arena.allocator(), args[2..]);
return;
}
}
Expand Down
64 changes: 30 additions & 34 deletions src/ziglets/calculator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const State = struct {
};

// Print the calculator display
fn printDisplay(state: *State, writer: anytype) !void {
fn printDisplay(state: *State, writer: *std.Io.Writer) !void {
if (state.entering_operand) {
try writer.print("\r{d:.8} ", .{state.operand});
} else {
Expand Down Expand Up @@ -67,16 +67,6 @@ const RawMode = if (builtin.os.tag == .windows) struct {
const posix = std.posix;

// Definizione manuale dei flag POSIX se non presenti in std.posix
const ICANON: u32 = 0x0002; // 0b0000000000000010
const ECHO: u32 = 0x0008; // 0b0000000000001000
const ISIG: u32 = 0x0001; // 0b0000000000000001
const IEXTEN: u32 = 0x8000; // 0b1000000000000000
const IXON: u32 = 0x0400; // 0b0000010000000000
const ICRNL: u32 = 0x0100; // 0b0000000100000000
const BRKINT: u32 = 0x0002; // 0b0000000000000010
const INPCK: u32 = 0x0010; // 0b0000000001000000
const ISTRIP: u32 = 0x0020; // 0b0000000010000000
const OPOST: u32 = 0x0001; // 0b0000000000000001
const VMIN: u32 = 6; // 0b0000000000010110
const VTIME: u32 = 5; // 0b0000000000010101

Expand All @@ -88,9 +78,16 @@ const RawMode = if (builtin.os.tag == .windows) struct {
var raw = original_termios;

// Disabilita echo, modalità canonica e segnali
raw.lflag = @bitCast(@as(u32, @bitCast(raw.lflag)) & ~@as(u32, ICANON | ECHO | ISIG | IEXTEN));
raw.iflag = @bitCast(@as(u32, @bitCast(raw.iflag)) & ~@as(u32, IXON | ICRNL | BRKINT | INPCK | ISTRIP));
raw.oflag = @bitCast(@as(u32, @bitCast(raw.oflag)) & ~@as(u32, OPOST));
raw.lflag.ICANON = false;
raw.lflag.ECHO = false;
raw.lflag.ISIG = false;
raw.lflag.IEXTEN = false;
raw.iflag.IXON = false;
raw.iflag.ICRNL = false;
raw.iflag.BRKINT = false;
raw.iflag.INPCK = false;
raw.iflag.ISTRIP = false;
raw.oflag.OPOST = false;
raw.cc[VMIN] = 1;
raw.cc[VTIME] = 0;

Expand All @@ -103,35 +100,34 @@ const RawMode = if (builtin.os.tag == .windows) struct {
};

pub fn run(_: std.mem.Allocator, _: []const []const u8) !void {
const io = std.Io.Threaded.global_single_threaded.io();
var state = State{};
var stdin = std.io.getStdIn().reader();
var stdout = std.io.getStdOut().writer();
var stdin_buffer: [128]u8 = undefined;
var stdout_buffer: [0]u8 = undefined;
var stdin = std.Io.File.stdin().reader(io, &stdin_buffer);
var stdout = std.Io.File.stdout().writer(io, &stdout_buffer);

// Abilita la modalità raw per l'input istantaneo
try RawMode.enable();
defer {
RawMode.disable() catch {};
}

try stdout.print("Calculator (press Q to exit)\n", .{});
try printDisplay(&state, stdout);
try stdout.interface.print("Calculator (press Q to exit)\n", .{});
try printDisplay(&state, &stdout.interface);

while (true) {
var buf: [1]u8 = undefined;

// Leggiamo un singolo carattere (ora senza bisogno di premere Enter)
const bytes_read = stdin.read(&buf) catch |err| {
try stdout.print("\nError durante la lettura: {s}\n", .{@errorName(err)});
return err;
const c = stdin.interface.takeByte() catch |err| switch (err) {
error.EndOfStream => return,
error.ReadFailed => {
try stdout.interface.print("\nError durante la lettura: {s}\n", .{@errorName(stdin.err.?)});
return stdin.err.?;
},
};

// Se non abbiamo letto nulla, continuiamo
if (bytes_read == 0) continue;

const c = buf[0];

if (c == 'q' or c == 'Q') { // Q key
try stdout.print("\nBye!\n", .{});
try stdout.interface.print("\nBye!\n", .{});
return;
}

Expand All @@ -156,7 +152,7 @@ pub fn run(_: std.mem.Allocator, _: []const []const u8) !void {
else => digit = 0, // Should not happen due to the check above
}
state.operand = state.operand * 10 + digit;
try printDisplay(&state, stdout);
try printDisplay(&state, &stdout.interface);
} else if (c == '.' or c == ',') {
// Decimal point not implemented for simplicity
} else if (c == '+' or c == '-' or c == '*' or c == '/') {
Expand All @@ -170,23 +166,23 @@ pub fn run(_: std.mem.Allocator, _: []const []const u8) !void {
state.operand = 0;
}
state.op = c;
try printDisplay(&state, stdout);
try printDisplay(&state, &stdout.interface);
} else if (c == '=' or c == '\r' or c == '\n') {
if (state.op != null and state.entering_operand) {
applyOp(&state);
state.op = null;
state.entering_operand = false;
state.operand = 0;
try printDisplay(&state, stdout);
try printDisplay(&state, &stdout.interface);
}
} else if (c == 8 or c == 127) { // Backspace
if (state.entering_operand) {
state.operand = @floor(state.operand / 10);
try printDisplay(&state, stdout);
try printDisplay(&state, &stdout.interface);
}
} else if (c == 'c' or c == 'C') { // Clear
state = State{};
try printDisplay(&state, stdout);
try printDisplay(&state, &stdout.interface);
}
}
}
19 changes: 12 additions & 7 deletions src/ziglets/clock.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {
_ = allocator; // allocator not used in this implementation
_ = args; // args not used in this implementation

const stdout = std.io.getStdOut().writer();
const io = std.Io.Threaded.global_single_threaded.io();
var stdout_buffer: [0]u8 = undefined;
var stdout = std.Io.File.stdout().writer(io, &stdout_buffer);

// Print initial message
try stdout.print("Terminal Clock - Press Ctrl+C to exit\n\n", .{});
try stdout.interface.print("Terminal Clock - Press Ctrl+C to exit\n\n", .{});

// Simple implementation that works on all platforms
while (true) {
// Clear the current line and move cursor to beginning
try stdout.print("\r", .{});
try stdout.interface.print("\r", .{});

// Get current time
const timestamp = std.time.timestamp();
const epoch_seconds = @as(u64, @intCast(timestamp));
const timestamp = std.Io.Clock.real.now(io);
const epoch_seconds = @as(u64, @intCast(timestamp.toSeconds()));

// Convert to broken down time (UTC)
const epoch_day = epoch_seconds / std.time.s_per_day;
Expand All @@ -36,10 +38,13 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {
const month_day = calculateMonthDay(day_of_year, isLeapYear(year));

// Display formatted time and date with emojis
try stdout.print("{d:0>4}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2} UTC", .{ year, month_day.month, month_day.day, hours, minutes, seconds });
try stdout.interface.print("{d:0>4}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2} UTC", .{ year, month_day.month, month_day.day, hours, minutes, seconds });

// Sleep for 1 second
std.time.sleep(1 * std.time.ns_per_s);
try std.Io.Clock.Duration.sleep(.{
.clock = .boot,
.raw = .fromSeconds(1),
}, io);
}
}

Expand Down
41 changes: 23 additions & 18 deletions src/ziglets/factorial.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ const DEFAULT_THREAD_COUNT = 2;
/// For n > 34, uses big integer arithmetic to handle arbitrarily large results.
/// Usage: ziglets factorial <number> [num_threads]
pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {
const stdout = std.io.getStdOut().writer();
const io = std.Io.Threaded.global_single_threaded.io();
var stdout_buffer: [0]u8 = undefined;
var stdout = std.Io.File.stdout().writer(io, &stdout_buffer);

// Validate command line arguments
if (args.len == 0) {
try stdout.print("Usage: ziglets factorial <number> [num_threads]\n", .{});
try stdout.interface.print("Usage: ziglets factorial <number> [num_threads]\n", .{});
return;
}

// Parse the input number
const n = std.fmt.parseInt(u32, args[0], 10) catch {
try stdout.print("Invalid number: {s}\n", .{args[0]});
try stdout.interface.print("Invalid number: {s}\n", .{args[0]});
return;
};

Expand All @@ -31,7 +33,7 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {

// Validate thread count
if (num_threads < 1) {
try stdout.print("Number of threads must be at least 1.\n", .{});
try stdout.interface.print("Number of threads must be at least 1.\n", .{});
return;
}

Expand All @@ -48,12 +50,14 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {

/// Calculates factorial using u128 arithmetic with multithreading for n <= 34
fn calculateU128Factorial(allocator: std.mem.Allocator, n: u32, num_threads: u32) !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Calculating {d}! using {d} thread(s) with u128 arithmetic...\n", .{ n, num_threads });
const io = std.Io.Threaded.global_single_threaded.io();
var stdout_buffer: [0]u8 = undefined;
var stdout = std.Io.File.stdout().writer(io, &stdout_buffer);
try stdout.interface.print("Calculating {d}! using {d} thread(s) with u128 arithmetic...\n", .{ n, num_threads });

// Handle special case: 0! = 1
if (n == 0) {
try stdout.print("Result: 1\n", .{});
try stdout.interface.print("Result: 1\n", .{});
return;
}

Expand All @@ -64,7 +68,8 @@ fn calculateU128Factorial(allocator: std.mem.Allocator, n: u32, num_threads: u32
defer allocator.free(results);

// Distribute work across threads
const work_distribution = calculateWorkDistribution(n, num_threads);
const work_distribution = try calculateWorkDistribution(allocator, n, num_threads);
defer work_distribution.deinit(allocator);

// Spawn threads to compute partial products
for (0..num_threads) |i| {
Expand All @@ -83,7 +88,7 @@ fn calculateU128Factorial(allocator: std.mem.Allocator, n: u32, num_threads: u32
final_result *= partial_result;
}

try stdout.print("Result: {d}\n", .{final_result});
try stdout.interface.print("Result: {d}\n", .{final_result});
}

/// Represents a range of numbers for computation
Expand All @@ -104,10 +109,8 @@ const WorkDistribution = struct {
};

/// Calculates how to distribute work across threads efficiently
fn calculateWorkDistribution(n: u32, num_threads: u32) WorkDistribution {
// This is a simplified version - in practice you'd want to allocate this properly
// For now, we'll use a static array approach for clarity
var ranges: [8]ComputationRange = undefined; // Assume max 8 threads for simplicity
fn calculateWorkDistribution(allocator: std.mem.Allocator, n: u32, num_threads: u32) !WorkDistribution {
const ranges = try allocator.alloc(ComputationRange, num_threads);

const chunk_size = n / num_threads;
const remainder = n % num_threads;
Expand All @@ -132,7 +135,7 @@ fn calculateWorkDistribution(n: u32, num_threads: u32) WorkDistribution {
current = end + 1;
}

return WorkDistribution{ .ranges = ranges[0..num_threads] };
return WorkDistribution{ .ranges = ranges };
}

/// Thread worker function: computes the product of numbers in range [start, end]
Expand All @@ -154,8 +157,10 @@ fn computePartialProduct(start: u32, end: u32, result: *u128) void {
/// Calculates factorial using big integer arithmetic for numbers > 34
/// Uses sequential computation for simplicity and memory efficiency
fn calculateBigFactorial(allocator: std.mem.Allocator, n: u32, num_threads: u32) !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Calculating {d}! using big integer arithmetic...\n", .{n});
const io = std.Io.Threaded.global_single_threaded.io();
var stdout_buffer: [0]u8 = undefined;
var stdout = std.Io.File.stdout().writer(io, &stdout_buffer);
try stdout.interface.print("Calculating {d}! using big integer arithmetic...\n", .{n});

// Note: Threading with big integers is complex due to memory management
// For now, we use sequential computation which is still very efficient
Expand All @@ -172,7 +177,7 @@ fn calculateBigFactorial(allocator: std.mem.Allocator, n: u32, num_threads: u32)
if (n == 0) {
const result_str = try result.toString(allocator, 10, .lower);
defer allocator.free(result_str);
try stdout.print("Result: {s}\n", .{result_str});
try stdout.interface.print("Result: {s}\n", .{result_str});
return;
}

Expand All @@ -193,5 +198,5 @@ fn calculateBigFactorial(allocator: std.mem.Allocator, n: u32, num_threads: u32)
const result_str = try result.toString(allocator, 10, .lower);
defer allocator.free(result_str);

try stdout.print("Result: {s}\n", .{result_str});
try stdout.interface.print("Result: {s}\n", .{result_str});
}
Loading