aboutsummaryrefslogtreecommitdiff
path: root/src/config.zig
diff options
context:
space:
mode:
authorNguyễn Gia Phong <mcsinyx@disroot.org>2021-09-08 15:46:39 +0700
committerNguyễn Gia Phong <mcsinyx@disroot.org>2021-09-08 15:52:39 +0700
commitda79599ad5201f4eebd3edaabbe4b33498de448e (patch)
tree4f026ad0bb2ab643baadf057d8f391dbc4a9568f /src/config.zig
parent67cf9f61e91462eaf8e8caeaa7d0d7d3d9d1f711 (diff)
downloadblackshades-da79599ad5201f4eebd3edaabbe4b33498de448e.tar.gz
Move configuration parsing to Zig2.1.0
The config file is now read from configuration directories instead of pwd.
Diffstat (limited to 'src/config.zig')
-rw-r--r--src/config.zig117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/config.zig b/src/config.zig
new file mode 100644
index 0000000..4bde82c
--- /dev/null
+++ b/src/config.zig
@@ -0,0 +1,117 @@
+// Configuration parser
+// Copyright (C) 2021 Nguyễn Gia Phong
+//
+// This file is part of Black Shades.
+//
+// Black Shades is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Black Shades is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Black Shades. If not, see <https://www.gnu.org/licenses/>.
+
+const Allocator = std.mem.Allocator;
+const createFile = std.fs.createFileAbsolute;
+const eql = std.mem.eql;
+const ini = @import("ini");
+const join = std.fs.path.join;
+const mkdir = std.os.mkdir;
+const openFile = std.fs.openFileAbsolute;
+const parseFloat = std.fmt.parseFloat;
+const parseInt = std.fmt.parseInt;
+const std = @import("std");
+
+/// Game configuration.
+pub const Config = extern struct {
+ screen_width: c_int = 640,
+ screen_height: c_int = 480,
+ mouse_sensitivity: f32 = 0.7,
+ debug: bool = false,
+ vsync: bool = true,
+ blood: bool = true,
+ blur: bool = false,
+ menu: bool = true,
+ custom_levels: bool = false,
+ music: bool = true,
+ azerty: bool = false,
+};
+
+/// Parse boolean values.
+fn parseBool(s: []const u8) !bool {
+ if (eql(u8, s, "false"))
+ return false;
+ if (eql(u8, s, "true"))
+ return true;
+ return error.InvalidCharacter;
+}
+
+/// Parse settings.ini in the given base directory.
+pub fn parse(allocator: *Allocator, base_dir: []const u8) !Config {
+ const config_dir = try join(allocator, &.{ base_dir, "blackshades" });
+ defer allocator.free(config_dir);
+ const path = try join(allocator, &.{ config_dir, "settings.ini" });
+ defer allocator.free(path);
+
+ var config = Config{};
+ const input = openFile(path, .{}) catch {
+ mkdir(config_dir, 0o644) catch |err| switch (err) {
+ error.PathAlreadyExists => {},
+ else => return err,
+ };
+ const output = try createFile(path, .{});
+ defer output.close();
+ const writer = output.writer();
+ try writer.print("screen width = {}\n", .{ config.screen_width });
+ try writer.print("screen height = {}\n", .{ config.screen_height });
+ try writer.print("mouse sensitivity = {d:.1}\n",
+ .{ config.mouse_sensitivity });
+ try writer.print("debug = {}\n", .{ config.debug });
+ try writer.print("vsync = {}\n", .{ config.vsync });
+ try writer.print("blood = {}\n", .{ config.blood });
+ try writer.print("blur = {}\n", .{ config.blur });
+ try writer.print("menu = {}\n", .{ config.menu });
+ try writer.print("custom levels = {}\n", .{ config.custom_levels });
+ try writer.print("music = {}\n", .{ config.music });
+ try writer.print("azerty = {}\n", .{ config.azerty });
+ return config;
+ };
+ defer input.close();
+
+ var parser = ini.parse(allocator, input.reader());
+ defer parser.deinit();
+
+ while (try parser.next()) |record|
+ switch (record) {
+ .property => |kv| if (eql(u8, kv.key, "screen width")) {
+ config.screen_width = try parseInt(c_int, kv.value, 10);
+ } else if (eql(u8, kv.key, "screen height")) {
+ config.screen_height = try parseInt(c_int, kv.value, 10);
+ } else if (eql(u8, kv.key, "mouse_sensitivity")) {
+ config.mouse_sensitivity = try parseFloat(f32, kv.value);
+ } else if (eql(u8, kv.key, "debug")) {
+ config.debug = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "vsync")) {
+ config.vsync = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "blood")) {
+ config.blood = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "blur")) {
+ config.blur = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "menu")) {
+ config.menu = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "custom levels")) {
+ config.custom_levels = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "music")) {
+ config.music = try parseBool(kv.value);
+ } else if (eql(u8, kv.key, "azerty")) {
+ config.azerty = try parseBool(kv.value);
+ },
+ else => unreachable,
+ };
+ return config;
+}