mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
commit
89ab6b161d
10 changed files with 94 additions and 84 deletions
|
|
@ -38,20 +38,38 @@ pub fn build(b: *std.Build) void {
|
|||
"../../tools/gen_spirv_spec.zig",
|
||||
"../../tools/gen_stubs.zig",
|
||||
"../../tools/generate_c_size_and_align_checks.zig",
|
||||
"../../tools/generate_JSONTestSuite.zig",
|
||||
"../../tools/generate_linux_syscalls.zig",
|
||||
"../../tools/process_headers.zig",
|
||||
"../../tools/migrate_langref.zig",
|
||||
"../../tools/update-linux-headers.zig",
|
||||
"../../tools/update_clang_options.zig",
|
||||
"../../tools/update_cpu_features.zig",
|
||||
"../../tools/update_crc_catalog.zig",
|
||||
"../../tools/update_freebsd_libc.zig",
|
||||
"../../tools/update_glibc.zig",
|
||||
"../../tools/update_mingw.zig",
|
||||
"../../tools/update_netbsd_libc.zig",
|
||||
}) |tool_src_path| {
|
||||
if (std.mem.endsWith(u8, tool_src_path, "dump-cov.zig") and tools_target.result.os.tag == .windows) continue;
|
||||
|
||||
const tool = b.addExecutable(.{
|
||||
.name = std.fs.path.stem(tool_src_path),
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path(tool_src_path),
|
||||
.target = tools_target,
|
||||
}),
|
||||
});
|
||||
tools_tests_step.dependOn(&tool.step);
|
||||
}
|
||||
for ([_][]const u8{
|
||||
// Alphabetically sorted. Only ones with `test` blocks.
|
||||
"../../tools/doctest.zig",
|
||||
}) |tool_src_path| {
|
||||
const tool = b.addTest(.{
|
||||
.name = std.fs.path.stem(tool_src_path),
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path(tool_src_path),
|
||||
.optimize = .Debug,
|
||||
.target = tools_target,
|
||||
}),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ pub fn main() anyerror!void {
|
|||
|
||||
const sysroot_path = sysroot orelse blk: {
|
||||
const target = try std.zig.system.resolveTargetQuery(.{});
|
||||
break :blk std.zig.system.darwin.getSdk(allocator, target) orelse
|
||||
break :blk std.zig.system.darwin.getSdk(allocator, &target) orelse
|
||||
fatal("no SDK found; you can provide one explicitly with '--sysroot' flag", .{});
|
||||
};
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ pub fn main() anyerror!void {
|
|||
15 => .sequoia,
|
||||
else => unreachable,
|
||||
};
|
||||
info("found SDK deployment target macOS {} aka '{s}'", .{ version, @tagName(os_ver) });
|
||||
info("found SDK deployment target macOS {f} aka '{s}'", .{ version, @tagName(os_ver) });
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
|
|
@ -198,7 +198,7 @@ fn fetchTarget(
|
|||
var dirs = std.StringHashMap(fs.Dir).init(arena);
|
||||
try dirs.putNoClobber(".", dest_dir);
|
||||
|
||||
const headers_list_str = try headers_list_file.reader().readAllAlloc(arena, std.math.maxInt(usize));
|
||||
const headers_list_str = try headers_list_file.deprecatedReader().readAllAlloc(arena, std.math.maxInt(usize));
|
||||
const prefix = "/usr/include";
|
||||
|
||||
var it = mem.splitScalar(u8, headers_list_str, '\n');
|
||||
|
|
@ -270,12 +270,8 @@ const Version = struct {
|
|||
|
||||
pub fn format(
|
||||
v: Version,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
writer: *std.Io.Writer,
|
||||
) std.Io.Writer.Error!void {
|
||||
try writer.print("{d}.{d}.{d}", .{ v.major, v.minor, v.patch });
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ pub fn main() !void {
|
|||
libc_so_path,
|
||||
100 * 1024 * 1024,
|
||||
1 * 1024 * 1024,
|
||||
@alignOf(elf.Elf64_Ehdr),
|
||||
.of(elf.Elf64_Ehdr),
|
||||
null,
|
||||
) catch |err| {
|
||||
std.debug.panic("unable to read '{s}/{s}': {s}", .{
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ fn processPreprocessedFile(
|
|||
const name = (getOverridenNameNew(value) orelse sys_name)["sys_".len..];
|
||||
const fixed_name = if (stdlib_renames_new.get(name)) |f| f else if (stdlib_renames.get(name)) |f| f else name;
|
||||
|
||||
try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), value });
|
||||
try writer.print(" {f} = {s},\n", .{ zig.fmtId(fixed_name), value });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +510,7 @@ fn processTableBasedArch(
|
|||
}
|
||||
const fixed_name = if (filters.fixedName) |fixedNameFn| fixedNameFn(name) else name;
|
||||
|
||||
try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
try writer.print(" {f} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -543,7 +543,7 @@ fn processMipsBasedArch(
|
|||
}
|
||||
const fixed_name = if (filters.fixedName) |fixedNameFn| fixedNameFn(name) else name;
|
||||
|
||||
try writer.print(" {p} = linux_base + {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
try writer.print(" {f} = linux_base + {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -568,12 +568,12 @@ fn processPowerPcBasedArch(
|
|||
if (mem.eql(u8, abi, "spu")) {
|
||||
continue;
|
||||
} else if (mem.eql(u8, abi, "32")) {
|
||||
try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
try writer.print(" {f} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
} else if (mem.eql(u8, abi, "64")) {
|
||||
try optional_writer.?.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
try optional_writer.?.print(" {f} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
} else { // common/nospu
|
||||
try writer.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
try optional_writer.?.print(" {p} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
try writer.print(" {f} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
try optional_writer.?.print(" {f} = {s},\n", .{ zig.fmtId(fixed_name), number });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ pub fn main() !void {
|
|||
var out_dir = try fs.cwd().openDir(fs.path.dirname(output_file).?, .{});
|
||||
defer out_dir.close();
|
||||
|
||||
const input_file_bytes = try in_file.reader().readAllAlloc(arena, std.math.maxInt(u32));
|
||||
const input_file_bytes = try in_file.deprecatedReader().readAllAlloc(arena, std.math.maxInt(u32));
|
||||
|
||||
var buffered_writer = io.bufferedWriter(out_file.writer());
|
||||
var buffered_writer = io.bufferedWriter(out_file.deprecatedWriter());
|
||||
|
||||
var tokenizer = Tokenizer.init(input_file, input_file_bytes);
|
||||
|
||||
|
|
@ -388,39 +388,39 @@ fn walk(arena: Allocator, tokenizer: *Tokenizer, out_dir: std.fs.Dir, w: anytype
|
|||
try file.writeAll("\n\n");
|
||||
|
||||
if (just_check_syntax) {
|
||||
try file.writer().print("// syntax\n", .{});
|
||||
try file.deprecatedWriter().print("// syntax\n", .{});
|
||||
} else switch (code_kind_id) {
|
||||
.@"test" => try file.writer().print("// test\n", .{}),
|
||||
.lib => try file.writer().print("// lib\n", .{}),
|
||||
.test_error => |s| try file.writer().print("// test_error={s}\n", .{s}),
|
||||
.test_safety => |s| try file.writer().print("// test_safety={s}\n", .{s}),
|
||||
.exe => |s| try file.writer().print("// exe={s}\n", .{@tagName(s)}),
|
||||
.@"test" => try file.deprecatedWriter().print("// test\n", .{}),
|
||||
.lib => try file.deprecatedWriter().print("// lib\n", .{}),
|
||||
.test_error => |s| try file.deprecatedWriter().print("// test_error={s}\n", .{s}),
|
||||
.test_safety => |s| try file.deprecatedWriter().print("// test_safety={s}\n", .{s}),
|
||||
.exe => |s| try file.deprecatedWriter().print("// exe={s}\n", .{@tagName(s)}),
|
||||
.obj => |opt| if (opt) |s| {
|
||||
try file.writer().print("// obj={s}\n", .{s});
|
||||
try file.deprecatedWriter().print("// obj={s}\n", .{s});
|
||||
} else {
|
||||
try file.writer().print("// obj\n", .{});
|
||||
try file.deprecatedWriter().print("// obj\n", .{});
|
||||
},
|
||||
}
|
||||
|
||||
if (mode != .Debug)
|
||||
try file.writer().print("// optimize={s}\n", .{@tagName(mode)});
|
||||
try file.deprecatedWriter().print("// optimize={s}\n", .{@tagName(mode)});
|
||||
|
||||
for (link_objects.items) |link_object| {
|
||||
try file.writer().print("// link_object={s}\n", .{link_object});
|
||||
try file.deprecatedWriter().print("// link_object={s}\n", .{link_object});
|
||||
}
|
||||
|
||||
if (target_str) |s|
|
||||
try file.writer().print("// target={s}\n", .{s});
|
||||
try file.deprecatedWriter().print("// target={s}\n", .{s});
|
||||
|
||||
if (link_libc) try file.writer().print("// link_libc\n", .{});
|
||||
if (disable_cache) try file.writer().print("// disable_cache\n", .{});
|
||||
if (verbose_cimport) try file.writer().print("// verbose_cimport\n", .{});
|
||||
if (link_libc) try file.deprecatedWriter().print("// link_libc\n", .{});
|
||||
if (disable_cache) try file.deprecatedWriter().print("// disable_cache\n", .{});
|
||||
if (verbose_cimport) try file.deprecatedWriter().print("// verbose_cimport\n", .{});
|
||||
|
||||
if (link_mode) |m|
|
||||
try file.writer().print("// link_mode={s}\n", .{@tagName(m)});
|
||||
try file.deprecatedWriter().print("// link_mode={s}\n", .{@tagName(m)});
|
||||
|
||||
for (additional_options.items) |o| {
|
||||
try file.writer().print("// additional_option={s}\n", .{o});
|
||||
try file.deprecatedWriter().print("// additional_option={s}\n", .{o});
|
||||
}
|
||||
try w.print("{{#code|{s}#}}\n", .{basename});
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -266,10 +266,10 @@ pub fn main() !void {
|
|||
if (gop.found_existing) {
|
||||
max_bytes_saved += raw_bytes.len;
|
||||
gop.value_ptr.hit_count += 1;
|
||||
std.debug.print("duplicate: {s} {s} ({:2})\n", .{
|
||||
std.debug.print("duplicate: {s} {s} ({B})\n", .{
|
||||
libc_dir,
|
||||
rel_path,
|
||||
std.fmt.fmtIntSizeDec(raw_bytes.len),
|
||||
raw_bytes.len,
|
||||
});
|
||||
} else {
|
||||
gop.value_ptr.* = Contents{
|
||||
|
|
@ -311,9 +311,9 @@ pub fn main() !void {
|
|||
std.debug.print("warning: libc target not found: {s}\n", .{libc_dir});
|
||||
}
|
||||
}
|
||||
std.debug.print("summary: {:2} could be reduced to {:2}\n", .{
|
||||
std.fmt.fmtIntSizeDec(total_bytes),
|
||||
std.fmt.fmtIntSizeDec(total_bytes - max_bytes_saved),
|
||||
std.debug.print("summary: {B} could be reduced to {B}\n", .{
|
||||
total_bytes,
|
||||
total_bytes - max_bytes_saved,
|
||||
});
|
||||
try std.fs.cwd().makePath(out_dir);
|
||||
|
||||
|
|
@ -343,8 +343,8 @@ pub fn main() !void {
|
|||
if (contender.hit_count > 1) {
|
||||
const this_missed_bytes = contender.hit_count * contender.bytes.len;
|
||||
missed_opportunity_bytes += this_missed_bytes;
|
||||
std.debug.print("Missed opportunity ({:2}): {s}\n", .{
|
||||
std.fmt.fmtIntSizeDec(this_missed_bytes),
|
||||
std.debug.print("Missed opportunity ({B}): {s}\n", .{
|
||||
this_missed_bytes,
|
||||
path_kv.key_ptr.*,
|
||||
});
|
||||
} else break;
|
||||
|
|
|
|||
|
|
@ -218,10 +218,10 @@ pub fn main() !void {
|
|||
if (gop.found_existing) {
|
||||
max_bytes_saved += raw_bytes.len;
|
||||
gop.value_ptr.hit_count += 1;
|
||||
std.debug.print("duplicate: {s} {s} ({:2})\n", .{
|
||||
std.debug.print("duplicate: {s} {s} ({B})\n", .{
|
||||
linux_target.name,
|
||||
rel_path,
|
||||
std.fmt.fmtIntSizeDec(raw_bytes.len),
|
||||
raw_bytes.len,
|
||||
});
|
||||
} else {
|
||||
gop.value_ptr.* = Contents{
|
||||
|
|
@ -249,9 +249,9 @@ pub fn main() !void {
|
|||
std.debug.print("warning: libc target not found: {s}\n", .{linux_target.name});
|
||||
}
|
||||
}
|
||||
std.debug.print("summary: {:2} could be reduced to {:2}\n", .{
|
||||
std.fmt.fmtIntSizeDec(total_bytes),
|
||||
std.fmt.fmtIntSizeDec(total_bytes - max_bytes_saved),
|
||||
std.debug.print("summary: {B} could be reduced to {B}\n", .{
|
||||
total_bytes,
|
||||
total_bytes - max_bytes_saved,
|
||||
});
|
||||
try std.fs.cwd().makePath(out_dir);
|
||||
|
||||
|
|
@ -281,8 +281,8 @@ pub fn main() !void {
|
|||
if (contender.hit_count > 1) {
|
||||
const this_missed_bytes = contender.hit_count * contender.bytes.len;
|
||||
missed_opportunity_bytes += this_missed_bytes;
|
||||
std.debug.print("Missed opportunity ({:2}): {s}\n", .{
|
||||
std.fmt.fmtIntSizeDec(this_missed_bytes),
|
||||
std.debug.print("Missed opportunity ({B}): {s}\n", .{
|
||||
this_missed_bytes,
|
||||
path_kv.key_ptr.*,
|
||||
});
|
||||
} else break;
|
||||
|
|
|
|||
|
|
@ -635,7 +635,7 @@ pub fn main() anyerror!void {
|
|||
const args = try std.process.argsAlloc(allocator);
|
||||
|
||||
var stdout_buffer: [4000]u8 = undefined;
|
||||
var stdout_writer = fs.stdout().writerStreaming(&stdout_buffer);
|
||||
var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
|
||||
const stdout = &stdout_writer.interface;
|
||||
|
||||
if (args.len <= 1) printUsageAndExit(args[0]);
|
||||
|
|
@ -767,7 +767,7 @@ pub fn main() anyerror!void {
|
|||
try stdout.print(
|
||||
\\.{{
|
||||
\\ .name = "{s}",
|
||||
\\ .syntax = {s},
|
||||
\\ .syntax = {f},
|
||||
\\ .zig_equivalent = .{s},
|
||||
\\ .pd1 = {},
|
||||
\\ .pd2 = {},
|
||||
|
|
@ -797,7 +797,7 @@ pub fn main() anyerror!void {
|
|||
try stdout.print(
|
||||
\\.{{
|
||||
\\ .name = "{s}",
|
||||
\\ .syntax = {s},
|
||||
\\ .syntax = {f},
|
||||
\\ .zig_equivalent = .other,
|
||||
\\ .pd1 = {},
|
||||
\\ .pd2 = {},
|
||||
|
|
@ -845,14 +845,10 @@ const Syntax = union(enum) {
|
|||
|
||||
pub fn format(
|
||||
self: Syntax,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
out_stream: anytype,
|
||||
) !void {
|
||||
_ = fmt;
|
||||
_ = options;
|
||||
out_stream: *std.Io.Writer,
|
||||
) std.Io.Writer.Error!void {
|
||||
switch (self) {
|
||||
.multi_arg => |n| return out_stream.print(".{{.{s}={}}}", .{ @tagName(self), n }),
|
||||
.multi_arg => |n| return out_stream.print(".{{.{t}={d}}}", .{ self, n }),
|
||||
else => return out_stream.print(".{s}", .{@tagName(self)}),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1906,7 +1906,7 @@ fn processOneTarget(job: Job) void {
|
|||
var zig_code_file = try target_dir.createFile(zig_code_basename, .{});
|
||||
defer zig_code_file.close();
|
||||
|
||||
var bw = std.io.bufferedWriter(zig_code_file.writer());
|
||||
var bw = std.io.bufferedWriter(zig_code_file.deprecatedWriter());
|
||||
const w = bw.writer();
|
||||
|
||||
try w.writeAll(
|
||||
|
|
@ -1920,7 +1920,7 @@ fn processOneTarget(job: Job) void {
|
|||
);
|
||||
|
||||
for (all_features.items, 0..) |feature, i| {
|
||||
try w.print("\n {p},", .{std.zig.fmtId(feature.zig_name)});
|
||||
try w.print("\n {f},", .{std.zig.fmtId(feature.zig_name)});
|
||||
|
||||
if (i == all_features.items.len - 1) try w.writeAll("\n");
|
||||
}
|
||||
|
|
@ -1949,27 +1949,27 @@ fn processOneTarget(job: Job) void {
|
|||
for (all_features.items) |feature| {
|
||||
if (feature.llvm_name) |llvm_name| {
|
||||
try w.print(
|
||||
\\ result[@intFromEnum(Feature.{p_})] = .{{
|
||||
\\ .llvm_name = "{}",
|
||||
\\ .description = "{}",
|
||||
\\ result[@intFromEnum(Feature.{f})] = .{{
|
||||
\\ .llvm_name = "{f}",
|
||||
\\ .description = "{f}",
|
||||
\\ .dependencies = featureSet(&[_]Feature{{
|
||||
,
|
||||
.{
|
||||
std.zig.fmtId(feature.zig_name),
|
||||
std.zig.fmtEscapes(llvm_name),
|
||||
std.zig.fmtEscapes(feature.desc),
|
||||
std.zig.fmtIdPU(feature.zig_name),
|
||||
std.zig.fmtString(llvm_name),
|
||||
std.zig.fmtString(feature.desc),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
try w.print(
|
||||
\\ result[@intFromEnum(Feature.{p_})] = .{{
|
||||
\\ result[@intFromEnum(Feature.{f})] = .{{
|
||||
\\ .llvm_name = null,
|
||||
\\ .description = "{}",
|
||||
\\ .description = "{f}",
|
||||
\\ .dependencies = featureSet(&[_]Feature{{
|
||||
,
|
||||
.{
|
||||
std.zig.fmtId(feature.zig_name),
|
||||
std.zig.fmtEscapes(feature.desc),
|
||||
std.zig.fmtIdPU(feature.zig_name),
|
||||
std.zig.fmtString(feature.desc),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -1996,7 +1996,7 @@ fn processOneTarget(job: Job) void {
|
|||
} else {
|
||||
try w.writeAll("\n");
|
||||
for (dependencies.items) |dep| {
|
||||
try w.print(" .{p_},\n", .{std.zig.fmtId(dep)});
|
||||
try w.print(" .{f},\n", .{std.zig.fmtIdPU(dep)});
|
||||
}
|
||||
try w.writeAll(
|
||||
\\ }),
|
||||
|
|
@ -2033,24 +2033,24 @@ fn processOneTarget(job: Job) void {
|
|||
mem.sort([]const u8, cpu_features.items, {}, asciiLessThan);
|
||||
if (cpu.llvm_name) |llvm_name| {
|
||||
try w.print(
|
||||
\\ pub const {}: CpuModel = .{{
|
||||
\\ .name = "{}",
|
||||
\\ .llvm_name = "{}",
|
||||
\\ pub const {f}: CpuModel = .{{
|
||||
\\ .name = "{f}",
|
||||
\\ .llvm_name = "{f}",
|
||||
\\ .features = featureSet(&[_]Feature{{
|
||||
, .{
|
||||
std.zig.fmtId(cpu.zig_name),
|
||||
std.zig.fmtEscapes(cpu.zig_name),
|
||||
std.zig.fmtEscapes(llvm_name),
|
||||
std.zig.fmtString(cpu.zig_name),
|
||||
std.zig.fmtString(llvm_name),
|
||||
});
|
||||
} else {
|
||||
try w.print(
|
||||
\\ pub const {}: CpuModel = .{{
|
||||
\\ .name = "{}",
|
||||
\\ pub const {f}: CpuModel = .{{
|
||||
\\ .name = "{f}",
|
||||
\\ .llvm_name = null,
|
||||
\\ .features = featureSet(&[_]Feature{{
|
||||
, .{
|
||||
std.zig.fmtId(cpu.zig_name),
|
||||
std.zig.fmtEscapes(cpu.zig_name),
|
||||
std.zig.fmtString(cpu.zig_name),
|
||||
});
|
||||
}
|
||||
if (cpu_features.items.len == 0) {
|
||||
|
|
@ -2062,7 +2062,7 @@ fn processOneTarget(job: Job) void {
|
|||
} else {
|
||||
try w.writeAll("\n");
|
||||
for (cpu_features.items) |feature_zig_name| {
|
||||
try w.print(" .{p_},\n", .{std.zig.fmtId(feature_zig_name)});
|
||||
try w.print(" .{f},\n", .{std.zig.fmtIdPU(feature_zig_name)});
|
||||
}
|
||||
try w.writeAll(
|
||||
\\ }),
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub fn main() anyerror!void {
|
|||
var zig_code_file = try hash_target_dir.createFile("crc.zig", .{});
|
||||
defer zig_code_file.close();
|
||||
|
||||
var cbw = std.io.bufferedWriter(zig_code_file.writer());
|
||||
var cbw = std.io.bufferedWriter(zig_code_file.deprecatedWriter());
|
||||
defer cbw.flush() catch unreachable;
|
||||
const code_writer = cbw.writer();
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ pub fn main() anyerror!void {
|
|||
var zig_test_file = try crc_target_dir.createFile("test.zig", .{});
|
||||
defer zig_test_file.close();
|
||||
|
||||
var tbw = std.io.bufferedWriter(zig_test_file.writer());
|
||||
var tbw = std.io.bufferedWriter(zig_test_file.deprecatedWriter());
|
||||
defer tbw.flush() catch unreachable;
|
||||
const test_writer = tbw.writer();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue