diff --git a/build.zig b/build.zig index 9b69db7..80b482b 100644 --- a/build.zig +++ b/build.zig @@ -7,6 +7,7 @@ pub fn build(b: *Builder) void { exe.setBuildMode(mode); exe.linkSystemLibrary("SDL2"); exe.linkSystemLibrary("SDL2_TTF"); + exe.linkSystemLibrary("magic"); exe.linkSystemLibrary("c"); b.default_step.dependOn(&exe.step); diff --git a/src/main.zig b/src/main.zig index 1cd7a26..35c0853 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,280 +1,329 @@ -const std = @import("std"); - -const c = @cImport({ - @cInclude("SDL.h"); - @cInclude("SDL_ttf.h"); -}); - -const assert = @import("std").debug.assert; - -const DrawnText = struct { - surface: [*c]c.SDL_Surface, - texture: ?*c.SDL_Texture, - rect: c.SDL_Rect, -}; - -const FileDocMap = struct { - title_text: DrawnText, - contents: []u8, -}; - -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer { - if(gpa.deinit()) { - std.debug.print("Allocator leak\n", .{}); - } - } - - const allocator = gpa.allocator(); - - const window_width = 300; - const window_height = 500; - const column_width = 100; - - if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0) { - c.SDL_Log("Unable to initialize SDL: %s", c.SDL_GetError()); - return error.SDLInitializationFailed; - } - defer c.SDL_Quit(); - - const screen = c.SDL_CreateWindow("Document Map Viewer", c.SDL_WINDOWPOS_UNDEFINED, c.SDL_WINDOWPOS_UNDEFINED, window_width, window_height, c.SDL_WINDOW_OPENGL) orelse - { - c.SDL_Log("Unable to create window: %s", c.SDL_GetError()); - return error.SDLInitializationFailed; - }; - defer c.SDL_DestroyWindow(screen); - - const renderer = c.SDL_CreateRenderer(screen, -1, 0) orelse { - c.SDL_Log("Unable to create renderer: %s", c.SDL_GetError()); - return error.SDLInitializationFailed; - }; - defer c.SDL_DestroyRenderer(renderer); - - // Turn on anti-aliasing - // :( doesn't seem to work - const aa_result = c.SDL_SetHint(c.SDL_HINT_RENDER_SCALE_QUALITY, "1"); - if (aa_result != c.SDL_TRUE) { - c.SDL_Log("Unable to set anti-aliasing: %d", c.SDL_GetError()); - return error.SDLInitializationFailed; - } - - // https://github.com/cirosantilli/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/ttf.c - const ttf_init_result: c_int = c.TTF_Init(); - if (ttf_init_result != 0) { - c.SDL_Log("Unable to init TTF: %d", ttf_init_result); - return error.TTFInitializationFailed; - } - defer c.TTF_Quit(); - - const text_color: c.SDL_Color = c.SDL_Color { - .r = 0, - .g = 0, - .b = 0, - .a = 255 - }; - - // TODO: can we embed this file? - const font: ?*c.TTF_Font = c.TTF_OpenFont("FreeSans.ttf", 12); - if (font == null) { - const err = c.TTF_GetError(); - c.SDL_Log("Unable to load font: %s", err); - return error.TTFFontLoadFailed; - } - - var file_paths = std.ArrayList([]const u8).init(allocator); - defer file_paths.deinit(); - try file_paths.append("src/main.zig"); - try file_paths.append("GapProbeScan.cs"); - - var file_docmaps = std.ArrayList(FileDocMap).init(allocator); - defer file_docmaps.deinit(); - - for (file_paths.items) |path| { - const surface: [*c]c.SDL_Surface = c.TTF_RenderText_Solid(font, @ptrCast([*c]const u8, path), text_color); - if (surface == null) { - c.SDL_Log("Unable to render text"); - return error.RenderTextFailed; - } - - const texture: ?*c.SDL_Texture = c.SDL_CreateTextureFromSurface(renderer, surface); - if (texture == null) { - c.SDL_Log("Unable to create texture from surface"); - return error.CreateTextureFailed; - } - - var rect = c.SDL_Rect { - .x = 0, - .y = 0, - .w = surface.*.w, - .h = surface.*.h, - }; - - const file = try std.fs.cwd().openFile(path, .{ }); - defer file.close(); - - const stat = try file.stat(); - var buffer = try allocator.alloc(u8, stat.size); - - const bytes_read = try file.readAll(buffer); - if (bytes_read != stat.size) { - std.debug.print("bytes_read: {any}, stat.size: {any}\n", .{ - bytes_read, - stat.size, - }); - return error.FileReadError; - } - - var docmap = FileDocMap { - .title_text = DrawnText { - .surface = surface, - .texture = texture, - .rect = rect, - }, - .contents = buffer, - }; - - try file_docmaps.append(docmap); - } - defer { - for (file_docmaps.items) |docmap| { - c.SDL_FreeSurface(docmap.title_text.surface); - c.SDL_DestroyTexture(docmap.title_text.texture); - allocator.free(docmap.contents); - } - } - - const color_result: c_int = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - if (color_result != 0) { - c.SDL_Log("Unable to set draw color: %d", color_result); - return error.SDLInitializationFailed; - } - - // const surface = c.SDL_GetWindowSurface(screen); - - var quit = false; - while (!quit) { - var event: c.SDL_Event = undefined; - while (c.SDL_PollEvent(&event) != 0) { - switch (event.@"type") { - c.SDL_QUIT => { - quit = true; - }, - else => {}, - } - } - - const initial_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - if (initial_color_result != 0) { - c.SDL_Log("Unable to set draw color: %d", initial_color_result); - return error.SDLInitializationFailed; - } - - // Draw white background - var x: c_int = 0; - while (x < window_width) : (x += 1) { - var y: c_int = 0; - while (y < window_height) : (y += 1) { - const draw_result = c.SDL_RenderDrawPoint(renderer, x, y); - if (draw_result != 0) { - c.SDL_Log("Unable to draw point: %d", draw_result); - return error.SDLDrawingFailed; - } - } - } - - var i: usize = 0; - var column: c_int = 0; - x = 0; - var y: c_int = 0; - - for (file_docmaps.items) |docmap| { - i = 0; - - var rect = c.SDL_Rect { - .x = x, - .y = y, - .w = docmap.title_text.surface.*.w, - .h = docmap.title_text.surface.*.h, - }; - - // Display text - if (c.SDL_RenderCopy(renderer, docmap.title_text.texture, null, &rect) != 0) { - c.SDL_Log("Unable to render copy"); - } - - y += docmap.title_text.rect.h; - // white: false, black: true - var color: bool = false; - while (i < docmap.contents.len) : (i += 1) { - if (docmap.contents[i] == 10) { - y += 1; - if (y > window_height) { - y = 0; - column += 1; - // std.debug.print("Column: {any}, x: {any}\n", .{column, column*column_width}); - } - x = column * column_width; - - continue; - } - - if (docmap.contents[i] == 32 and color) { - color = false; - const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - if (white_color_result != 0) { - c.SDL_Log("Unable to set draw color: %d", white_color_result); - return error.SDLInitializationFailed; - } - } else if (docmap.contents[i] != 32 and !color) { - color = true; - const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - if (black_color_result != 0) { - c.SDL_Log("Unable to set draw color: %d", black_color_result); - return error.SDLInitializationFailed; - } - } - - if (x < (column + 1) * column_width) { - const draw_result = c.SDL_RenderDrawPoint(renderer, x, y); - if (draw_result != 0) { - c.SDL_Log("Unable to draw point: %d", draw_result); - return error.SDLDrawingFailed; - } - } else { - const red_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); - if (red_color_result != 0) { - c.SDL_Log("Unable to set draw color: %d", red_color_result); - return error.SDLInitializationFailed; - } - - const draw_result = c.SDL_RenderDrawPoint(renderer, (column + 1) * column_width - 1, y); - if (draw_result != 0) { - c.SDL_Log("Unable to draw point: %d", draw_result); - return error.SDLDrawingFailed; - } - - if (!color) { - const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); - if (white_color_result != 0) { - c.SDL_Log("Unable to set draw color: %d", white_color_result); - return error.SDLInitializationFailed; - } - } else { - const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - if (black_color_result != 0) { - c.SDL_Log("Unable to set draw color: %d", black_color_result); - return error.SDLInitializationFailed; - } - } - } - - x += 1; - } - } - - c.SDL_RenderPresent(renderer); - - c.SDL_Delay(17); - } -} +const std = @import("std"); + +const c = @cImport({ + @cInclude("SDL.h"); + @cInclude("SDL_ttf.h"); +}); + +const m = @cImport({ + @cInclude("magic.h"); +}); + +const assert = @import("std").debug.assert; + +const DrawnText = struct { + surface: [*c]c.SDL_Surface, + texture: ?*c.SDL_Texture, + rect: c.SDL_Rect, +}; + +const FileDocMap = struct { + title_text: DrawnText, + contents: []u8, +}; + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer { + if (gpa.deinit()) { + std.debug.print("Allocator leak\n", .{}); + } + } + + var magic = m.magic_open(m.MAGIC_MIME | m.MAGIC_CHECK); + const load_result = m.magic_load(magic, null); + if (load_result != 0) { + std.debug.print("Unable to initialize magic: {d}", .{load_result}); + return error.MagicInitializationFailed; + } + + const allocator = gpa.allocator(); + + const args = try std.process.argsAlloc(allocator); + defer std.process.argsFree(allocator, args); + + const window_width = 700; + const window_height = 500; + const column_width = 100; + + if (c.SDL_Init(c.SDL_INIT_VIDEO) != 0) { + c.SDL_Log("Unable to initialize SDL: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + } + defer c.SDL_Quit(); + + const screen = c.SDL_CreateWindow("Document Map Viewer", c.SDL_WINDOWPOS_UNDEFINED, c.SDL_WINDOWPOS_UNDEFINED, window_width, window_height, c.SDL_WINDOW_OPENGL) orelse + { + c.SDL_Log("Unable to create window: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + }; + defer c.SDL_DestroyWindow(screen); + + const renderer = c.SDL_CreateRenderer(screen, -1, 0) orelse { + c.SDL_Log("Unable to create renderer: %s", c.SDL_GetError()); + return error.SDLInitializationFailed; + }; + defer c.SDL_DestroyRenderer(renderer); + + // Turn on anti-aliasing + // :( doesn't seem to work + const aa_result = c.SDL_SetHint(c.SDL_HINT_RENDER_SCALE_QUALITY, "1"); + if (aa_result != c.SDL_TRUE) { + c.SDL_Log("Unable to set anti-aliasing: %d", c.SDL_GetError()); + return error.SDLInitializationFailed; + } + + // https://github.com/cirosantilli/cpp-cheat/blob/e52ed4b838e2697d8f44ab5bef3e7a170705d48e/sdl/ttf.c + const ttf_init_result: c_int = c.TTF_Init(); + if (ttf_init_result != 0) { + c.SDL_Log("Unable to init TTF: %d", ttf_init_result); + return error.TTFInitializationFailed; + } + defer c.TTF_Quit(); + + const text_color: c.SDL_Color = c.SDL_Color{ .r = 0, .g = 0, .b = 0, .a = 255 }; + + // TODO: can we embed this file? + const font: ?*c.TTF_Font = c.TTF_OpenFont("FreeSans.ttf", 12); + if (font == null) { + const err = c.TTF_GetError(); + c.SDL_Log("Unable to load font: %s", err); + return error.TTFFontLoadFailed; + } + + var file_paths = std.ArrayList([]const u8).init(allocator); + defer file_paths.deinit(); + defer { + for (file_paths.items) |item| { + allocator.free(item); + } + } + + var args_i: usize = 1; + while (args_i < args.len) : (args_i += 1) { + const arg = args[args_i]; + if (std.fs.cwd().openIterableDir(arg, .{})) |iter_dir| { + std.debug.print("searching dir for files: '{s}'\n", .{arg}); + + var iter = iter_dir.iterate(); + while (try iter.next()) |entry| { + if (entry.kind == .File) { + const entry_path = try std.fmt.allocPrint(allocator, "{s}{c}{s}\x00", .{ + arg, + std.fs.path.sep, + entry.name, + }); + const magic_result = m.magic_file(magic, @ptrCast([*c]const u8, entry_path)); + std.debug.print("'{s}': {s}\n", .{ entry.name, magic_result }); + if (std.mem.eql(u8, magic_result[0..5], "text/")) { + try file_paths.append(entry_path[0..(entry_path.len - 1)]); + } else { + allocator.free(entry_path); + } + } + } + } else |_| { + if (std.fs.cwd().openFile(arg, .{})) |file| { + file.close(); + std.debug.print("Will do docmap for: '{s}'\n", .{arg}); + var path = try allocator.alloc(u8, arg.len); + std.mem.copy(u8, path, arg); + try file_paths.append(path); + } else |_| { + std.debug.print("Arg not file: '{s}'\n", .{arg}); + } + } + } + + var file_docmaps = std.ArrayList(FileDocMap).init(allocator); + defer file_docmaps.deinit(); + + for (file_paths.items) |path| { + const surface: [*c]c.SDL_Surface = c.TTF_RenderText_Solid(font, @ptrCast([*c]const u8, path), text_color); + if (surface == null) { + c.SDL_Log("Unable to render text"); + return error.RenderTextFailed; + } + + const texture: ?*c.SDL_Texture = c.SDL_CreateTextureFromSurface(renderer, surface); + if (texture == null) { + c.SDL_Log("Unable to create texture from surface"); + return error.CreateTextureFailed; + } + + var rect = c.SDL_Rect{ + .x = 0, + .y = 0, + .w = surface.*.w, + .h = surface.*.h, + }; + + std.debug.print("open file: {s}\n", .{path}); + const file = try std.fs.cwd().openFile(path, .{}); + defer file.close(); + + const stat = try file.stat(); + var buffer = try allocator.alloc(u8, stat.size); + + const bytes_read = try file.readAll(buffer); + if (bytes_read != stat.size) { + std.debug.print("bytes_read: {any}, stat.size: {any}\n", .{ + bytes_read, + stat.size, + }); + return error.FileReadError; + } + + var docmap = FileDocMap{ + .title_text = DrawnText{ + .surface = surface, + .texture = texture, + .rect = rect, + }, + .contents = buffer, + }; + + try file_docmaps.append(docmap); + } + defer { + for (file_docmaps.items) |docmap| { + c.SDL_FreeSurface(docmap.title_text.surface); + c.SDL_DestroyTexture(docmap.title_text.texture); + allocator.free(docmap.contents); + } + } + + const color_result: c_int = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + if (color_result != 0) { + c.SDL_Log("Unable to set draw color: %d", color_result); + return error.SDLInitializationFailed; + } + + // const surface = c.SDL_GetWindowSurface(screen); + + var quit = false; + while (!quit) { + var event: c.SDL_Event = undefined; + while (c.SDL_PollEvent(&event) != 0) { + switch (event.@"type") { + c.SDL_QUIT => { + quit = true; + }, + else => {}, + } + } + + const initial_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + if (initial_color_result != 0) { + c.SDL_Log("Unable to set draw color: %d", initial_color_result); + return error.SDLInitializationFailed; + } + + // Draw white background + var x: c_int = 0; + while (x < window_width) : (x += 1) { + var y: c_int = 0; + while (y < window_height) : (y += 1) { + const draw_result = c.SDL_RenderDrawPoint(renderer, x, y); + if (draw_result != 0) { + c.SDL_Log("Unable to draw point: %d", draw_result); + return error.SDLDrawingFailed; + } + } + } + + var i: usize = 0; + var column: c_int = 0; + x = 0; + var y: c_int = 0; + + for (file_docmaps.items) |docmap| { + i = 0; + + var rect = c.SDL_Rect{ + .x = x, + .y = y, + .w = docmap.title_text.surface.*.w, + .h = docmap.title_text.surface.*.h, + }; + + // Display text + if (c.SDL_RenderCopy(renderer, docmap.title_text.texture, null, &rect) != 0) { + c.SDL_Log("Unable to render copy"); + } + + y += docmap.title_text.rect.h; + // white: false, black: true + var color: bool = false; + while (i < docmap.contents.len) : (i += 1) { + if (docmap.contents[i] == 10) { + y += 1; + if (y > window_height) { + y = 0; + column += 1; + // std.debug.print("Column: {any}, x: {any}\n", .{column, column*column_width}); + } + x = column * column_width; + + continue; + } + + if (docmap.contents[i] == 32 and color) { + color = false; + const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + if (white_color_result != 0) { + c.SDL_Log("Unable to set draw color: %d", white_color_result); + return error.SDLInitializationFailed; + } + } else if (docmap.contents[i] != 32 and !color) { + color = true; + const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + if (black_color_result != 0) { + c.SDL_Log("Unable to set draw color: %d", black_color_result); + return error.SDLInitializationFailed; + } + } + + if (x < (column + 1) * column_width) { + const draw_result = c.SDL_RenderDrawPoint(renderer, x, y); + if (draw_result != 0) { + c.SDL_Log("Unable to draw point: %d", draw_result); + return error.SDLDrawingFailed; + } + } else { + const red_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); + if (red_color_result != 0) { + c.SDL_Log("Unable to set draw color: %d", red_color_result); + return error.SDLInitializationFailed; + } + + const draw_result = c.SDL_RenderDrawPoint(renderer, (column + 1) * column_width - 1, y); + if (draw_result != 0) { + c.SDL_Log("Unable to draw point: %d", draw_result); + return error.SDLDrawingFailed; + } + + if (!color) { + const white_color_result = c.SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); + if (white_color_result != 0) { + c.SDL_Log("Unable to set draw color: %d", white_color_result); + return error.SDLInitializationFailed; + } + } else { + const black_color_result = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + if (black_color_result != 0) { + c.SDL_Log("Unable to set draw color: %d", black_color_result); + return error.SDLInitializationFailed; + } + } + } + + x += 1; + } + } + + c.SDL_RenderPresent(renderer); + + c.SDL_Delay(17); + } +}