const std = @import("std"); const Allocator = std.mem.Allocator; /// Remove SDL_ prefix from a name pub fn stripSDLPrefix(name: []const u8) []const u8 { if (std.mem.startsWith(u8, name, "SDL_")) { return name[4..]; } return name; } /// Convert SDL type name to Zig type name /// SDL_GPUDevice -> GPUDevice pub fn typeNameToZig(c_name: []const u8) []const u8 { return stripSDLPrefix(c_name); } /// Convert SDL function name to Zig function name /// SDL_CreateGPUDevice -> createGPUDevice pub fn functionNameToZig(c_name: []const u8, allocator: Allocator) ![]const u8 { const without_prefix = stripSDLPrefix(c_name); if (without_prefix.len == 0) return try allocator.dupe(u8, c_name); // Lowercase the first character var result = try allocator.dupe(u8, without_prefix); if (result.len > 0) { result[0] = std.ascii.toLower(result[0]); } return result; } /// Detect common prefix in a list of names /// Returns the longest common prefix pub fn detectCommonPrefix(names: []const []const u8, allocator: Allocator) ![]const u8 { if (names.len == 0) return try allocator.dupe(u8, ""); if (names.len == 1) return try allocator.dupe(u8, names[0]); const first = names[0]; var prefix_len: usize = 0; // Find longest common prefix outer: for (first, 0..) |c, i| { for (names[1..]) |name| { if (i >= name.len or name[i] != c) { break :outer; } } prefix_len = i + 1; } return try allocator.dupe(u8, first[0..prefix_len]); } /// Convert enum value name to Zig /// SDL_GPU_PRIMITIVETYPE_TRIANGLELIST -> primitivetypeTrianglelist pub fn enumValueToZig(c_name: []const u8, prefix: []const u8, allocator: Allocator) ![]const u8 { // Remove prefix var name = c_name; if (std.mem.startsWith(u8, name, prefix)) { name = name[prefix.len..]; } // Convert SCREAMING_SNAKE_CASE to camelCase return try screaminToLowerCamel(name, allocator); } /// Convert flag name to Zig /// SDL_GPU_TEXTUREUSAGE_SAMPLER -> textureusageSampler pub fn flagNameToZig(c_name: []const u8, prefix: []const u8, allocator: Allocator) ![]const u8 { return enumValueToZig(c_name, prefix, allocator); } /// Convert SCREAMING_SNAKE_CASE to lowerCamelCase fn screaminToLowerCamel(s: []const u8, allocator: Allocator) ![]const u8 { if (s.len == 0) return try allocator.dupe(u8, ""); var result = try std.ArrayList(u8).initCapacity(allocator, s.len); errdefer result.deinit(allocator); var capitalize_next = false; var is_first = true; for (s) |c| { if (c == '_') { capitalize_next = true; continue; } if (is_first) { try result.append(allocator, std.ascii.toLower(c)); is_first = false; } else if (capitalize_next) { try result.append(allocator, std.ascii.toUpper(c)); capitalize_next = false; } else { try result.append(allocator, std.ascii.toLower(c)); } } return try result.toOwnedSlice(allocator); } test "strip SDL prefix" { try std.testing.expectEqualStrings("GPUDevice", stripSDLPrefix("SDL_GPUDevice")); try std.testing.expectEqualStrings("Foo", stripSDLPrefix("SDL_Foo")); try std.testing.expectEqualStrings("Bar", stripSDLPrefix("Bar")); } test "type name to Zig" { try std.testing.expectEqualStrings("GPUDevice", typeNameToZig("SDL_GPUDevice")); try std.testing.expectEqualStrings("GPUPrimitiveType", typeNameToZig("SDL_GPUPrimitiveType")); } test "function name to Zig" { const name1 = try functionNameToZig("SDL_CreateGPUDevice", std.testing.allocator); defer std.testing.allocator.free(name1); try std.testing.expectEqualStrings("createGPUDevice", name1); const name2 = try functionNameToZig("SDL_DestroyGPUDevice", std.testing.allocator); defer std.testing.allocator.free(name2); try std.testing.expectEqualStrings("destroyGPUDevice", name2); } test "detect common prefix" { const names = [_][]const u8{ "SDL_GPU_PRIMITIVETYPE_TRIANGLELIST", "SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP", "SDL_GPU_PRIMITIVETYPE_LINELIST", }; const prefix = try detectCommonPrefix(&names, std.testing.allocator); defer std.testing.allocator.free(prefix); try std.testing.expectEqualStrings("SDL_GPU_PRIMITIVETYPE_", prefix); } test "enum value to Zig" { const result = try enumValueToZig( "SDL_GPU_PRIMITIVETYPE_TRIANGLELIST", "SDL_GPU_PRIMITIVETYPE_", std.testing.allocator, ); defer std.testing.allocator.free(result); try std.testing.expectEqualStrings("trianglelist", result); } test "screaming to lower camel" { const result1 = try screaminToLowerCamel("TRIANGLE_LIST", std.testing.allocator); defer std.testing.allocator.free(result1); try std.testing.expectEqualStrings("triangleList", result1); const result2 = try screaminToLowerCamel("SAMPLER", std.testing.allocator); defer std.testing.allocator.free(result2); try std.testing.expectEqualStrings("sampler", result2); }