tangled
alpha
login
or
join now
abeestrada.com
/
lsr
forked from
rockorager.dev/lsr
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
pulls
pipelines
initial commit
rockorager.dev
10 months ago
27abb8ad
29a22641
+120
-26
1 changed file
expand all
collapse all
unified
split
src
main.zig
+120
-26
src/main.zig
···
1
1
const std = @import("std");
2
2
const builtin = @import("builtin");
3
3
-
const io = @import("ourio");
3
3
+
const ourio = @import("ourio");
4
4
5
5
const linux = std.os.linux;
6
6
+
const posix = std.posix;
7
7
+
8
8
+
const Options = struct {
9
9
+
all: bool = false,
10
10
+
};
11
11
+
12
12
+
fn eql(a: []const u8, b: []const u8) bool {
13
13
+
return std.mem.eql(u8, a, b);
14
14
+
}
15
15
+
16
16
+
fn optKind(a: []const u8) enum { short, long, positional } {
17
17
+
if (std.mem.startsWith(u8, a, "--")) return .long;
18
18
+
if (std.mem.startsWith(u8, a, "-")) return .short;
19
19
+
return .positional;
20
20
+
}
6
21
7
22
pub fn main() !void {
8
23
var debug_allocator: std.heap.DebugAllocator(.{}) = .init;
···
19
34
var arena = std.heap.ArenaAllocator.init(gpa);
20
35
defer arena.deinit();
21
36
22
22
-
var ring: io.Ring = try .init(arena.allocator(), 64);
23
23
-
defer ring.deinit();
37
37
+
var cmd: Command = .{ .arena = arena.allocator() };
38
38
+
39
39
+
var args = std.process.args();
40
40
+
while (args.next()) |arg| {
41
41
+
switch (optKind(arg)) {
42
42
+
.short => {
43
43
+
const str = arg[1..];
44
44
+
for (str) |b| {
45
45
+
switch (b) {
46
46
+
'a' => cmd.opts.all = true,
47
47
+
else => {
48
48
+
const w = std.io.getStdErr().writer();
49
49
+
try w.print("Invalid opt: '{c}'", .{b});
50
50
+
std.process.exit(1);
51
51
+
},
52
52
+
}
53
53
+
}
54
54
+
},
55
55
+
.long => {
56
56
+
const opt = arg[2..];
57
57
+
if (eql(opt, "all"))
58
58
+
cmd.opts.all = true
59
59
+
else {
60
60
+
const w = std.io.getStdErr().writer();
61
61
+
try w.print("Invalid opt: '{s}'", .{opt});
62
62
+
std.process.exit(1);
63
63
+
}
64
64
+
},
65
65
+
.positional => {},
66
66
+
}
67
67
+
}
24
68
25
25
-
// TODO: implement openat in ourio
26
26
-
var cwd = try std.fs.cwd().openDir(".", .{ .iterate = true });
27
27
-
defer cwd.close();
69
69
+
var ring: ourio.Ring = try .init(arena.allocator(), 64);
70
70
+
defer ring.deinit();
28
71
29
29
-
var results: std.ArrayListUnmanaged(*Entry) = .empty;
72
72
+
_ = try ring.open(".", .{ .DIRECTORY = true, .CLOEXEC = true }, 0, .{
73
73
+
.ptr = &cmd,
74
74
+
.cb = onCompletion,
75
75
+
.msg = @intFromEnum(Msg.cwd),
76
76
+
});
30
77
31
31
-
var iter = cwd.iterate();
32
32
-
while (try iter.next()) |dirent| {
33
33
-
const nameZ = try arena.allocator().dupeZ(u8, dirent.name);
34
34
-
const entry = try arena.allocator().create(Entry);
35
35
-
entry.* = .{ .name = nameZ, .kind = dirent.kind, .statx = undefined };
36
36
-
try results.append(arena.allocator(), entry);
37
37
-
_ = try ring.stat(nameZ, &entry.statx, .{ .cb = onCompletion });
78
78
+
if (cmd.opts.all) {
79
79
+
// We need to also open /etc/localtime and /etc/passwd
80
80
+
_ = try ring.open("/etc/localtime", .{ .CLOEXEC = true }, 0, .{
81
81
+
.ptr = &cmd,
82
82
+
.cb = onCompletion,
83
83
+
.msg = @intFromEnum(Msg.localtime),
84
84
+
});
85
85
+
_ = try ring.open("/etc/passwd", .{ .CLOEXEC = true }, 0, .{
86
86
+
.ptr = &cmd,
87
87
+
.cb = onCompletion,
88
88
+
.msg = @intFromEnum(Msg.localtime),
89
89
+
});
38
90
}
39
91
40
92
try ring.run(.until_done);
41
93
42
42
-
var output: std.ArrayListUnmanaged(u8) = .empty;
43
43
-
var writer = output.writer(arena.allocator());
44
44
-
for (results.items) |entry| {
45
45
-
try writer.print("{s}\r\n", .{entry.name});
94
94
+
const stdout = std.io.getStdOut();
95
95
+
var bw = std.io.bufferedWriter(stdout.writer());
96
96
+
for (cmd.entries) |entry| {
97
97
+
try bw.writer().print("{s}\r\n", .{entry.name});
46
98
}
47
99
48
48
-
try std.io.getStdOut().writeAll(output.items);
100
100
+
try bw.flush();
49
101
}
50
102
103
103
+
const Command = struct {
104
104
+
arena: std.mem.Allocator,
105
105
+
opts: Options = .{},
106
106
+
entries: []Entry = &.{},
107
107
+
};
108
108
+
109
109
+
const Msg = enum(u16) {
110
110
+
cwd,
111
111
+
localtime,
112
112
+
passwd,
113
113
+
stat,
114
114
+
};
115
115
+
51
116
const Entry = struct {
52
117
name: [:0]const u8,
53
118
kind: std.fs.File.Kind,
54
54
-
statx: io.Statx,
119
119
+
statx: ourio.Statx,
55
120
56
56
-
fn lessThan(_: void, lhs: *Entry, rhs: *Entry) bool {
121
121
+
fn lessThan(_: void, lhs: Entry, rhs: Entry) bool {
57
122
return std.ascii.orderIgnoreCase(lhs.name, rhs.name).compare(.lt);
58
123
}
59
124
};
60
125
61
61
-
fn onCompletion(_: *io.Ring, task: io.Task) anyerror!void {
126
126
+
fn onCompletion(io: *ourio.Ring, task: ourio.Task) anyerror!void {
127
127
+
const cmd = task.userdataCast(Command);
128
128
+
const msg = task.msgToEnum(Msg);
62
129
const result = task.result.?;
63
130
64
64
-
_ = result.statx catch |err| {
65
65
-
std.log.err("stat error: {}", .{err});
66
66
-
return;
67
67
-
};
131
131
+
switch (msg) {
132
132
+
.cwd => {
133
133
+
const fd = try result.open;
134
134
+
const dir: std.fs.Dir = .{ .fd = fd };
135
135
+
136
136
+
var results: std.ArrayListUnmanaged(Entry) = .empty;
137
137
+
138
138
+
var iter = dir.iterate();
139
139
+
while (try iter.next()) |dirent| {
140
140
+
const nameZ = try cmd.arena.dupeZ(u8, dirent.name);
141
141
+
try results.append(cmd.arena, .{
142
142
+
.name = nameZ,
143
143
+
.kind = dirent.kind,
144
144
+
.statx = undefined,
145
145
+
});
146
146
+
}
147
147
+
cmd.entries = results.items;
148
148
+
// best effort close
149
149
+
_ = try io.close(fd, .{});
150
150
+
151
151
+
for (cmd.entries) |*entry| {
152
152
+
_ = try io.stat(entry.name, &entry.statx, .{
153
153
+
.cb = onCompletion,
154
154
+
.ptr = cmd,
155
155
+
.msg = @intFromEnum(Msg.stat),
156
156
+
});
157
157
+
}
158
158
+
},
159
159
+
160
160
+
else => {},
161
161
+
}
68
162
}