summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2024-08-29 20:41:04 +0800
committerGravatar Uko Kokņevičs2024-08-29 20:41:04 +0800
commit34b7dc964b3516457f04d00d3ec910d3b6fd585b (patch)
tree7a0a44ce334cc1411952cdbde056b7b57720f06e
parentDo some extra user input validation (diff)
downloadukkobot-34b7dc964b3516457f04d00d3ec910d3b6fd585b.tar.gz
ukkobot-34b7dc964b3516457f04d00d3ec910d3b6fd585b.tar.xz
ukkobot-34b7dc964b3516457f04d00d3ec910d3b6fd585b.zip
thank you Q&A, now theres proper unicode support n shit
-rw-r--r--build.zig12
-rw-r--r--build.zig.zon4
-rw-r--r--src/main.zig50
-rw-r--r--src/utils.zig55
4 files changed, 97 insertions, 24 deletions
diff --git a/build.zig b/build.zig
index caf84f5..52d916b 100644
--- a/build.zig
+++ b/build.zig
@@ -7,15 +7,17 @@ pub fn build(b: *Build) void {
7 const target = b.standardTargetOptions(.{}); 7 const target = b.standardTargetOptions(.{});
8 const optimize = b.standardOptimizeOption(.{}); 8 const optimize = b.standardOptimizeOption(.{});
9 9
10 const version = getVersion(b);
11
12 const config = b.addOptions();
13 config.addOption(SemanticVersion, "version", version);
14
10 const sqlite = b.dependency("sqlite", .{ 15 const sqlite = b.dependency("sqlite", .{
11 .target = target, 16 .target = target,
12 .optimize = optimize, 17 .optimize = optimize,
13 }); 18 });
14 19
15 const version = getVersion(b); 20 const zg = b.dependency("zg", .{});
16
17 const config = b.addOptions();
18 config.addOption(SemanticVersion, "version", version);
19 21
20 const exe = b.addExecutable(.{ 22 const exe = b.addExecutable(.{
21 .name = "ukkobot", 23 .name = "ukkobot",
@@ -25,6 +27,8 @@ pub fn build(b: *Build) void {
25 .optimize = optimize, 27 .optimize = optimize,
26 }); 28 });
27 exe.root_module.addOptions("ukkobot-config", config); 29 exe.root_module.addOptions("ukkobot-config", config);
30 exe.root_module.addImport("CaseData", zg.module("CaseData"));
31 exe.root_module.addImport("GenCatData", zg.module("GenCatData"));
28 exe.root_module.addImport("sqlite", sqlite.module("sqlite")); 32 exe.root_module.addImport("sqlite", sqlite.module("sqlite"));
29 exe.linkLibrary(sqlite.artifact("sqlite")); 33 exe.linkLibrary(sqlite.artifact("sqlite"));
30 b.installArtifact(exe); 34 b.installArtifact(exe);
diff --git a/build.zig.zon b/build.zig.zon
index 0346cf0..4a582c0 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -7,5 +7,9 @@
7 .url = "https://git.enes.lv/zig-sqlite/snapshot/zig-sqlite-e4afe26b30e03ee5d8b61946893b19c2585745f8.tar.xz", 7 .url = "https://git.enes.lv/zig-sqlite/snapshot/zig-sqlite-e4afe26b30e03ee5d8b61946893b19c2585745f8.tar.xz",
8 .hash = "122019ea6e071dbd932c3e51d9631d99f007240e3e08d5436a1da20ad088343ca4a7", 8 .hash = "122019ea6e071dbd932c3e51d9631d99f007240e3e08d5436a1da20ad088343ca4a7",
9 }, 9 },
10 .zg = .{
11 .url = "https://git.enes.lv/zg/snapshot/zg-0.13.2.tar.xz",
12 .hash = "122055beff332830a391e9895c044d33b15ea21063779557024b46169fb1984c6e40",
13 },
10 }, 14 },
11} 15}
diff --git a/src/main.zig b/src/main.zig
index 544b105..2e33cfc 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -199,22 +199,29 @@ fn onTextMessage(bot: *Bot, msg: types.Message, text: []const u8) !void {
199 }, 199 },
200 }); 200 });
201 } else if (std.ascii.startsWithIgnoreCase(text, "big ")) { 201 } else if (std.ascii.startsWithIgnoreCase(text, "big ")) {
202 var output = ArrayList(u8).init(bot.allocator); 202 const trimmed = try utils.trim(text[4..]);
203 defer output.deinit(); 203 const cd = try utils.getCD();
204 if (trimmed.len > 0) {
205 const uppercased = try cd.toUpperStr(bot.allocator, trimmed);
206 defer bot.allocator.free(uppercased);
204 207
205 try output.appendSlice("<b>"); 208 var output = ArrayList(u8).init(bot.allocator);
206 try utils.escapeXml(output.writer(), text[4..]); 209 defer output.deinit();
207 try output.appendSlice("</b>");
208 210
209 try bot.sendMessage_(.{ 211 try output.appendSlice("<b>");
210 .chat_id = msg.chat.id, 212 try utils.escapeXml(output.writer(), uppercased);
211 .text = output.items, 213 try output.appendSlice("</b>");
212 .parse_mode = .html, 214
213 .reply_parameters = .{ 215 try bot.sendMessage_(.{
214 .message_id = msg.message_id,
215 .chat_id = msg.chat.id, 216 .chat_id = msg.chat.id,
216 }, 217 .text = output.items,
217 }); 218 .parse_mode = .html,
219 .reply_parameters = .{
220 .message_id = msg.message_id,
221 .chat_id = msg.chat.id,
222 },
223 });
224 }
218 } else if (std.ascii.eqlIgnoreCase(text, "forgor")) { 225 } else if (std.ascii.eqlIgnoreCase(text, "forgor")) {
219 try bot.sendMessage_(.{ 226 try bot.sendMessage_(.{
220 .chat_id = msg.chat.id, 227 .chat_id = msg.chat.id,
@@ -244,14 +251,17 @@ fn onTextMessage(bot: *Bot, msg: types.Message, text: []const u8) !void {
244 }, 251 },
245 }); 252 });
246 } else if (std.ascii.startsWithIgnoreCase(text, "say ")) { 253 } else if (std.ascii.startsWithIgnoreCase(text, "say ")) {
247 try bot.sendMessage_(.{ 254 const trimmed = try utils.trim(text[4..]);
248 .chat_id = msg.chat.id, 255 if (trimmed.len > 0) {
249 .text = text[4..], 256 try bot.sendMessage_(.{
250 .reply_parameters = .{
251 .message_id = msg.message_id,
252 .chat_id = msg.chat.id, 257 .chat_id = msg.chat.id,
253 }, 258 .text = trimmed,
254 }); 259 .reply_parameters = .{
260 .message_id = msg.message_id,
261 .chat_id = msg.chat.id,
262 },
263 });
264 }
255 } else if (std.ascii.eqlIgnoreCase(text, "uwu")) { 265 } else if (std.ascii.eqlIgnoreCase(text, "uwu")) {
256 try bot.sendMessage_(.{ 266 try bot.sendMessage_(.{
257 .chat_id = msg.chat.id, 267 .chat_id = msg.chat.id,
diff --git a/src/utils.zig b/src/utils.zig
index c6e8508..631e464 100644
--- a/src/utils.zig
+++ b/src/utils.zig
@@ -2,6 +2,9 @@ const std = @import("std");
2 2
3const Allocator = std.mem.Allocator; 3const Allocator = std.mem.Allocator;
4const ArrayList = std.ArrayList; 4const ArrayList = std.ArrayList;
5const CaseData = @import("CaseData");
6const GenCatData = @import("GenCatData");
7const Utf8View = std.unicode.Utf8View;
5 8
6pub fn escapeXml(writer: anytype, text: []const u8) !void { 9pub fn escapeXml(writer: anytype, text: []const u8) !void {
7 for (text) |ch| { 10 for (text) |ch| {
@@ -15,6 +18,26 @@ pub fn escapeXml(writer: anytype, text: []const u8) !void {
15 } 18 }
16} 19}
17 20
21var gcd_global: ?GenCatData = null;
22
23pub fn getGCD() !GenCatData {
24 if (gcd_global) |gcd| {
25 return gcd;
26 }
27 gcd_global = try GenCatData.init(std.heap.page_allocator);
28 return gcd_global.?;
29}
30
31var cd_global: ?CaseData = null;
32
33pub fn getCD() !CaseData {
34 if (cd_global) |cd| {
35 return cd;
36 }
37 cd_global = try CaseData.init(std.heap.page_allocator);
38 return cd_global.?;
39}
40
18pub inline fn isNull(value: anytype) bool { 41pub inline fn isNull(value: anytype) bool {
19 return switch (@typeInfo(@TypeOf(value))) { 42 return switch (@typeInfo(@TypeOf(value))) {
20 .Null => true, 43 .Null => true,
@@ -22,3 +45,35 @@ pub inline fn isNull(value: anytype) bool {
22 else => false, 45 else => false,
23 }; 46 };
24} 47}
48
49pub fn trim(str: []const u8) ![]const u8 {
50 const view = try Utf8View.init(str);
51 const gcd = try getGCD();
52
53 var it = view.iterator();
54 var idx: usize = 0;
55 const first = while (it.nextCodepoint()) |cp| {
56 if (!isTrimmable(gcd, cp)) {
57 break idx;
58 }
59 idx = it.i;
60 } else {
61 return "";
62 };
63
64 idx = it.i;
65
66 var last = first;
67 while (it.nextCodepoint()) |cp| {
68 if (!isTrimmable(gcd, cp)) {
69 last = idx + (std.unicode.utf8CodepointSequenceLength(cp) catch unreachable) - 1;
70 }
71 idx = it.i;
72 }
73
74 return str[first .. last + 1];
75}
76
77inline fn isTrimmable(gcd: GenCatData, cp: u21) bool {
78 return gcd.isSeparator(cp) or gcd.isControl(cp);
79}